赞
踩
第一步:拿到图片信息
第二步:计算基准框大小,设置预览图片基准值
第三步:预览图片宽高处理
第四步:获取屏幕宽高,绘制蒙层
第五步:图片预览
第六步:预览图拖拽处理
第七步:图像裁剪
- <template>
- <view class="settingHeadImage" @touchstart="onTouchstart" @touchmove.stop.prevent="onTouchmove" @touchend="touchE">
- <!-- 蒙层 -->
- <canvas class="pre-canvas" canvas-id="firstCanvas" :style="{ width: 100 + 'vw', height: 100 + 'vh' }"></canvas>
- <!-- img预览 -->
- <view class="preImage" :style="{ width: preImgW + 'px' }">
- <canvas canvas-id="mycanvas" class="pre-i"
- :style="{ width: preImgW + 'px', height: preImgH + 'px', transform: `translate(${x}px,${y}px)` }"></canvas>
- </view>
- <!-- 工具 -->
- <view class="setting-btns"><text @click="onCrop">确定</text></view>
- </view>
- </template>
-
- <script>
- export default {
- data() {
- return {
- maxW: 250, // 最大宽度
- maxH: 250,
- screenWidth: '', // 屏幕宽
- screenHeight: '',
- xToTop: 0, // x方向距离顶部距离
- scale: 1, // 缩放
- preSrc: '',
- preImgW: '',
- preImgH: '',
- x: 0,
- y: 0,
- oldx: 0,
- oldy: 0,
- isMove: false,
- start: {
- left: 0,
- top: 0
- }
- };
- },
- computed: {},
- onLoad(option) {
- // 选择照片信息
- let data = JSON.parse(decodeURIComponent(option.item));
- const query = uni.createSelectorQuery();
- query.select('.settingHeadImage').boundingClientRect();
- query.exec(res => {
- // 设置屏幕大小
- this.screenWidth = res[0].width;
- this.screenHeight = res[0].height;
- // 设置图像基准值,图像基准值按屏幕宽度设置,两边留白各40
- this.maxH = res[0].width - 80;
- this.maxW = res[0].width - 80;
- // 设置X轴值,算式:屏幕高度的一半减去基准框高度的一半
- this.xToTop = this.screenHeight / 2 - this.maxH / 2;
- this.setImageSize(data);
- });
- },
- methods: {
- // 宽高处理
- setImageSize(data) {
- const {
- tempFilePath
- } = data;
- const {
- maxH,
- maxW
- } = this;
- uni.getImageInfo({
- src: tempFilePath,
- success: res => {
- const {
- errMsg,
- path,
- width,
- height
- } = res;
- let w = '';
- let h = '';
- if (errMsg === 'getImageInfo:ok') {
- w = width;
- h = height;
- // 宽大与高大于最大宽度
- if (width > height && width > maxW) {
- w = Math.floor((width / height) * maxW);
- h = maxH;
- }
- // 高大于宽大于最大高度
- if (height > width && height > maxH) {
- h = Math.floor((height / width) * maxH);
- w = maxW;
- }
- // 宽高相等或者宽高小于最大值
- if (width === height || (width < maxW && height < maxH)) {
- h = maxH;
- w = maxW;
- }
- this.preSrc = path;
- this.preImgH = h;
- this.preImgW = w;
- // 设置蒙层
- this.setBgBox();
- // 图像预览
- this.previewCanvas({
- w,
- h,
- path
- });
- }
- }
- });
- },
-
- // 设置蒙层
- setBgBox() {
- const {
- maxW,
- maxH,
- screenHeight,
- screenWidth,
- xToTop
- } = this;
- const ctx = uni.createCanvasContext('firstCanvas');
- // 先清除矩形
- ctx.clearRect(0, 0, screenWidth, screenHeight);
- // 设置canvas透明度
- ctx.setGlobalAlpha(0.7);
- // 设置蒙层颜色
- ctx.setFillStyle('#000000');
- // 绘制蒙层
- ctx.fillRect(0, 0, screenWidth, screenHeight);
- // 基准框留白
- ctx.clearRect(40, xToTop, maxW, maxH);
- // 绘制基准框
- ctx.beginPath();
- ctx.setStrokeStyle('#FFFFFF');
- ctx.strokeRect(40, xToTop, maxW, maxH);
- ctx.closePath();
- ctx.draw();
- },
- // 预览
- previewCanvas({
- w,
- h,
- path
- }) {
- const ctx = uni.createCanvasContext('mycanvas');
- ctx.drawImage(path, 0, 0, w, h);
- ctx.draw();
- },
- onTouchstart(ev) {
- if (ev.changedTouches.length === 1) {
- this.isMove = true;
- this.start.left = ev.changedTouches[0].clientX;
- this.start.top = ev.changedTouches[0].clientY;
- }
- },
- onTouchmove(ev) {
- const {
- maxW,
- maxH,
- preImgH,
- preImgW,
- xToTop
- } = this;
- if (this.isMove && ev.changedTouches.length === 1) {
- let clientX = ev.changedTouches[0].clientX,
- clientY = ev.changedTouches[0].clientY;
- this.x = preImgW <= maxW ? 0 : this.oldx + clientX - this.start.left;
- this.y = preImgH <= maxH ? 0 : this.oldy + clientY - this.start.top;
- }
- },
- touchE(val) {
- const {
- preImgH,
- preImgW,
- maxH,
- maxW
- } = this;
- const query = uni.createSelectorQuery();
- const fx = this.x;
- query.select('.pre-i').boundingClientRect();
- query.exec(res => {
- // x、y回弹计算
- let y = (res[0].height - res[0].width) / 2;
- /**
- * 判断照片可移动的距离是否大于留白的值,如果大于向右划时图片的宽减去基准框的宽减去留白向左时留白,小于时按图片的可移动值
- * */
- let x = (preImgW - maxW) / 2 > 40 ? (fx < 0 ? preImgW - maxW - 40 : 40) : (preImgW - maxW) / 2;
- if (preImgH > maxH) {
- this.y = this.y > y ? y : this.y < -y ? -y : this.y;
- }
- if (preImgW > maxW) {
- this.x = this.x > x ? x : this.x < -x ? -x : this.x;
- }
- this.oldx = this.x;
- this.oldy = this.y;
- this.isMove = false;
- });
- },
- // 裁剪
- onCrop() {
- let y = 0;
- let x = 0;
- const query = uni.createSelectorQuery();
- query.select('.pre-i').boundingClientRect();
- query.exec(res => {
- // 获取预览img距离左上的距离
- y = Math.abs(res[0].top);
- x = Math.abs(res[0].left);
- const {
- maxW,
- maxH,
- preImgH,
- preImgW,
- xToTop
- } = this;
- uni.canvasToTempFilePath({
- x: Math.abs(res[0].left < 0 ? x + 40 : x - 40),
- y: Math.abs(res[0].top < 0 ? xToTop + y : xToTop - y),
- width: maxW,
- height: maxH,
- destWidth: maxW,
- destHeight: maxH,
- canvasId: 'mycanvas',
- success: fileRes => {
- console.log(fileRes);
- uni.previewImage({
- count: 1,
- urls: [fileRes.tempFilePath]
- });
- },
- fail: function(err) {
- console.log(err);
- uni.showToast({
- title: '上传失败:图片生成过程中遇到错误',
- icon: 'none'
- });
- }
- });
- });
- }
- }
- };
- </script>
-
- <style lang="scss" scoped>
- .settingHeadImage {
- background-color: #000000;
- overflow: hidden;
-
- .pre-canvas {
- position: fixed;
- top: 0;
- left: 0;
- z-index: 20;
- }
-
- .preImage {
- min-width: 100vw;
- height: 100vh;
- display: flex;
- justify-content: center;
- align-items: center;
- overflow: hidden;
- z-index: 1;
-
- .pre-i {
- // transition: all 0.1s;
- }
- }
-
- .setting-btns {
- position: fixed;
- bottom: 0;
- left: 0;
- z-index: 20;
- font-size: 14px;
- color: #ffffff;
- }
- }
- </style>
