日照项目的居民端小程序
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

483 lines
12 KiB

import words from "@config/words";
import {
wxLogin,
wxChooseImage,
wxUploadFile,
wxRequestPost,
} from "@utils/promise-wx-api";
import promiseWxApi from "@utils/promise-wx-api";
import nextTick from "@npm/dai-mp/tools/nextTick.js";
import translateStyle from "@npm/dai-mp/tools/translateStyle.js";
import computedBehavior from "@npm/dai-mp/mixins/computed-component/index.js";
const app = getApp();
const systemInfo = wx.getSystemInfoSync();
const windowWidth = systemInfo.windowWidth;
const dpr = systemInfo.pixelRatio > 2 ? 2 : systemInfo.pixelRatio;
let showImageWidth = (600 / 750) * windowWidth;
let showImageHeight = (600 / 750) * windowWidth;
Component({
behaviors: [computedBehavior],
properties: {
src: {
type: String,
value: "",
},
// 以rpx为单位,最多750
width: {
type: Number,
value: 600,
},
height: {
type: Number,
value: 600,
},
showCircle: {
type: Boolean,
value: false,
},
uploadUrl: {
type: String,
value: "oss/file/uploadimg",
},
},
data: {
dpr,
avatar: {
tempFilePath: "",
x: 0,
y: 0,
width: 0,
height: 0,
rotate: 0, // 90 180 270
zoom: 1, // 1-10
srcWidth: 0,
srcHeight: 0,
},
// 单点触摸移动
singleTouchData: {
isActived: false,
srcX: 0,
srcY: 0,
x: 0,
y: 0,
},
// 单点触摸移动
doubleTouchData: {
isActived: false,
srcDistance: 0,
distance: 0,
},
fmData: {
wx_form_id: "",
avatar_url: "",
},
},
computed: {
imgStyle(data) {
const {
x,
y,
width,
height,
zoom,
rotate,
srcWidth,
srcHeight,
} = data.avatar;
const ratio = srcWidth / width;
const afterX = x - (srcWidth - width) / 2;
const afterY = y - (srcHeight - height) / 2;
const afterZoom = Math.round((10000 * zoom) / ratio) / 10000;
let styleObj = {
width: `${srcWidth}px`,
height: `${srcHeight}px`,
transform: `translate3d(${afterX}px, ${afterY}px, 0) rotate(${rotate}deg) scale(${afterZoom})`,
};
return translateStyle(styleObj);
},
},
watch: {},
lifetimes: {
attached() {
this.init();
},
},
methods: {
async init() {
const { src, width, height } = this.data;
// 根据配置更新图片默认高度
showImageWidth = (width / 750) * windowWidth;
showImageHeight = (height / 750) * windowWidth;
// 初始化默认图片
if (src) {
console.log("初始化截图", src);
this.iniHttpImage(src);
} else {
this.handleTapReselectBtn();
}
},
async selectOneImage() {
const {
data: { tempFilePaths },
} = await wxChooseImage({
count: 1,
sizeType: ["compressed"],
});
return tempFilePaths[0];
},
// 获取canvas对象
async getCanvas(id = "#myCanvas") {
return new Promise((reslove) => {
this.createSelectorQuery()
.select(id)
.fields({ node: true, size: true })
.exec((res) => {
reslove(res[0].node);
});
});
},
// 或许canvas创建的图片对象
async getCanvasImg(canvas, src) {
const img = canvas.createImage();
return new Promise((reslove) => {
img.src = src;
img.onload = () => {
reslove(img);
};
});
},
async createImage() {
const { avatar } = this.data;
const { x, y, width, height, zoom, rotate } = avatar;
const destWidth = 600;
const destHeight = 600 * (showImageHeight / showImageWidth);
const canvas = await this.getCanvas();
// 不赋值就会显示默认宽高。。
(canvas.width = showImageWidth * dpr),
(canvas.height = showImageHeight * dpr);
const ctx = canvas.getContext("2d");
ctx.scale(dpr, dpr);
const img = await this.getCanvasImg(canvas, avatar.tempFilePath);
// console.log(
// x - ((zoom - 1) * width) / 2,
// y - ((zoom - 1) * height) / 2,
// width * zoom,
// height * zoom,
// canvas.width,
// canvas.height
// );
ctx.drawImage(
img,
//这里的位置处理很奇怪吧,没办法,显示用的是css3中的transfrom,它的原理是居中缩放
x - ((zoom - 1) * width) / 2,
y - ((zoom - 1) * height) / 2,
width * zoom,
height * zoom
);
// ctx.restore();
await nextTick(1000);
const {
data: { tempFilePath },
} = await promiseWxApi("canvasToTempFilePath")({
canvas,
});
ctx.clearRect(0, 0, showImageWidth * dpr, showImageHeight * dpr);
ctx.scale(1 / dpr, 1 / dpr);
// wx.previewImage({
// urls: [tempFilePath],
// });
return tempFilePath;
},
// 旋转图片
async rotateImg() {
const { avatar } = this.data;
if (!avatar.tempFilePath) return;
wx.showLoading();
const canvas = await this.getCanvas("#rotateCanvas");
let { srcWidth, srcHeight } = avatar;
// 不赋值就会显示默认宽高。。
(canvas.width = srcHeight), (canvas.height = srcWidth);
const ctx = canvas.getContext("2d");
const img = await this.getCanvasImg(canvas, avatar.tempFilePath);
// 旋转90度
ctx.translate(srcHeight, 0);
ctx.rotate((Math.PI * 90) / 180);
ctx.drawImage(img, 0, 0, srcWidth, srcHeight);
// ctx.restore();
await nextTick(1000);
const {
data: { tempFilePath },
} = await promiseWxApi("canvasToTempFilePath")({
canvas,
});
ctx.clearRect(0, 0, srcWidth, srcHeight);
ctx.rotate((Math.PI * -90) / 180);
ctx.translate(-srcHeight, 0);
console.log(tempFilePath);
wx.hideLoading();
this.reselectImage(tempFilePath);
},
async reselectImage(argSrcImage) {
const srcImage = argSrcImage || (await this.selectOneImage());
const {
data: { width, height },
} = await promiseWxApi("getImageInfo")({ src: srcImage });
const ratio = width / height;
const defaultRatio = showImageWidth / showImageHeight;
let avatarWidth, avatarHeight;
if (ratio > defaultRatio) {
// 图片更宽
avatarWidth = showImageHeight * ratio;
avatarHeight = showImageHeight;
} else {
avatarWidth = showImageWidth;
avatarHeight = showImageWidth / ratio;
}
let avatarX = 0,
avatarY = 0;
if (ratio > defaultRatio) {
// 图片更宽
avatarX = (showImageWidth - avatarWidth) / 2;
} else {
avatarY = (showImageHeight - avatarHeight) / 2;
}
let { avatar } = this.data;
avatar.tempFilePath = srcImage;
avatar.width = avatarWidth;
avatar.height = avatarHeight;
avatar.x = avatarX;
avatar.y = avatarY;
avatar.zoom = 1;
avatar.rotate = 0;
// 太大的图片容易崩溃
let srcWidth = width;
let srcHeight = height;
if (srcWidth > 1200) {
srcHeight = (1200 * srcHeight) / srcWidth;
srcWidth = 1200;
}
avatar.srcWidth = srcWidth;
avatar.srcHeight = srcHeight;
this.setData({ avatar });
},
handleTapReselectBtn() {
this.reselectImage();
},
handelTouchstartCropper(e) {
const { touches } = e;
const { singleTouchData, doubleTouchData } = this.data;
if (touches.length === 1) {
// 单点位移
const { clientX, clientY } = touches[0];
singleTouchData.isActived = true;
singleTouchData.srcX = clientX;
singleTouchData.srcY = clientY;
singleTouchData.x = clientX;
singleTouchData.y = clientY;
} else if (touches.length > 1) {
// 两点缩放
doubleTouchData.isActived = true;
const t1 = touches[0];
const t2 = touches[1];
// 两指间距离
const distance = parseInt(
Math.sqrt(
Math.pow(t1.clientX - t2.clientX, 2) +
Math.pow(t1.clientY - t2.clientY, 2)
)
);
doubleTouchData.srcDistance = distance;
doubleTouchData.distance = distance;
}
this.setData({
doubleTouchData,
singleTouchData,
});
},
handelTouchendCropper() {
const { singleTouchData, doubleTouchData } = this.data;
singleTouchData.isActived = false;
doubleTouchData.isActived = false;
this.setData({
doubleTouchData,
singleTouchData,
});
},
handelTouchmoveCropper(e) {
const { touches } = e;
const { avatar, singleTouchData, doubleTouchData } = this.data;
if (touches.length === 1) {
// 单点位移
const { clientX, clientY } = touches[0];
if (singleTouchData.isActived) {
// 边界
const { zoom, width, height } = avatar;
const maxX = ((zoom - 1) * width) / 2,
minX = showImageWidth - width - maxX,
maxY = ((zoom - 1) * height) / 2,
minY = showImageHeight - height - maxY;
let { x, y } = avatar;
x += clientX - singleTouchData.x;
y += clientY - singleTouchData.y;
x = Math.min(x, maxX);
x = Math.max(x, minX);
y = Math.min(y, maxY);
y = Math.max(y, minY);
avatar.x = x;
avatar.y = y;
singleTouchData.x = clientX;
singleTouchData.y = clientY;
}
} else if (touches.length > 1) {
// 两点缩放
doubleTouchData.isActived = true;
const t1 = touches[0];
const t2 = touches[1];
if (doubleTouchData.isActived) {
// 两指间距离
const distance = parseInt(
Math.sqrt(
Math.pow(t1.clientX - t2.clientX, 2) +
Math.pow(t1.clientY - t2.clientY, 2)
)
);
// 放大比例
let { zoom } = avatar;
zoom += ((distance - doubleTouchData.distance) * 2) / windowWidth;
zoom = Math.max(zoom, 1);
zoom = Math.min(zoom, 8);
// 边界
const { width, height } = avatar;
const maxX = ((zoom - 1) * width) / 2,
minX = showImageWidth - width - maxX,
maxY = ((zoom - 1) * height) / 2,
minY = showImageHeight - height - maxY;
let { x, y } = avatar;
x = Math.min(x, maxX);
x = Math.max(x, minX);
y = Math.min(y, maxY);
y = Math.max(y, minY);
avatar.x = x;
avatar.y = y;
avatar.zoom = zoom;
doubleTouchData.srcDistance = distance;
doubleTouchData.distance = distance;
}
}
this.setData({ avatar, doubleTouchData, singleTouchData });
},
// 提交信息
async submit(e) {
const { avatar, uploadUrl } = this.data;
if (avatar.tempFilePath == "") {
return wx.showToast({
title: "请先选择图片",
icon: "none",
duration: 1500,
});
}
wx.showLoading({
title: "保存中…",
mask: true,
});
// 生成头像图片本地地址
const avatarTempUrl = await this.createImage();
console.log("剪裁成功图片临时地址", avatarTempUrl);
const {
data: {
data: { code, data },
},
msg,
} = await wxUploadFile(uploadUrl, avatarTempUrl, {
// isMock: true
});
wx.hideLoading();
if (msg === "success" && code === 0) {
console.log(data);
this.triggerEvent("cropSuccess", { ...data });
}
},
// 初始化网络图片为默认图片
async iniHttpImage(src) {
const {
msg,
data: { tempFilePath },
} = await promiseWxApi("downloadFile")({
url: src,
});
if (msg == "success") {
this.reselectImage(tempFilePath);
}
},
},
});