<template> <view v-show="properties.content" class="ksp-image-cutter" @tap="onok" style="position: relative; width: 100%; height: 100%; overflow: hidden;"> <view class="body"> <!-- 背景图 --> <!-- <image v-if="properties.content" class="image" @load="imageLoad" :style="{left: image.left + 'px', top: image.top + 'px', width: image.width + 'px', height: image.height + 'px',transform: 'rotate(' + properties.angle + 'deg)'}" :src="properties.content"></image> --> <view v-if="mask.show" class="mask"></view> <!-- 窗口 --> <view @touchstart="touchStart($event, 'plank')" :data-time="lastTapTime" @touchmove="touchMove" @touchend="touchEnd" @touchcancel="touchCancel" class="plank" :style="{transform: 'rotate(' + properties.angle + 'deg)'}"> <view class="frame" @touchstart="touchStart($event, 'frame')" @touchstart.stop.prevent="touchHandle" :data-time="lastTapTime" :style="{left: frame.left + 'px', top: frame.top + 'px', width: frame.width + 'px', height: frame.height + 'px'}"> <!-- 图片 --> <image v-if="properties.content" class="image" :data-time="lastTapTime" @load="imageLoad" :style="{'margin-left': -(frame.left - image.left) + 'px', 'margin-top': -(frame.top - image.top) + 'px', width: image.width + 'px', height: image.height + 'px'}" :src="properties.content"></image> <view class="rect"></view> <view class="line-one"></view> <view class="line-two"></view> <view class="line-three"></view> <view class="line-four"></view> <view @touchstart="touchStart($event, 'left')" @touchstart.stop.prevent="touchHandle" class="frame-left"> <view class='left_edge'></view> </view> <view @touchstart="touchStart($event, 'right')" @touchstart.stop.prevent="touchHandle" class="frame-right"> <view class='rightedge'> </view> </view> <view @touchstart="touchStart($event, 'top')" @touchstart.stop.prevent="touchHandle" class="frame-top"> <view class='topedge'> </view> </view> <view @touchstart="touchStart($event, 'bottom')" @touchstart.stop.prevent="touchHandle" class="frame-bottom"> <view class='bottomedge'> </view> </view> <view @touchstart="touchStart($event, 'left-top')" @touchstart.stop.prevent="touchHandle" class="frame-left-top-wrap"> <view class='frame-left-top'> </view> </view> <view @touchstart="touchStart($event, 'left-bottom')" @touchstart.stop.prevent="touchHandle" class="frame-left-bottom-wrap"> <view class='frame-left-bottom'> </view> </view> <view @touchstart="touchStart($event, 'right-top')" @touchstart.stop.prevent="touchHandle" class="frame-right-top-wrap"> <view class='frame-right-top'> </view> </view> <view @touchstart="touchStart($event, 'right-bottom')" @touchstart.stop.prevent="touchHandle" class="frame-right-bottom-wrap"> <view class='frame-right-bottom'> </view> </view> </view> </view> </view> </view> </template> <script> import drag from '../../pages/index/js/drag.js'// 封装 export default { props: { properties: { type: Object, default () { return {} } }, url: { type: String, default: "" }, fixed: { type: Boolean, default: false }, width: { type: Number, default: 200 }, height: { type: Number, default: 200 }, maxWidth: { type: Number, default: 1024 }, maxHeight: { type: Number, default: 1024 }, blob: { type: Boolean, default: true } }, data() { return { mask: { show: false }, // 裁剪的窗口 frame: { left: 100, top: 100, width: this.properties.width, height: this.properties.height }, // 背景图 image: { left: 100, top: 100, width: this.properties.initialWidth, height: this.properties.initialHeight }, // 背景图初始 real: { width: this.properties.initialWidth, height: this.properties.initialHeight }, // 裁剪的窗口初始 target: { width: this.properties.width, height: this.properties.height }, touches: [], type: "", start: { frame: { left: 0, top: 0, width: 0, height: 0 }, image: { left: 0, top: 0, width: 0, height: 0 }, }, timeoutId: -1, context: Object, targetContext: Object, // 后添加属性值 Centerleft: null, Centertop: null, lastTapTime: 0, //判断点击时间间隔 }; }, mounted() { //#ifdef H5 this.$el.addEventListener("touchmove", (ev) => { ev.preventDefault(); }); // #endif // this.context = uni.createCanvasContext("canvas", this); // this.targetContext = uni.createCanvasContext("target", this); }, methods: { doubleTap(e){ console.log(e) var curTime = e.timeStamp var lastTime = e.currentTarget.dataset.time // 通过e.currentTarget.dataset.time 访问到绑定到该组件的自定义数据 if (curTime - lastTime > 0) { if (curTime - lastTime < 300) { //是双击事件 } } this.lastTapTime = curTime }, /** * 初始化方法 * 获取图片宽高后,把图片缩放至剪切框大小, * 并使剪切框位于图片中央 **/ init() { if (!this.properties.content) return let { windowWidth, windowHeight, pixelRatio } = wx.getSystemInfoSync() let clipSize = windowWidth / 750 let clipHeight = windowHeight / 1206 // console.log(windowHeight / windowWidth) // 计算宽度高度 this.real.width = this.properties.initialWidth * this.properties.initialScale this.real.height = this.properties.initialHeight * this.properties.initialScale this.image.width = this.properties.initialWidth * this.properties.initialScale this.image.height = this.properties.initialHeight * this.properties.initialScale this.image.angle = this.properties.angle this.frame.width = this.properties.width; this.frame.height = this.properties.height; this.frame.angle = this.properties.angle; // 默认居中 this.Centerleft = (windowWidth - this.properties.width) / 2 - this.properties.frame_left this.Centertop = (windowHeight - this.properties.height) / 2 - this.properties.frame_top this.image.left = this.Centerleft this.image.top = this.Centertop this.frame.left = this.Centerleft this.frame.top = this.Centertop // 有值替换 if (this.properties.frame_left) { this.frame.left = this.properties.frame_left + this.Centerleft } if (this.properties.frame_top) { this.frame.top = this.properties.frame_top + this.Centertop } if (this.properties.image_left) { this.image.left = this.properties.image_left + this.Centerleft } if (this.properties.image_top) { this.image.top = this.properties.image_top + this.Centertop } // 初始化的位置 drag.initPos(this.frame) drag.initPos(this.image) }, imageLoad(ev) { this.mask.show = true; }, touchHandle(ev) { console.log(ev) var curTime = ev.timeStamp var lastTime = ev.currentTarget.dataset.time // 通过e.currentTarget.dataset.time 访问到绑定到该组件的自定义数据 if (curTime - lastTime > 0) { if (curTime - lastTime < 300) { //是双击事件 this.onok() } } this.lastTapTime = curTime }, touchStart(ev, type) { this.mask.show = false; if (this.touches.length == 0) { this.type = type; this.start.frame.left = this.frame.left; this.start.frame.top = this.frame.top; this.start.frame.width = this.frame.width; this.start.frame.height = this.frame.height; this.start.image.left = this.image.left; this.start.image.top = this.image.top; this.start.image.width = this.image.width; this.start.image.height = this.image.height; } var touches = ev.changedTouches; for (var i = 0; i < touches.length; i++) { var touch = touches[i]; this.touches.push(touch); } }, touchMove(ev) { ev.preventDefault(); var touches = ev.touches; // 点击 if (this.touches.length == 1) { if (this.type == "plank" || this.type == "frame" || this.fixed) { this.moveImage(this.touches[0], touches[0]); } else { this.scaleFrame(this.touches[0], touches[0], this.type); } } else if (this.touches.length == 2 && touches.length == 2) { // 双指头操作 var ta = this.touches[0]; var tb = this.touches[1]; var tc = touches[0]; var td = touches[1]; if (ta.identifier != tc.identifier) { var temp = tc; tc = td; td = temp; } this.scaleImage(ta, tb, tc, td); } }, touchEnd(ev) { this.type = ""; this.touches = []; drag.getTransferPosition(this.frame.left, this.frame.top, this.frame.width, this.frame.height, this.frame.angle, this.frame.centerPos,this.frame) drag.getTransferPosition(this.image.left, this.image.top, this.image.width, this.image.height, this.image.angle, this.image.centerPos,this.image) }, touchCancel(ev) { this.type = ""; this.touches = []; }, moveImage(ta, tb) { // 计算角度 // let roat = Math.abs(this.properties.angle) % 360 // if (this.properties.angle < 0) { // let multiple = Math.ceil(Math.abs(this.properties.angle) / 360) // roat = this.properties.angle + multiple * 360 // } var ax = tb.clientX - ta.clientX; var ay = tb.clientY - ta.clientY; this.image.left = this.start.image.left + ax; this.image.top = this.start.image.top + ay; if (this.image.left > this.frame.left) { this.image.left = this.frame.left; } if (this.image.top > this.frame.top) { this.image.top = this.frame.top; } if (this.image.left + this.image.width < this.frame.left + this.frame.width) { this.image.left = this.frame.left + this.frame.width - this.image.width; } if (this.image.top + this.image.height < this.frame.top + this.frame.height) { this.image.top = this.frame.top + this.frame.height - this.image.height; } }, scaleImage(ta, tb, tc, td) { var x1 = ta.clientX; var y1 = ta.clientY; var x2 = tb.clientX; var y2 = tb.clientY; var x3 = tc.clientX; var y3 = tc.clientY; var x4 = td.clientX; var y4 = td.clientY; var ol = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); var el = Math.sqrt((x3 - x4) * (x3 - x4) + (y3 - y4) * (y3 - y4)); var ocx = (x1 + x2) / 2; var ocy = (y1 + y2) / 2; var ecx = (x3 + x4) / 2; var ecy = (y3 + y4) / 2; var ax = ecx - ocx; var ay = ecy - ocy; var scale = el / ol; if (this.start.image.width * scale < this.frame.width) { scale = this.frame.width / this.start.image.width; } if (this.start.image.height * scale < this.frame.height) { scale = this.frame.height / this.start.image.height; } if (this.start.image.width * scale < this.frame.width) { scale = this.frame.width / this.start.image.width; } this.image.left = this.start.image.left + ax - (ocx - this.start.image.left) * (scale - 1); this.image.top = this.start.image.top + ay - (ocy - this.start.image.top) * (scale - 1); this.image.width = this.start.image.width * scale; this.image.height = this.start.image.height * scale; if (this.image.left > this.frame.left) { this.image.left = this.frame.left; } if (this.image.top > this.frame.top) { this.image.top = this.frame.top; } if (this.image.left + this.image.width < this.frame.left + this.frame.width) { this.image.left = this.frame.left + this.frame.width - this.image.width; } if (this.image.top + this.image.height < this.frame.top + this.frame.height) { this.image.top = this.frame.top + this.frame.height - this.image.height; } }, scaleFrame(ta, tb, type) { // 计算角度 var ax = tb.clientX - ta.clientX; var ay = tb.clientY - ta.clientY; var x1 = this.start.frame.left; var y1 = this.start.frame.top; var x2 = this.start.frame.left + this.start.frame.width; var y2 = this.start.frame.top + this.start.frame.height; if (type == "left") { x1 += ax; this.frame.width = x2 - x1; if(this.frame.width <= 50){ x1 = x2 - 50 } } else if (type == "right") { x2 += ax; this.frame.width = x2 - x1; if(this.frame.width <= 50){ x2 = x1 + 50 } } else if (type == "top") { y1 += ay; this.frame.height = y2 - y1; if(this.frame.height <= 50){ y1 = y2 - 50 } } else if (type == "bottom") { y2 += ay; this.frame.height = y2 - y1; if(this.frame.height <= 50){ y2 = y1 + 50 } } else if (type == "left-top") { x1 += ax; y1 += ay; this.frame.width = x2 - x1; if(this.frame.width <= 50){ x1 = x2 - 50 } this.frame.height = y2 - y1; if(this.frame.height <= 50){ y1 = y2 - 50 } } else if (type == "left-bottom") { x1 += ax; y2 += ay; this.frame.width = x2 - x1; if(this.frame.width <= 50){ x1 = x2 - 50 } this.frame.height = y2 - y1; if(this.frame.height <= 50){ y2 = y1 + 50 } } else if (type == "right-top") { x2 += ax; y1 += ay; this.frame.width = x2 - x1; if(this.frame.width <= 50){ x2 = x1 + 50 } this.frame.height = y2 - y1; if(this.frame.height <= 50){ y1 = y2 - 50 } } else if (type == "right-bottom") { x2 += ax; y2 += ay; this.frame.width = x2 - x1; if(this.frame.width <= 50){ x2 = x1 + 50 } this.frame.height = y2 - y1; if(this.frame.height <= 50){ y2 = y1 + 50 } } if (x1 < this.image.left) { x1 = this.image.left; } if (y1 < this.image.top) { y1 = this.image.top; } if (x2 > this.image.left + this.image.width) { x2 = this.image.left + this.image.width; } if (y2 > this.image.top + this.image.height) { y2 = this.image.top + this.image.height; } this.frame.left = x1; this.frame.top = y1; this.frame.width = x2 - x1; this.frame.height = y2 - y1; }, onok() { var scale = this.image.width / this.real.width; var x = (this.frame.left - this.image.left) / scale; var y = (this.frame.top - this.image.top) / scale; var width = this.frame.width / scale; var height = this.frame.height / scale; var tw = width; var th = height; // if (this.fixed) { // tw = this.width / 2; // th = this.height / 2; // } else { // if (tw > this.maxWidth / 2) { // var sc = this.maxWidth / 2 / tw; // tw = tw * sc; // th = th * sc; // } // if (th > this.maxHeight / 2) { // var sc = this.maxHeight / 2 / th; // th = th * sc; // tw = tw * sc; // } // } this.target.width = tw; this.target.height = th; // 复制数据 // 裁剪的宽和高 this.properties.width = this.frame.width this.properties.height = this.frame.height // 图片放大比率 this.properties.initialScale = this.properties.initialScale * scale this.properties.initialscaling = this.properties.initialScale // 裁剪区和原图顶点 this.properties.frame_left = 0 this.properties.frame_top = 0 this.properties.image_left = -(this.frame.left - this.image.left) this.properties.image_top = -(this.frame.top - this.image.top) // 初始x,y放大比率 this.properties.initialScalex = 1 this.properties.initialScaley = 1 this.$emit('ok', this.properties); }, // 返回 oncancle() { this.$emit("cancel"); } } } </script> <style lang="scss" scoped> .ksp-image-cutter { position: absolute; width: 100%; height: 100%; top: 0; bottom: 0; z-index: 1000; } .body { position: absolute; left: 0upx; right: 0upx; top: 0upx; bottom: 0upx; } .mask { position: absolute; left: 0upx; right: 0upx; top: 0upx; bottom: 0upx; background: black; opacity: 0.4; } .plank { position: absolute; left: 0upx; right: 0upx; top: 0upx; bottom: 0upx; } .image { position: absolute; } .frame { position: absolute; } .canvas { position: absolute; display: block; left: 0px; top: 0px; } .rect { position: absolute; left: -2px; top: -2px; width: 100%; height: 100%; border: 2px solid white; } .line-one { position: absolute; width: 100%; height: 1px; background: white; left: 0; top: 33.3%; } .line-two { position: absolute; width: 100%; height: 1px; background: white; left: 0; top: 66.7%; } .line-three { position: absolute; width: 1px; height: 100%; background: white; top: 0; left: 33.3%; } .line-four { position: absolute; width: 1px; height: 100%; background: white; top: 0; left: 66.7%; } .frame-left { position: absolute; left: -30upx; width: 40upx; height: 100%; top: 0; background: transparent; .left_edge { position: absolute; z-index: 99; left: 24upx; width: 6upx; height: 40upx; background: #5CE6B5; top: calc(50% - 20upx); } } .frame-right { position: absolute; z-index: 99; right: -30upx; width: 40upx; height: 100%; background: transparent; top: 0; .rightedge { position: absolute; z-index: 99; right: 24upx; width: 6upx; height: 40upx; background: #5CE6B5; top: calc(50% - 20upx); } } .frame-top { position: absolute; z-index: 99; top: -30upx; width: 100%; height: 40upx; background: transparent; left: 0; right: 0; margin: auto; .topedge { position: absolute; z-index: 99; top: 24upx; width: 40upx; height: 6upx; background: #5CE6B5; left: 0; right: 0; margin: auto; } } .frame-bottom { position: absolute; z-index: 99; bottom: -30upx; width: 100%; height: 40upx; background: transparent; left: 0; right: 0; margin: auto; .bottomedge { position: absolute; z-index: 99; bottom: 24upx; width: 40upx; height: 6upx; background: #5CE6B5; left: 0; right: 0; margin: auto; } } .left_edge::after, .rightedge::after, .topedge::after, .bottomedge::after { content: ''; position: absolute; left: 0; right: 0; top: 0; bottom: 0; transform: scale(2); } .frame-left-top-wrap { position: absolute; z-index: 100; width: 60upx; height: 60upx; left: -30upx; top: -30upx; .frame-left-top{ position: absolute; z-index: 100; width: 30upx; height: 30upx; left: 24upx; top: 24upx; border-left: 6upx solid #5CE6B5; border-top: 6upx solid #5CE6B5; } } .frame-left-bottom-wrap { position: absolute; z-index: 100; width: 60upx; height: 60upx; left: -30upx; bottom: -30upx; .frame-left-bottom { position: absolute; z-index: 100; width: 30upx; height: 30upx; left: 24upx; bottom: 24upx; border-left: 6upx solid #5CE6B5; border-bottom: 6upx solid #5CE6B5; } } .frame-right-top-wrap { position: absolute; z-index: 100; width: 60upx; height: 60upx; right: -30upx; top: -30upx; .frame-right-top { position: absolute; z-index: 100; width: 30upx; height: 30upx; right: 24upx; top: 24upx; border-right: 6upx solid #5CE6B5; border-top: 6upx solid #5CE6B5; } } .frame-right-bottom-wrap { position: absolute; z-index: 100; width: 60upx; height: 60upx; right: -30upx; bottom: -30upx; .frame-right-bottom { position: absolute; z-index: 100; width: 30upx; height: 30upx; right: 24upx; bottom: 24upx; border-right: 6upx solid #5CE6B5; border-bottom: 6upx solid #5CE6B5; } } .frame-left-top::after,.frame-right-top::after, .frame-left-bottom::after,.frame-right-bottom::after{ content: ''; position: absolute; left: 0; right: 0; top: 0; bottom: 0; transform: scale(1.5); } </style>