262 lines
7.2 KiB
Vue
262 lines
7.2 KiB
Vue
<template>
|
|
<view @touchmove.prevent class="_movcontain" :style="'width:'+width+';height:'+height+'; overflow: hidden;'">
|
|
<view :style="{width:cwidth+'px',height:cheight+'px',transition:trans, transformOrigin:'0 0', transform: 'translate('+mapx+'px,'+mapy+'px) scale('+scale+')'}" @touchstart="handleTouchStart" @touchmove="handleTouchMove" @touchend="handleTouchEnd">
|
|
<image :src="src" style="width:100%;height:100%;" />
|
|
<view v-for="(item,index) in boxs" :key="index" class="abs t0 l0" :style="{zIndex:item.z,transform: 'translate('+item.x+'px,'+item.y+'px)'}" @tap="boxtap(index)" @touchstart="boxhandleTouchStart($event, index)" @touchmove="boxhandleTouchMove($event, index)" @touchend="boxhandleTouchEnd($event, index)">
|
|
<slot :box="item"></slot>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
</template>
|
|
|
|
<script>
|
|
export default {
|
|
emits: ['change', 'boxclick'],
|
|
props: {
|
|
width: {
|
|
type: String,
|
|
default: '100%'
|
|
},
|
|
height: {
|
|
type: String,
|
|
default: '100vw'
|
|
},
|
|
boxmove: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
},
|
|
data() {
|
|
return {
|
|
src: '',
|
|
containwidth: 0,
|
|
containheight: 0,
|
|
cwidth: 0,
|
|
cheight: 0,
|
|
trans: '',
|
|
|
|
scale: 1,
|
|
minScale: 0.5,
|
|
maxScale: 5,
|
|
mapx: 0,
|
|
mapy: 0,
|
|
last: {
|
|
x: 0,
|
|
y: 0
|
|
},
|
|
isDragging: false, // 是否正在拖拽
|
|
initialDistance: 0, // 初始双指距离
|
|
initialScale: 1, // 初始缩放比例
|
|
|
|
boxisDragging: false, // 是否正在拖拽
|
|
boxindex: 0,
|
|
boxs: []
|
|
};
|
|
},
|
|
watch: {},
|
|
computed: {},
|
|
mounted() {},
|
|
methods: {
|
|
Setbox(boxs) {
|
|
this.zindex = 0;
|
|
this.boxs = boxs;
|
|
for (var i = 0; i < this.boxs.length; i++) {
|
|
if (this.boxs[i].z === undefined)
|
|
continue;
|
|
if (this.boxs[i].z > this.zindex)
|
|
this.zindex = this.boxs[i].z;
|
|
}
|
|
},
|
|
Getbox() {
|
|
return this.objclone(this.boxs);
|
|
},
|
|
Setmap(opn) {
|
|
this.src = this.file_stor(opn.src);
|
|
// #ifdef MP-WEIXIN
|
|
this.src = this.src.replace('http://', 'https://');
|
|
// #endif
|
|
this.getrect('._movcontain').then(res => {
|
|
this.containwidth = res.width;
|
|
this.containheight = res.height;
|
|
});
|
|
uni.getImageInfo({
|
|
src: this.src,
|
|
success: res => {
|
|
this.cwidth = res.width;
|
|
this.cheight = res.height;
|
|
this.mapx = -this.toint(opn.x);
|
|
this.mapy = -this.toint(opn.y);
|
|
this.scale = opn.scale;
|
|
},
|
|
fail: res => {
|
|
console.log('getImageInfo err', res);
|
|
}
|
|
});
|
|
},
|
|
handleTouchStart(e) {
|
|
this.trans = '';
|
|
this.pagenoscroll(true);
|
|
if (e.touches.length === 1) {
|
|
// 单指触摸
|
|
this.isDragging = true
|
|
this.last.x = e.touches[0].clientX
|
|
this.last.y = e.touches[0].clientY
|
|
} else if (e.touches.length === 2) {
|
|
// 双指触摸
|
|
this.isDragging = false
|
|
const x1 = e.touches[0].clientX
|
|
const y1 = e.touches[0].clientY
|
|
const x2 = e.touches[1].clientX
|
|
const y2 = e.touches[1].clientY
|
|
this.initialDistance = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2))
|
|
this.initialScale = this.scale
|
|
}
|
|
},
|
|
handleTouchMove(e) {
|
|
if (e.touches.length === 1 && this.isDragging) {
|
|
// 单指移动 - 平移
|
|
const deltaX = e.touches[0].clientX - this.last.x
|
|
const deltaY = e.touches[0].clientY - this.last.y
|
|
|
|
this.last.x = e.touches[0].clientX
|
|
this.last.y = e.touches[0].clientY
|
|
// 计算新的位置
|
|
let newTranslateX = this.mapx + deltaX
|
|
let newTranslateY = this.mapy + deltaY
|
|
|
|
this.mapx = newTranslateX
|
|
this.mapy = newTranslateY
|
|
this.last.x = e.touches[0].clientX
|
|
this.last.y = e.touches[0].clientY
|
|
} else if (e.touches.length === 2) {
|
|
// 双指移动 - 缩放
|
|
const x1 = e.touches[0].clientX
|
|
const y1 = e.touches[0].clientY
|
|
const x2 = e.touches[1].clientX
|
|
const y2 = e.touches[1].clientY
|
|
const currentDistance = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2))
|
|
|
|
if (this.initialDistance > 0) {
|
|
let newScale = this.initialScale * (currentDistance / this.initialDistance)
|
|
newScale = Math.min(Math.max(newScale, this.minScale), this.maxScale)
|
|
|
|
// 计算缩放中心点
|
|
const centerX = (x1 + x2) / 2
|
|
const centerY = (y1 + y2) / 2
|
|
|
|
// 调整位置使缩放中心保持稳定
|
|
const ratio = (newScale - this.scale) / this.scale
|
|
this.mapx -= (centerX - this.mapx) * ratio
|
|
this.mapy -= (centerY - this.mapy) * ratio
|
|
|
|
this.scale = newScale
|
|
}
|
|
}
|
|
},
|
|
handleTouchEnd() {
|
|
this.trans = 'transform 0.5s';
|
|
this.pagenoscroll(false);
|
|
this.isDragging = false
|
|
this.initialDistance = 0
|
|
// 缩放结束后检查边界
|
|
const containerWidth = this.containwidth
|
|
const containerHeight = this.containheight
|
|
const imageWidth = this.cwidth * this.scale
|
|
const imageHeight = this.cheight * this.scale
|
|
|
|
// X轴边界检查
|
|
const maxX = containerWidth - imageWidth
|
|
const minX = 0
|
|
if (this.mapx < maxX / 2) {
|
|
if (this.mapx < maxX)
|
|
this.mapx = maxX
|
|
} else {
|
|
if (this.mapx > minX)
|
|
this.mapx = minX
|
|
}
|
|
|
|
// Y轴边界检查
|
|
const maxY = containerHeight - imageHeight
|
|
const minY = 0
|
|
if (this.mapy < maxY / 2) {
|
|
if (this.mapy < maxY)
|
|
this.mapy = maxY
|
|
} else {
|
|
if (this.mapy > minY)
|
|
this.mapy = minY
|
|
}
|
|
this.$emit('change', {
|
|
x: this.mapx,
|
|
y: this.mapy,
|
|
sacle: this.sacle,
|
|
index: -1,
|
|
boxs: this.boxs
|
|
});
|
|
},
|
|
boxtap(index) {
|
|
this.$emit('boxclick', {
|
|
index: index,
|
|
boxs: this.boxs
|
|
});
|
|
},
|
|
boxhandleTouchStart(e, index) {
|
|
if (!this.boxmove)
|
|
return;
|
|
e.stopPropagation()
|
|
this.pagenoscroll(true);
|
|
this.boxisDragging = true
|
|
this.boxindex = index;
|
|
this.last.x = e.touches[0].clientX
|
|
this.last.y = e.touches[0].clientY
|
|
if (typeof(this.boxs[this.boxindex].z) == 'number')
|
|
this.boxs[this.boxindex].z = ++this.zindex;
|
|
},
|
|
boxhandleTouchMove(e, index) {
|
|
e.stopPropagation()
|
|
if (!this.boxisDragging)
|
|
return;
|
|
|
|
// 单指移动 - 平移
|
|
const deltaX = (e.touches[0].clientX - this.last.x) / this.scale
|
|
const deltaY = (e.touches[0].clientY - this.last.y) / this.scale
|
|
|
|
this.last.x = e.touches[0].clientX
|
|
this.last.y = e.touches[0].clientY
|
|
// 计算新的位置
|
|
let newTranslateX = this.boxs[this.boxindex].x + deltaX
|
|
let newTranslateY = this.boxs[this.boxindex].y + deltaY
|
|
|
|
this.boxs[this.boxindex].x = newTranslateX
|
|
this.boxs[this.boxindex].y = newTranslateY
|
|
this.last.x = e.touches[0].clientX
|
|
this.last.y = e.touches[0].clientY
|
|
},
|
|
boxhandleTouchEnd(e) {
|
|
e.stopPropagation()
|
|
this.pagenoscroll(false);
|
|
this.boxisDragging = false
|
|
if (this.boxs[this.boxindex].x < 0)
|
|
this.boxs[this.boxindex].x = 0;
|
|
if (this.boxs[this.boxindex].y < 0)
|
|
this.boxs[this.boxindex].y = 0;
|
|
const maxx = this.cwidth - this.toint(this.boxs[this.boxindex].w);
|
|
const maxy = this.cheight - this.toint(this.boxs[this.boxindex].h);
|
|
if (this.boxs[this.boxindex].x > maxx)
|
|
this.boxs[this.boxindex].x = maxx;
|
|
if (this.boxs[this.boxindex].y > maxy)
|
|
this.boxs[this.boxindex].y = maxy;
|
|
|
|
this.$emit('change', {
|
|
x: this.mapx,
|
|
y: this.mapy,
|
|
sacle: this.sacle,
|
|
index: this.boxindex,
|
|
boxs: this.boxs
|
|
});
|
|
},
|
|
}
|
|
}
|
|
</script>
|
|
<style scoped>
|
|
</style> |