Browse Source

更改图片上传方法

Limengbo 6 years ago
parent
commit
ae8d9cca33

+ 1 - 0
component/welCropper/package.json

@@ -0,0 +1 @@
+{}

+ 872 - 0
component/welCropper/welCropper.js

@@ -0,0 +1,872 @@
+let cropperUtil = require('./welCropperUtil.js')
+
+var init = function (W, H) {
+    let that = this
+
+    that.setData({
+        cropperData: {
+            drawSign: 0,
+            hidden: true,
+            left: 0,
+            top: 0,
+            width: W,
+            height: H,
+            W: W,
+            H: H,
+            itemLength: 50,
+            imageInfo: {
+                path: '',
+                width: 0,
+                height: 0
+            },
+            scaleInfo: {
+                x: 1,
+                y: 1
+            },
+            cropCallback: null,
+            sizeType: ['original', 'compressed'],    //'original'(default) | 'compressed'
+            original: false,  // 默认压缩,压缩比例为截图的0.4
+            mode: 'rectangle', //默认矩形
+        },
+        cropperMovableItems: {
+            topleft: {
+                x: 50,
+                y: 50
+            },
+            topright: {
+                x: W - 50,
+                y: 50
+            },
+            bottomleft: {
+                x: 50,
+                y: H - 50
+            },
+            bottomright: {
+                x: W - 50,
+                y: H - 50
+            }
+        },
+        cropperMainItem:{
+            x:110,
+            y:110,
+            w:50,
+            h:50
+        },
+        cropperChangableData: {
+            canCrop: true,
+            rotateDegree: 0,
+            originalSize: {
+                width: 0,
+                height: 0
+            },
+            scaleSize: {
+                width: 0,
+                height: 0
+            },
+            shape: {
+
+            },
+            previewImageInfo: {
+                x: 0,
+                y: 0,
+                w: 0,
+                h: 0
+            }
+        }
+    })
+
+    // 显示cropper,如果有图片则载入
+    that.showCropper = (options) => {
+        console.log(options)
+        let z = this
+        let cropperData = z.data.cropperData
+        let src = options.src
+        let callback = options.callback
+        let sizeType = options.sizeType
+        let mode = options.mode
+
+        let filterType = []
+        if (sizeType.indexOf('original') > -1) {
+            filterType.push('original')
+        }
+        if (sizeType.indexOf('compressed') > -1) {
+            filterType.push('compressed')
+        }
+        if (filterType.length == 1 && filterType.indexOf('original') > -1) {
+            cropperData.original = true
+        }
+
+        if (mode) {
+            cropperData.mode = mode
+        }
+        cropperData.hidden = false
+        cropperData.hash = Math.random()
+        cropperData.cropCallback = callback
+        cropperData.sizeType = filterType
+
+        // z.setData({
+        //     cropperData: cropperData,
+        // })
+
+        if (src) {
+            console.log(src)
+            wx.getImageInfo({
+                src: src,
+                success: function (res) {
+                    var w = res.width, h = res.height
+
+                    // let cropperData = z.data.cropperData
+                    cropperData.imageInfo = {
+                        path: src,
+                        width: w,
+                        height: h
+                    }
+                    z.setData({
+                        cropperData: cropperData,
+                        // cropperMainItem: {
+                        //     x: 210,
+                        //     y: 110,
+                        //     w: 50,
+                        //     h: 50
+                        // }
+                    })
+                    console.log('cropperData1')
+
+                    z.loadImage(src, w, h, false)
+                }
+            })
+        }
+    }
+
+    // 隐藏cropper
+    that.hideCropper = () => {
+        let that = this
+
+        that.data.cropperData.hidden = true
+        that.data.cropperData.cropCallback = null
+
+        that.setData({
+            cropperData: that.data.cropperData,
+            cropperMovableItems: {
+                topleft: {
+                    x: -1,
+                    y: -1
+                },
+                topright: {
+                    x: -1,
+                    y: -1
+                },
+                bottomleft: {
+                    x: -1,
+                    y: -1
+                },
+                bottomright: {
+                    x: -1,
+                    y: -1
+                }
+            },
+            cropperChangableData: {
+                canCrop: true,
+                rotateDegree: 0,
+                previewImageInfo: {
+                    x: 0,
+                    y: 0,
+                    w: 0,
+                    h: 0,
+                }
+            }
+        })
+
+        that.clearCanvas(that.data.cropperData.imageInfo)
+    }
+
+
+    // 原图按钮被点击
+    that.originalChange = () => {
+        let that = this
+        let imageInfo = that.data.cropperData.imageInfo
+        let originalSize = that.data.cropperChangableData.originalSize
+        let width = originalSize.width
+        let height = originalSize.height
+        let original = !that.data.cropperData.original
+
+        let compressedScale = original ? 1.0 : 0.4
+        let size = cropperUtil.getAdjustSize(W, H, width, height)
+
+        console.log("change original=" + original)
+
+        that.data.cropperData.original = original
+        that.data.cropperData.scaleInfo = {
+            x: width * compressedScale / size.width,
+            y: height * compressedScale / size.height
+        }
+
+        // 之所以要设置cropperMovableItems,然后延时在设置一次,是因为改变cropperData后,movable-view会莫名其妙移动到左上角
+        let cropperMovableItemsCopy = that.data.cropperMovableItems
+        let cropperMovableItems = {
+            topleft: {
+                x: 0,
+                y: 0
+            },
+            topright: {
+                x: 0,
+                y: 0
+            },
+            bottomleft: {
+                x: 0,
+                y: 0
+            },
+            bottomright: {
+                x: 0,
+                y: 0
+            }
+        }
+
+        that.setData({
+            cropperData: that.data.cropperData,
+            cropperMovableItems: cropperMovableItems
+        })
+
+        setTimeout(() => {
+            that.setData({
+                cropperMovableItems: cropperMovableItemsCopy
+            })
+        }, 100)
+
+        that.drawOriginalImage()
+    }
+
+    // 截取选中图片,如果有回调,则调用
+    that.cropImage = () => {
+        let that = this
+        let cropperData = that.data.cropperData
+        let mode = cropperData.mode
+        let scaleInfo = cropperData.scaleInfo
+        let width = cropperData.width
+        let height = cropperData.height
+        
+        let cropperMovableItems = that.data.cropperMovableItems
+
+        if (mode == 'rectangle') {
+            let maxX = 0, maxY = 0
+            for (let key in cropperMovableItems) {
+                let item = cropperMovableItems[key]
+                maxX = item.x > maxX ? item.x : maxX
+                maxY = item.y > maxY ? item.y : maxY
+            }
+
+            let minX = maxX, minY = maxY
+            for (let key in cropperMovableItems) {
+                let item = cropperMovableItems[key]
+                minX = item.x < minX ? item.x : minX
+                minY = item.y < minY ? item.y : minY
+            }
+
+            let w = maxX - minX, h = maxY - minY
+            w *= scaleInfo.x
+            h *= scaleInfo.y
+
+            let x = minX * scaleInfo.x, y = minY * scaleInfo.y
+
+            console.log('crop rect: x=' + x + ',y=' + y + ',w=' + w + ',h=' + h)
+
+            let ctx = wx.createCanvasContext("originalCanvas")
+
+            wx.showLoading({
+                title: '正在截取...',
+            })
+            wx.canvasToTempFilePath({
+                x: x,
+                y: y,
+                width: w,
+                height: h,
+                destWidth: w,
+                destHeight: h,
+                canvasId: 'originalCanvas',
+                success:  (res) => {
+                    let tempFilePath = res.tempFilePath
+
+                    wx.hideLoading()
+
+                    // wx.saveImageToPhotosAlbum({
+                    //     filePath: tempFilePath,
+                    //     success(res) {
+                    //     }
+                    // })
+                    //console.log('截取成功', res);
+                    
+                    if (that.data.cropperData.cropCallback) {
+                        
+                        that.data.cropperData.cropCallback(tempFilePath)
+                    }
+                },
+                fail(res) {
+                    wx.hideLoading()
+                    wx.showModal({
+                        title: '截取失败',
+                        content: res.errMsg
+                    })
+                    console.log("fail res:")
+                    console.log(res)
+                }
+            })
+        }
+        else {
+            let res = [[0, 0], [0, 0], [0, 0], [0, 0]]
+            let points = []
+            for (let key in cropperMovableItems) {
+                let x = Math.ceil(cropperMovableItems[key].x * scaleInfo.x)
+                let y = Math.ceil(cropperMovableItems[key].y * scaleInfo.y)
+
+
+                let index = 0
+                if (key == 'topleft') {
+                    index = 0
+                }
+                else if (key == 'bottomleft') {
+                    index = 1
+                }
+                else if (key == 'bottomright') {
+                    index = 2
+                }
+                else if (key == 'topright') {
+                    index = 3
+                }
+                res[index] = [x, y]
+
+                points.push({ x, y })
+            }
+
+            cropperUtil.convexHull(points, points.length)
+
+            if (that.data.cropperData.cropCallback) {
+                that.data.cropperData.cropCallback(res)
+            }
+        }
+    }
+
+    // 测试
+    // 截取形状
+    // that.changeCropShapeHandler = () => {
+    //     const map = [
+    //         'no',
+    //         'square'
+    //     ]
+    //     wx.showActionSheet({
+    //         itemList: ['不定形状', '正方形'],
+    //         success: function (res) {
+    //             console.log(res.tapIndex)
+    //         },
+    //         fail: function (res) {
+    //             console.log(res.errMsg)
+    //         }
+    //     })
+    // }
+
+    // 旋转图片
+    that.rotateImage = () => {
+        console.log("rotate image")
+        let that = this
+        let imageInfo = that.data.cropperData.imageInfo
+        let width = imageInfo.width
+        let height = imageInfo.height
+        let rotateDegree = that.data.cropperChangableData.rotateDegree
+
+        rotateDegree = rotateDegree == 360 ? 90 : rotateDegree + 90
+
+        // 判断是否为垂直方向
+        let isVertical = rotateDegree % 180 > 0
+        let rotateWidth = isVertical ? height : width
+        let rotateHeight = isVertical ? width : height
+
+        let size = cropperUtil.getAdjustSize(W, H, rotateWidth, rotateHeight)
+
+        // 适应屏幕的位置
+        let left = (W - size.width) / 2
+        let top = (H - size.height) / 2
+        let cropperData = that.data.cropperData
+
+        cropperData.left = left
+        cropperData.top = top
+
+        let cropperChangableData = that.data.cropperChangableData
+        cropperChangableData.originalSize = {
+            width: rotateWidth,
+            height: rotateHeight
+        }
+        cropperChangableData.scaleSize = {
+            width: size.width,
+            height: size.height
+        }
+        cropperChangableData.rotateDegree = rotateDegree
+
+        that.setData({
+            cropperChangableData: cropperChangableData,
+            cropperData: cropperData
+        })
+
+        console.log(cropperChangableData)
+
+        let cropperMovableItemsCopy = that.data.cropperMovableItems
+        let cropperMovableItems = {
+            topleft: {
+                x: 0,
+                y: 0
+            },
+            topright: {
+                x: 0,
+                y: 0
+            },
+            bottomleft: {
+                x: 0,
+                y: 0
+            },
+            bottomright: {
+                x: 0,
+                y: 0
+            }
+        }
+
+        that.setData({
+            cropperMovableItems: cropperMovableItems
+        })
+
+        setTimeout(() => {
+            that.loadImage(imageInfo.path, rotateWidth, rotateHeight, true)
+            // that.setData({
+            //     cropperMovableItems: cropperMovableItemsCopy
+            // })
+        }, 100)
+
+    }
+
+    // 根据图片大小设置canvas大小,并绘制图片
+    that.loadImage = (src, width, height, isRotate) => {
+        let z = this
+        let size = cropperUtil.getAdjustSize(W, H, width, height)
+
+        // 适应屏幕的位置
+        let left = (W - size.width) / 2
+        let top = (H - size.height) / 2
+
+        // set data
+        let updateData = {}
+        let cropperData = z.data.cropperData
+
+        cropperData.drawSign = !cropperData.drawSign
+        if (!isRotate) {
+            cropperData.imageInfo = {
+                path: src,
+                width: width,
+                height: height
+            }
+        }
+        cropperData.left = left
+        cropperData.top = top
+        cropperData.width = size.width
+        cropperData.height = size.height
+
+        let compressedScale = z.data.cropperData.original ? 1.0 : 0.4
+        // let scaleSize = cropperUtil.getAdjustSize(W, H, width, height)
+
+        cropperData.scaleInfo = {
+            x: width * compressedScale / size.width,
+            y: height * compressedScale / size.height
+        }
+
+        updateData.cropperData = cropperData
+
+        updateData.cropperMovableItems = {
+            topleft: {
+                x: 50,
+                y: 50
+            },
+            topright: {
+                x: size.width - 50,
+                y: 50
+            },
+            bottomleft: {
+                x: 50,
+                y: size.height - 50
+            },
+            bottomright: {
+                x: size.width - 50,
+                y: size.height - 50
+            }
+        }
+
+        // updateData.cropperMainItem = {
+        //     x: 100,
+        //     y: 100,
+        //     w: 100,
+        //     h: 100
+        // }
+
+        // setTimeout(()=>{
+        //     console.log('main item')
+        //     z.setData({
+        //         cropperMainItem: {
+        //             x: 100,
+        //             y: 100,
+        //             w: 100,
+        //             h: 100
+        //         }
+        //     })
+        // }, 2000)
+
+        let cropperChangableData = z.data.cropperChangableData
+        let rotateDegree = cropperChangableData.rotateDegree
+
+        // 判断是否为垂直方向
+        let isVertical = rotateDegree % 180 > 0
+        let rotateWidth = isVertical ? size.height : size.width
+        let rotateHeight = isVertical ? size.width : size.height
+        console.log(size)
+        console.log('rotateDegree:' + rotateDegree)
+        console.log('rotateWidth:' + rotateWidth + ', rotateHeight:' + rotateHeight)
+
+        cropperChangableData.previewImageInfo.x = (W - rotateWidth) / 2
+        cropperChangableData.previewImageInfo.y = (H - rotateHeight) / 2
+        cropperChangableData.previewImageInfo.w = rotateWidth
+        cropperChangableData.previewImageInfo.h = rotateHeight
+
+        cropperChangableData.originalSize = {
+            width: width,
+            height: height
+        }
+        cropperChangableData.scaleSize = {
+            width: size.width,
+            height: size.height
+        }
+
+        updateData.cropperChangableData = cropperChangableData
+
+        z.setData(updateData)
+
+
+        console.log('cropperData2')
+
+        // console.log("loadImage size:" + width + "*" + height)
+        z.drawImage({
+            path: z.data.cropperData.imageInfo.path,
+            width: width,
+            height: height
+        })
+        // that.drawImage(that.data.cropperData.imageInfo)
+        z.drawLines(z.data.cropperMovableItems, z.data.cropperData.imageInfo)
+    }
+
+    // 清空canvas上的数据
+    that.clearCanvas = (imageInfo) => {
+        let cropperData = that.data.cropperData
+        let size = cropperUtil.getAdjustSize(W, H, imageInfo.width, imageInfo.height)
+
+        if (imageInfo.path != '') {
+            let compressedScale = that.data.cropperData.original ? 1.0 : 0.4
+
+            //清空原图
+            let ctx = wx.createCanvasContext("originalCanvas")
+            ctx.clearRect(0, 0, imageInfo.width * compressedScale, imageInfo.height * compressedScale)
+            ctx.draw()
+
+            //清空选择区图片
+            let canvas = wx.createCanvasContext("canvas")
+            canvas.clearRect(0, 0, size.width, size.height)
+            canvas.draw()
+
+            // 清空白线框
+            let moveCanvas = wx.createCanvasContext("moveCanvas")
+            moveCanvas.clearRect(0, 0, size.width, size.height)
+            moveCanvas.draw()
+        }
+    }
+
+    //绘制图片
+    that.drawImage = (imageInfo) => {
+        let z = this
+        let cropperData = z.data.cropperData
+        let size = cropperUtil.getAdjustSize(W, H, imageInfo.width, imageInfo.height)
+
+        if (imageInfo.path != '') {
+            let path = imageInfo.path
+            let compressedScale = z.data.cropperData.original ? 1.0 : 0.4
+            let rotateDegree = z.data.cropperChangableData.rotateDegree
+            let canvasCtx = wx.createCanvasContext('canvas', z)
+            let originalCanvasCtx = wx.createCanvasContext('originalCanvas', z)
+            //绘制原图
+            cropperUtil.drawImageWithDegree(
+                originalCanvasCtx,
+                path,
+                imageInfo.width * compressedScale,
+                imageInfo.height * compressedScale,
+                rotateDegree
+            )
+            // let originalCanvas = wx.createCanvasContext("originalCanvas")
+            // originalCanvas.drawImage(path, 0, 0, imageInfo.width * compressedScale, imageInfo.height * compressedScale)
+            // originalCanvas.draw()
+
+            //绘制选择区图片
+            cropperUtil.drawImageWithDegree(canvasCtx, path, size.width, size.height, rotateDegree)
+            // let canvas = wx.createCanvasContext("canvas")
+            // canvas.drawImage(path, 0, 0, size.width, size.height)
+            // canvas.draw()
+
+            console.log("draw=" + path)
+        }
+    }
+
+    // 单独绘制原图,当切换原图与非原图时使用
+    that.drawOriginalImage = () => {
+        let z = this
+        let cropperData = z.data.cropperData
+        let imageInfo = cropperData.imageInfo
+        let originalSize = z.data.cropperChangableData.originalSize
+
+        if (imageInfo.path != '') {
+            let path = imageInfo.path
+            let compressedScale = z.data.cropperData.original ? 1.0 : 0.4
+            let rotateDegree = z.data.cropperChangableData.rotateDegree
+
+            let originalCanvasCtx = wx.createCanvasContext('originalCanvas', z)
+            //绘制原图
+            cropperUtil.drawImageWithDegree(
+                originalCanvasCtx,
+                path,
+                originalSize.width * compressedScale,
+                originalSize.height * compressedScale,
+                rotateDegree
+            )
+            // let originalCanvas = wx.createCanvasContext("originalCanvas")
+            // originalCanvas.drawImage(path, 0, 0, imageInfo.width * compressedScale, imageInfo.height * compressedScale)
+            // originalCanvas.draw()
+        }
+    }
+
+    //绘制选框
+    that.drawLines = function (cropperMovableItems, imageInfo, callback) {
+        // console.log((new Date()).getTime())
+        let that = this
+        let cropperData = that.data.cropperData
+        let mode = cropperData.mode
+        let rotateDegree = that.data.cropperChangableData.rotateDegree
+        let size
+        if (rotateDegree % 180 > 0) {
+            size = cropperUtil.getAdjustSize(W, H, imageInfo.height, imageInfo.width)
+        }
+        else {
+            size = cropperUtil.getAdjustSize(W, H, imageInfo.width, imageInfo.height)
+        }
+
+        let convexDots = []
+        let orderedDots = []
+
+        orderedDots.push(cropperMovableItems['topleft'])
+        orderedDots.push(cropperMovableItems['topright'])
+        orderedDots.push(cropperMovableItems['bottomright'])
+        orderedDots.push(cropperMovableItems['bottomleft'])
+
+        // 获取凸边形的点
+        convexDots = cropperUtil.convexHull(orderedDots, orderedDots.length)
+
+        // 四个点组成的四边形是不是凸四边形
+        let canCrop = convexDots.length == 4
+        if (callback) {
+            callback(canCrop)
+        }
+
+        let ctx = wx.createCanvasContext("moveCanvas")
+
+        //绘制高亮选中区域
+        let rect = cropperUtil.getCropRect(convexDots)
+
+        if (mode == 'rectangle') {
+            // 绘制半透明遮罩
+            ctx.setFillStyle('rgba(0,0,0,0.5)')
+
+            ctx.fillRect(0, 0, size.width, size.height)
+
+            // 清除选中区域的半透明遮罩,使选中区域高亮
+            ctx.setFillStyle('rgba(0,0,0,0)')
+            ctx.clearRect(rect.x, rect.y, rect.w, rect.h)
+
+            //绘制选中边框
+            ctx.setStrokeStyle('white')
+            ctx.setLineWidth(2)
+            ctx.beginPath()
+            ctx.moveTo(rect.x, rect.y)
+            ctx.lineTo(rect.x + rect.w, rect.y)
+            ctx.lineTo(rect.x + rect.w, rect.y + rect.h)
+            ctx.lineTo(rect.x, rect.y + rect.h)
+            ctx.lineTo(rect.x, rect.y)
+
+            ctx.stroke()
+            ctx.closePath()
+        }
+        else {
+            //绘制选中边框
+            // 如果四个点组成的四边形不是凸四边形,则显示红色,表示不可取
+            let color = canCrop ? 'white' : 'red'
+
+            ctx.setStrokeStyle(color)
+            ctx.setLineWidth(2)
+            ctx.beginPath()
+            for (let i = 0, len = convexDots.length; i < len; i++) {
+                let dot = convexDots[i]
+                if (i == 0) {
+                    ctx.moveTo(dot.x, dot.y)
+                }
+                else {
+                    ctx.lineTo(dot.x, dot.y)
+                }
+            }
+            let dot = convexDots[0]
+            ctx.lineTo(dot.x, dot.y)
+
+            ctx.stroke()
+            ctx.closePath()
+        }
+
+        //绘制四个角
+        let cornerType = mode == 'rectangle' ? 'rect' : 'circle'
+        ctx.setFillStyle('white')
+        ctx.setStrokeStyle('white')
+
+        // 绘制不同样式的角
+        if (cornerType == 'circle') {
+            for (let i = 0, len = orderedDots.length; i < len; i++) {
+                let dot = orderedDots[i]
+
+                ctx.beginPath()
+                ctx.arc(dot.x, dot.y, 10, 0, 2 * Math.PI, true)
+                ctx.fill()
+                ctx.closePath()
+            }
+        }
+        else if (cornerType == 'rect') {
+            let len = 20, w = 3.0, offset = w / 2.0
+
+            ctx.setLineWidth(w)
+            ctx.beginPath()
+
+            ctx.moveTo(rect.x - offset, rect.y - offset + len)
+            ctx.lineTo(rect.x - offset, rect.y - offset)
+            ctx.lineTo(rect.x - offset + len, rect.y - offset)
+
+            ctx.moveTo(rect.x + offset + rect.w - len, rect.y - offset)
+            ctx.lineTo(rect.x + offset + rect.w, rect.y - offset)
+            ctx.lineTo(rect.x + offset + rect.w, rect.y - offset + len)
+
+            ctx.moveTo(rect.x + offset + rect.w, rect.y + offset + rect.h - len)
+            ctx.lineTo(rect.x + offset + rect.w, rect.y + offset + rect.h)
+            ctx.lineTo(rect.x + offset + rect.w - len, rect.y + offset + rect.h)
+
+            ctx.moveTo(rect.x - offset, rect.y + offset + rect.h - len)
+            ctx.lineTo(rect.x - offset, rect.y + offset + rect.h)
+            ctx.lineTo(rect.x - offset + len, rect.y + offset + rect.h)
+
+            ctx.stroke()
+
+            ctx.closePath()
+        }
+
+        ctx.draw()
+    }
+
+    // move events
+    that.setupMoveItem = (key, changedTouches, imageInfo, callback) => {
+        let that = this
+        let cropperData = that.data.cropperData
+        let cropperMovableItems = that.data.cropperMovableItems
+        let left = cropperData.left
+        let top = cropperData.top
+        let mode = cropperData.mode
+        let size = cropperUtil.getAdjustSize(W, H, imageInfo.width, imageInfo.height)
+
+        if (changedTouches.length == 1) {
+            let touch = changedTouches[0]
+            let x = touch.clientX
+            let y = touch.clientY
+
+            // 相对画布的点
+            x = x - left
+            y = y - top
+
+            cropperMovableItems[key].x = x
+            cropperMovableItems[key].y = y
+
+            // 边界检测,使截图不超出截图区域
+            x = x < 0 ? 0 : (x > size.width ? size.width : x)
+            y = y < 0 ? 0 : (y > size.height ? size.height : y)
+            cropperMovableItems[key].x = x
+            cropperMovableItems[key].y = y
+
+            // 如果是在矩形模式下
+            if (mode == 'rectangle') {
+                // 同时设置相连两个点的位置,是相邻的两个点跟随着移动点动,保证选框为矩形
+                if (key == 'topleft') {
+                    cropperMovableItems['bottomleft'].x = x
+                    cropperMovableItems['topright'].y = y
+                }
+                else if (key == 'topright') {
+                    cropperMovableItems['bottomright'].x = x
+                    cropperMovableItems['topleft'].y = y
+                }
+                else if (key == 'bottomleft') {
+                    cropperMovableItems['topleft'].x = x
+                    cropperMovableItems['bottomright'].y = y
+                }
+                else if (key == 'bottomright') {
+                    cropperMovableItems['topright'].x = x
+                    cropperMovableItems['bottomleft'].y = y
+                }
+            }
+
+            that.drawLines(cropperMovableItems, imageInfo, function (canCrop) {
+                if (callback) {
+                    callback(cropperMovableItems, canCrop)
+                }
+            })
+        }
+    }
+
+    // moveable-view touchmove
+    that.moveEvent = (e) => {
+        let that = this
+        let key = e.currentTarget.dataset.key
+        let originalSize = that.data.cropperChangableData.originalSize
+
+        that.setupMoveItem(key, e.changedTouches, {
+            path: that.data.cropperData.imageInfo.path,
+            width: originalSize.width,
+            height: originalSize.height
+        })
+    }
+
+    // moveable-view touchend,end的时候设置movable-view的位置,如果在move阶段设置位置,选中会不流畅
+    that.endEvent = (e) => {
+        console.log("end")
+        let that = this
+        let cropperData = that.data.cropperData
+        let cropperMovableItems = that.data.cropperMovableItems
+        let cropperChangableData = that.data.cropperChangableData
+        let originalSize = cropperChangableData.originalSize
+        let key = e.currentTarget.dataset.key
+
+        that.setupMoveItem(key, e.changedTouches, {
+            path: that.data.cropperData.imageInfo.path,
+            width: originalSize.width,
+            height: originalSize.height
+        }, (cropperMovableItems, canCrop) => {
+            cropperChangableData.canCrop = canCrop
+            that.setData({
+                cropperChangableData: cropperChangableData,
+                cropperMovableItems: cropperMovableItems
+            })
+        })
+    }
+}
+
+
+module.exports = {
+    init
+}

+ 54 - 0
component/welCropper/welCropper.wxml

@@ -0,0 +1,54 @@
+<template name="welCropper">
+    <scroll-view class="cropper_main_container {{cropperData.hidden ? 'hidden':''}}">
+        <view class="cropper_container" style="width:{{cropperData.W}}px; height:{{cropperData.H}}px;">
+            <canvas class="original_canvas" canvas-id="originalCanvas" style="width:{{cropperChangableData.originalSize.width}}px;height:{{cropperChangableData.originalSize.height}}px;"></canvas>
+
+            <image src='{{cropperData.imageInfo.path}}' class='scale-image cropper_canvas_container_item' mode='aspectFill' style="left:{{cropperChangableData.previewImageInfo.x}}px; top:{{cropperChangableData.previewImageInfo.y}}px; width:{{cropperChangableData.previewImageInfo.w}}px; height:{{cropperChangableData.previewImageInfo.h}}px; transform:rotate({{cropperChangableData.rotateDegree}}deg);"></image>
+            <view class='cropper_canvas_container' style="width:{{cropperChangableData.scaleSize.width}}px;height:{{cropperChangableData.scaleSize.height}}px;">
+                <canvas class="move_canvas cropper_canvas_container_item" canvas-id="moveCanvas"></canvas>
+
+                <block wx:if="{{cropperData.drawSign==1}}">
+                    <movable-area class="cropper_movable_area_container" style="width:{{cropperChangableData.scaleSize.width}}px;height:{{cropperChangableData.scaleSize.height}}px;">
+                        <!-- <movable-view class='main_move_item' style="width:{{cropperMainItem.w}}px; height:{{cropperMainItem.h}}px;" direction="all" x="{{cropperMainItem.x}}" y="{{cropperMainItem.y}}"></movable-view> -->
+                        <block wx:if="{{cropperMovableItems}}">
+                            <block wx:for="{{cropperMovableItems}}" wx:key="moveItem">
+                                <movable-view class="move_item" style="width:{{cropperData.itemLength}}px; height:{{cropperData.itemLength}}px;" direction="all" x="{{item.x-cropperData.itemLength/2}}" y="{{item.y-cropperData.itemLength/2}}" bindtouchmove="moveEvent" bindtouchend="endEvent" data-key="{{index}}"></movable-view>
+                            </block>
+                        </block>
+                    </movable-area>
+                </block>
+                <block wx:else>
+                    <movable-area class="cropper_movable_area_container" style="width:{{cropperChangableData.scaleSize.width}}px;height:{{cropperChangableData.scaleSize.height}}px;">
+                            <!-- <movable-view class='main_move_item' style="width:{{cropperMainItem.w}}px; height:{{cropperMainItem.h}}px;" direction="all" x="{{cropperMainItem.x}}" y="{{cropperMainItem.y}}"></movable-view> -->
+                        <block wx:if="{{cropperMovableItems}}">
+                            <block wx:for="{{cropperMovableItems}}" wx:key="moveItem">
+                                <movable-view class="move_item" style="width:{{cropperData.itemLength}}px; height:{{cropperData.itemLength}}px;" direction="all" x="{{item.x-cropperData.itemLength/2}}" y="{{item.y-cropperData.itemLength/2}}" bindtouchmove="moveEvent" bindtouchend="endEvent" data-key="{{index}}"></movable-view>
+                            </block>
+                        </block>
+                    </movable-area>
+                </block>
+            </view>
+        </view>
+
+        <view class="cropper_toolbar">
+            <view class="button_item cancel_button" bindtap="hideCropper">
+                取消
+            </view>
+            <!-- <view class="button_item crop_shape_button" bindtap="changeCropShapeHandler">
+                形状
+            </view> -->
+            <view class="button_item rotate_button" bindtap="rotateImage">
+                旋转
+            </view>
+
+            <block wx:if="{{cropperData.sizeType.length==2}}">
+                <view class="original_button button_item {{cropperData.original?'checked':''}}" bindtap="originalChange">
+                    <view>原图</view>
+                </view>
+            </block>
+            <view class="crop_image_button button_item {{cropperChangableData.canCrop?'':'disable'}}" bindtap="{{cropperChangableData.canCrop?'cropImage':''}}">
+                完成
+            </view>
+        </view>
+    </scroll-view>
+</template>

+ 126 - 0
component/welCropper/welCropper.wxss

@@ -0,0 +1,126 @@
+.cropper_main_container {
+    position: absolute;
+    left: 0;
+    top: 0;
+    z-index: 100;
+    width: 750rpx;
+    height: 100vh;
+    background: #555;
+    overflow: hidden;
+}
+
+.cropper_main_container.hidden {
+    display: none;
+}
+
+.cropper_container {
+    position: absolute;
+    left: 0;
+    top: 0;
+    display: flex;
+    align-items: center;
+    justify-content:center;
+}
+
+/* button */
+
+.cropper_toolbar {
+    position: absolute;
+    z-index: 100;
+    bottom: 0;
+    height: 50px;
+    background: black;
+    width: 100%;
+    line-height: 50px;
+    font-size: 15px;
+    text-align: center;
+    color: white;
+}
+
+.cropper_toolbar .button_item {
+    /* width: 70px; */
+    float: left;
+     /* width: 20%;  */
+     width: 25%; 
+    height: 50px;
+}
+
+.original_button .check_container {
+    position: relative;
+    float: left;
+    margin-top: 14px;
+    width: 18px;
+    height: 18px;
+    border: 1px solid white;
+}
+
+.original_button.checked {
+    background: #26ab28;
+}
+
+/* crop_image_button */
+
+.crop_image_button {
+    color: #26ab28;
+}
+
+.crop_image_button.disable {
+    /* color: #038905;  */
+    color: rgba(0, 0, 0, 0);
+}
+
+/* canvas */
+
+.cropper_movable_area_container {
+    position: relative;
+    /* background: salmon;
+    border: 2px solid red; */
+}
+.cropper_canvas_container_item {
+    position: absolute;
+    left: 0;
+    top: 0;
+    width: 100%;
+    height: 100%;
+}
+
+.cropper_canvas_container {
+    position: relative;
+}
+
+/* opacity:0隐藏,如果想看就设置为1,只能在测试机能看到,真机上canvas层级在最高层 */
+
+
+.cropper_movable_area_container .main_move_item {
+    z-index: 100;
+    opacity: 0.7;
+    /* opacity: 0;  */
+    background: white;
+     border-radius: 50%; 
+}
+
+.cropper_canvas_container .canvas {
+    position: absolute;
+    left: 0;
+    top: 0;
+    /* opacity: 0; */
+}
+
+/* 因为display:none在真机上会造成无法截取图片,所以这里是通过移到显示区域外来达到隐藏效果的 */
+
+.original_canvas {
+    position: absolute;
+    left: 750rpx;
+    top: 100vh;
+}
+
+.scale-image {
+    position: absolute;
+    left: 0;
+    top: 0;
+}
+
+.move_canvas {
+    /* border: 2px solid blue; */
+     /* background: red;  */
+}

+ 178 - 0
component/welCropper/welCropperUtil.js

@@ -0,0 +1,178 @@
+// 获取选中区域的(x, y, w, h)
+const getCropRect = (cropperMovableItems) => {
+    let maxX = 0, maxY = 0
+    for (let key in cropperMovableItems) {
+        let item = cropperMovableItems[key]
+        maxX = Math.max(item.x, maxX)
+        maxY = Math.max(item.y, maxY)
+    }
+
+    let minX = maxX, minY = maxY
+    for (let key in cropperMovableItems) {
+        let item = cropperMovableItems[key]
+        minX = Math.min(item.x, minX)
+        minY = Math.min(item.y, minY)
+    }
+
+    return {
+        x: minX,
+        y: minY,
+        w: maxX - minX,
+        h: maxY - minY
+    }
+}
+
+// 获取适应屏幕的图片显示大小
+const getAdjustSize = (W, H, width, height) => {
+    if (width > W) {
+        height = W / width * height
+        width = W
+    }
+
+    if (height > H) {
+        width = H / height * width
+        height = H
+    }
+
+    return {
+        width: width,
+        height: height
+    }
+}
+
+// http://www.geeksforgeeks.org/convex-hull-set-1-jarviss-algorithm-or-wrapping/
+
+// To find orientation of ordered triplet (p, q, r).
+// The function returns following values
+// 0 --> p, q and r are colinear
+// 1 --> Clockwise
+// 2 --> Counterclockwise
+function orientation(p, q, r) {
+    var val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
+
+    if (val == 0) return 0;  // collinear
+    return (val > 0) ? 1 : 2; // clock or counterclock wise
+}
+
+// Prints convex hull of a set of n points.
+function convexHull(points, n) {
+    // There must be at least 3 points
+    if (n < 3) return;
+
+    // Initialize Result
+    var hull = [];
+
+    // Find the leftmost point
+    var l = 0;
+    for (var i = 1; i < n; i++) {
+        if (points[i].x < points[l].x) {
+            l = i;
+        }
+    }
+    // Start from leftmost point, keep moving 
+    // counterclockwise until reach the start point
+    // again. This loop runs O(h) times where h is
+    // number of points in result or output.
+    var p = l, q;
+    do {
+        // Add current point to result
+        // Prevent duplicates object
+        // if (hull.findIndex(i => i.x == points[p].x && i.y == points[p].y)==-1){
+        hull.push(points[p]);
+        // }
+
+        // Search for a point 'q' such that 
+        // orientation(p, x, q) is counterclockwise 
+        // for all points 'x'. The idea is to keep 
+        // track of last visited most counterclock-
+        // wise point in q. If any point 'i' is more 
+        // counterclock-wise than q, then update q.
+        q = (p + 1) % n;
+
+        for (var i = 0; i < n; i++) {
+            // If i is more counterclockwise than 
+            // current q, then update q
+            if (orientation(points[p], points[i], points[q]) == 2)
+                q = i;
+        }
+
+        // Now q is the most counterclockwise with
+        // respect to p. Set p as q for next iteration, 
+        // so that q is added to result 'hull'
+        p = q;
+
+    } while (p != l);  // While we don't come to first 
+    // point
+
+    // Print Result
+    // for (var i in hull) {
+    //     var temp = hull[i]
+    //     console.log("(" + temp.x + ", " + temp.y + ")");
+    // }
+    return hull
+}
+
+function drawImageWithDegree(ctx, path, width, height, degree) {
+    let isVertical = degree % 180 > 0
+
+    let drawWidth = isVertical ? height : width
+    let drawHeight = isVertical ? width : height
+
+    let centerX = width / 2
+    let cneterY = height / 2
+
+    let drawCenterX = drawWidth / 2
+    let drawCneterY = drawHeight / 2
+
+    let d = Math.abs(width - height) / 2
+
+    // ctx.translate(drawCenterX, drawCneterY)
+    // ctx.rotate(degree * Math.PI / 180)
+    // ctx.translate(-drawCenterX, -drawCneterY)
+
+    ctx.translate(centerX, cneterY)
+    ctx.rotate(degree * Math.PI / 180)
+    ctx.translate(-centerX, -cneterY)
+
+    // ctx.translate(-d, d)
+    if (isVertical) {
+        if (drawHeight > drawWidth) {
+            ctx.drawImage(path, d, -d, drawWidth, drawHeight)
+        }
+        else {
+            ctx.drawImage(path, -d, d, drawWidth, drawHeight)
+        }
+    }
+    else {
+        ctx.drawImage(path, 0, 0, drawWidth, drawHeight)
+    }
+
+    ctx.draw(false, function (e) {
+        console.log('draw callback')
+    })
+}
+
+// 查找topleft的点
+function findTopLeft(items) {
+    let x = items.topleft.x, y = items.topleft.y
+    for (let i in items) {
+        let item = items[i]
+        if (x > item.x) {
+            x = item.x
+        }
+        if (y > item.y) {
+            y = item.y
+        }
+    }
+    return {
+        x, y
+    }
+}
+
+module.exports = {
+    getCropRect,
+    getAdjustSize,
+    convexHull,
+    drawImageWithDegree,
+    findTopLeft
+}

+ 127 - 42
pages/album/album.js

@@ -1,4 +1,13 @@
 // pages/album/album.js
+// 获取显示区域长宽
+const device = wx.getSystemInfoSync()
+const W = device.windowWidth
+const H = device.windowHeight - 50
+
+let cropper = require('../../component/welCropper/welCropper.js');
+
+console.log(device)
+
 const HOST = require('../../utils/const.js').apiUrl;
 import httpRequestApi from '../../utils/APIRequest';
 Page({
@@ -26,7 +35,10 @@ Page({
     });
   },
   //上传相册
-  addPhoto: function () {
+  addPhoto: function (e) {
+    let that = this
+    let mode = e.currentTarget.dataset.mode
+    //如果用户没有填写信息不能上传图片
     const userInfo = wx.getStorageSync('userInfo');
     if(!userInfo.data.data.mobileNo || !userInfo.data.data.avatar) {
       wx.navigateTo({
@@ -34,6 +46,7 @@ Page({
       })
       return false;
     };
+    //提示图片上传不能超过15张
     if(this.data.photoList.length >= 15) {
       wx.showModal({  
         title: '温馨提示',  
@@ -55,50 +68,118 @@ Page({
           mask: true,  
           duration: 1000 
         }) 
-        wx.navigateTo({
-          url: '/pages/clipPhoto/clipPhoto?imageUrl=' + tempFilePaths[0] 
-        })
-        /*
-        const that = this; 
-        tempFilePaths.forEach(item => {
-          //上传文件
-          wx.uploadFile({  
-            url: HOST + 'wx/file/upload',  
-            filePath: item,  
-            name: 'uploadfile_ant',  
-            header: {  
-              "Content-Type": "multipart/form-data"  
-            },  
-            success: (res) => {  
-              uploadImgCount++; 
-              const data = JSON.parse(res.data);
-              if(data.success) {
-                //上传文件成功后放到相册里
-                httpRequestApi.addPhotoList({
-                  path: data.data
-                }).success((res) => {
-                  if(res.data.success) {
-                    //再次调用相册列表
-                    that.getPhotoList();
-                  }
-                }).fail(() => {
+        //调用图片截取方法
+        that.showCropper({
+          src: tempFilePaths[0],
+          mode: mode,
+          sizeType: ['original', 'compressed'],   //'original'(default) | 'compressed'
+          callback: (res) => {
+            if (mode == 'rectangle') {
+              // wx.previewImage({
+              //   current: res,
+              //   urls: [res]
+              // })
+
+              that.hideCropper() //隐藏,项目里是点击完成就上传,所以如果回调是上传,那么隐藏掉就行了,不用previewImage
+              wx.showToast({  
+                title: '玩命加载中...',  
+                icon: 'loading',  
+                mask: true,  
+                duration: 1000 
+              }) 
+              //上传文件
+              wx.uploadFile({  
+                url: HOST + 'wx/file/upload',  
+                filePath: res,  
+                name: 'uploadfile_ant',  
+                header: {  
+                  "Content-Type": "multipart/form-data"  
+                },  
+                success: (res) => {  
+                  const data = JSON.parse(res.data);
+                  if(data.success) {
+                    //上传文件成功后放到相册里
+                    httpRequestApi.addPhotoList({
+                      path: data.data
+                    }).success((res) => {
+                      if(res.data.success) {
+                        //再次调用相册列表
+                        that.getPhotoList();
+                      }
+                    }).fail(() => {
+                      wx.showModal({  
+                        title: '错误提示',  
+                        content: '图片上传到相册失败'
+                      }) 
+                    });
+                  } 
+                },  
+                fail: function (res) {  
+                  wx.hideToast();  
                   wx.showModal({  
                     title: '错误提示',  
-                    content: '图片上传到相册失败'
-                  }) 
+                    content: '上传图片失败'
+                  })  
+                }  
+              }); 
+
+
+
+                /*
+                const that = this; 
+                tempFilePaths.forEach(item => {
+                  //上传文件
+                  wx.uploadFile({  
+                    url: HOST + 'wx/file/upload',  
+                    filePath: item,  
+                    name: 'uploadfile_ant',  
+                    header: {  
+                      "Content-Type": "multipart/form-data"  
+                    },  
+                    success: (res) => {  
+                      uploadImgCount++; 
+                      const data = JSON.parse(res.data);
+                      if(data.success) {
+                        //上传文件成功后放到相册里
+                        httpRequestApi.addPhotoList({
+                          path: data.data
+                        }).success((res) => {
+                          if(res.data.success) {
+                            //再次调用相册列表
+                            that.getPhotoList();
+                          }
+                        }).fail(() => {
+                          wx.showModal({  
+                            title: '错误提示',  
+                            content: '图片上传到相册失败'
+                          }) 
+                        });
+                      } 
+                    },  
+                    fail: function (res) {  
+                      wx.hideToast();  
+                      wx.showModal({  
+                        title: '错误提示',  
+                        content: '上传图片失败'
+                      })  
+                    }  
+                  });  
                 });
-              } 
-            },  
-            fail: function (res) {  
-              wx.hideToast();  
-              wx.showModal({  
-                title: '错误提示',  
-                content: '上传图片失败'
-              })  
-            }  
-          });  
-        });
-        */
+                */
+
+            }
+            else {
+              wx.showModal({
+                title: '',
+                content: JSON.stringify(res),
+              })
+
+            }
+          }
+        })
+        // wx.navigateTo({
+        //   url: '/pages/clipPhoto/clipPhoto?imageUrl=' + tempFilePaths[0] 
+        // })
       }
     })
   },
@@ -130,6 +211,10 @@ Page({
    * 生命周期函数--监听页面加载
    */
   onLoad: function (options) {
+    var that = this
+    // 初始化组件数据和绑定事件
+    cropper.init.apply(that, [W, H]);
+    //获取相册列表
     this.getPhotoList();
     //初始化相册是否加密
     const photoBox = (wx.getStorageSync('photoBox') === 'OPEN' ? true : false);

+ 6 - 1
pages/album/album.wxml

@@ -1,4 +1,9 @@
 <!--pages/album/album.wxml-->
+<!-- 引入组件 -->
+<import src="/component/welCropper/welCropper.wxml" />
+
+<!-- 调用组件 -->
+<template is="welCropper" data="{{cropperData:cropperData, cropperMovableItems:cropperMovableItems, cropperChangableData:cropperChangableData}}"></template> 
 <view class="album">
     <view class="album-state">
         <text>相册状态</text>
@@ -22,7 +27,7 @@
         </view>
     </view>
     <view class="photo">
-        <view class="img" bindtap="addPhoto">
+        <view class="img" bindtap="addPhoto" data-mode='rectangle'>
             <image src="../../static/image/add.jpg"></image>    
         </view>
         <view class="img" wx:for="{{photoList}}" wx:key="{{index}}" bindtap="preview" data-index="{{index}}">

+ 1 - 0
pages/album/album.wxss

@@ -1,4 +1,5 @@
 /* pages/album/album.wxss */
+@import "/component/welCropper/welCropper.wxss";
 .album {
     width: 100%;
     height: 100%;