c5_labsci/fapp/ciyon_ap/components/ciy-movable/ciy-movable.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>