| <template> | 
|     <view class="picture-cut" :class="{'picture-cut-show':isShow}"> | 
|          | 
|          <!-- :style="{width:choosePictureWidth+'px',height:choosePictureHeight+'px',top:choosePictureTop+'px',left:choosePictureLeft+'px'}" --> | 
|         <view class="select-box" :style="{width: '70%', height: '250px', top:choosePictureTop+'px',left: '15%'}"> | 
|             <view class="horn"> | 
|                 <!-- <view class="lt" data-drag="leftTop"  @touchstart.stop="dragStart" @touchmove.stop.prevent="dragMove" ></view> | 
|                 <view class="rt"  data-drag="topTight" @touchstart.stop="dragStart" @touchmove.stop.prevent="dragMove" ></view> | 
|                 <view class="rb" data-drag="rightBottom" @touchstart.stop="dragStart" @touchmove.stop.prevent="dragMove"></view> | 
|                 <view class="lb" data-drag="bottomLeft"  @touchstart.stop="dragStart" @touchmove.stop.prevent="dragMove"></view> --> | 
|             </view> | 
|         </view> | 
|          | 
|          | 
|         <movable-area class="picture-area" :style="{width:areaWidth+'px',height:areaHeight+'px',top:areaHeightTop+'px',left:areaWidthLeft+'px'}"> | 
|             <movable-view class="picture-view" :style="{width:img_width/img_scaling+'px',height:img_height/img_scaling+'px'}" | 
|              direction="all" :x="offsetX" :y="offsetY" scale="true" :scale-min="scaleMin" @change="movableChange" @scale="movableScale"> | 
|                 <image :style="{width:img_width/img_scaling+'px',height:img_height/img_scaling+'px'}" :src="pictureSrc"></image> | 
|             </movable-view> | 
|         </movable-area> | 
|         <view class="area-bottom"> | 
|             <view class="area-bottom-box"> | 
|                 <view @click="cancelArea">取消</view> | 
|                 <!-- <view @click="changeImg">换个图片</view> --> | 
|                 <view @click="createImg">完成</view> | 
|             </view> | 
|      | 
|         </view> | 
|         <canvas canvas-id="picture-canvas" :style="'position:absolute;border: 1px solid red; width:'+canvasWidth+'px;height:'+canvasHeight+'px;top:-9999px;left:-9999px;'" class="canvas-view"></canvas> | 
|     </view> | 
| </template> | 
|   | 
| <script> | 
|      | 
|     let tailorSize = 240; // 需要截取的尺寸240x240px,此变量要和样式中的240px和120px相对应,120px为此变量的一半,若要修改成其他值一定要一一对应 | 
|     let tailorWidth = 0; | 
|     let tailorHeight = 0; | 
|     let    newOffsetX = 0; // 拖动缩放完成后的X轴偏移量 | 
|     let newOffsetY = 0; // 拖动缩放完成后的Y轴偏移量 | 
|     let T_PAGE_X, // 手移动的时候x的位置 | 
|         T_PAGE_Y, // 手移动的时候Y的位置 | 
|         area_x, | 
|         area_y | 
|     let [choosePictureMinWidth,choosePictureMinHeight] = [50,50]; | 
|     export default { | 
|         name: "tly-picture-cut", | 
|         props: { | 
|             // 图片路径 | 
|             pictureSrc: { | 
|                 type: String, | 
|                 required: true | 
|             } | 
|         }, | 
|         data() { | 
|             return { | 
|                 offsetX: 0, // 图像初始化的X轴偏移量 | 
|                 offsetY: 0, // 图像初始化的Y轴偏移量 | 
|                 img_width: 0, // 图片真实宽度 | 
|                 img_height: 0, // 图片真实高度 | 
|                 img_scaling: 1, //图片初始化缩放比例 | 
|                 scale: 1, // 拖动缩放完成后的图片缩放比例 | 
|                 scaleMin: 0.5, // 最小缩放值 | 
|                 isShow: false, | 
|                 choosePictureWidth:0, | 
|                 choosePictureHeight:0, | 
|                 choosePictureTop:0, | 
|                 choosePictureLeft:0, | 
|                 chooseVisible:0.5, | 
|                 areaWidth:0, | 
|                 areaHeight:0, | 
|                 movableViewTop:0, | 
|                 movableViewLeft:0, | 
|                 areaWidthLeft:0, | 
|                 areaHeightTop:0, | 
|                 canvasWidth:0, | 
|                 canvasHeight:0, | 
|                  | 
|             }; | 
|         }, | 
|         watch: { | 
|             pictureSrc() { | 
|                 this.getImgInfo(); | 
|             } | 
|         }, | 
|         methods: { | 
|             changeImg(){ | 
|                 this.$emit('changeImg') | 
|             }, | 
|             cancelArea(){ | 
|                 this.hidePop(); | 
|             }, | 
|             // 设置大小的时候触发的touchStart事件 | 
|             dragStart(e) { | 
|                 T_PAGE_X = e.touches[0].pageX | 
|                 T_PAGE_Y = e.touches[0].pageY | 
|             }, | 
|               | 
|             // 设置大小的时候触发的touchMove事件 | 
|             dragMove(e) { | 
|                 var _this = this | 
|                 var dragType = e.target.dataset.drag | 
|                 var dragLengthX = (T_PAGE_X - e.touches[0].pageX); | 
|                 var dragLengthY = (T_PAGE_Y - e.touches[0].pageY); | 
|                     switch (dragType) { | 
|                         case 'leftTop': | 
|                             this.choosePictureWidth += dragLengthX; | 
|                             this.choosePictureLeft  -= dragLengthX; | 
|                             this.choosePictureTop  -= dragLengthY; | 
|                             this.choosePictureHeight += dragLengthY; | 
|                             this.canvasY -= dragLengthY | 
|                             this.canvasX -= dragLengthX | 
|                             break; | 
|                         case 'topTight': | 
|                             this.choosePictureWidth -= dragLengthX; | 
|                             this.choosePictureHeight += dragLengthY; | 
|                             this.choosePictureTop  -= dragLengthY; | 
|                             this.canvasY -= dragLengthY | 
|                             break; | 
|                         case 'bottomLeft': | 
|                             this.choosePictureWidth += dragLengthX; | 
|                             this.choosePictureLeft  -= dragLengthX; | 
|                             this.choosePictureHeight -= dragLengthY; | 
|                             this.canvasX  -= dragLengthX | 
|                              | 
|                             break; | 
|                         case 'rightBottom': | 
|                             this.choosePictureWidth -= dragLengthX; | 
|                             this.choosePictureHeight -= dragLengthY; | 
|                             break; | 
|                         default: | 
|                             break; | 
|                     } | 
|                     T_PAGE_Y -= dragLengthY; | 
|                     T_PAGE_X -= dragLengthX; | 
|             }, | 
|             // 显示组件 | 
|             showPop() { | 
|                 this.isShow = true; | 
|             }, | 
|             // 隐藏组件 | 
|             hidePop() { | 
|                 this.isShow = false; | 
|             }, | 
|             // 初始化图片 | 
|             getImgInfo() { | 
|                 uni.getImageInfo({ | 
|                     src: this.pictureSrc, | 
|                     success: (res) => { | 
|                          | 
|                         // 屏幕可用宽高 | 
|                         let sysInfo = uni.getSystemInfoSync(); | 
|                         let windowWidth = sysInfo.windowWidth; | 
|                         let windowHeight = sysInfo.windowHeight; | 
|                         // 图片宽高 | 
|                         // 等比缩放 | 
|                         this.img_width = windowWidth*0.8; | 
|                         this.img_height = res.height*(this.img_width/res.width); | 
|                         this.canvasWidth = this.img_width; | 
|                         this.canvasHeight = this.img_height; | 
|                         //截图宽 | 
|                         this.choosePictureWidth = this.img_width*this.chooseVisible; | 
|                         //截图高 | 
|                         this.choosePictureHeight = this.img_height*this.chooseVisible; | 
|                          | 
|                         this.canvasX = (this.img_width - this.choosePictureWidth) /2; | 
|                         this.canvasY = (this.img_height - this.choosePictureHeight) /2; | 
|                         area_x = this.canvasX ; | 
|                         area_y = this.canvasY ; | 
|                         this.choosePictureTop = windowHeight/2-this.choosePictureHeight/2; | 
|                         this.choosePictureLeft = windowWidth/2-this.choosePictureWidth/2; | 
|                         // 计算初始缩放比和最小缩放值 | 
|                         if (this.img_width < this.choosePictureWidth || this.img_height < this.choosePictureHeight) { // 当图片宽或高小于240px时 | 
|                             let count = this.img_width <= this.img_height ? this.img_width : this.img_height; | 
|                             let check = this.choosePictureWidth <= this.choosePictureHeight ? this.choosePictureWidth : this.choosePictureHeight; | 
|                             this.img_scaling = count / check; | 
|                             this.scaleMin = 1; | 
|                         } else if (this.img_width > windowWidth && this.img_width <= this.img_height) { // 当图片宽度大于屏幕宽度并且图片宽度小于图片高度时 | 
|                             this.img_scaling = this.img_width / windowWidth; | 
|                             this.scaleMin = tailorSize / windowWidth; | 
|                         } else { | 
|                             this.img_scaling  = 1; | 
|                             //this.img_scaling = count / check; | 
|                             let count = this.img_width <= this.img_height ? this.img_width : this.img_height; | 
|                             let check = this.choosePictureWidth <= this.choosePictureHeight ? this.choosePictureWidth : this.choosePictureHeight; | 
|                             this.scaleMin = check / count; | 
|                         } | 
|                         //外块宽高 | 
|                         this.areaWidth = this.choosePictureWidth*3; | 
|                         this.areaHeight = this.choosePictureHeight*3; | 
|                         //外块偏移量 | 
|                         this.areaHeightTop = -((this.areaHeight - windowHeight)/2); | 
|                         this.areaWidthLeft = -((this.areaWidth - windowWidth)/2); | 
|   | 
|                         this.offsetX = this.areaWidth/2-(this.img_width/this.img_scaling)/2; | 
|                         this.offsetY = this.areaHeight/2-(this.img_height/this.img_scaling)/2; | 
|   | 
|                         // 获取新的偏移量 | 
|                         newOffsetX = this.offsetX; | 
|                         newOffsetY = this.offsetY; | 
|                     } | 
|                 }) | 
|             }, | 
|             // 计算拖动偏移量 | 
|             movableChange(e) { | 
|              | 
|                 this.canvasX = this.canvasX-(e.detail.x-area_x); | 
|                 area_x = e.detail.x; | 
|                 this.canvasY = this.canvasY-(e.detail.y-area_y) | 
|                 if(this.canvasY<0){ | 
|                     this.canvasY = 0; | 
|                 } | 
|                 area_y = e.detail.y; | 
|                  | 
|             }, | 
|             // 计算缩放比例和偏移量 | 
|             movableScale(e) { | 
|                 newOffsetX = e.detail.x | 
|                 newOffsetY = e.detail.y | 
|                 this.canvasWidth = this.canvasWidth*e.detail.scale; | 
|                 this.canvasHeight = this.canvasHeight*e.detail.scale; | 
|                 this.scale = e.detail.scale; | 
|             }, | 
|             // 截取图片 | 
|             createImg() { | 
|                 var that = this; | 
|                 let ctx = uni.createCanvasContext("picture-canvas",this); | 
|                 ctx.drawImage(this.pictureSrc, 0, 0, this.img_width*this.scale,this.img_height*this.scale ); | 
|                     // ctx.draw(); | 
|                 ctx.draw(false, () => { | 
|                      | 
|                     uni.canvasToTempFilePath({ | 
|                         x: this.canvasX, | 
|                         y: this.canvasY, | 
|                         width: this.choosePictureWidth, | 
|                         height: this.choosePictureHeight, | 
|                         destWidth: this.choosePictureWidth, | 
|                         destHeight: this.choosePictureHeight, | 
|                         quality: 0.9, | 
|                         canvasId: 'picture-canvas', | 
|                         success: function (res) { | 
|                      | 
|                               //#ifdef H5 | 
|                               that.hidePop(); | 
|                               that.$emit("createImg",res.tempFilePath) | 
|                               //#endif | 
|                               //#ifdef MP-WEIXIN || APP | 
|                                uni.getFileSystemManager().readFile({ | 
|                                    filePath: res.tempFilePath, | 
|                                    encoding: 'base64', | 
|                                    success: res => { | 
|                                        let base64 = 'data:image/png;base64,' + res.data; | 
|                                     | 
|                                        that.hidePop(); | 
|                                        that.$emit("createImg",base64) | 
|                                    } | 
|                                }) | 
|                                 //#endif | 
|   | 
|   | 
|                         } | 
|                     },this); | 
|                      | 
|                      | 
|          | 
|                 }); | 
|             } | 
|         } | 
|     } | 
| </script> | 
|   | 
| <style> | 
|     .picture-cut { | 
|         position: fixed; | 
|         top: 0; | 
|         left: 0; | 
|         bottom: 0; | 
|         right: 0; | 
|         width: 100%; | 
|         height: 100%; | 
|          | 
|         z-index: 999999; | 
|          | 
|         transform: translateX(100%); | 
|         transition: all 200ms ease; | 
|         visibility: hidden; | 
|     } | 
|   | 
|     .picture-cut-show { | 
|         transform: translateY(0) !important; | 
|         visibility: visible; | 
|          | 
|          | 
|     } | 
|   | 
|     /* 拖动域的位置和大小 */ | 
|     .picture-cut .picture-area { | 
|   | 
|         position: absolute; | 
|         /* 使其居中定位 */ | 
|          | 
|          | 
|   | 
|     } | 
|   | 
|     /* 拖动控件的大小 */ | 
|     .picture-area { | 
|          | 
|         pointer-events: none; | 
|         z-index: 998; | 
|          | 
|     } | 
|   | 
|     .picture-view { | 
|              | 
|         pointer-events: auto; | 
|              | 
|     } | 
|          | 
|     /* 中间选择框的大小,本意是视觉上模拟拖动域 */ | 
|     .select-box { | 
|      | 
|         position: absolute; | 
|         /* top: calc(50% - 120px); | 
|         left: calc(50% - 120px); */ | 
| /*         width: 240px; | 
|         height: 240px; */ | 
|         box-sizing: border-box; | 
|     /*     border-radius: 50%; */ | 
|   | 
|   | 
|         box-shadow: 0px 0px 0px 2005px rgba(0, 0, 0, 0.7) ;    | 
|         z-index: 999;   | 
|         pointer-events: none; | 
|     /*     min-width: 50px; | 
|         min-height: 50px; */ | 
|     } | 
|     .horn{ | 
|         position: absolute; | 
|         width: 100%; | 
|         height: 100%; | 
|         /* border:1rpx solid #ff0000; */ | 
|   | 
|     } | 
|     .horn>view{ | 
|         width: 15px; | 
|         height: 15px; | 
|         position:absolute; | 
|     } | 
|     .horn .lt{ | 
|         pointer-events: auto; | 
|         /* border-top: 3px solid #ff0000; | 
|         border-left: 3px solid #ff0000; */ | 
|         left: -4px; | 
|         top: -4px; | 
|     } | 
|     .horn .rt{ | 
|         pointer-events: auto; | 
|         /* border-top: 3px solid #ff0000; | 
|         border-right: 3px solid #ff0000; */ | 
|         right: -2px; | 
|         top: -2px; | 
|     } | 
|     .horn .rb{ | 
|         pointer-events: auto; | 
|         /* border-bottom:3px solid #ff0000; | 
|         border-right: 3px solid #ff0000; */ | 
|         right: -2px; | 
|         bottom: -2px; | 
|     } | 
|     .horn .lb{ | 
|         pointer-events: auto; | 
|         /* border-bottom:3px solid #ff0000; | 
|         border-left: 3px solid #ff0000; */ | 
|         left: -2px; | 
|         bottom: -2px; | 
|     } | 
|     .area-bottom{ | 
|         position: absolute; | 
|         width:100%; | 
|         height:75px; | 
|   | 
|         bottom: 0; | 
|         z-index:999; | 
|         box-shadow: 0 -8px 12px -5px  #ffffff; | 
|         background-color: rgba(66, 66, 66, 0.4); | 
|     } | 
|     .area-bottom-box{ | 
|          | 
|         display: flex; | 
|         justify-content: space-between; | 
|         width:86%; | 
|         height:50px; | 
|         line-height: 60px; | 
|         color:#FFFFFF; | 
|         margin:0 auto; | 
|     } | 
|     .button-view { | 
|         position: absolute; | 
|         bottom: 20px; | 
|         right: 20px; | 
|         width: 60px; | 
|         background-color: #007AFF; | 
|         font-size: 14px; | 
|         color: #FFFFFF; | 
|         z-index:101; | 
|     } | 
|   | 
|     /* 画布大小,画布大小就是截取的原始大小 */ | 
|     .canvas-view { | 
|         position: absolute; | 
|     /*     visibility: hidden; */ | 
|     } | 
| </style> |