From c7d5e1c2db9801b7d675d24624a41446616923eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=A8=E8=8D=A3?= <372638156@qq.com> Date: Tue, 4 Aug 2020 21:12:09 +0800 Subject: [PATCH 01/37] =?UTF-8?q?feat(ImageClipper):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=9B=BE=E7=89=87=E8=A3=81=E5=89=AA=E7=BB=84=E4=BB=B6=20close?= =?UTF-8?q?=20#561?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- commitlint.config.js | 3 +- examples/app.json | 3 +- .../form/pages/image-clipper/clipper-nav.js | 144 ++++ .../form/pages/image-clipper/index.js | 69 ++ .../form/pages/image-clipper/index.json | 7 + .../form/pages/image-clipper/index.wxml | 55 ++ .../form/pages/image-clipper/index.wxss | 14 + .../navigator/content/config/form-navi.js | 6 + src/image-clipper-tools/index.js | 80 ++ src/image-clipper-tools/index.json | 4 + src/image-clipper-tools/index.less | 19 + src/image-clipper-tools/index.wxml | 28 + src/image-clipper/calculate.js | 276 ++++++ src/image-clipper/images/close.png | Bin 0 -> 2768 bytes src/image-clipper/images/photo.png | Bin 0 -> 1288 bytes src/image-clipper/images/rotate-along.png | Bin 0 -> 1796 bytes src/image-clipper/images/rotate-inverse.png | Bin 0 -> 1786 bytes src/image-clipper/images/sure.png | Bin 0 -> 2620 bytes src/image-clipper/index.js | 802 ++++++++++++++++++ src/image-clipper/index.json | 4 + src/image-clipper/index.less | 131 +++ src/image-clipper/index.wxml | 68 ++ 22 files changed, 1711 insertions(+), 2 deletions(-) create mode 100644 examples/pages/components/form/pages/image-clipper/clipper-nav.js create mode 100644 examples/pages/components/form/pages/image-clipper/index.js create mode 100644 examples/pages/components/form/pages/image-clipper/index.json create mode 100644 examples/pages/components/form/pages/image-clipper/index.wxml create mode 100644 examples/pages/components/form/pages/image-clipper/index.wxss create mode 100644 src/image-clipper-tools/index.js create mode 100644 src/image-clipper-tools/index.json create mode 100644 src/image-clipper-tools/index.less create mode 100644 src/image-clipper-tools/index.wxml create mode 100644 src/image-clipper/calculate.js create mode 100755 src/image-clipper/images/close.png create mode 100755 src/image-clipper/images/photo.png create mode 100755 src/image-clipper/images/rotate-along.png create mode 100755 src/image-clipper/images/rotate-inverse.png create mode 100755 src/image-clipper/images/sure.png create mode 100644 src/image-clipper/index.js create mode 100644 src/image-clipper/index.json create mode 100644 src/image-clipper/index.less create mode 100644 src/image-clipper/index.wxml diff --git a/commitlint.config.js b/commitlint.config.js index 29412e43..1396f7e6 100644 --- a/commitlint.config.js +++ b/commitlint.config.js @@ -69,7 +69,8 @@ module.exports = { 'IndexList', 'Behavior', 'CapsuleBar', - 'Circle' + 'Circle', + 'ImageClipper' ] ] } diff --git a/examples/app.json b/examples/app.json index c4a215e4..b359f126 100644 --- a/examples/app.json +++ b/examples/app.json @@ -96,6 +96,7 @@ "pages/checkbox/index", "pages/textarea/index", "pages/image-picker/index", + "pages/image-clipper/index", "pages/rules/index", "pages/rate/index", "pages/form/index" @@ -142,4 +143,4 @@ "content-card": "/components/content-card/index" }, "sitemapLocation": "sitemap.json" -} +} \ No newline at end of file diff --git a/examples/pages/components/form/pages/image-clipper/clipper-nav.js b/examples/pages/components/form/pages/image-clipper/clipper-nav.js new file mode 100644 index 00000000..8852c8ce --- /dev/null +++ b/examples/pages/components/form/pages/image-clipper/clipper-nav.js @@ -0,0 +1,144 @@ +const clipperNaviConfigs = [{ + title: '基本案例', + type: 0, + config: { + show: false, + zIndex: 99, + imageUrl: '', + type: 'url', + quality: 1, + width: 400, + height: 400, + minWidth: 200, + maxWidth: 600, + minHeight: 200, + maxHeight: 600, + lockWidth: false, + lockHeight: false, + lockRatio: true, + scaleRatio: 1, + minRatio: 0.5, + maxRatio: 2, + disableScale: false, + disableRotate: false, + limitMove: false, + resultImageUrl: '', + checkImage: true, + checkImageIcon: './images/photo.png', + rotateAlong: true, + rotateAlongIcon: './images/rotate-along.png', + rotateInverse: true, + rotateInverseIcon: './images/rotate-inverse.png', + sure: true, + sureIcon: './images/sure.png', + close: true, + closeIcon: './images/close.png', + }, + toolsConfig: { + zIndex: 999, + rotateAngle: 90, + lockWidth: false, + lockHeight: false, + lockRatio: false, + disableScale: false, + disableRotate: false, + limitMove: false + } +}, +{ + title: '页面选择图片', + type: 1, + config: { + show: false, + zIndex: 99, + imageUrl: '', + type: 'url', + quality: 1, + width: 400, + height: 400, + minWidth: 200, + maxWidth: 600, + minHeight: 200, + maxHeight: 600, + lockWidth: false, + lockHeight: false, + lockRatio: false, + scaleRatio: 1, + minRatio: 0.5, + maxRatio: 2, + disableScale: false, + disableRotate: false, + limitMove: false, + resultImageUrl: '', + checkImage: true, + checkImageIcon: './images/photo.png', + rotateAlong: true, + rotateAlongIcon: './images/rotate-along.png', + rotateInverse: true, + rotateInverseIcon: './images/rotate-inverse.png', + sure: true, + sureIcon: './images/sure.png', + close: true, + closeIcon: './images/close.png', + }, + toolsConfig: { + zIndex: 999, + rotateAngle: 90, + lockWidth: false, + lockHeight: false, + lockRatio: false, + disableScale: false, + disableRotate: false, + limitMove: false + } +}, +{ + title: '自定义工具栏功能', + type: 2, + config: { + show: false, + zIndex: 99, + imageUrl: '', + type: 'url', + quality: 1, + width: 400, + height: 400, + minWidth: 200, + maxWidth: 600, + minHeight: 200, + maxHeight: 600, + lockWidth: false, + lockHeight: false, + lockRatio: true, + scaleRatio: 1, + minRatio: 0.5, + maxRatio: 2, + disableScale: false, + disableRotate: false, + limitMove: false, + resultImageUrl: '', + checkImage: true, + checkImageIcon: './images/photo.png', + rotateAlong: true, + rotateAlongIcon: './images/rotate-along.png', + rotateInverse: true, + rotateInverseIcon: './images/rotate-inverse.png', + sure: true, + sureIcon: './images/sure.png', + close: true, + closeIcon: './images/close.png', + }, + toolsConfig: { + zIndex: 999, + rotateAngle: 90, + lockWidth: true, + lockHeight: true, + lockRatio: true, + disableScale: true, + disableRotate: true, + limitMove: true + } +} +]; + +export default clipperNaviConfigs; diff --git a/examples/pages/components/form/pages/image-clipper/index.js b/examples/pages/components/form/pages/image-clipper/index.js new file mode 100644 index 00000000..65348693 --- /dev/null +++ b/examples/pages/components/form/pages/image-clipper/index.js @@ -0,0 +1,69 @@ +import clipperNaviConfigs from './clipper-nav'; +Page({ + + /** + * 页面的初始数据 + */ + data: { + clipperNaviConfigs, + currentConfig: {}, + toolsConfig: {}, + currentIndex: 0 + }, + /** + * 生命周期函数--监听页面加载 + */ + onLoad: function () { + const current = this.data.clipperNaviConfigs[this.data.currentIndex]; + this.setData({ + currentConfig: current.config, + toolsConfig: current.toolsConfig + }); + }, + linclip(event) { + let { + clipperNaviConfigs, + currentIndex + } = this.data; + clipperNaviConfigs[currentIndex].config.resultImageUrl = event.detail.url; + this.setData({ + clipperNaviConfigs, + 'currentConfig.show': false + }); + }, + upload(event) { + const currentIndex = event.currentTarget.dataset.index; + const current = this.data.clipperNaviConfigs[currentIndex]; + let currentConfig = current.config; + let toolsConfig = current.toolsConfig; + + wx.chooseImage({ + count: 1, + sizeType: ['original', 'compressed'], + sourceType: ['album', 'camera'], + success: (res) => { + // tempFilePath可以作为img标签的src属性显示图片 + const tempFilePaths = res.tempFilePaths; + currentConfig.imageUrl = tempFilePaths; + currentConfig.show = true; + this.setData({ + currentConfig, + toolsConfig, + currentIndex + }); + } + }); + }, + showClipper(event) { + const currentIndex = event.currentTarget.dataset.index; + const current = this.data.clipperNaviConfigs[currentIndex]; + let currentConfig = current.config; + let toolsConfig = current.toolsConfig; + currentConfig.show = true; + this.setData({ + currentConfig, + currentIndex, + toolsConfig + }); + }, +}); diff --git a/examples/pages/components/form/pages/image-clipper/index.json b/examples/pages/components/form/pages/image-clipper/index.json new file mode 100644 index 00000000..17966d79 --- /dev/null +++ b/examples/pages/components/form/pages/image-clipper/index.json @@ -0,0 +1,7 @@ +{ + "usingComponents": { + "l-image-clipper": "/dist/image-clipper/index", + "l-image-clipper-tools": "/dist/image-clipper-tools/index", + "l-card": "/dist/card/index" + } +} \ No newline at end of file diff --git a/examples/pages/components/form/pages/image-clipper/index.wxml b/examples/pages/components/form/pages/image-clipper/index.wxml new file mode 100644 index 00000000..a8f4b4f3 --- /dev/null +++ b/examples/pages/components/form/pages/image-clipper/index.wxml @@ -0,0 +1,55 @@ + + + + + + + 显示组件 + 选择图片 + + + + + + \ No newline at end of file diff --git a/examples/pages/components/form/pages/image-clipper/index.wxss b/examples/pages/components/form/pages/image-clipper/index.wxss new file mode 100644 index 00000000..404127de --- /dev/null +++ b/examples/pages/components/form/pages/image-clipper/index.wxss @@ -0,0 +1,14 @@ + +.image-wrapper { + width: 100%; + display: flex; + justify-content: center; + margin-top: 20rpx; + padding: 20rpx; + box-sizing: border-box; +} + +.image-wrapper image { + width: 100%; + height: 100%; +} \ No newline at end of file diff --git a/examples/pages/navigator/content/config/form-navi.js b/examples/pages/navigator/content/config/form-navi.js index 8455b367..346f60ab 100644 --- a/examples/pages/navigator/content/config/form-navi.js +++ b/examples/pages/navigator/content/config/form-navi.js @@ -29,6 +29,12 @@ const formNaviConfigs = [ desc: '图片选择器', componentsPath: '/pages/components/form/pages/image-picker/index' }, + { + icon: '/images/component/progress.png', + title: 'ImageClipper', + desc: '图片裁剪', + componentsPath: '/pages/components/form/pages/image-clipper/index' + }, { icon: '/images/component/rate.png', title: 'Rate', diff --git a/src/image-clipper-tools/index.js b/src/image-clipper-tools/index.js new file mode 100644 index 00000000..3226d451 --- /dev/null +++ b/src/image-clipper-tools/index.js @@ -0,0 +1,80 @@ +Component({ + + relations: { + '../image-clipper/index': { + type: 'parent' + } + }, + externalClasses: ['l-class'], + + /** + * 组件的属性列表 + */ + properties: { + // 组件层级 + zIndex: { + type: Number, + value: 999 + }, + // 是否显示锁定裁剪框宽度按钮 + lockWidth: { + type: Boolean, + value: false + }, + // 是否显示锁定裁剪框高度按钮 + lockHeight: { + type: Boolean, + value: false + }, + // 是否显示锁定裁剪框比例按钮 + lockRatio: { + type: Boolean, + value: false + }, + // 是否显示禁止缩放按钮 + disableScale: { + type: Number, + value: false + }, + // 是否显示禁止旋转按钮 + disableRotate: { + type: Number, + value: false + }, + // 是否显示限制移动范围按钮 + limitMove: { + type: Boolean, + value: false + } + }, + + /** + * 组件的初始数据 + */ + data: { + formColor: '#3963bc', + lockWidthValue: false, + lockHeightValue: false, + lockRatioValue: true, + disableScaleValue: false, + disableRotateValue: false, + limitMoveValue: false + }, + + /** + * 组件的方法列表 + */ + methods: { + /** + * switch change事件 + */ + bindSwitchChange: async function(event) { + const value = event.detail.value; + const type = event.currentTarget.dataset.type; + let parent = this.getRelationNodes('../image-clipper/index')[0]; + await parent.setData({ + [type]: value + }); + }, + } +}); diff --git a/src/image-clipper-tools/index.json b/src/image-clipper-tools/index.json new file mode 100644 index 00000000..e8cfaaf8 --- /dev/null +++ b/src/image-clipper-tools/index.json @@ -0,0 +1,4 @@ +{ + "component": true, + "usingComponents": {} +} \ No newline at end of file diff --git a/src/image-clipper-tools/index.less b/src/image-clipper-tools/index.less new file mode 100644 index 00000000..893bf57c --- /dev/null +++ b/src/image-clipper-tools/index.less @@ -0,0 +1,19 @@ +.tools-container { + width: 100%; + padding: 20rpx 40rpx; + box-sizing: border-box; + + .tools-form { + margin-top: 20rpx; + display: flex; + flex-wrap: wrap; + color: #ffffff; + .slider-wrapper { + display: flex; + align-items: center; + } + switch { + transform: scale(0.7); + } + } +} \ No newline at end of file diff --git a/src/image-clipper-tools/index.wxml b/src/image-clipper-tools/index.wxml new file mode 100644 index 00000000..35f37ef2 --- /dev/null +++ b/src/image-clipper-tools/index.wxml @@ -0,0 +1,28 @@ + + + + 锁定裁剪框宽 + + + + 锁定裁剪框高 + + + + 锁定裁剪框比例 + + + + 限制移动范围 + + + + 禁止缩放 + + + + 禁止旋转 + + + + \ No newline at end of file diff --git a/src/image-clipper/calculate.js b/src/image-clipper/calculate.js new file mode 100644 index 00000000..1dffc8e7 --- /dev/null +++ b/src/image-clipper/calculate.js @@ -0,0 +1,276 @@ +/** + * 判断手指触摸位置 + * + * @param {*} cutX + * @param {*} cutY + * @param {*} clipWidth + * @param {*} clipHeight + * @param {*} currentX + * @param {*} currentY + * @returns + */ +export function determineDirection(cutX, cutY, clipWidth, clipHeight, currentX, currentY) { + /* + * (右下>>1 右上>>2 左上>>3 左下>>4) + * left_x: 裁剪框左边线距离视口最左侧两点位置 [3,4] + * right_x: 裁剪框右边线距离视口最右侧两点位置 [1,2] + * top_y: 裁剪框顶部线距离视口最顶部两点位置 [2,3] + * bottom_y:裁剪框底部线距离视口最底部两点位置 [1,4] + */ + // 用户体验优化,增加裁剪框四角可触摸区域 + const EXPAND_SIZE = 24; + + let left_x1 = cutX - EXPAND_SIZE; + let left_x2 = cutX + EXPAND_SIZE; + + let top_y1 = cutY - EXPAND_SIZE; + let top_y2 = cutY + EXPAND_SIZE; + + let right_x1 = cutX + clipWidth - EXPAND_SIZE; + let right_x2 = cutX + clipWidth + EXPAND_SIZE; + + let bottom_y1 = cutY + clipHeight - EXPAND_SIZE; + let bottom_y2 = cutY + clipHeight + EXPAND_SIZE; + /* + * 四角 + * (右下>>1 右上>>2 左上>>3 左下>>4) + */ + let corner; + + const isRight = currentX > right_x1 && currentX < right_x2; + const isLeft = currentX > left_x1 && currentX < left_x2; + const isBottom = currentY > bottom_y1 && currentY < bottom_y2; + const isTop = currentY > top_y1 && currentY < top_y2; + + if (isRight && isBottom) { + corner = 1; + } else if (isRight && isTop) { + corner = 2; + } else if (isLeft && isTop) { + corner = 3; + } else if (isLeft && isBottom) { + corner = 4; + } + return corner; +} + +/** + * 图片边缘检测检测时,计算图片偏移量 + * + * @param {*} data + * @param {*} scale + * @returns + */ +export function calcImageOffset(data, scale) { + let left = data.imageLeft; + let top = data.imageTop; + scale = scale || data.scale; + + let imageWidth = data.imageWidth; + let imageHeight = data.imageHeight; + if ((data.angle / 90) % 2) { + imageWidth = data.imageHeight; + imageHeight = data.imageWidth; + } + const { + cutX, + clipWidth, + cutY, + clipHeight + } = data; + // 当前图片宽度/高度 + const currentImageSize = (size) => (size * scale) / 2; + const currentImageWidth = currentImageSize(imageWidth); + const currentImageHeight = currentImageSize(imageHeight); + + left = cutX + currentImageWidth >= left ? left : cutX + currentImageWidth; + left = cutX + clipWidth - currentImageWidth <= left ? left : cutX + clipWidth - currentImageWidth; + top = cutY + currentImageHeight >= top ? top : cutY + currentImageHeight; + top = cutY + clipHeight - currentImageHeight <= top ? top : cutY + clipHeight - currentImageHeight; + return { + left, + top, + scale + }; +} + +/** + * 图片边缘检测时,计算图片缩放比例 + * + * @param {*} data + * @param {*} scale + * @returns + */ +export function calcImageScale(data, scale) { + scale = scale || data.scale; + let imageWidth = data.imageWidth; + let imageHeight = data.imageHeight; + if ((data.angle / 90) % 2) { + imageWidth = data.imageHeight; + imageHeight = data.imageWidth; + } + if (imageWidth * scale < data.clipWidth) { + scale = data.clipWidth / imageWidth; + } + if (imageHeight * scale < data.clipHeight) { + scale = Math.max(scale, data.clipHeight / imageHeight); + } + return scale; +} + +/** + * 计算图片尺寸 + * + * @export + * @param {*} width + * @param {*} height + * @param {*} data + * @returns + */ +export function calcImageSize(width, height, data) { + // 默认按图片最小边 = 对应裁剪框尺寸 + let imageWidth = width, + imageHeight = height; + if (imageWidth && imageHeight) { + if (imageWidth / imageHeight > (data.clipWidth || data.width) / (data.clipWidth || data.height)) { + imageHeight = data.clipHeight || data.height; + imageWidth = (width / height) * imageHeight; + } else { + imageWidth = data.clipWidth || data.width; + imageHeight = (height / width) * imageWidth; + } + } else { + let sys = data._SYS_INFO || wx.getSystemInfoSync(); + imageWidth = sys.windowWidth; + imageHeight = 0; + } + return { + imageWidth, + imageHeight + }; +} + +/** + * 勾股定理求斜边 + * + * @param {*} width + * @param {*} height + * @returns + */ +export function calcPythagoreanTheorem(width, height) { + return Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2)); +} + +/** + * 拖动裁剪框时计算 + * + * @export + * @param {*} data + * @param {*} event + * @returns + */ +export function clipTouchMoveOfCalculate(data, event) { + const clientX = event.touches[0].clientX; + const clientY = event.touches[0].clientY; + + const { + clipWidth, + clipHeight, + cutY: oldCutY, + cutX: oldCutX, + _CUT_START, + lockRatio + } = data; + let { + maxWidth, + minWidth, + maxHeight, + minHeight + } = data; + maxWidth = maxWidth / 2; + minWidth = minWidth / 2; + minHeight = minHeight / 2; + maxHeight = maxHeight / 2; + + let width = clipWidth, + height = clipHeight, + cutY = oldCutY, + cutX = oldCutX, + // 获取裁剪框实际宽度/高度 + // 如果大于最大值则使用最大值 + // 如果小于最小值则使用最小值 + size_correct = () => { + width = width <= maxWidth ? (width >= minWidth ? width : minWidth) : maxWidth; + height = height <= maxHeight ? (height >= minHeight ? height : minHeight) : maxHeight; + }, + size_inspect = () => { + if ((width > maxWidth || width < minWidth || height > maxHeight || height < minHeight) && lockRatio) { + size_correct(); + return false; + } else { + size_correct(); + return true; + } + }; + height = _CUT_START.height + (_CUT_START.corner > 1 && _CUT_START.corner < 4 ? 1 : -1) * (_CUT_START.y - clientY); + switch (_CUT_START.corner) { + case 1: + width = _CUT_START.width - _CUT_START.x + clientX; + if (lockRatio) { + height = width / (clipWidth / clipHeight); + } + if (!size_inspect()) return; + break; + case 2: + width = _CUT_START.width - _CUT_START.x + clientX; + if (lockRatio) { + height = width / (clipWidth / clipHeight); + } + if (!size_inspect()) return; + cutY = _CUT_START.cutY - (height - _CUT_START.height); + break; + case 3: + width = _CUT_START.width + _CUT_START.x - clientX; + if (lockRatio) { + height = width / (clipWidth / clipHeight); + } + if (!size_inspect()) return; + cutY = _CUT_START.cutY - (height - _CUT_START.height); + cutX = _CUT_START.cutX - (width - _CUT_START.width); + break; + case 4: + width = _CUT_START.width + _CUT_START.x - clientX; + if (lockRatio) { + height = width / (clipWidth / clipHeight); + } + if (!size_inspect()) return; + cutX = _CUT_START.cutX - (width - _CUT_START.width); + break; + default: + break; + } + return { + width, + height, + cutX, + cutY + }; +} + +/** + * 单指拖动图片计算偏移 + * + * @export + * @param {*} data + * @param {*} clientXForLeft + * @param {*} clientYForLeft + * @returns + */ +export function imageTouchMoveOfCalcOffset(data, clientXForLeft, clientYForLeft) { + let left = clientXForLeft - data._touchRelative[0].x, + top = clientYForLeft - data._touchRelative[0].y; + return { + left, + top + }; +} diff --git a/src/image-clipper/images/close.png b/src/image-clipper/images/close.png new file mode 100755 index 0000000000000000000000000000000000000000..a1c6c99c250b02bce100042a50b460444cf9ddc8 GIT binary patch literal 2768 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 literal 0 HcmV?d00001 diff --git a/src/image-clipper/images/photo.png b/src/image-clipper/images/photo.png new file mode 100755 index 0000000000000000000000000000000000000000..80928c3ba4ef40c66af2ba0df3b6ea33cbbc61ef GIT binary patch literal 1288 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 Tk*#;_{|5z(C(ff88JYPnu8*-u literal 0 HcmV?d00001 diff --git a/src/image-clipper/images/rotate-inverse.png b/src/image-clipper/images/rotate-inverse.png new file mode 100755 index 0000000000000000000000000000000000000000..ec77b6b55b31ce92efac9fd60c3ee9bff3832f45 GIT binary patch literal 1786 zcmdUw`#%#3AIHgEn`V?vE?ee)8=2+S!#1{|S!=Nv@id7Ja#x1sw)DgqX*Tr`XD%}> zmrnE;hup@b$gy10LqyVXjygGVI?n6${1eaT_4<6?zkXidAHJVLG6@gV)Ynu{PyiAM zILbbye_LH?KPw8tn)V?g`%}I5`R)Hi&mK1L_v@ZWrjX7kSWo&bwizDQ*xZpeh6Ez3 zvcAJYS17fqi0#>dirWm=^>K;#1}nq!3OjWJkyEaGF=@9vLQJHJ_rii3p|c5L&%`%hQ8rAPLRHCNN^%4Kg8pWG|a zdb_@$d31Kcsr6$1uh;#PW-})*zmEMHNptn6h;+Q(`P#1cjeU%9rf&;2Y1f4X>r53= ztj;aDWa->$v4|9}9$RQ_(6c}VzwX99wMr&_znj%=5|RJOpmgK6qRH7istQMrf)fpQ z$vtjoi7l>KJ2s%8wu6x|86Jk7B|)wBUc#H+Bahr~aJS9LaZD3$BNnZ2_AXXw*DIz8 z76>+~CPw>MrGqTj9^N0HHoeO7Br>p~AG{}EP783$g8XA6p|?tlQT z-~(>faCNZOR?eo`T+r@=zWJ1q{P$u9Bj7K^ltlOtky@8+nPwIsX(}a1?}NF8wO54c zGk!2pa&t2Of>(PTn6D}P?svYze%*<#iI5tF zoW}`y%7)kEUGf5mU$&Ibm@@+=UHmup=b*}%NB7`P`y0G%{F6G z%eH$0VRnL=Wh0i5L?_^h%5^FUa8py$X%texEVbfpm(c0n)Po9x)CXatx!sxHR=f(UW;4L3+IFJXwxd2g(#7a`x?)un~Dgs43R`P z!)x_h?PqE4O~O_l=-X06nn#X*9@}$L#@-%vQ0>bd9arot96fz8;GF6f?_g~1tsYNR zXl}2d>s3*cKf(Rmvk9sUTwQ|_zaum_E_VREGT5i#AL`f-@HC5a6!&aPZbLCJowkUpijS=< zC*n&;wY;!<5`$0OL&h*trp@#^-gtWwtDvsK`2ixefaWNFM6t7 zr{g^btY^$j!~j(5qEglyr36zinna8ov#MV z6a2KlSe?3d=6Np9ju?X>r1`|Zvw>ftO-bUu#D0yr>1OCf!?nW1x+NX6pEVN9fz~eE zB{Um1=N4*guTC$W>hqI~~C%F&|s)T188&swjdYw%9x7W0lxds%pzh6M z>)Zd|p^yrS{JT;<;9o;i5_BBsxMniQpkK5ka}EC)>KtmxPkC;}<>d+-j#3U^w&&f- zm77aq-41>ty;o7B^`JeO*1Xi>iiCukMHdV*3tqr4&im!7Gg4y51SoXWh13~e&2(EK zd4!8@Z(GeOB+NNDN&C?Hn6f=U``EHSmzD>@i{a!@hbF80EN6nZ=nHKN&WdkA>V`St z1Uze4*P}Zvx)}sjS|w(HVP$qHWFCl@!O+)^D03P2@8|cGE3F0*i`D+g zl{=c&YFMfs;B+>yJ04(f)JnSenFW54Gz|=pEK;qzhk2~^MoP1|b&$^-+y>y4ewEhbstB@u|LI>nG>MDs!?UNdRqQU@o!m_4iw?3ifBRlU4P<>tfXtSg11jc^5GXS7Q@ zQk)yxmrK(!8k#erS?g%c^&mjjdVp7zT79CQcS~;&`w0~;BGqJ5P76Y)9;xz4RdB+u z#j)}L5^X?JX9Xg~DA)9YNJaWH$R)omQqc|%V4SsTM zdJI>n;R8|VQZt1B)1pi~Q#4Y96dvZg+G5Kfd$>$Dt{(_{wdPmI(mV$Fi>tt)a6F`o zIwTugCs2g$)+C*8B?9!`SEf}&HbQvIqJOgA+8TM2QO+;bC8q8s zkTFAIH3Hxxfr{r_w8nRD!M$CUnD|T4jNeO^1}XlO3XJeQmt;06`%32x+COO_)%c&A zJfq5a<`-(GvW*U)tI{7s_f+~3C8)V-tnk(3oH6jrk@AMgTiRzldX}_Fsv1E=98<&I zsc`O$v1opDe(5sk(MYo3>*G(vN!TIl4?n>_>7mav>8-g(Pdj8Tv!5%WQix+RV$1p| z?}vEW*OIZ>*fP~1D4W&Voaf`)w++WFJz`3~v?O+aW>3aXsq!f1MD?%Wy7?berecy^dTDNrM)(2 z{q+mBY3ohVb0ZY}0)A|%{dqH$9gO)4DLeF_;1=`YRYMB*RGK5tu}r^$k7X_@utlx^ zKxF(#s``(RL6CbVTYXez;M4z}Nd{~ueXAu$d!&2A7Qs^{dn(eE2EXSmF`txyYy?eC z?hgKLb@w(HLIu4>;6EP)7Fz3usXOIfUpBn=sc1X@9_#e^?1>ji`jeo(d_hxy!KZX@ zS8)}Y4!v1;MmYV@L6S&K+@c4=VV9>{+fh0Zn&Tnvvirnk2c=D*j_`2SXZPQ)nzS07 z1^K@aX{nP~@lobz+T(WsScHOGMob*U(yqWm@$x2sBnyR@DE&L3YP4zu>YJ+D8u0!XKP1*{y51 zSo3tPiQ{;u0v-Db<3JlnzD#JzTaiP!D?){cV0W~>rq9@EuJaPW@gf87ubnbDti9`f z<#2R{wWbO5wfo-3{MIy6+EW6@`){DH|7f442P(`R|Iq?AJo~kfo8dM4&WXU_P$~Kp z0DHMIx7?HK!LKAO@n?CZLrR#Q!sMerLkA<4k%>%LQs8xUmGr@_=gx&Y#OS_sx|^H( z8H}_hLBDc(`9C9#Savn4WF=|F(3XW1b|9uYS7;4E&i7Dh_d}u={3?!to1s$a7rJk! zz3@^MZpN(f`dz)!uag8eXVu14TVntES2losTuy0=EQ`Ue`uqqhpi=B0Rj%l9Nklo! zYLOort|O8p`rqLkpVkUQiB})$$jQKG0sJi-N|zE8sZ4)`_S^70EYpxn8#?})-^T+8 z+txVzF1aU0c(fMm+YcWAhye=6uZ*u*lL1jd9AhA3RC;PD{}t2`p8O+!w|#-ogA`|J zoOG^yKriX6`TYB1i#$S4Tcl^%5YrZ;iMC^zcI!!7Lu)_$gW`sp2huA(%5C*gPxS&m zcWVa`6_Sb!JvUr{EJLU+rGVV*sLawE;VCA-fYMgLhnn`emvK?H1t^XOlfGS4(a(b| z6qh(ley^kw2v8vdO*hpIlO8&u{iTH)r|GWUqzm88X+bY;9jp)sSKr6FZ7Hc!cv(}V zAlaKS_3JO2#Vve24_B6T&dp(s2|sPZiNV89nRT>ids4%_B1V<3DszuWw%)} zJ~kne+v}hxVvfFj(EA7%DcxR*herl zFltjZ?}!%;AFI#|Fx^cFMub8$LN;4@v5ktg1148-AHNpRAND!6O}iajR!X4#d|x4^a{XFN@yAp7m-O}EhS?zdB+qqpGV@P#*+k9hC2A^ z)Wgd4w$r4LwZ;M9;LKDD0-kO3Pc=0;Yz$;{7{QR`LbX!Qio~n#X^lFFv(?_rTMl}f zAQ2e}ucQoxRyjHQivv7~Dqhg&)^++V(+h|WfhgNob9wG>uC{f3A-fY#hz|ZkX~{L3 VXF { + // 计算图片尺寸 + this.imgComputeSize(res.width, res.height); + if (this.properties.limitMove) { + // 限制移动,不留空白处理 + this.imgMarginDetectionScale(); + eventUtil.emit(this, 'linimageready', res); + } + }, + fail: () => { + this.imgComputeSize(); + if (this.properties.limitMove) { + this.imgMarginDetectionScale(); + } + } + }); + }, + 'clipWidth, clipHeight'(widthVal, heightVal) { + let { minWidth, minHeight } = this.data; + minWidth = minWidth / 2; + minHeight = minHeight / 2; + if (widthVal < minWidth) { + dataUtil.setDiffData(this, { clipWidth: minWidth }); + } + if (heightVal < minHeight) { + dataUtil.setDiffData(this, { clipHeight: minHeight }); + } + this.computeCutSize(); + }, + 'rotateAngle'(val) { + dataUtil.setDiffData(this, { cutAnimation: true, angle: val }); + }, + 'angle'(val) { + this.moveStop(); + const { + limitMove + } = this.properties; + if (limitMove && val % 90) { + dataUtil.setDiffData(this, { angle: Math.round(val / 90) * 90 }); + } + this.imgMarginDetectionScale(); + }, + 'cutAnimation'(val) { + // 开启过渡260毫秒之后自动关闭 + clearTimeout(this.data._cutAnimationTime); + if (val) { + let _cutAnimationTime = setTimeout(() => { + dataUtil.setDiffData(this, { cutAnimation: false }); + }, 260); + dataUtil.setDiffData(this, { _cutAnimationTime }); + } + }, + 'limitMove'(val) { + if (val) { + if (this.data.angle % 90) { + dataUtil.setDiffData(this, { angle: Math.round(this.data.angle / 90) * 90 }); + } + this.imgMarginDetectionScale(); + } + }, + 'cutY, cutX'() { + this.cutDetectionPosition(); + }, + 'width, height'(width, height) { + if(width !== this.width) { + dataUtil.setDiffData(this, {clipWidth: width / 2}); + } + if(height !== this.height) { + dataUtil.setDiffData(this, {clipHeight: height / 2}); + } + } + }, + /** + * 组件的方法列表 + */ + methods: { + /** + * 设置裁剪框的一些信息 + */ + setCutInfo() { + const { + width, + height + } = this.properties; + const { + _SYS_INFO + } = this.data; + // 本组件动态style默认单位为px,需将用户传入值/2 + const clipWidth = width / 2; + const clipHeight = height / 2; + const cutY = (_SYS_INFO.windowHeight - clipHeight) / 2; + const cutX = (_SYS_INFO.windowWidth - clipWidth) / 2; + const imageLeft = _SYS_INFO.windowWidth / 2; + const imageTop = _SYS_INFO.windowHeight / 2; + const _ctx = wx.createCanvasContext('image-clipper', this); + this.setData({ + clipWidth, + clipHeight, + cutX, + cutY, + CANVAS_HEIGHT: clipHeight, + CANVAS_WIDTH: clipWidth, + _ctx, + imageLeft, + imageTop + }); + }, + /** + * 裁剪框居中 + */ + setCutCenter() { + const { sysInfo, clipHeight, clipWidth, imageTop, imageLeft } = this.data; + let sys = sysInfo || wx.getSystemInfoSync(); + let cutY = (sys.windowHeight - clipHeight) * 0.5; + let cutX = (sys.windowWidth - clipWidth) * 0.5; + this.setData({ + imageTop: imageTop - this.data.cutY + cutY, + imageLeft: imageLeft - this.data.cutX + cutX, + cutY, + cutX + }); + }, + /** + * 开始拖动裁剪框 + * 需在此处查找到是否拖动的裁剪框四角 + */ + clipTouchStart(event) { + if (!this.properties.imageUrl) { + wx.showToast({ + title: '请选择图片', + icon: 'none' + }); + return; + } + const currentX = event.touches[0].clientX; + const currentY = event.touches[0].clientY; + const { cutX, cutY, clipWidth, clipHeight } = this.data; + const corner = determineDirection(cutX, cutY, clipWidth, clipHeight, currentX, currentY); + this.moveDuring(); + const _CUT_START = { + width: clipWidth, + height: clipHeight, + x: currentX, + y: currentY, + cutY, + cutX, + corner + }; + this.setData({ _flagCutTouch: true, _flagEndTouch: true, _CUT_START }); + }, + /** + * 拖动裁剪框 + * 当拖动的裁剪框区域时处理数据 + */ + clipTouchMove(event) { + if (!this.properties.imageUrl) { + wx.showToast({ + title: '请选择图片', + icon: 'none' + }); + return; + } + + const { _flagCutTouch, _MOVE_THROTTLE_FLAG } = this.data; + if (_flagCutTouch && _MOVE_THROTTLE_FLAG) { + const { lockRatio, lockHeight, lockWidth } = this.properties; + if (lockRatio && (lockWidth || lockHeight)) return; + dataUtil.setDiffData(this, { _MOVE_THROTTLE_FLAG: false }); + this.moveThrottle(); + const { width, height, cutX, cutY } = clipTouchMoveOfCalculate(this.data, event); + if (!lockWidth && !lockHeight) { + dataUtil.setDiffData(this, { clipWidth: width, clipHeight: height, cutX, cutY }); + } else if (!lockWidth) { + dataUtil.setDiffData(this, { clipWidth: width, cutX }); + } else if (!lockHeight) { + dataUtil.setDiffData(this, { clipHeight: height, cutY }); + } + this.imgMarginDetectionScale(); + } + }, + /** + * 拖动裁剪框结束 + * 当拖动的裁剪框区域时处理数据 + */ + clipTouchEnd() { + this.moveStop(); + this.setData({ _flagCutTouch: false }); + }, + /** + * 清空之前的自动居中延迟函数 + */ + moveDuring() { + clearTimeout(this.data._TIME_CUT_CENTER); + }, + /** + * 停止移动时需要做的操作 + * 清空之前的自动居中延迟函数并添加最新的 + */ + moveStop() { + clearTimeout(this.data._TIME_CUT_CENTER); + const _TIME_CUT_CENTER = setTimeout(() => { + //动画启动 + if (!this.data.cutAnimation) { + dataUtil.setDiffData(this, { cutAnimation: true }); + } + this.setCutCenter(); + }, 800); + dataUtil.setDiffData(this, { _TIME_CUT_CENTER }); + }, + /** + * 重置延迟函数 + */ + moveThrottle() { + if (this.data._SYS_INFO.platform === 'android') { + clearTimeout(this.data._MOVE_THROTTLE); + const _MOVE_THROTTLE = setTimeout(() => { + dataUtil.setDiffData(this, { _MOVE_THROTTLE_FLAG: true }); + }, 800 / 40); + dataUtil.setDiffData(this, { _MOVE_THROTTLE }); + } else { + dataUtil.setDiffData(this, { _MOVE_THROTTLE_FLAG: true }); + } + }, + /** + * 图片初始化 + */ + imageReset() { + const sys = this.data._SYS_INFO || wx.getSystemInfoSync(); + this.setData({ scale: 1, angle: 0, imageTop: sys.windowHeight / 2, imageLeft: sys.windowWidth / 2 }); + }, + /** + * 图片加载完成 + */ + imageLoad() { + this.imageReset(); + wx.hideLoading(); + eventUtil.emit(this, 'linimageload', detail); + }, + /** + * 计算图片尺寸 + */ + imgComputeSize(width, height) { + const { imageWidth, imageHeight } = calcImageSize(width, height, this.data); + this.setData({ imageWidth, imageHeight }); + }, + /** + * 图片边缘检测-缩放 + */ + imgMarginDetectionScale(scale) { + if (!this.properties.limitMove) return; + const currentScale = calcImageScale(this.data, scale); + this.imgMarginDetectionPosition(currentScale); + }, + /** + * 图片边缘检测-位置 + */ + imgMarginDetectionPosition(scale) { + if (!this.properties.limitMove) return; + const { scale: currentScale, left, top } = calcImageOffset(this.data, scale); + dataUtil.setDiffData(this, { imageLeft: left, imageTop: top, scale: currentScale }); + }, + /** + * 开始图片触摸 + */ + imageTouchStart(e) { + this.setData({ _flagEndTouch: false }); + const { imageLeft, imageTop } = this.data; + // 双指左指坐标 + const clientXForLeft = e.touches[0].clientX; + const clientYForLeft = e.touches[0].clientY; + + let _touchRelative = []; + if (e.touches.length === 1) { + // 单指拖动 + _touchRelative[0] = { + x: clientXForLeft - imageLeft, + y: clientYForLeft - imageTop + }; + this.setData({ _touchRelative }); + } else { + // 双指右指坐标 + const clientXForRight = e.touches[1].clientX; + const clientYForRight = e.touches[1].clientY; + // 双指放大 + let width = Math.abs(clientXForLeft - clientXForRight); + let height = Math.abs(clientYForLeft - clientYForRight); + // 勾股定理求出斜边长度 + const _hypotenuseLength = calcPythagoreanTheorem(width, height); + + _touchRelative = [{ + x: clientXForLeft - imageLeft, + y: clientYForLeft - imageTop + }, + { + x: clientXForRight - imageLeft, + y: clientYForRight - imageTop + } + ]; + this.setData({_touchRelative, _hypotenuseLength}); + } + }, + /** + * 图片放大旋转等操作 + */ + imageTouchMove(e) { + const { + _flagEndTouch, + _MOVE_THROTTLE_FLAG + } = this.data; + if (_flagEndTouch || !_MOVE_THROTTLE_FLAG) return; + // 双指左指坐标 + const clientXForLeft = e.touches[0].clientX; + const clientYForLeft = e.touches[0].clientY; + + dataUtil.setDiffData(this, { _MOVE_THROTTLE_FLAG: false }); + this.moveThrottle(); + this.moveDuring(); + if (e.touches.length === 1) { + //单指拖动 + const { left, top } = imageTouchMoveOfCalcOffset(this.data, clientXForLeft, clientYForLeft); + dataUtil.setDiffData(this, { imageLeft: left, imageTop: top}); + // 图像边缘检测,防止截取到空白 + this.imgMarginDetectionPosition(); + } else { + // 双指右指坐标 + const clientXForRight = e.touches[1].clientX; + const clientYForRight = e.touches[1].clientY; + // 双指放大 + let width = Math.abs(clientXForLeft - clientXForRight), + height = Math.abs(clientYForLeft - clientYForRight), + // 勾股定理求出斜边长度 + hypotenuse = calcPythagoreanTheorem(width, height), // 斜边 + scale = this.data.scale * (hypotenuse / this.data._hypotenuseLength); + // 计算出真实缩放倍率 + // 如果禁止缩放则倍率一直为1 + if (this.properties.disableScale) { + scale = 1; + } else { + scale = scale <= this.properties.minRatio ? this.properties.minRatio : scale; + scale = scale >= this.properties.maxRatio ? this.properties.maxRatio : scale; + eventUtil.emit(this, 'linsizechange', { + imageWidth: this.data.imageWidth * scale, + imageHeight: this.data.imageHeight * scale + }); + } + + this.imgMarginDetectionScale(scale); + dataUtil.setDiffData(this, { + _hypotenuseLength: Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2)), + scale + }); + } + }, + /** + * 图片手指触摸结束 + */ + imageTouchEnd() { + dataUtil.setDiffData(this, { _flagEndTouch: true }); + this.moveStop(); + }, + + /** + * 检测剪裁框位置是否在允许的范围内(屏幕内) + */ + cutDetectionPosition() { + const { cutX, cutY, _SYS_INFO, clipHeight, clipWidth } = this.data; + let cutDetectionPositionTop = () => { + //检测上边距是否在范围内 + if (cutY < 0) { + dataUtil.setDiffData(this, { cutY: 0 }); + } + if (cutY > _SYS_INFO.windowHeight - clipHeight) { + dataUtil.setDiffData(this, { cutY: _SYS_INFO.windowHeight - clipHeight }); + } + }, + cutDetectionPositionLeft = () => { + //检测左边距是否在范围内 + if (cutX < 0) { + dataUtil.setDiffData(this, { cutX: 0 }); + } + if (cutX > _SYS_INFO.windowWidth - clipWidth) { + dataUtil.setDiffData(this, { cutX: _SYS_INFO.windowWidth - clipWidth }); + } + }; + //裁剪框坐标处理(如果只写一个参数则另一个默认为0,都不写默认居中) + if (cutY === null && cutX === null) { + let newCutY = (_SYS_INFO.windowHeight - clipHeight) * 0.5; + let newCutX = (_SYS_INFO.windowWidth - clipWidth) * 0.5; + dataUtil.setDiffData(this, { + cutX: newCutX, // 截取的框上边距 + cutY: newCutY // 截取的框左边距 + }); + } else if (cutY !== null && cutX !== null) { + cutDetectionPositionTop(); + cutDetectionPositionLeft(); + } else if (cutY !== null && cutX === null) { + cutDetectionPositionTop(); + dataUtil.setDiffData(this, { cutX: (_SYS_INFO.windowWidth - clipWidth) / 2 }); + } else if (cutY === null && cutX !== null) { + cutDetectionPositionLeft(); + dataUtil.setDiffData(this, { cutY: (_SYS_INFO.windowHeight - clipHeight) / 2 }); + } + }, + /** + * 改变截取框大小 + */ + computeCutSize() { + const { clipHeight, clipWidth, _SYS_INFO, cutX, cutY } = this.data; + if (clipWidth > _SYS_INFO.windowWidth) { + // 设置裁剪框宽度 + dataUtil.setDiffData(this, { clipWidth: _SYS_INFO.windowWidth }); + } else if (clipWidth + cutX > _SYS_INFO.windowWidth) { + dataUtil.setDiffData(this, { cutX: _SYS_INFO.windowWidth - cutX }); + } + if (clipHeight > _SYS_INFO.windowHeight) { + // 设置裁剪框高度 + dataUtil.setDiffData(this, { clipHeight: _SYS_INFO.windowHeight }); + } else if (clipHeight + cutY > _SYS_INFO.windowHeight) { + dataUtil.setDiffData(this, { cutY: _SYS_INFO.windowHeight - cutY }); + } + }, + /** + * 获取图片数据 + */ + getImageData() { + if (!this.properties.imageUrl) { + wx.showToast({ + title: '请选择图片', + icon: 'none' + }); + return; + } + wx.showLoading({ + title: '加载中' + }); + + const { clipHeight, clipWidth, _ctx, scale, imageLeft, imageTop, cutX, cutY, angle } = this.data; + let { CANVAS_HEIGHT, CANVAS_WIDTH } = this.data; + const { scaleRatio, imageUrl, quality, type: imageType } = this.properties; + // 绘制函数 + const draw = () => { + // 图片真实大小 + const imageWidth = this.data.imageWidth * scale * scaleRatio; + const imageHeight = this.data.imageHeight * scale * scaleRatio; + // canvas和图片的相对距离 + const xpos = imageLeft - cutX; + const ypos = imageTop - cutY; + // 旋转画布 + _ctx.translate(xpos * scaleRatio, ypos * scaleRatio); + _ctx.rotate((angle * Math.PI) / 180); + _ctx.drawImage(imageUrl, -imageWidth / 2, -imageHeight / 2, imageWidth, imageHeight); + _ctx.draw(false, () => { + let params = { + width: clipWidth * scaleRatio, + height: Math.round(clipHeight * scaleRatio), + destWidth: clipWidth * scaleRatio, + destHeight: Math.round(clipHeight) * scaleRatio, + fileType: 'png', + quality + }; + + let data = { + url: '', + base64: '', + width: clipWidth * scaleRatio, + height: clipHeight * scaleRatio + }; + + if (IMAGE_TYPE.base64 === imageType) { + wx.canvasGetImageData({ + canvasId: 'image-clipper', + x: 0, + y: 0, + width: clipWidth * scaleRatio, + height: Math.round(clipHeight * scaleRatio), + success: res => { + const arrayBuffer = new Uint8Array(res.data); + const base64 = wx.arrayBufferToBase64(arrayBuffer); + data.url = base64; + data.base64 = base64; + wx.hideLoading(); + eventUtil.emit(this, 'linclip', data); + } + }); + } else { + wx.canvasToTempFilePath({ + ...params, + canvasId: 'image-clipper', + success: res => { + data.url = res.tempFilePath; + data.base64 = res.tempFilePath; + wx.hideLoading(); + eventUtil.emit(this, 'linclip', data); + }, + fail(res) { + throw res; + } + }, + this + ); + } + }); + }; + + if (CANVAS_WIDTH !== clipWidth || CANVAS_HEIGHT !== clipHeight) { + CANVAS_WIDTH = clipWidth; + CANVAS_HEIGHT = clipHeight; + _ctx.draw(); + setTimeout(() => { + draw(); + }, 100); + } else { + draw(); + } + }, + /** + * 上传图片 + */ + uploadImage() { + wx.chooseImage({ + count: 1, + sizeType: ['original', 'compressed'], + sourceType: ['album', 'camera'], + success: (res) => { + const tempFilePaths = res.tempFilePaths; + this.setData({ imageUrl: tempFilePaths }); + } + }); + }, + /** + * 工具栏旋转 + */ + rotate(event) { + if (this.properties.disableRotate) return; + if (!this.properties.imageUrl) { + wx.showToast({ + title: '请选择图片', + icon: 'none' + }); + return; + } + const { rotateAngle } = this.properties; + const originAngle = this.data.angle; + const type = event.currentTarget.dataset.type; + if (type === 'along') { + this.setData({ angle: originAngle + rotateAngle }); + } else { + this.setData({ angle: originAngle - rotateAngle}); + } + eventUtil.emit(this, 'linrotate', { currentDeg: this.data.angle }); + }, + /** + * 关闭 + */ + close() { + this.setData({ show: false }); + }, + }, + + /** + * 组件的生命周期 + */ + lifetimes: { + ready() { + const _SYS_INFO = wx.getSystemInfoSync(); + this.setData({ _SYS_INFO }); + this.setCutInfo(); + this.setCutCenter(); + this.computeCutSize(); + this.cutDetectionPosition(); + } + } +}); diff --git a/src/image-clipper/index.json b/src/image-clipper/index.json new file mode 100644 index 00000000..e8cfaaf8 --- /dev/null +++ b/src/image-clipper/index.json @@ -0,0 +1,4 @@ +{ + "component": true, + "usingComponents": {} +} \ No newline at end of file diff --git a/src/image-clipper/index.less b/src/image-clipper/index.less new file mode 100644 index 00000000..ac8fa2ad --- /dev/null +++ b/src/image-clipper/index.less @@ -0,0 +1,131 @@ +.container { + width: 100vw; + height: 100vh; + background-color: rgba(0, 0, 0, 0.6); + position: fixed; + top: 0; + left: 0; + z-index: 1; + + .clip-wrapper { + position: absolute; + width: 100vw; + height: 100vh; + + .clip-content { + width: 100vw; + height: 100vh; + position: absolute; + z-index: 99; + display: flex; + flex-direction: column; + pointer-events: none; + + .flex-auto { + flex: auto; + } + + .clip-content-top, + .clip-content-footer { + width: 100%; + pointer-events: none; + } + + .clip-content-middle { + width: 100%; + height: 400rpx; + display: flex; + box-sizing: border-box; + + .clip-content-middle-left, + .clip-content-middle-right { + height: 100%; + } + + .clip-content-middle-center { + position: relative; + border: 1px solid; + box-sizing: border-box; + + .clip-edge { + position: absolute; + left: 6rpx; + width: 34rpx; + height: 34rpx; + border: 2rpx solid #ffffff; + pointer-events: auto; + box-sizing: border-box; + + &.clip-edge-top-left { + border-bottom-width: 0 !important; + border-right-width: 0 !important; + } + + &.clip-edge-top-right { + border-bottom-width: 0 !important; + border-left-width: 0 !important; + } + + &.clip-edge-bottom-left { + border-top-width: 0 !important; + border-right-width: 0 !important; + } + + &.clip-edge-bottom-right { + border-top-width: 0 !important; + border-left-width: 0 !important; + } + } + } + } + } + + .bg-transparent { + background-color: rgba(0, 0, 0, 0.6); + transition-duration: 0.35s; + } + } + + .cropper-image { + width: 100%; + border-style: none; + position: absolute; + top: 0; + left: 0; + z-index: 2; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + transform-origin: center; + } + + .clipper-canvas { + position: fixed; + z-index: 10; + left: -2000px; + top: -2000px; + pointer-events: none; + } + + .footer-tools { + position: absolute; + left: 0; + bottom: 0; + width: 100%; + z-index: 99; + .tools-icon { + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + padding: 20rpx 40rpx; + box-sizing: border-box; + + image { + display: block; + width: 50rpx; + height: 50rpx; + } + } + } + +} \ No newline at end of file diff --git a/src/image-clipper/index.wxml b/src/image-clipper/index.wxml new file mode 100644 index 00000000..7bc12fd6 --- /dev/null +++ b/src/image-clipper/index.wxml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From b9c5e583ecd575ce1377f532da17e04d37e052d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A1=94=E5=AD=90?= Date: Tue, 4 Aug 2020 15:21:40 +0800 Subject: [PATCH 02/37] =?UTF-8?q?refactor(Counter):=20=E5=88=A0=E9=99=A4?= =?UTF-8?q?=20count-selector=20=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit count-selector 是 counter 更名前的组件,现在已无用 BREAKING CHANGE: 删除 CountSelector 组件 --- examples/app.json | 2 +- .../shopping/pages/count-selector/index.wxml | 5 - .../{count-selector => counter}/count-nav.js | 0 .../{count-selector => counter}/index.js | 2 +- .../{count-selector => counter}/index.json | 4 +- .../shopping/pages/counter/index.wxml | 5 + .../{count-selector => counter}/index.wxss | 0 src/count-selector/index.js | 158 ------------------ src/count-selector/index.json | 6 - src/count-selector/index.less | 68 -------- src/count-selector/index.wxml | 22 --- 11 files changed, 9 insertions(+), 263 deletions(-) delete mode 100644 examples/pages/components/shopping/pages/count-selector/index.wxml rename examples/pages/components/shopping/pages/{count-selector => counter}/count-nav.js (100%) rename examples/pages/components/shopping/pages/{count-selector => counter}/index.js (94%) rename examples/pages/components/shopping/pages/{count-selector => counter}/index.json (72%) create mode 100644 examples/pages/components/shopping/pages/counter/index.wxml rename examples/pages/components/shopping/pages/{count-selector => counter}/index.wxss (100%) delete mode 100644 src/count-selector/index.js delete mode 100644 src/count-selector/index.json delete mode 100644 src/count-selector/index.less delete mode 100644 src/count-selector/index.wxml diff --git a/examples/app.json b/examples/app.json index b359f126..b6565f20 100644 --- a/examples/app.json +++ b/examples/app.json @@ -122,7 +122,7 @@ "root": "pages/components/shopping", "pages": [ "pages/price/index", - "pages/count-selector/index", + "pages/counter/index", "pages/search-bar/index" ] }, diff --git a/examples/pages/components/shopping/pages/count-selector/index.wxml b/examples/pages/components/shopping/pages/count-selector/index.wxml deleted file mode 100644 index d7421f16..00000000 --- a/examples/pages/components/shopping/pages/count-selector/index.wxml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/examples/pages/components/shopping/pages/count-selector/count-nav.js b/examples/pages/components/shopping/pages/counter/count-nav.js similarity index 100% rename from examples/pages/components/shopping/pages/count-selector/count-nav.js rename to examples/pages/components/shopping/pages/counter/count-nav.js diff --git a/examples/pages/components/shopping/pages/count-selector/index.js b/examples/pages/components/shopping/pages/counter/index.js similarity index 94% rename from examples/pages/components/shopping/pages/count-selector/index.js rename to examples/pages/components/shopping/pages/counter/index.js index 2e4d28a7..97327303 100644 --- a/examples/pages/components/shopping/pages/count-selector/index.js +++ b/examples/pages/components/shopping/pages/counter/index.js @@ -1,5 +1,5 @@ // pages/shopping/pages/count/index.js -import countConfig from '../count-selector/count-nav.js'; +import countConfig from './count-nav.js'; Page({ diff --git a/examples/pages/components/shopping/pages/count-selector/index.json b/examples/pages/components/shopping/pages/counter/index.json similarity index 72% rename from examples/pages/components/shopping/pages/count-selector/index.json rename to examples/pages/components/shopping/pages/counter/index.json index 614acaf4..ece83113 100644 --- a/examples/pages/components/shopping/pages/count-selector/index.json +++ b/examples/pages/components/shopping/pages/counter/index.json @@ -2,6 +2,6 @@ "usingComponents": { "content-title": "/components/content-title/index", "content-card": "/components/content-card/index", - "l-count-selector": "/dist/count-selector/index" + "l-counter": "/dist/counter/index" } -} \ No newline at end of file +} diff --git a/examples/pages/components/shopping/pages/counter/index.wxml b/examples/pages/components/shopping/pages/counter/index.wxml new file mode 100644 index 00000000..e3714ffc --- /dev/null +++ b/examples/pages/components/shopping/pages/counter/index.wxml @@ -0,0 +1,5 @@ + + + + + diff --git a/examples/pages/components/shopping/pages/count-selector/index.wxss b/examples/pages/components/shopping/pages/counter/index.wxss similarity index 100% rename from examples/pages/components/shopping/pages/count-selector/index.wxss rename to examples/pages/components/shopping/pages/counter/index.wxss diff --git a/src/count-selector/index.js b/src/count-selector/index.js deleted file mode 100644 index c037e059..00000000 --- a/src/count-selector/index.js +++ /dev/null @@ -1,158 +0,0 @@ -Component({ - externalClasses: [ - 'l-class', - 'l-symbol-class', - 'l-count-class', - 'l-disabled-class' - ], - properties: { - count: { - type: Number, - value: 1 - }, - max: { - type: Number, - value: 9999 - }, - min: { - type: Number, - value: 1 - }, - step: { - type: Number, - value: 1 - }, - disabled: Boolean, - iconSize: String, - iconColor: String - }, - - /** - * 组件的初始数据 - */ - data: { - focus: false, - result: 1 - }, - - observers: { - 'count,min,max': function () { - this.valueRange(this.data.count, 'parameter'); - } - }, - - /** - * 组件的方法列表 - */ - methods: { - doNothing(e) { - const { type } = e.currentTarget.dataset; - this.triggerEvent('linout', { type, way: 'icon' }, { - bubbles: true, - composed: true - }); - }, - - onCount() { - this.setData({ - focus: true - }); - }, - - onBlur(e) { - this.setData({ - focus: false - }); - let { - value - } = e.detail; - setTimeout(() => { - this.blurCount(Number(value), () => { - this.data.count = this.data.result; - this.triggerEvent('lintap', { - count: this.data.result, - type: 'blur' - }, { - bubbles: true, - composed: true - }); - }); - }, 50); - }, - - blurCount(value, callback) { - if (value) { - this.valueRange(value); - } else { - this.setData({ - result: this.properties.count - }); - } - callback && callback(); - }, - - valueRange(value, way = 'input') { - if (value > this.properties.max) { - this.setData({ - result: this.properties.max - }, () => { - this.triggerEvent('linout', { type: 'overflow_max', way }, { - bubbles: true, - composed: true - }); - }); - } else if (value < this.properties.min) { - this.setData({ - result: this.properties.min - }, () => { - this.triggerEvent('linout', { type: 'overflow_min', way }, { - bubbles: true, - composed: true - }); - }); - } else { - this.setData({ - result: value - }); - } - }, - - reduceTap() { - let distance = this.data.count - this.properties.step; - if (distance <= this.properties.min) { - this.data.count = this.properties.min; - } else { - this.data.count -= this.properties.step; - } - this.setData({ - result: this.data.count - }); - this.triggerEvent('lintap', { - count: this.data.result, - type: 'reduce' - }, { - bubbles: true, - composed: true - }); - }, - - addTap() { - let distance = this.data.count + this.properties.step; - if (distance >= this.properties.max) { - this.data.count = this.properties.max; - } else { - this.data.count += this.properties.step; - } - this.setData({ - result: this.data.count - }); - this.triggerEvent('lintap', { - count: this.data.result, - type: 'add' - }, { - bubbles: true, - composed: true - }); - }, - } -}); \ No newline at end of file diff --git a/src/count-selector/index.json b/src/count-selector/index.json deleted file mode 100644 index c01e2d7e..00000000 --- a/src/count-selector/index.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "component": true, - "usingComponents": { - "l-icon":"../icon/index" - } -} \ No newline at end of file diff --git a/src/count-selector/index.less b/src/count-selector/index.less deleted file mode 100644 index 4345f8b2..00000000 --- a/src/count-selector/index.less +++ /dev/null @@ -1,68 +0,0 @@ -.container-count { - display : flex; - flex-direction: row; - width : 170rpx; - height : 56rpx; -} - -.symbol { - height : 100%; - width : 56rpx; - font-size : 28rpx; - color : #596C8E; - display : flex; - align-items : center; - justify-content: center; -} - -.disabled { - background-color: #f3f3f3; - color : #c4c9d2; -} - -.abled { - background-color: #ecf1f8; - color : #596c8e; -} - -.count { - height : 100%; - flex : 1; - min-height : 56rpx; - line-height : 56rpx; - font-size : 24rpx; - color : #596c8e; - background : #f6f7f9; - text-align : center; - overflow : hidden; - text-overflow: ellipsis; - white-space : nowrap; -} - -@font-face { - font-family: "iconfont"; - src : url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAALEAAsAAAAABqwAAAJ3AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCDBgqBFIEWATYCJAMMCwgABCAFhG0HNxvdBcgekiSBqhRCJKIogADMEYRr5GySu0dQoBAloETFRVKmqpWoK1wVG1th2Ij732n7N5fsqTh2xyneKfa2N3/anZKGvYXFohGGrUFIEA6JogD/fZ7L6U2gA7nGtyynNW3s8fyoF2AcUEBjbYqsRALxFtlF3ImLOE6g3ZheoYOxmRVIKtC4QLww9QYkCxFFMfKtQt2wtIjXKq3pZfrEq+j78d9qJEmqDE09fTTahoFf6deHfNxwgxOiBHl1hYx5oBC3GjMXIsLgItpN0e7yWhHSXPEmkcq31Dv94yWihmo7wbQcS/yiMoJf9yskkEFdzE0Diwo7eF2IkexeNr35cvtSjmQ/fjt5zeTy++93z1I4x8LHT3u9VVdH6SHr0r8+OjOTtCopyONe0uFsIlZDiaMZyTdAmzFfZzrm0+EOQPOcP/IeANGP4rNA8KN0+V8rbPwlMwX83P7UK0Wa5wJwS+sZvMEfUwMbiq9F1lxcFVWFvmwE4ErICtOvARTo9zPeMgROEVoL2hG+FqMeslbjZGHnUemwjlqrbbSbM766wwAuIkobZl1ICL0ekXT7jqzXF1nYb1SG/aLWGxG0O4uBLTtMhpne59gQ2CbNHWK2mEeJXaTj+iXUN5wGz2sjfg15YMaJJqvl/Dh6yOeYEWzqFSEooZy5ZEw6DR2HEZ8zC1tCNoTwq4pCm94kt5gLafs41CCgNqJpB2FqYTyUtxbSlc8vQboNjgbeIejJr0FcwOyc0MhUADlu8kCCe3klsElXIQgUQXGMixiTBiGHgyH85kEW1CLIjBEpX5WCm1GoSV7f4n7fNmiH9syRIkeR77bbiWdmwzMaDAAA') format('woff2') -} - -.l-icon-add:before { - content: "\e602"; -} - -.l-icon-reduce:before { - content: "\e69c"; -} - -.l-icon { - font-family : "iconfont"; - font-style : normal; - -webkit-font-smoothing : antialiased; - -moz-osx-font-smoothing: grayscale; -} - -.l-icon::before { - display: inline-flex; -} - -.count-hover{ - opacity: .8; -} \ No newline at end of file diff --git a/src/count-selector/index.wxml b/src/count-selector/index.wxml deleted file mode 100644 index c1b1cff4..00000000 --- a/src/count-selector/index.wxml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - {{result}} - - - - \ No newline at end of file From 01544c2feb460b78c63665855dfbfa989798f8e2 Mon Sep 17 00:00:00 2001 From: Juzi Date: Wed, 5 Aug 2020 10:12:11 +0800 Subject: [PATCH 03/37] build: Travis CI automatic compilation --- dist/image-clipper-tools/index.js | 1 + dist/image-clipper-tools/index.json | 1 + dist/image-clipper-tools/index.wxml | 28 + dist/image-clipper-tools/index.wxss | 1 + dist/image-clipper/calculate.js | 1 + dist/image-clipper/images/close.png | Bin 0 -> 2768 bytes dist/image-clipper/images/photo.png | Bin 0 -> 1288 bytes dist/image-clipper/images/rotate-along.png | Bin 0 -> 1796 bytes dist/image-clipper/images/rotate-inverse.png | Bin 0 -> 1786 bytes dist/image-clipper/images/sure.png | Bin 0 -> 2620 bytes dist/image-clipper/index.js | 1 + dist/image-clipper/index.json | 1 + dist/image-clipper/index.wxml | 45 + dist/image-clipper/index.wxss | 1 + examples/dist/image-clipper-tools/index.js | 80 ++ examples/dist/image-clipper-tools/index.json | 4 + examples/dist/image-clipper-tools/index.wxml | 28 + examples/dist/image-clipper-tools/index.wxss | 1 + examples/dist/image-clipper/calculate.js | 276 ++++++ examples/dist/image-clipper/images/close.png | Bin 0 -> 2768 bytes examples/dist/image-clipper/images/photo.png | Bin 0 -> 1288 bytes .../image-clipper/images/rotate-along.png | Bin 0 -> 1796 bytes .../image-clipper/images/rotate-inverse.png | Bin 0 -> 1786 bytes examples/dist/image-clipper/images/sure.png | Bin 0 -> 2620 bytes examples/dist/image-clipper/index.js | 802 ++++++++++++++++++ examples/dist/image-clipper/index.json | 4 + examples/dist/image-clipper/index.wxml | 68 ++ examples/dist/image-clipper/index.wxss | 1 + 28 files changed, 1344 insertions(+) create mode 100644 dist/image-clipper-tools/index.js create mode 100644 dist/image-clipper-tools/index.json create mode 100644 dist/image-clipper-tools/index.wxml create mode 100644 dist/image-clipper-tools/index.wxss create mode 100644 dist/image-clipper/calculate.js create mode 100755 dist/image-clipper/images/close.png create mode 100755 dist/image-clipper/images/photo.png create mode 100755 dist/image-clipper/images/rotate-along.png create mode 100755 dist/image-clipper/images/rotate-inverse.png create mode 100755 dist/image-clipper/images/sure.png create mode 100644 dist/image-clipper/index.js create mode 100644 dist/image-clipper/index.json create mode 100644 dist/image-clipper/index.wxml create mode 100644 dist/image-clipper/index.wxss create mode 100644 examples/dist/image-clipper-tools/index.js create mode 100644 examples/dist/image-clipper-tools/index.json create mode 100644 examples/dist/image-clipper-tools/index.wxml create mode 100644 examples/dist/image-clipper-tools/index.wxss create mode 100644 examples/dist/image-clipper/calculate.js create mode 100755 examples/dist/image-clipper/images/close.png create mode 100755 examples/dist/image-clipper/images/photo.png create mode 100755 examples/dist/image-clipper/images/rotate-along.png create mode 100755 examples/dist/image-clipper/images/rotate-inverse.png create mode 100755 examples/dist/image-clipper/images/sure.png create mode 100644 examples/dist/image-clipper/index.js create mode 100644 examples/dist/image-clipper/index.json create mode 100644 examples/dist/image-clipper/index.wxml create mode 100644 examples/dist/image-clipper/index.wxss diff --git a/dist/image-clipper-tools/index.js b/dist/image-clipper-tools/index.js new file mode 100644 index 00000000..5d71273c --- /dev/null +++ b/dist/image-clipper-tools/index.js @@ -0,0 +1 @@ +Component({relations:{"../image-clipper/index":{type:"parent"}},externalClasses:["l-class"],properties:{zIndex:{type:Number,value:999},lockWidth:{type:Boolean,value:!1},lockHeight:{type:Boolean,value:!1},lockRatio:{type:Boolean,value:!1},disableScale:{type:Number,value:!1},disableRotate:{type:Number,value:!1},limitMove:{type:Boolean,value:!1}},data:{formColor:"#3963bc",lockWidthValue:!1,lockHeightValue:!1,lockRatioValue:!0,disableScaleValue:!1,disableRotateValue:!1,limitMoveValue:!1},methods:{bindSwitchChange:async function(e){const a=e.detail.value,l=e.currentTarget.dataset.type;let t=this.getRelationNodes("../image-clipper/index")[0];await t.setData({[l]:a})}}}); \ No newline at end of file diff --git a/dist/image-clipper-tools/index.json b/dist/image-clipper-tools/index.json new file mode 100644 index 00000000..1450e2ec --- /dev/null +++ b/dist/image-clipper-tools/index.json @@ -0,0 +1 @@ +{"component":true,"usingComponents":{}} \ No newline at end of file diff --git a/dist/image-clipper-tools/index.wxml b/dist/image-clipper-tools/index.wxml new file mode 100644 index 00000000..0add6c56 --- /dev/null +++ b/dist/image-clipper-tools/index.wxml @@ -0,0 +1,28 @@ + + + + 锁定裁剪框宽 + + + + 锁定裁剪框高 + + + + 锁定裁剪框比例 + + + + 限制移动范围 + + + + 禁止缩放 + + + + 禁止旋转 + + + + \ No newline at end of file diff --git a/dist/image-clipper-tools/index.wxss b/dist/image-clipper-tools/index.wxss new file mode 100644 index 00000000..f072ec77 --- /dev/null +++ b/dist/image-clipper-tools/index.wxss @@ -0,0 +1 @@ +.tools-container{width:100%;padding:20rpx 40rpx;box-sizing:border-box}.tools-container .tools-form{margin-top:20rpx;display:flex;flex-wrap:wrap;color:#fff}.tools-container .tools-form .slider-wrapper{display:flex;align-items:center}.tools-container .tools-form switch{transform:scale(.7)} \ No newline at end of file diff --git a/dist/image-clipper/calculate.js b/dist/image-clipper/calculate.js new file mode 100644 index 00000000..fea59075 --- /dev/null +++ b/dist/image-clipper/calculate.js @@ -0,0 +1 @@ +export function determineDirection(t,e,i,c,h,a){let n;const r=h>t+i-24&&ht-24&&he+c-24&&ae-24&&at*e/2,u=g(h),d=g(a);return i=n+u>=i?i:n+u,i=n+r-u<=i?i:n+r-u,c=l+d>=c?c:l+d,c=l+o-d<=c?c:l+o-d,{left:i,top:c,scale:e}}export function calcImageScale(t,e){e=e||t.scale;let i=t.imageWidth,c=t.imageHeight;return t.angle/90%2&&(i=t.imageHeight,c=t.imageWidth),i*e(i.clipWidth||i.width)/(i.clipWidth||i.height)?(h=i.clipHeight||i.height,c=t/e*h):(c=i.clipWidth||i.width,h=e/t*c);else{c=(i._SYS_INFO||wx.getSystemInfoSync()).windowWidth,h=0}return{imageWidth:c,imageHeight:h}}export function calcPythagoreanTheorem(t,e){return Math.sqrt(Math.pow(t,2)+Math.pow(e,2))}export function clipTouchMoveOfCalculate(t,e){const i=e.touches[0].clientX,c=e.touches[0].clientY,{clipWidth:h,clipHeight:a,cutY:n,cutX:r,_CUT_START:l,lockRatio:o}=t;let{maxWidth:g,minWidth:u,maxHeight:d,minHeight:p}=t;g/=2,u/=2,p/=2,d/=2;let m=h,f=a,s=n,x=r,w=()=>{m=m<=g?m>=u?m:u:g,f=f<=d?f>=p?f:p:d},W=()=>(m>g||md||f1&&l.corner<4?1:-1)*(l.y-c),l.corner){case 1:if(m=l.width-l.x+i,o&&(f=m/(h/a)),!W())return;break;case 2:if(m=l.width-l.x+i,o&&(f=m/(h/a)),!W())return;s=l.cutY-(f-l.height);break;case 3:if(m=l.width+l.x-i,o&&(f=m/(h/a)),!W())return;s=l.cutY-(f-l.height),x=l.cutX-(m-l.width);break;case 4:if(m=l.width+l.x-i,o&&(f=m/(h/a)),!W())return;x=l.cutX-(m-l.width)}return{width:m,height:f,cutX:x,cutY:s}}export function imageTouchMoveOfCalcOffset(t,e,i){return{left:e-t._touchRelative[0].x,top:i-t._touchRelative[0].y}} \ No newline at end of file diff --git a/dist/image-clipper/images/close.png b/dist/image-clipper/images/close.png new file mode 100755 index 0000000000000000000000000000000000000000..a1c6c99c250b02bce100042a50b460444cf9ddc8 GIT binary patch literal 2768 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 literal 0 HcmV?d00001 diff --git a/dist/image-clipper/images/photo.png b/dist/image-clipper/images/photo.png new file mode 100755 index 0000000000000000000000000000000000000000..80928c3ba4ef40c66af2ba0df3b6ea33cbbc61ef GIT binary patch literal 1288 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 Tk*#;_{|5z(C(ff88JYPnu8*-u literal 0 HcmV?d00001 diff --git a/dist/image-clipper/images/rotate-inverse.png b/dist/image-clipper/images/rotate-inverse.png new file mode 100755 index 0000000000000000000000000000000000000000..ec77b6b55b31ce92efac9fd60c3ee9bff3832f45 GIT binary patch literal 1786 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 VXF{this.imgComputeSize(t.width,t.height),this.properties.limitMove&&(this.imgMarginDetectionScale(),eventUtil.emit(this,"linimageready",t))},fail:()=>{this.imgComputeSize(),this.properties.limitMove&&this.imgMarginDetectionScale()}}))},"clipWidth, clipHeight"(t,e){let{minWidth:i,minHeight:a}=this.data;i/=2,a/=2,t{dataUtil.setDiffData(this,{cutAnimation:!1})},260);dataUtil.setDiffData(this,{_cutAnimationTime:t})}},limitMove(t){t&&(this.data.angle%90&&dataUtil.setDiffData(this,{angle:90*Math.round(this.data.angle/90)}),this.imgMarginDetectionScale())},"cutY, cutX"(){this.cutDetectionPosition()},"width, height"(t,e){t!==this.width&&dataUtil.setDiffData(this,{clipWidth:t/2}),e!==this.height&&dataUtil.setDiffData(this,{clipHeight:e/2})}},methods:{setCutInfo(){const{width:t,height:e}=this.properties,{_SYS_INFO:i}=this.data,a=t/2,s=e/2,o=(i.windowHeight-s)/2,h=(i.windowWidth-a)/2,l=i.windowWidth/2,n=i.windowHeight/2,c=wx.createCanvasContext("image-clipper",this);this.setData({clipWidth:a,clipHeight:s,cutX:h,cutY:o,CANVAS_HEIGHT:s,CANVAS_WIDTH:a,_ctx:c,imageLeft:l,imageTop:n})},setCutCenter(){const{sysInfo:t,clipHeight:e,clipWidth:i,imageTop:a,imageLeft:s}=this.data;let o=t||wx.getSystemInfoSync(),h=.5*(o.windowHeight-e),l=.5*(o.windowWidth-i);this.setData({imageTop:a-this.data.cutY+h,imageLeft:s-this.data.cutX+l,cutY:h,cutX:l})},clipTouchStart(t){if(!this.properties.imageUrl)return void wx.showToast({title:"请选择图片",icon:"none"});const e=t.touches[0].clientX,i=t.touches[0].clientY,{cutX:a,cutY:s,clipWidth:o,clipHeight:h}=this.data,l=determineDirection(a,s,o,h,e,i);this.moveDuring();const n={width:o,height:h,x:e,y:i,cutY:s,cutX:a,corner:l};this.setData({_flagCutTouch:!0,_flagEndTouch:!0,_CUT_START:n})},clipTouchMove(t){if(!this.properties.imageUrl)return void wx.showToast({title:"请选择图片",icon:"none"});const{_flagCutTouch:e,_MOVE_THROTTLE_FLAG:i}=this.data;if(e&&i){const{lockRatio:e,lockHeight:i,lockWidth:a}=this.properties;if(e&&(a||i))return;dataUtil.setDiffData(this,{_MOVE_THROTTLE_FLAG:!1}),this.moveThrottle();const{width:s,height:o,cutX:h,cutY:l}=clipTouchMoveOfCalculate(this.data,t);a||i?a?i||dataUtil.setDiffData(this,{clipHeight:o,cutY:l}):dataUtil.setDiffData(this,{clipWidth:s,cutX:h}):dataUtil.setDiffData(this,{clipWidth:s,clipHeight:o,cutX:h,cutY:l}),this.imgMarginDetectionScale()}},clipTouchEnd(){this.moveStop(),this.setData({_flagCutTouch:!1})},moveDuring(){clearTimeout(this.data._TIME_CUT_CENTER)},moveStop(){clearTimeout(this.data._TIME_CUT_CENTER);const t=setTimeout(()=>{this.data.cutAnimation||dataUtil.setDiffData(this,{cutAnimation:!0}),this.setCutCenter()},800);dataUtil.setDiffData(this,{_TIME_CUT_CENTER:t})},moveThrottle(){if("android"===this.data._SYS_INFO.platform){clearTimeout(this.data._MOVE_THROTTLE);const t=setTimeout(()=>{dataUtil.setDiffData(this,{_MOVE_THROTTLE_FLAG:!0})},20);dataUtil.setDiffData(this,{_MOVE_THROTTLE:t})}else dataUtil.setDiffData(this,{_MOVE_THROTTLE_FLAG:!0})},imageReset(){const t=this.data._SYS_INFO||wx.getSystemInfoSync();this.setData({scale:1,angle:0,imageTop:t.windowHeight/2,imageLeft:t.windowWidth/2})},imageLoad(){this.imageReset(),wx.hideLoading(),eventUtil.emit(this,"linimageload",!0)},imgComputeSize(t,e){const{imageWidth:i,imageHeight:a}=calcImageSize(t,e,this.data);this.setData({imageWidth:i,imageHeight:a})},imgMarginDetectionScale(t){if(!this.properties.limitMove)return;const e=calcImageScale(this.data,t);this.imgMarginDetectionPosition(e)},imgMarginDetectionPosition(t){if(!this.properties.limitMove)return;const{scale:e,left:i,top:a}=calcImageOffset(this.data,t);dataUtil.setDiffData(this,{imageLeft:i,imageTop:a,scale:e})},imageTouchStart(t){this.setData({_flagEndTouch:!1});const{imageLeft:e,imageTop:i}=this.data,a=t.touches[0].clientX,s=t.touches[0].clientY;let o=[];if(1===t.touches.length)o[0]={x:a-e,y:s-i},this.setData({_touchRelative:o});else{const h=t.touches[1].clientX,l=t.touches[1].clientY;let n=Math.abs(a-h),c=Math.abs(s-l);const u=calcPythagoreanTheorem(n,c);o=[{x:a-e,y:s-i},{x:h-e,y:l-i}],this.setData({_touchRelative:o,_hypotenuseLength:u})}},imageTouchMove(t){const{_flagEndTouch:e,_MOVE_THROTTLE_FLAG:i}=this.data;if(e||!i)return;const a=t.touches[0].clientX,s=t.touches[0].clientY;if(dataUtil.setDiffData(this,{_MOVE_THROTTLE_FLAG:!1}),this.moveThrottle(),this.moveDuring(),1===t.touches.length){const{left:t,top:e}=imageTouchMoveOfCalcOffset(this.data,a,s);dataUtil.setDiffData(this,{imageLeft:t,imageTop:e}),this.imgMarginDetectionPosition()}else{const e=t.touches[1].clientX,i=t.touches[1].clientY;let o=Math.abs(a-e),h=Math.abs(s-i),l=calcPythagoreanTheorem(o,h),n=this.data.scale*(l/this.data._hypotenuseLength);this.properties.disableScale?n=1:(n=n<=this.properties.minRatio?this.properties.minRatio:n,n=n>=this.properties.maxRatio?this.properties.maxRatio:n,eventUtil.emit(this,"linsizechange",{imageWidth:this.data.imageWidth*n,imageHeight:this.data.imageHeight*n})),this.imgMarginDetectionScale(n),dataUtil.setDiffData(this,{_hypotenuseLength:Math.sqrt(Math.pow(o,2)+Math.pow(h,2)),scale:n})}},imageTouchEnd(){dataUtil.setDiffData(this,{_flagEndTouch:!0}),this.moveStop()},cutDetectionPosition(){const{cutX:t,cutY:e,_SYS_INFO:i,clipHeight:a,clipWidth:s}=this.data;let o=()=>{e<0&&dataUtil.setDiffData(this,{cutY:0}),e>i.windowHeight-a&&dataUtil.setDiffData(this,{cutY:i.windowHeight-a})},h=()=>{t<0&&dataUtil.setDiffData(this,{cutX:0}),t>i.windowWidth-s&&dataUtil.setDiffData(this,{cutX:i.windowWidth-s})};if(null===e&&null===t){let t=.5*(i.windowHeight-a),e=.5*(i.windowWidth-s);dataUtil.setDiffData(this,{cutX:e,cutY:t})}else null!==e&&null!==t?(o(),h()):null!==e&&null===t?(o(),dataUtil.setDiffData(this,{cutX:(i.windowWidth-s)/2})):null===e&&null!==t&&(h(),dataUtil.setDiffData(this,{cutY:(i.windowHeight-a)/2}))},computeCutSize(){const{clipHeight:t,clipWidth:e,_SYS_INFO:i,cutX:a,cutY:s}=this.data;e>i.windowWidth?dataUtil.setDiffData(this,{clipWidth:i.windowWidth}):e+a>i.windowWidth&&dataUtil.setDiffData(this,{cutX:i.windowWidth-a}),t>i.windowHeight?dataUtil.setDiffData(this,{clipHeight:i.windowHeight}):t+s>i.windowHeight&&dataUtil.setDiffData(this,{cutY:i.windowHeight-s})},getImageData(){if(!this.properties.imageUrl)return void wx.showToast({title:"请选择图片",icon:"none"});wx.showLoading({title:"加载中"});const{clipHeight:t,clipWidth:e,_ctx:i,scale:a,imageLeft:s,imageTop:o,cutX:h,cutY:l,angle:n}=this.data;let{CANVAS_HEIGHT:c,CANVAS_WIDTH:u}=this.data;const{scaleRatio:g,imageUrl:r,quality:d,type:m}=this.properties,p=()=>{const c=this.data.imageWidth*a*g,u=this.data.imageHeight*a*g,p=s-h,f=o-l;i.translate(p*g,f*g),i.rotate(n*Math.PI/180),i.drawImage(r,-c/2,-u/2,c,u),i.draw(!1,()=>{let i={width:e*g,height:Math.round(t*g),destWidth:e*g,destHeight:Math.round(t)*g,fileType:"png",quality:d},a={url:"",base64:"",width:e*g,height:t*g};IMAGE_TYPE.base64===m?wx.canvasGetImageData({canvasId:"image-clipper",x:0,y:0,width:e*g,height:Math.round(t*g),success:t=>{const e=new Uint8Array(t.data),i=wx.arrayBufferToBase64(e);a.url=i,a.base64=i,wx.hideLoading(),eventUtil.emit(this,"linclip",a)}}):wx.canvasToTempFilePath({...i,canvasId:"image-clipper",success:t=>{a.url=t.tempFilePath,a.base64=t.tempFilePath,wx.hideLoading(),eventUtil.emit(this,"linclip",a)},fail(t){throw t}},this)})};u!==e||c!==t?(u=e,c=t,i.draw(),setTimeout(()=>{p()},100)):p()},uploadImage(){wx.chooseImage({count:1,sizeType:["original","compressed"],sourceType:["album","camera"],success:t=>{const e=t.tempFilePaths;this.setData({imageUrl:e})}})},rotate(t){if(this.properties.disableRotate)return;if(!this.properties.imageUrl)return void wx.showToast({title:"请选择图片",icon:"none"});const{rotateAngle:e}=this.properties,i=this.data.angle;"along"===t.currentTarget.dataset.type?this.setData({angle:i+e}):this.setData({angle:i-e}),eventUtil.emit(this,"linrotate",{currentDeg:this.data.angle})},close(){this.setData({show:!1})}},lifetimes:{ready(){const t=wx.getSystemInfoSync();this.setData({_SYS_INFO:t}),this.setCutInfo(),this.setCutCenter(),this.computeCutSize(),this.cutDetectionPosition()}}}); \ No newline at end of file diff --git a/dist/image-clipper/index.json b/dist/image-clipper/index.json new file mode 100644 index 00000000..1450e2ec --- /dev/null +++ b/dist/image-clipper/index.json @@ -0,0 +1 @@ +{"component":true,"usingComponents":{}} \ No newline at end of file diff --git a/dist/image-clipper/index.wxml b/dist/image-clipper/index.wxml new file mode 100644 index 00000000..b7c48546 --- /dev/null +++ b/dist/image-clipper/index.wxml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dist/image-clipper/index.wxss b/dist/image-clipper/index.wxss new file mode 100644 index 00000000..cf1b26bc --- /dev/null +++ b/dist/image-clipper/index.wxss @@ -0,0 +1 @@ +.container{width:100vw;height:100vh;background-color:rgba(0,0,0,.6);position:fixed;top:0;left:0;z-index:1}.container .clip-wrapper{position:absolute;width:100vw;height:100vh}.container .clip-wrapper .clip-content{width:100vw;height:100vh;position:absolute;z-index:99;display:flex;flex-direction:column;pointer-events:none}.container .clip-wrapper .clip-content .flex-auto{flex:auto}.container .clip-wrapper .clip-content .clip-content-footer,.container .clip-wrapper .clip-content .clip-content-top{width:100%;pointer-events:none}.container .clip-wrapper .clip-content .clip-content-middle{width:100%;height:400rpx;display:flex;box-sizing:border-box}.container .clip-wrapper .clip-content .clip-content-middle .clip-content-middle-left,.container .clip-wrapper .clip-content .clip-content-middle .clip-content-middle-right{height:100%}.container .clip-wrapper .clip-content .clip-content-middle .clip-content-middle-center{position:relative;border:1px solid;box-sizing:border-box}.container .clip-wrapper .clip-content .clip-content-middle .clip-content-middle-center .clip-edge{position:absolute;left:6rpx;width:34rpx;height:34rpx;border:2rpx solid #fff;pointer-events:auto;box-sizing:border-box}.container .clip-wrapper .clip-content .clip-content-middle .clip-content-middle-center .clip-edge.clip-edge-top-left{border-bottom-width:0!important;border-right-width:0!important}.container .clip-wrapper .clip-content .clip-content-middle .clip-content-middle-center .clip-edge.clip-edge-top-right{border-bottom-width:0!important;border-left-width:0!important}.container .clip-wrapper .clip-content .clip-content-middle .clip-content-middle-center .clip-edge.clip-edge-bottom-left{border-top-width:0!important;border-right-width:0!important}.container .clip-wrapper .clip-content .clip-content-middle .clip-content-middle-center .clip-edge.clip-edge-bottom-right{border-top-width:0!important;border-left-width:0!important}.container .clip-wrapper .bg-transparent{background-color:rgba(0,0,0,.6);transition-duration:.35s}.container .cropper-image{width:100%;border-style:none;position:absolute;top:0;left:0;z-index:2;-webkit-backface-visibility:hidden;backface-visibility:hidden;transform-origin:center}.container .clipper-canvas{position:fixed;z-index:10;left:-2000px;top:-2000px;pointer-events:none}.container .footer-tools{position:absolute;left:0;bottom:0;width:100%;z-index:99}.container .footer-tools .tools-icon{display:flex;align-items:center;justify-content:space-between;width:100%;padding:20rpx 40rpx;box-sizing:border-box}.container .footer-tools .tools-icon image{display:block;width:50rpx;height:50rpx} \ No newline at end of file diff --git a/examples/dist/image-clipper-tools/index.js b/examples/dist/image-clipper-tools/index.js new file mode 100644 index 00000000..3226d451 --- /dev/null +++ b/examples/dist/image-clipper-tools/index.js @@ -0,0 +1,80 @@ +Component({ + + relations: { + '../image-clipper/index': { + type: 'parent' + } + }, + externalClasses: ['l-class'], + + /** + * 组件的属性列表 + */ + properties: { + // 组件层级 + zIndex: { + type: Number, + value: 999 + }, + // 是否显示锁定裁剪框宽度按钮 + lockWidth: { + type: Boolean, + value: false + }, + // 是否显示锁定裁剪框高度按钮 + lockHeight: { + type: Boolean, + value: false + }, + // 是否显示锁定裁剪框比例按钮 + lockRatio: { + type: Boolean, + value: false + }, + // 是否显示禁止缩放按钮 + disableScale: { + type: Number, + value: false + }, + // 是否显示禁止旋转按钮 + disableRotate: { + type: Number, + value: false + }, + // 是否显示限制移动范围按钮 + limitMove: { + type: Boolean, + value: false + } + }, + + /** + * 组件的初始数据 + */ + data: { + formColor: '#3963bc', + lockWidthValue: false, + lockHeightValue: false, + lockRatioValue: true, + disableScaleValue: false, + disableRotateValue: false, + limitMoveValue: false + }, + + /** + * 组件的方法列表 + */ + methods: { + /** + * switch change事件 + */ + bindSwitchChange: async function(event) { + const value = event.detail.value; + const type = event.currentTarget.dataset.type; + let parent = this.getRelationNodes('../image-clipper/index')[0]; + await parent.setData({ + [type]: value + }); + }, + } +}); diff --git a/examples/dist/image-clipper-tools/index.json b/examples/dist/image-clipper-tools/index.json new file mode 100644 index 00000000..e8cfaaf8 --- /dev/null +++ b/examples/dist/image-clipper-tools/index.json @@ -0,0 +1,4 @@ +{ + "component": true, + "usingComponents": {} +} \ No newline at end of file diff --git a/examples/dist/image-clipper-tools/index.wxml b/examples/dist/image-clipper-tools/index.wxml new file mode 100644 index 00000000..35f37ef2 --- /dev/null +++ b/examples/dist/image-clipper-tools/index.wxml @@ -0,0 +1,28 @@ + + + + 锁定裁剪框宽 + + + + 锁定裁剪框高 + + + + 锁定裁剪框比例 + + + + 限制移动范围 + + + + 禁止缩放 + + + + 禁止旋转 + + + + \ No newline at end of file diff --git a/examples/dist/image-clipper-tools/index.wxss b/examples/dist/image-clipper-tools/index.wxss new file mode 100644 index 00000000..f072ec77 --- /dev/null +++ b/examples/dist/image-clipper-tools/index.wxss @@ -0,0 +1 @@ +.tools-container{width:100%;padding:20rpx 40rpx;box-sizing:border-box}.tools-container .tools-form{margin-top:20rpx;display:flex;flex-wrap:wrap;color:#fff}.tools-container .tools-form .slider-wrapper{display:flex;align-items:center}.tools-container .tools-form switch{transform:scale(.7)} \ No newline at end of file diff --git a/examples/dist/image-clipper/calculate.js b/examples/dist/image-clipper/calculate.js new file mode 100644 index 00000000..1dffc8e7 --- /dev/null +++ b/examples/dist/image-clipper/calculate.js @@ -0,0 +1,276 @@ +/** + * 判断手指触摸位置 + * + * @param {*} cutX + * @param {*} cutY + * @param {*} clipWidth + * @param {*} clipHeight + * @param {*} currentX + * @param {*} currentY + * @returns + */ +export function determineDirection(cutX, cutY, clipWidth, clipHeight, currentX, currentY) { + /* + * (右下>>1 右上>>2 左上>>3 左下>>4) + * left_x: 裁剪框左边线距离视口最左侧两点位置 [3,4] + * right_x: 裁剪框右边线距离视口最右侧两点位置 [1,2] + * top_y: 裁剪框顶部线距离视口最顶部两点位置 [2,3] + * bottom_y:裁剪框底部线距离视口最底部两点位置 [1,4] + */ + // 用户体验优化,增加裁剪框四角可触摸区域 + const EXPAND_SIZE = 24; + + let left_x1 = cutX - EXPAND_SIZE; + let left_x2 = cutX + EXPAND_SIZE; + + let top_y1 = cutY - EXPAND_SIZE; + let top_y2 = cutY + EXPAND_SIZE; + + let right_x1 = cutX + clipWidth - EXPAND_SIZE; + let right_x2 = cutX + clipWidth + EXPAND_SIZE; + + let bottom_y1 = cutY + clipHeight - EXPAND_SIZE; + let bottom_y2 = cutY + clipHeight + EXPAND_SIZE; + /* + * 四角 + * (右下>>1 右上>>2 左上>>3 左下>>4) + */ + let corner; + + const isRight = currentX > right_x1 && currentX < right_x2; + const isLeft = currentX > left_x1 && currentX < left_x2; + const isBottom = currentY > bottom_y1 && currentY < bottom_y2; + const isTop = currentY > top_y1 && currentY < top_y2; + + if (isRight && isBottom) { + corner = 1; + } else if (isRight && isTop) { + corner = 2; + } else if (isLeft && isTop) { + corner = 3; + } else if (isLeft && isBottom) { + corner = 4; + } + return corner; +} + +/** + * 图片边缘检测检测时,计算图片偏移量 + * + * @param {*} data + * @param {*} scale + * @returns + */ +export function calcImageOffset(data, scale) { + let left = data.imageLeft; + let top = data.imageTop; + scale = scale || data.scale; + + let imageWidth = data.imageWidth; + let imageHeight = data.imageHeight; + if ((data.angle / 90) % 2) { + imageWidth = data.imageHeight; + imageHeight = data.imageWidth; + } + const { + cutX, + clipWidth, + cutY, + clipHeight + } = data; + // 当前图片宽度/高度 + const currentImageSize = (size) => (size * scale) / 2; + const currentImageWidth = currentImageSize(imageWidth); + const currentImageHeight = currentImageSize(imageHeight); + + left = cutX + currentImageWidth >= left ? left : cutX + currentImageWidth; + left = cutX + clipWidth - currentImageWidth <= left ? left : cutX + clipWidth - currentImageWidth; + top = cutY + currentImageHeight >= top ? top : cutY + currentImageHeight; + top = cutY + clipHeight - currentImageHeight <= top ? top : cutY + clipHeight - currentImageHeight; + return { + left, + top, + scale + }; +} + +/** + * 图片边缘检测时,计算图片缩放比例 + * + * @param {*} data + * @param {*} scale + * @returns + */ +export function calcImageScale(data, scale) { + scale = scale || data.scale; + let imageWidth = data.imageWidth; + let imageHeight = data.imageHeight; + if ((data.angle / 90) % 2) { + imageWidth = data.imageHeight; + imageHeight = data.imageWidth; + } + if (imageWidth * scale < data.clipWidth) { + scale = data.clipWidth / imageWidth; + } + if (imageHeight * scale < data.clipHeight) { + scale = Math.max(scale, data.clipHeight / imageHeight); + } + return scale; +} + +/** + * 计算图片尺寸 + * + * @export + * @param {*} width + * @param {*} height + * @param {*} data + * @returns + */ +export function calcImageSize(width, height, data) { + // 默认按图片最小边 = 对应裁剪框尺寸 + let imageWidth = width, + imageHeight = height; + if (imageWidth && imageHeight) { + if (imageWidth / imageHeight > (data.clipWidth || data.width) / (data.clipWidth || data.height)) { + imageHeight = data.clipHeight || data.height; + imageWidth = (width / height) * imageHeight; + } else { + imageWidth = data.clipWidth || data.width; + imageHeight = (height / width) * imageWidth; + } + } else { + let sys = data._SYS_INFO || wx.getSystemInfoSync(); + imageWidth = sys.windowWidth; + imageHeight = 0; + } + return { + imageWidth, + imageHeight + }; +} + +/** + * 勾股定理求斜边 + * + * @param {*} width + * @param {*} height + * @returns + */ +export function calcPythagoreanTheorem(width, height) { + return Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2)); +} + +/** + * 拖动裁剪框时计算 + * + * @export + * @param {*} data + * @param {*} event + * @returns + */ +export function clipTouchMoveOfCalculate(data, event) { + const clientX = event.touches[0].clientX; + const clientY = event.touches[0].clientY; + + const { + clipWidth, + clipHeight, + cutY: oldCutY, + cutX: oldCutX, + _CUT_START, + lockRatio + } = data; + let { + maxWidth, + minWidth, + maxHeight, + minHeight + } = data; + maxWidth = maxWidth / 2; + minWidth = minWidth / 2; + minHeight = minHeight / 2; + maxHeight = maxHeight / 2; + + let width = clipWidth, + height = clipHeight, + cutY = oldCutY, + cutX = oldCutX, + // 获取裁剪框实际宽度/高度 + // 如果大于最大值则使用最大值 + // 如果小于最小值则使用最小值 + size_correct = () => { + width = width <= maxWidth ? (width >= minWidth ? width : minWidth) : maxWidth; + height = height <= maxHeight ? (height >= minHeight ? height : minHeight) : maxHeight; + }, + size_inspect = () => { + if ((width > maxWidth || width < minWidth || height > maxHeight || height < minHeight) && lockRatio) { + size_correct(); + return false; + } else { + size_correct(); + return true; + } + }; + height = _CUT_START.height + (_CUT_START.corner > 1 && _CUT_START.corner < 4 ? 1 : -1) * (_CUT_START.y - clientY); + switch (_CUT_START.corner) { + case 1: + width = _CUT_START.width - _CUT_START.x + clientX; + if (lockRatio) { + height = width / (clipWidth / clipHeight); + } + if (!size_inspect()) return; + break; + case 2: + width = _CUT_START.width - _CUT_START.x + clientX; + if (lockRatio) { + height = width / (clipWidth / clipHeight); + } + if (!size_inspect()) return; + cutY = _CUT_START.cutY - (height - _CUT_START.height); + break; + case 3: + width = _CUT_START.width + _CUT_START.x - clientX; + if (lockRatio) { + height = width / (clipWidth / clipHeight); + } + if (!size_inspect()) return; + cutY = _CUT_START.cutY - (height - _CUT_START.height); + cutX = _CUT_START.cutX - (width - _CUT_START.width); + break; + case 4: + width = _CUT_START.width + _CUT_START.x - clientX; + if (lockRatio) { + height = width / (clipWidth / clipHeight); + } + if (!size_inspect()) return; + cutX = _CUT_START.cutX - (width - _CUT_START.width); + break; + default: + break; + } + return { + width, + height, + cutX, + cutY + }; +} + +/** + * 单指拖动图片计算偏移 + * + * @export + * @param {*} data + * @param {*} clientXForLeft + * @param {*} clientYForLeft + * @returns + */ +export function imageTouchMoveOfCalcOffset(data, clientXForLeft, clientYForLeft) { + let left = clientXForLeft - data._touchRelative[0].x, + top = clientYForLeft - data._touchRelative[0].y; + return { + left, + top + }; +} diff --git a/examples/dist/image-clipper/images/close.png b/examples/dist/image-clipper/images/close.png new file mode 100755 index 0000000000000000000000000000000000000000..a1c6c99c250b02bce100042a50b460444cf9ddc8 GIT binary patch literal 2768 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 literal 0 HcmV?d00001 diff --git a/examples/dist/image-clipper/images/photo.png b/examples/dist/image-clipper/images/photo.png new file mode 100755 index 0000000000000000000000000000000000000000..80928c3ba4ef40c66af2ba0df3b6ea33cbbc61ef GIT binary patch literal 1288 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 Tk*#;_{|5z(C(ff88JYPnu8*-u literal 0 HcmV?d00001 diff --git a/examples/dist/image-clipper/images/rotate-inverse.png b/examples/dist/image-clipper/images/rotate-inverse.png new file mode 100755 index 0000000000000000000000000000000000000000..ec77b6b55b31ce92efac9fd60c3ee9bff3832f45 GIT binary patch literal 1786 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 VXF { + // 计算图片尺寸 + this.imgComputeSize(res.width, res.height); + if (this.properties.limitMove) { + // 限制移动,不留空白处理 + this.imgMarginDetectionScale(); + eventUtil.emit(this, 'linimageready', res); + } + }, + fail: () => { + this.imgComputeSize(); + if (this.properties.limitMove) { + this.imgMarginDetectionScale(); + } + } + }); + }, + 'clipWidth, clipHeight'(widthVal, heightVal) { + let { minWidth, minHeight } = this.data; + minWidth = minWidth / 2; + minHeight = minHeight / 2; + if (widthVal < minWidth) { + dataUtil.setDiffData(this, { clipWidth: minWidth }); + } + if (heightVal < minHeight) { + dataUtil.setDiffData(this, { clipHeight: minHeight }); + } + this.computeCutSize(); + }, + 'rotateAngle'(val) { + dataUtil.setDiffData(this, { cutAnimation: true, angle: val }); + }, + 'angle'(val) { + this.moveStop(); + const { + limitMove + } = this.properties; + if (limitMove && val % 90) { + dataUtil.setDiffData(this, { angle: Math.round(val / 90) * 90 }); + } + this.imgMarginDetectionScale(); + }, + 'cutAnimation'(val) { + // 开启过渡260毫秒之后自动关闭 + clearTimeout(this.data._cutAnimationTime); + if (val) { + let _cutAnimationTime = setTimeout(() => { + dataUtil.setDiffData(this, { cutAnimation: false }); + }, 260); + dataUtil.setDiffData(this, { _cutAnimationTime }); + } + }, + 'limitMove'(val) { + if (val) { + if (this.data.angle % 90) { + dataUtil.setDiffData(this, { angle: Math.round(this.data.angle / 90) * 90 }); + } + this.imgMarginDetectionScale(); + } + }, + 'cutY, cutX'() { + this.cutDetectionPosition(); + }, + 'width, height'(width, height) { + if(width !== this.width) { + dataUtil.setDiffData(this, {clipWidth: width / 2}); + } + if(height !== this.height) { + dataUtil.setDiffData(this, {clipHeight: height / 2}); + } + } + }, + /** + * 组件的方法列表 + */ + methods: { + /** + * 设置裁剪框的一些信息 + */ + setCutInfo() { + const { + width, + height + } = this.properties; + const { + _SYS_INFO + } = this.data; + // 本组件动态style默认单位为px,需将用户传入值/2 + const clipWidth = width / 2; + const clipHeight = height / 2; + const cutY = (_SYS_INFO.windowHeight - clipHeight) / 2; + const cutX = (_SYS_INFO.windowWidth - clipWidth) / 2; + const imageLeft = _SYS_INFO.windowWidth / 2; + const imageTop = _SYS_INFO.windowHeight / 2; + const _ctx = wx.createCanvasContext('image-clipper', this); + this.setData({ + clipWidth, + clipHeight, + cutX, + cutY, + CANVAS_HEIGHT: clipHeight, + CANVAS_WIDTH: clipWidth, + _ctx, + imageLeft, + imageTop + }); + }, + /** + * 裁剪框居中 + */ + setCutCenter() { + const { sysInfo, clipHeight, clipWidth, imageTop, imageLeft } = this.data; + let sys = sysInfo || wx.getSystemInfoSync(); + let cutY = (sys.windowHeight - clipHeight) * 0.5; + let cutX = (sys.windowWidth - clipWidth) * 0.5; + this.setData({ + imageTop: imageTop - this.data.cutY + cutY, + imageLeft: imageLeft - this.data.cutX + cutX, + cutY, + cutX + }); + }, + /** + * 开始拖动裁剪框 + * 需在此处查找到是否拖动的裁剪框四角 + */ + clipTouchStart(event) { + if (!this.properties.imageUrl) { + wx.showToast({ + title: '请选择图片', + icon: 'none' + }); + return; + } + const currentX = event.touches[0].clientX; + const currentY = event.touches[0].clientY; + const { cutX, cutY, clipWidth, clipHeight } = this.data; + const corner = determineDirection(cutX, cutY, clipWidth, clipHeight, currentX, currentY); + this.moveDuring(); + const _CUT_START = { + width: clipWidth, + height: clipHeight, + x: currentX, + y: currentY, + cutY, + cutX, + corner + }; + this.setData({ _flagCutTouch: true, _flagEndTouch: true, _CUT_START }); + }, + /** + * 拖动裁剪框 + * 当拖动的裁剪框区域时处理数据 + */ + clipTouchMove(event) { + if (!this.properties.imageUrl) { + wx.showToast({ + title: '请选择图片', + icon: 'none' + }); + return; + } + + const { _flagCutTouch, _MOVE_THROTTLE_FLAG } = this.data; + if (_flagCutTouch && _MOVE_THROTTLE_FLAG) { + const { lockRatio, lockHeight, lockWidth } = this.properties; + if (lockRatio && (lockWidth || lockHeight)) return; + dataUtil.setDiffData(this, { _MOVE_THROTTLE_FLAG: false }); + this.moveThrottle(); + const { width, height, cutX, cutY } = clipTouchMoveOfCalculate(this.data, event); + if (!lockWidth && !lockHeight) { + dataUtil.setDiffData(this, { clipWidth: width, clipHeight: height, cutX, cutY }); + } else if (!lockWidth) { + dataUtil.setDiffData(this, { clipWidth: width, cutX }); + } else if (!lockHeight) { + dataUtil.setDiffData(this, { clipHeight: height, cutY }); + } + this.imgMarginDetectionScale(); + } + }, + /** + * 拖动裁剪框结束 + * 当拖动的裁剪框区域时处理数据 + */ + clipTouchEnd() { + this.moveStop(); + this.setData({ _flagCutTouch: false }); + }, + /** + * 清空之前的自动居中延迟函数 + */ + moveDuring() { + clearTimeout(this.data._TIME_CUT_CENTER); + }, + /** + * 停止移动时需要做的操作 + * 清空之前的自动居中延迟函数并添加最新的 + */ + moveStop() { + clearTimeout(this.data._TIME_CUT_CENTER); + const _TIME_CUT_CENTER = setTimeout(() => { + //动画启动 + if (!this.data.cutAnimation) { + dataUtil.setDiffData(this, { cutAnimation: true }); + } + this.setCutCenter(); + }, 800); + dataUtil.setDiffData(this, { _TIME_CUT_CENTER }); + }, + /** + * 重置延迟函数 + */ + moveThrottle() { + if (this.data._SYS_INFO.platform === 'android') { + clearTimeout(this.data._MOVE_THROTTLE); + const _MOVE_THROTTLE = setTimeout(() => { + dataUtil.setDiffData(this, { _MOVE_THROTTLE_FLAG: true }); + }, 800 / 40); + dataUtil.setDiffData(this, { _MOVE_THROTTLE }); + } else { + dataUtil.setDiffData(this, { _MOVE_THROTTLE_FLAG: true }); + } + }, + /** + * 图片初始化 + */ + imageReset() { + const sys = this.data._SYS_INFO || wx.getSystemInfoSync(); + this.setData({ scale: 1, angle: 0, imageTop: sys.windowHeight / 2, imageLeft: sys.windowWidth / 2 }); + }, + /** + * 图片加载完成 + */ + imageLoad() { + this.imageReset(); + wx.hideLoading(); + eventUtil.emit(this, 'linimageload', detail); + }, + /** + * 计算图片尺寸 + */ + imgComputeSize(width, height) { + const { imageWidth, imageHeight } = calcImageSize(width, height, this.data); + this.setData({ imageWidth, imageHeight }); + }, + /** + * 图片边缘检测-缩放 + */ + imgMarginDetectionScale(scale) { + if (!this.properties.limitMove) return; + const currentScale = calcImageScale(this.data, scale); + this.imgMarginDetectionPosition(currentScale); + }, + /** + * 图片边缘检测-位置 + */ + imgMarginDetectionPosition(scale) { + if (!this.properties.limitMove) return; + const { scale: currentScale, left, top } = calcImageOffset(this.data, scale); + dataUtil.setDiffData(this, { imageLeft: left, imageTop: top, scale: currentScale }); + }, + /** + * 开始图片触摸 + */ + imageTouchStart(e) { + this.setData({ _flagEndTouch: false }); + const { imageLeft, imageTop } = this.data; + // 双指左指坐标 + const clientXForLeft = e.touches[0].clientX; + const clientYForLeft = e.touches[0].clientY; + + let _touchRelative = []; + if (e.touches.length === 1) { + // 单指拖动 + _touchRelative[0] = { + x: clientXForLeft - imageLeft, + y: clientYForLeft - imageTop + }; + this.setData({ _touchRelative }); + } else { + // 双指右指坐标 + const clientXForRight = e.touches[1].clientX; + const clientYForRight = e.touches[1].clientY; + // 双指放大 + let width = Math.abs(clientXForLeft - clientXForRight); + let height = Math.abs(clientYForLeft - clientYForRight); + // 勾股定理求出斜边长度 + const _hypotenuseLength = calcPythagoreanTheorem(width, height); + + _touchRelative = [{ + x: clientXForLeft - imageLeft, + y: clientYForLeft - imageTop + }, + { + x: clientXForRight - imageLeft, + y: clientYForRight - imageTop + } + ]; + this.setData({_touchRelative, _hypotenuseLength}); + } + }, + /** + * 图片放大旋转等操作 + */ + imageTouchMove(e) { + const { + _flagEndTouch, + _MOVE_THROTTLE_FLAG + } = this.data; + if (_flagEndTouch || !_MOVE_THROTTLE_FLAG) return; + // 双指左指坐标 + const clientXForLeft = e.touches[0].clientX; + const clientYForLeft = e.touches[0].clientY; + + dataUtil.setDiffData(this, { _MOVE_THROTTLE_FLAG: false }); + this.moveThrottle(); + this.moveDuring(); + if (e.touches.length === 1) { + //单指拖动 + const { left, top } = imageTouchMoveOfCalcOffset(this.data, clientXForLeft, clientYForLeft); + dataUtil.setDiffData(this, { imageLeft: left, imageTop: top}); + // 图像边缘检测,防止截取到空白 + this.imgMarginDetectionPosition(); + } else { + // 双指右指坐标 + const clientXForRight = e.touches[1].clientX; + const clientYForRight = e.touches[1].clientY; + // 双指放大 + let width = Math.abs(clientXForLeft - clientXForRight), + height = Math.abs(clientYForLeft - clientYForRight), + // 勾股定理求出斜边长度 + hypotenuse = calcPythagoreanTheorem(width, height), // 斜边 + scale = this.data.scale * (hypotenuse / this.data._hypotenuseLength); + // 计算出真实缩放倍率 + // 如果禁止缩放则倍率一直为1 + if (this.properties.disableScale) { + scale = 1; + } else { + scale = scale <= this.properties.minRatio ? this.properties.minRatio : scale; + scale = scale >= this.properties.maxRatio ? this.properties.maxRatio : scale; + eventUtil.emit(this, 'linsizechange', { + imageWidth: this.data.imageWidth * scale, + imageHeight: this.data.imageHeight * scale + }); + } + + this.imgMarginDetectionScale(scale); + dataUtil.setDiffData(this, { + _hypotenuseLength: Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2)), + scale + }); + } + }, + /** + * 图片手指触摸结束 + */ + imageTouchEnd() { + dataUtil.setDiffData(this, { _flagEndTouch: true }); + this.moveStop(); + }, + + /** + * 检测剪裁框位置是否在允许的范围内(屏幕内) + */ + cutDetectionPosition() { + const { cutX, cutY, _SYS_INFO, clipHeight, clipWidth } = this.data; + let cutDetectionPositionTop = () => { + //检测上边距是否在范围内 + if (cutY < 0) { + dataUtil.setDiffData(this, { cutY: 0 }); + } + if (cutY > _SYS_INFO.windowHeight - clipHeight) { + dataUtil.setDiffData(this, { cutY: _SYS_INFO.windowHeight - clipHeight }); + } + }, + cutDetectionPositionLeft = () => { + //检测左边距是否在范围内 + if (cutX < 0) { + dataUtil.setDiffData(this, { cutX: 0 }); + } + if (cutX > _SYS_INFO.windowWidth - clipWidth) { + dataUtil.setDiffData(this, { cutX: _SYS_INFO.windowWidth - clipWidth }); + } + }; + //裁剪框坐标处理(如果只写一个参数则另一个默认为0,都不写默认居中) + if (cutY === null && cutX === null) { + let newCutY = (_SYS_INFO.windowHeight - clipHeight) * 0.5; + let newCutX = (_SYS_INFO.windowWidth - clipWidth) * 0.5; + dataUtil.setDiffData(this, { + cutX: newCutX, // 截取的框上边距 + cutY: newCutY // 截取的框左边距 + }); + } else if (cutY !== null && cutX !== null) { + cutDetectionPositionTop(); + cutDetectionPositionLeft(); + } else if (cutY !== null && cutX === null) { + cutDetectionPositionTop(); + dataUtil.setDiffData(this, { cutX: (_SYS_INFO.windowWidth - clipWidth) / 2 }); + } else if (cutY === null && cutX !== null) { + cutDetectionPositionLeft(); + dataUtil.setDiffData(this, { cutY: (_SYS_INFO.windowHeight - clipHeight) / 2 }); + } + }, + /** + * 改变截取框大小 + */ + computeCutSize() { + const { clipHeight, clipWidth, _SYS_INFO, cutX, cutY } = this.data; + if (clipWidth > _SYS_INFO.windowWidth) { + // 设置裁剪框宽度 + dataUtil.setDiffData(this, { clipWidth: _SYS_INFO.windowWidth }); + } else if (clipWidth + cutX > _SYS_INFO.windowWidth) { + dataUtil.setDiffData(this, { cutX: _SYS_INFO.windowWidth - cutX }); + } + if (clipHeight > _SYS_INFO.windowHeight) { + // 设置裁剪框高度 + dataUtil.setDiffData(this, { clipHeight: _SYS_INFO.windowHeight }); + } else if (clipHeight + cutY > _SYS_INFO.windowHeight) { + dataUtil.setDiffData(this, { cutY: _SYS_INFO.windowHeight - cutY }); + } + }, + /** + * 获取图片数据 + */ + getImageData() { + if (!this.properties.imageUrl) { + wx.showToast({ + title: '请选择图片', + icon: 'none' + }); + return; + } + wx.showLoading({ + title: '加载中' + }); + + const { clipHeight, clipWidth, _ctx, scale, imageLeft, imageTop, cutX, cutY, angle } = this.data; + let { CANVAS_HEIGHT, CANVAS_WIDTH } = this.data; + const { scaleRatio, imageUrl, quality, type: imageType } = this.properties; + // 绘制函数 + const draw = () => { + // 图片真实大小 + const imageWidth = this.data.imageWidth * scale * scaleRatio; + const imageHeight = this.data.imageHeight * scale * scaleRatio; + // canvas和图片的相对距离 + const xpos = imageLeft - cutX; + const ypos = imageTop - cutY; + // 旋转画布 + _ctx.translate(xpos * scaleRatio, ypos * scaleRatio); + _ctx.rotate((angle * Math.PI) / 180); + _ctx.drawImage(imageUrl, -imageWidth / 2, -imageHeight / 2, imageWidth, imageHeight); + _ctx.draw(false, () => { + let params = { + width: clipWidth * scaleRatio, + height: Math.round(clipHeight * scaleRatio), + destWidth: clipWidth * scaleRatio, + destHeight: Math.round(clipHeight) * scaleRatio, + fileType: 'png', + quality + }; + + let data = { + url: '', + base64: '', + width: clipWidth * scaleRatio, + height: clipHeight * scaleRatio + }; + + if (IMAGE_TYPE.base64 === imageType) { + wx.canvasGetImageData({ + canvasId: 'image-clipper', + x: 0, + y: 0, + width: clipWidth * scaleRatio, + height: Math.round(clipHeight * scaleRatio), + success: res => { + const arrayBuffer = new Uint8Array(res.data); + const base64 = wx.arrayBufferToBase64(arrayBuffer); + data.url = base64; + data.base64 = base64; + wx.hideLoading(); + eventUtil.emit(this, 'linclip', data); + } + }); + } else { + wx.canvasToTempFilePath({ + ...params, + canvasId: 'image-clipper', + success: res => { + data.url = res.tempFilePath; + data.base64 = res.tempFilePath; + wx.hideLoading(); + eventUtil.emit(this, 'linclip', data); + }, + fail(res) { + throw res; + } + }, + this + ); + } + }); + }; + + if (CANVAS_WIDTH !== clipWidth || CANVAS_HEIGHT !== clipHeight) { + CANVAS_WIDTH = clipWidth; + CANVAS_HEIGHT = clipHeight; + _ctx.draw(); + setTimeout(() => { + draw(); + }, 100); + } else { + draw(); + } + }, + /** + * 上传图片 + */ + uploadImage() { + wx.chooseImage({ + count: 1, + sizeType: ['original', 'compressed'], + sourceType: ['album', 'camera'], + success: (res) => { + const tempFilePaths = res.tempFilePaths; + this.setData({ imageUrl: tempFilePaths }); + } + }); + }, + /** + * 工具栏旋转 + */ + rotate(event) { + if (this.properties.disableRotate) return; + if (!this.properties.imageUrl) { + wx.showToast({ + title: '请选择图片', + icon: 'none' + }); + return; + } + const { rotateAngle } = this.properties; + const originAngle = this.data.angle; + const type = event.currentTarget.dataset.type; + if (type === 'along') { + this.setData({ angle: originAngle + rotateAngle }); + } else { + this.setData({ angle: originAngle - rotateAngle}); + } + eventUtil.emit(this, 'linrotate', { currentDeg: this.data.angle }); + }, + /** + * 关闭 + */ + close() { + this.setData({ show: false }); + }, + }, + + /** + * 组件的生命周期 + */ + lifetimes: { + ready() { + const _SYS_INFO = wx.getSystemInfoSync(); + this.setData({ _SYS_INFO }); + this.setCutInfo(); + this.setCutCenter(); + this.computeCutSize(); + this.cutDetectionPosition(); + } + } +}); diff --git a/examples/dist/image-clipper/index.json b/examples/dist/image-clipper/index.json new file mode 100644 index 00000000..e8cfaaf8 --- /dev/null +++ b/examples/dist/image-clipper/index.json @@ -0,0 +1,4 @@ +{ + "component": true, + "usingComponents": {} +} \ No newline at end of file diff --git a/examples/dist/image-clipper/index.wxml b/examples/dist/image-clipper/index.wxml new file mode 100644 index 00000000..7bc12fd6 --- /dev/null +++ b/examples/dist/image-clipper/index.wxml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/dist/image-clipper/index.wxss b/examples/dist/image-clipper/index.wxss new file mode 100644 index 00000000..cf1b26bc --- /dev/null +++ b/examples/dist/image-clipper/index.wxss @@ -0,0 +1 @@ +.container{width:100vw;height:100vh;background-color:rgba(0,0,0,.6);position:fixed;top:0;left:0;z-index:1}.container .clip-wrapper{position:absolute;width:100vw;height:100vh}.container .clip-wrapper .clip-content{width:100vw;height:100vh;position:absolute;z-index:99;display:flex;flex-direction:column;pointer-events:none}.container .clip-wrapper .clip-content .flex-auto{flex:auto}.container .clip-wrapper .clip-content .clip-content-footer,.container .clip-wrapper .clip-content .clip-content-top{width:100%;pointer-events:none}.container .clip-wrapper .clip-content .clip-content-middle{width:100%;height:400rpx;display:flex;box-sizing:border-box}.container .clip-wrapper .clip-content .clip-content-middle .clip-content-middle-left,.container .clip-wrapper .clip-content .clip-content-middle .clip-content-middle-right{height:100%}.container .clip-wrapper .clip-content .clip-content-middle .clip-content-middle-center{position:relative;border:1px solid;box-sizing:border-box}.container .clip-wrapper .clip-content .clip-content-middle .clip-content-middle-center .clip-edge{position:absolute;left:6rpx;width:34rpx;height:34rpx;border:2rpx solid #fff;pointer-events:auto;box-sizing:border-box}.container .clip-wrapper .clip-content .clip-content-middle .clip-content-middle-center .clip-edge.clip-edge-top-left{border-bottom-width:0!important;border-right-width:0!important}.container .clip-wrapper .clip-content .clip-content-middle .clip-content-middle-center .clip-edge.clip-edge-top-right{border-bottom-width:0!important;border-left-width:0!important}.container .clip-wrapper .clip-content .clip-content-middle .clip-content-middle-center .clip-edge.clip-edge-bottom-left{border-top-width:0!important;border-right-width:0!important}.container .clip-wrapper .clip-content .clip-content-middle .clip-content-middle-center .clip-edge.clip-edge-bottom-right{border-top-width:0!important;border-left-width:0!important}.container .clip-wrapper .bg-transparent{background-color:rgba(0,0,0,.6);transition-duration:.35s}.container .cropper-image{width:100%;border-style:none;position:absolute;top:0;left:0;z-index:2;-webkit-backface-visibility:hidden;backface-visibility:hidden;transform-origin:center}.container .clipper-canvas{position:fixed;z-index:10;left:-2000px;top:-2000px;pointer-events:none}.container .footer-tools{position:absolute;left:0;bottom:0;width:100%;z-index:99}.container .footer-tools .tools-icon{display:flex;align-items:center;justify-content:space-between;width:100%;padding:20rpx 40rpx;box-sizing:border-box}.container .footer-tools .tools-icon image{display:block;width:50rpx;height:50rpx} \ No newline at end of file From e570cdf65153f9ee80cc919938497b1f62e22035 Mon Sep 17 00:00:00 2001 From: Juzi Date: Wed, 5 Aug 2020 10:13:33 +0800 Subject: [PATCH 04/37] build: Travis CI automatic compilation --- dist/count-selector/index.js | 1 - dist/count-selector/index.json | 1 - dist/count-selector/index.wxml | 10 -- dist/count-selector/index.wxss | 1 - examples/dist/count-selector/index.js | 158 ------------------------ examples/dist/count-selector/index.json | 6 - examples/dist/count-selector/index.wxml | 22 ---- examples/dist/count-selector/index.wxss | 1 - 8 files changed, 200 deletions(-) delete mode 100644 dist/count-selector/index.js delete mode 100644 dist/count-selector/index.json delete mode 100644 dist/count-selector/index.wxml delete mode 100644 dist/count-selector/index.wxss delete mode 100644 examples/dist/count-selector/index.js delete mode 100644 examples/dist/count-selector/index.json delete mode 100644 examples/dist/count-selector/index.wxml delete mode 100644 examples/dist/count-selector/index.wxss diff --git a/dist/count-selector/index.js b/dist/count-selector/index.js deleted file mode 100644 index 2f9d831a..00000000 --- a/dist/count-selector/index.js +++ /dev/null @@ -1 +0,0 @@ -Component({externalClasses:["l-class","l-symbol-class","l-count-class","l-disabled-class"],properties:{count:{type:Number,value:1},max:{type:Number,value:9999},min:{type:Number,value:1},step:{type:Number,value:1},disabled:Boolean,iconSize:String,iconColor:String},data:{focus:!1,result:1},observers:{"count,min,max":function(){this.valueRange(this.data.count,"parameter")}},methods:{doNothing(t){const{type:e}=t.currentTarget.dataset;this.triggerEvent("linout",{type:e,way:"icon"},{bubbles:!0,composed:!0})},onCount(){this.setData({focus:!0})},onBlur(t){this.setData({focus:!1});let{value:e}=t.detail;setTimeout(()=>{this.blurCount(Number(e),()=>{this.data.count=this.data.result,this.triggerEvent("lintap",{count:this.data.result,type:"blur"},{bubbles:!0,composed:!0})})},50)},blurCount(t,e){t?this.valueRange(t):this.setData({result:this.properties.count}),e&&e()},valueRange(t,e="input"){t>this.properties.max?this.setData({result:this.properties.max},()=>{this.triggerEvent("linout",{type:"overflow_max",way:e},{bubbles:!0,composed:!0})}):t{this.triggerEvent("linout",{type:"overflow_min",way:e},{bubbles:!0,composed:!0})}):this.setData({result:t})},reduceTap(){this.data.count-this.properties.step<=this.properties.min?this.data.count=this.properties.min:this.data.count-=this.properties.step,this.setData({result:this.data.count}),this.triggerEvent("lintap",{count:this.data.result,type:"reduce"},{bubbles:!0,composed:!0})},addTap(){this.data.count+this.properties.step>=this.properties.max?this.data.count=this.properties.max:this.data.count+=this.properties.step,this.setData({result:this.data.count}),this.triggerEvent("lintap",{count:this.data.result,type:"add"},{bubbles:!0,composed:!0})}}}); \ No newline at end of file diff --git a/dist/count-selector/index.json b/dist/count-selector/index.json deleted file mode 100644 index e11651a3..00000000 --- a/dist/count-selector/index.json +++ /dev/null @@ -1 +0,0 @@ -{"component":true,"usingComponents":{"l-icon":"../icon/index"}} \ No newline at end of file diff --git a/dist/count-selector/index.wxml b/dist/count-selector/index.wxml deleted file mode 100644 index 95ba7c1a..00000000 --- a/dist/count-selector/index.wxml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - {{result}} - - - - \ No newline at end of file diff --git a/dist/count-selector/index.wxss b/dist/count-selector/index.wxss deleted file mode 100644 index 929666b8..00000000 --- a/dist/count-selector/index.wxss +++ /dev/null @@ -1 +0,0 @@ -.container-count{display:flex;flex-direction:row;width:170rpx;height:56rpx}.symbol{height:100%;width:56rpx;font-size:28rpx;color:#596c8e;display:flex;align-items:center;justify-content:center}.disabled{background-color:#f3f3f3;color:#c4c9d2}.abled{background-color:#ecf1f8;color:#596c8e}.count{height:100%;flex:1;min-height:56rpx;line-height:56rpx;font-size:24rpx;color:#596c8e;background:#f6f7f9;text-align:center;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}@font-face{font-family:iconfont;src:url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAALEAAsAAAAABqwAAAJ3AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCDBgqBFIEWATYCJAMMCwgABCAFhG0HNxvdBcgekiSBqhRCJKIogADMEYRr5GySu0dQoBAloETFRVKmqpWoK1wVG1th2Ij732n7N5fsqTh2xyneKfa2N3/anZKGvYXFohGGrUFIEA6JogD/fZ7L6U2gA7nGtyynNW3s8fyoF2AcUEBjbYqsRALxFtlF3ImLOE6g3ZheoYOxmRVIKtC4QLww9QYkCxFFMfKtQt2wtIjXKq3pZfrEq+j78d9qJEmqDE09fTTahoFf6deHfNxwgxOiBHl1hYx5oBC3GjMXIsLgItpN0e7yWhHSXPEmkcq31Dv94yWihmo7wbQcS/yiMoJf9yskkEFdzE0Diwo7eF2IkexeNr35cvtSjmQ/fjt5zeTy++93z1I4x8LHT3u9VVdH6SHr0r8+OjOTtCopyONe0uFsIlZDiaMZyTdAmzFfZzrm0+EOQPOcP/IeANGP4rNA8KN0+V8rbPwlMwX83P7UK0Wa5wJwS+sZvMEfUwMbiq9F1lxcFVWFvmwE4ErICtOvARTo9zPeMgROEVoL2hG+FqMeslbjZGHnUemwjlqrbbSbM766wwAuIkobZl1ICL0ekXT7jqzXF1nYb1SG/aLWGxG0O4uBLTtMhpne59gQ2CbNHWK2mEeJXaTj+iXUN5wGz2sjfg15YMaJJqvl/Dh6yOeYEWzqFSEooZy5ZEw6DR2HEZ8zC1tCNoTwq4pCm94kt5gLafs41CCgNqJpB2FqYTyUtxbSlc8vQboNjgbeIejJr0FcwOyc0MhUADlu8kCCe3klsElXIQgUQXGMixiTBiGHgyH85kEW1CLIjBEpX5WCm1GoSV7f4n7fNmiH9syRIkeR77bbiWdmwzMaDAAA') format('woff2')}.l-icon-add:before{content:"\e602"}.l-icon-reduce:before{content:"\e69c"}.l-icon{font-family:iconfont;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.l-icon::before{display:inline-flex}.count-hover{opacity:.8} \ No newline at end of file diff --git a/examples/dist/count-selector/index.js b/examples/dist/count-selector/index.js deleted file mode 100644 index c037e059..00000000 --- a/examples/dist/count-selector/index.js +++ /dev/null @@ -1,158 +0,0 @@ -Component({ - externalClasses: [ - 'l-class', - 'l-symbol-class', - 'l-count-class', - 'l-disabled-class' - ], - properties: { - count: { - type: Number, - value: 1 - }, - max: { - type: Number, - value: 9999 - }, - min: { - type: Number, - value: 1 - }, - step: { - type: Number, - value: 1 - }, - disabled: Boolean, - iconSize: String, - iconColor: String - }, - - /** - * 组件的初始数据 - */ - data: { - focus: false, - result: 1 - }, - - observers: { - 'count,min,max': function () { - this.valueRange(this.data.count, 'parameter'); - } - }, - - /** - * 组件的方法列表 - */ - methods: { - doNothing(e) { - const { type } = e.currentTarget.dataset; - this.triggerEvent('linout', { type, way: 'icon' }, { - bubbles: true, - composed: true - }); - }, - - onCount() { - this.setData({ - focus: true - }); - }, - - onBlur(e) { - this.setData({ - focus: false - }); - let { - value - } = e.detail; - setTimeout(() => { - this.blurCount(Number(value), () => { - this.data.count = this.data.result; - this.triggerEvent('lintap', { - count: this.data.result, - type: 'blur' - }, { - bubbles: true, - composed: true - }); - }); - }, 50); - }, - - blurCount(value, callback) { - if (value) { - this.valueRange(value); - } else { - this.setData({ - result: this.properties.count - }); - } - callback && callback(); - }, - - valueRange(value, way = 'input') { - if (value > this.properties.max) { - this.setData({ - result: this.properties.max - }, () => { - this.triggerEvent('linout', { type: 'overflow_max', way }, { - bubbles: true, - composed: true - }); - }); - } else if (value < this.properties.min) { - this.setData({ - result: this.properties.min - }, () => { - this.triggerEvent('linout', { type: 'overflow_min', way }, { - bubbles: true, - composed: true - }); - }); - } else { - this.setData({ - result: value - }); - } - }, - - reduceTap() { - let distance = this.data.count - this.properties.step; - if (distance <= this.properties.min) { - this.data.count = this.properties.min; - } else { - this.data.count -= this.properties.step; - } - this.setData({ - result: this.data.count - }); - this.triggerEvent('lintap', { - count: this.data.result, - type: 'reduce' - }, { - bubbles: true, - composed: true - }); - }, - - addTap() { - let distance = this.data.count + this.properties.step; - if (distance >= this.properties.max) { - this.data.count = this.properties.max; - } else { - this.data.count += this.properties.step; - } - this.setData({ - result: this.data.count - }); - this.triggerEvent('lintap', { - count: this.data.result, - type: 'add' - }, { - bubbles: true, - composed: true - }); - }, - } -}); \ No newline at end of file diff --git a/examples/dist/count-selector/index.json b/examples/dist/count-selector/index.json deleted file mode 100644 index c01e2d7e..00000000 --- a/examples/dist/count-selector/index.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "component": true, - "usingComponents": { - "l-icon":"../icon/index" - } -} \ No newline at end of file diff --git a/examples/dist/count-selector/index.wxml b/examples/dist/count-selector/index.wxml deleted file mode 100644 index c1b1cff4..00000000 --- a/examples/dist/count-selector/index.wxml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - {{result}} - - - - \ No newline at end of file diff --git a/examples/dist/count-selector/index.wxss b/examples/dist/count-selector/index.wxss deleted file mode 100644 index 929666b8..00000000 --- a/examples/dist/count-selector/index.wxss +++ /dev/null @@ -1 +0,0 @@ -.container-count{display:flex;flex-direction:row;width:170rpx;height:56rpx}.symbol{height:100%;width:56rpx;font-size:28rpx;color:#596c8e;display:flex;align-items:center;justify-content:center}.disabled{background-color:#f3f3f3;color:#c4c9d2}.abled{background-color:#ecf1f8;color:#596c8e}.count{height:100%;flex:1;min-height:56rpx;line-height:56rpx;font-size:24rpx;color:#596c8e;background:#f6f7f9;text-align:center;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}@font-face{font-family:iconfont;src:url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAALEAAsAAAAABqwAAAJ3AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCDBgqBFIEWATYCJAMMCwgABCAFhG0HNxvdBcgekiSBqhRCJKIogADMEYRr5GySu0dQoBAloETFRVKmqpWoK1wVG1th2Ij732n7N5fsqTh2xyneKfa2N3/anZKGvYXFohGGrUFIEA6JogD/fZ7L6U2gA7nGtyynNW3s8fyoF2AcUEBjbYqsRALxFtlF3ImLOE6g3ZheoYOxmRVIKtC4QLww9QYkCxFFMfKtQt2wtIjXKq3pZfrEq+j78d9qJEmqDE09fTTahoFf6deHfNxwgxOiBHl1hYx5oBC3GjMXIsLgItpN0e7yWhHSXPEmkcq31Dv94yWihmo7wbQcS/yiMoJf9yskkEFdzE0Diwo7eF2IkexeNr35cvtSjmQ/fjt5zeTy++93z1I4x8LHT3u9VVdH6SHr0r8+OjOTtCopyONe0uFsIlZDiaMZyTdAmzFfZzrm0+EOQPOcP/IeANGP4rNA8KN0+V8rbPwlMwX83P7UK0Wa5wJwS+sZvMEfUwMbiq9F1lxcFVWFvmwE4ErICtOvARTo9zPeMgROEVoL2hG+FqMeslbjZGHnUemwjlqrbbSbM766wwAuIkobZl1ICL0ekXT7jqzXF1nYb1SG/aLWGxG0O4uBLTtMhpne59gQ2CbNHWK2mEeJXaTj+iXUN5wGz2sjfg15YMaJJqvl/Dh6yOeYEWzqFSEooZy5ZEw6DR2HEZ8zC1tCNoTwq4pCm94kt5gLafs41CCgNqJpB2FqYTyUtxbSlc8vQboNjgbeIejJr0FcwOyc0MhUADlu8kCCe3klsElXIQgUQXGMixiTBiGHgyH85kEW1CLIjBEpX5WCm1GoSV7f4n7fNmiH9syRIkeR77bbiWdmwzMaDAAA') format('woff2')}.l-icon-add:before{content:"\e602"}.l-icon-reduce:before{content:"\e69c"}.l-icon{font-family:iconfont;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.l-icon::before{display:inline-flex}.count-hover{opacity:.8} \ No newline at end of file From 7f9aabe39847549f110c644c494ef69a39e6017c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A1=94=E5=AD=90?= Date: Tue, 4 Aug 2020 19:34:14 +0800 Subject: [PATCH 05/37] =?UTF-8?q?refactor(Example):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=20Transition=20=E7=BB=84=E4=BB=B6=E5=9B=BE=E6=A0=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/pages/navigator/content/config/animation-navi.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/pages/navigator/content/config/animation-navi.js b/examples/pages/navigator/content/config/animation-navi.js index d0c8088b..5f8050c1 100644 --- a/examples/pages/navigator/content/config/animation-navi.js +++ b/examples/pages/navigator/content/config/animation-navi.js @@ -1,7 +1,7 @@ const animationNaviConfigs = [ { - icon: '/images/component/icon.png', + icon: 'cloud://env-9eb476.656e-env-9eb476-1258886794/images/components/transition/transition-icon.png', title: 'Transition', desc: '过渡', componentsPath: '/pages/components/animation/pages/transition/index' From c90b08312bfd09ed5ed009553f944a67d3bc232e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A1=94=E5=AD=90?= Date: Tue, 4 Aug 2020 19:07:11 +0800 Subject: [PATCH 06/37] =?UTF-8?q?feat(Counter):=20=E6=96=B0=E5=A2=9E=20lin?= =?UTF-8?q?cahnge=20=E4=BA=8B=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 数量选择器值改变时触发 linchange 事件 close #992 --- src/counter/index.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/counter/index.js b/src/counter/index.js index 6a3a6b7d..20ed35b3 100644 --- a/src/counter/index.js +++ b/src/counter/index.js @@ -1,4 +1,5 @@ import hover from '../behaviors/hover'; +import eventUtil from '../core/utils/event-util'; Component({ behaviors: [hover], @@ -39,9 +40,12 @@ Component({ }, observers: { + 'result': function (count) { + eventUtil.emit(this, 'linchange', { value: count }); + }, 'count,min,max': function () { this.valueRange(this.data.count, 'parameter'); - } + }, }, /** @@ -158,4 +162,4 @@ Component({ }); }, } -}); \ No newline at end of file +}); From f4d4483f9c2fef253936e9067ec7e5d93270bfbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A1=94=E5=AD=90?= Date: Tue, 4 Aug 2020 19:10:15 +0800 Subject: [PATCH 07/37] =?UTF-8?q?refactor(Counter):=20=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=20EventUtil=20=E9=87=8D=E6=9E=84=E4=BA=8B=E4=BB=B6=E8=A7=A6?= =?UTF-8?q?=E5=8F=91=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/counter/index.js | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/src/counter/index.js b/src/counter/index.js index 20ed35b3..96499fc0 100644 --- a/src/counter/index.js +++ b/src/counter/index.js @@ -41,7 +41,7 @@ Component({ observers: { 'result': function (count) { - eventUtil.emit(this, 'linchange', { value: count }); + eventUtil.emit(this, 'linchange', { count }); }, 'count,min,max': function () { this.valueRange(this.data.count, 'parameter'); @@ -54,10 +54,7 @@ Component({ methods: { doNothing(e) { const { type } = e.currentTarget.dataset; - this.triggerEvent('linout', { type, way: 'icon' }, { - bubbles: true, - composed: true - }); + eventUtil.emit(this, 'linout', { type, way: 'icon' }); }, onCount() { @@ -76,13 +73,7 @@ Component({ setTimeout(() => { this.blurCount(Number(value), () => { this.data.count = this.data.result; - this.triggerEvent('lintap', { - count: this.data.result, - type: 'blur' - }, { - bubbles: true, - composed: true - }); + eventUtil.emit(this, 'lintap', { count: this.data.result, type: 'blur' }); }); }, 50); }, @@ -103,19 +94,13 @@ Component({ this.setData({ result: this.properties.max }, () => { - this.triggerEvent('linout', { type: 'overflow_max', way }, { - bubbles: true, - composed: true - }); + eventUtil.emit(this, 'linout', { type: 'overflow_max', way }); }); } else if (value < this.properties.min) { this.setData({ result: this.properties.min }, () => { - this.triggerEvent('linout', { type: 'overflow_min', way }, { - bubbles: true, - composed: true - }); + eventUtil.emit(this, 'linout', { type: 'overflow_min', way }); }); } else { this.setData({ From e6a62f6346665867a48d3ed91977dde889fb7669 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A1=94=E5=AD=90?= Date: Tue, 4 Aug 2020 14:37:33 +0800 Subject: [PATCH 08/37] =?UTF-8?q?refactor(Album):=20=E4=BF=AE=E6=94=B9=20b?= =?UTF-8?q?ind:tap=20=E4=B8=BA=20mut-bind:tap?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/album/index.wxml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/album/index.wxml b/src/album/index.wxml index 274d4d6f..4ed36dbc 100644 --- a/src/album/index.wxml +++ b/src/album/index.wxml @@ -1,6 +1,6 @@ - + From 05587be6920b2bc1465f026e2733ae55118a13fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A1=94=E5=AD=90?= Date: Tue, 4 Aug 2020 14:38:08 +0800 Subject: [PATCH 09/37] =?UTF-8?q?refactor(Avatar):=20=E4=BF=AE=E6=94=B9=20?= =?UTF-8?q?bind:tap=20=E4=B8=BA=20mut-bind:tap?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/avatar/index.wxml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/avatar/index.wxml b/src/avatar/index.wxml index 7f9ae0bc..b7529cf4 100644 --- a/src/avatar/index.wxml +++ b/src/avatar/index.wxml @@ -1,5 +1,5 @@ - + From 03f5963ddd524bb61cec9d25a7785824053a6bdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A1=94=E5=AD=90?= Date: Tue, 4 Aug 2020 14:38:40 +0800 Subject: [PATCH 10/37] =?UTF-8?q?refactor(Badge):=20=E4=BF=AE=E6=94=B9=20b?= =?UTF-8?q?ind:tap=20=E4=B8=BA=20mut-bind:tap?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/badge/index.wxml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/badge/index.wxml b/src/badge/index.wxml index 2854d246..33c6be88 100644 --- a/src/badge/index.wxml +++ b/src/badge/index.wxml @@ -1,7 +1,7 @@ - + {{finalCount}} - \ No newline at end of file + From 26df49c3f43edddc7a0a68d2bdba27c135b6eccf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A1=94=E5=AD=90?= Date: Tue, 4 Aug 2020 14:39:05 +0800 Subject: [PATCH 11/37] =?UTF-8?q?refactor(Button):=20=E4=BF=AE=E6=94=B9=20?= =?UTF-8?q?bind:tap=20=E4=B8=BA=20mut-bind:tap?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/button/index.wxml | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/button/index.wxml b/src/button/index.wxml index 3738cc7c..51d7dc3d 100644 --- a/src/button/index.wxml +++ b/src/button/index.wxml @@ -1,11 +1,11 @@ -