<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> 
 |