454 lines
11 KiB
Vue
454 lines
11 KiB
Vue
|
<!-- mosowe-canvas-image -->
|
|||
|
<template>
|
|||
|
<view class='mosowe-canvas-image'>
|
|||
|
<view class="slot-view" @click="createCanvas">
|
|||
|
<slot></slot>
|
|||
|
</view>
|
|||
|
<view class="canvas-wrap-box">
|
|||
|
<!-- 主面板绘制 -->
|
|||
|
<canvas class="canvas-wrap" canvas-id="canvas" :style="'width: '+ width +'px; height: '+ height +'px;'"></canvas>
|
|||
|
<!-- 这个是用来绘制圆形图片的 -->
|
|||
|
<canvas class="canvas-wrap" canvas-id="canvas-arc" :style="'width: '+ canvasArcWidth +'px; height: '+ canvasArcHeight +'px;'"></canvas>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
</template>
|
|||
|
|
|||
|
<script>
|
|||
|
import QR from './wxqrcode.js';
|
|||
|
export default {
|
|||
|
name: 'mosowe-canvas-image',
|
|||
|
components: {},
|
|||
|
props: {
|
|||
|
imgType: { // 图片类型
|
|||
|
type: String,
|
|||
|
default: 'jpg',
|
|||
|
validator: () => {
|
|||
|
return ['jpg', 'png'];
|
|||
|
}
|
|||
|
},
|
|||
|
compress: { // 是否开启压缩
|
|||
|
type: Boolean,
|
|||
|
default: false
|
|||
|
},
|
|||
|
compressSize: { // 压缩界限,超过界限压缩,默认2M
|
|||
|
type: [Number, String],
|
|||
|
default: 1024*1024*2
|
|||
|
},
|
|||
|
showPreview: { // 生成图像后是否预览
|
|||
|
type: Boolean,
|
|||
|
default: false
|
|||
|
},
|
|||
|
height: { // canvas高度
|
|||
|
type: [String, Number],
|
|||
|
default: 200
|
|||
|
},
|
|||
|
width: { // canvas宽度
|
|||
|
type: [String, Number],
|
|||
|
default: 200
|
|||
|
},
|
|||
|
lists: {
|
|||
|
type: Array,
|
|||
|
default: () => {
|
|||
|
return [];
|
|||
|
}
|
|||
|
}
|
|||
|
},
|
|||
|
data () {
|
|||
|
return {
|
|||
|
canvas: null,
|
|||
|
listsIndex: 0,
|
|||
|
listsLength: 0,
|
|||
|
canvasArc: null,
|
|||
|
canvasArcWidth: 100,
|
|||
|
canvasArcHeight: 100,
|
|||
|
compressQuality: 20,
|
|||
|
compressQualityH5: 5,
|
|||
|
};
|
|||
|
},
|
|||
|
watch: {},
|
|||
|
// 组件实例化之前
|
|||
|
beforeCreate () {},
|
|||
|
// 组件创建完成
|
|||
|
created () {
|
|||
|
this.canvas = uni.createCanvasContext('canvas', this);
|
|||
|
this.canvasArc = uni.createCanvasContext('canvas-arc', this);
|
|||
|
},
|
|||
|
// 组件挂载之前
|
|||
|
beforeMount () {},
|
|||
|
// 组件挂载之后
|
|||
|
mounted () {},
|
|||
|
// 组件数据更新时
|
|||
|
beforeUpdate () {},
|
|||
|
// 组价更新
|
|||
|
updated () {},
|
|||
|
// 组件销毁前
|
|||
|
beforeDestroy () {},
|
|||
|
// 组件销毁后
|
|||
|
destroyed () {},
|
|||
|
// 页面方法
|
|||
|
methods: {
|
|||
|
// 开始绘制
|
|||
|
createCanvas () {
|
|||
|
this.clearCanvas();
|
|||
|
if (this.lists.length === 0) {
|
|||
|
uni.showToast({
|
|||
|
title: 'lists不能为空',
|
|||
|
icon: 'none'
|
|||
|
});
|
|||
|
return;
|
|||
|
}
|
|||
|
this.listsIndex = 0;
|
|||
|
this.listsLength = this.lists.length - 1;
|
|||
|
uni.showToast({
|
|||
|
title:'正在生成图片...',
|
|||
|
icon:'loading'
|
|||
|
})
|
|||
|
this.dataDrawCanvas();
|
|||
|
},
|
|||
|
// 数据绘制
|
|||
|
dataDrawCanvas () {
|
|||
|
let item = this.lists[this.listsIndex];
|
|||
|
if (item.type === 'image') { // 图片
|
|||
|
if (item.content.indexOf('https://') > -1) { // https://网络图片
|
|||
|
// #ifndef H5
|
|||
|
// 非H5
|
|||
|
this.downloadImageNotH5(item);
|
|||
|
// #endif
|
|||
|
// #ifdef H5
|
|||
|
// H5
|
|||
|
this.downloadImageH5(item);
|
|||
|
// #endif
|
|||
|
} else { // 本地选择图片
|
|||
|
if (this.compress && item.hasOwnProperty('file') && item.file.size > this.compressSize) { // 大于限制2M压缩
|
|||
|
this.compressImage(item);
|
|||
|
} else {
|
|||
|
if (item.arc) {
|
|||
|
this.drawImageArc(item);
|
|||
|
} else {
|
|||
|
this.drawImage(item);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
} else if (item.type === 'text') { // 文本
|
|||
|
this.drawText(item);
|
|||
|
} else if (item.type === 'rect') { // 矩形(线条)
|
|||
|
this.drawRect(item);
|
|||
|
} else if (item.type === 'arc') { // 圆形
|
|||
|
this.drawArc(item);
|
|||
|
} else if (item.type === 'qr') { // 二维码
|
|||
|
this.drawQR(item);
|
|||
|
}
|
|||
|
},
|
|||
|
// #ifndef H5
|
|||
|
// https图片下载本地并绘制,非H5
|
|||
|
downloadImageNotH5 (item) {
|
|||
|
uni.downloadFile({
|
|||
|
url: item.content,
|
|||
|
header: {
|
|||
|
'Access-Control-Allow-Origin': '*',
|
|||
|
},
|
|||
|
success: (res) => {
|
|||
|
item.content = res.tempFilePath;
|
|||
|
if (item.arc) {
|
|||
|
this.drawImageArc(item);
|
|||
|
} else {
|
|||
|
this.drawImage(item);
|
|||
|
}
|
|||
|
},
|
|||
|
fail: (res) => {
|
|||
|
// console.log(res);
|
|||
|
}
|
|||
|
});
|
|||
|
},
|
|||
|
// #endif
|
|||
|
// #ifdef H5
|
|||
|
// https图片下载本地并绘制,H5
|
|||
|
downloadImageH5 (item) {
|
|||
|
let image = null;
|
|||
|
image = new Image();
|
|||
|
image.setAttribute('crossOrigin', 'anonymous');
|
|||
|
image.crossOrigin = 'Anonymous';
|
|||
|
image.src = item.content;
|
|||
|
image.onload = () => {
|
|||
|
let canvas = document.createElement('canvas');
|
|||
|
canvas.width = item.width;
|
|||
|
canvas.height = item.height;
|
|||
|
let ctx = canvas.getContext('2d');
|
|||
|
ctx.drawImage(
|
|||
|
image,
|
|||
|
0,
|
|||
|
0,
|
|||
|
item.width,
|
|||
|
item.height
|
|||
|
);
|
|||
|
let dataURL = canvas.toDataURL('image/png');
|
|||
|
if (item.arc) { // 绘制圆形
|
|||
|
item.content = dataURL;
|
|||
|
this.drawImageArc(item);
|
|||
|
} else {
|
|||
|
this.canvas.globalAlpha = item.hasOwnProperty('globalAlpha') ? item.globalAlpha : 1;
|
|||
|
this.canvas.drawImage(
|
|||
|
dataURL,
|
|||
|
item.x,
|
|||
|
item.y,
|
|||
|
item.hasOwnProperty('width') ? item.width : this.width,
|
|||
|
item.hasOwnProperty('height') ? item.height : this.height
|
|||
|
);
|
|||
|
|
|||
|
this.checkDrawOver();
|
|||
|
}
|
|||
|
|
|||
|
};
|
|||
|
},
|
|||
|
// #endif
|
|||
|
// 图片压缩
|
|||
|
compressImage (item) {
|
|||
|
// uni.showLoading({
|
|||
|
// title: '压缩中...',
|
|||
|
// mask: true
|
|||
|
// });
|
|||
|
uni.showToast({
|
|||
|
title: '压缩中...',
|
|||
|
icon:'loading'
|
|||
|
})
|
|||
|
// 非H5压缩
|
|||
|
// #ifndef H5
|
|||
|
uni.compressImage({
|
|||
|
src: item.content,
|
|||
|
quality: this.compressQuality,
|
|||
|
success: (res) => {
|
|||
|
// uni.showLoading({
|
|||
|
// title: '正在生成图片...',
|
|||
|
// mask: true
|
|||
|
// });
|
|||
|
uni.showToast({
|
|||
|
title: '正在生成图片...',
|
|||
|
icon:'loading'
|
|||
|
})
|
|||
|
item.content = res.tempFilePath;
|
|||
|
if (item.arc) {
|
|||
|
this.drawImageArc(item);
|
|||
|
} else {
|
|||
|
this.drawImage(item);
|
|||
|
}
|
|||
|
},
|
|||
|
fail: (res) => {
|
|||
|
// console.log(res);
|
|||
|
uni.showToast({
|
|||
|
title: '压缩失败',
|
|||
|
icon: 'none'
|
|||
|
});
|
|||
|
}
|
|||
|
});
|
|||
|
// #endif
|
|||
|
// H5压缩
|
|||
|
// #ifdef H5
|
|||
|
let image = new Image();
|
|||
|
image.setAttribute('crossOrigin', 'anonymous');
|
|||
|
image.crossOrigin = 'Anonymous';
|
|||
|
image.src = item.content;
|
|||
|
image.onload = () => {
|
|||
|
let canvas = document.createElement('canvas');
|
|||
|
canvas.width = item.width;
|
|||
|
canvas.height = item.height;
|
|||
|
let ctx = canvas.getContext('2d');
|
|||
|
ctx.drawImage(
|
|||
|
image,
|
|||
|
0,
|
|||
|
0,
|
|||
|
item.width,
|
|||
|
item.height
|
|||
|
);
|
|||
|
let dataURL = canvas.toDataURL('image/png');
|
|||
|
item.content = dataURL;
|
|||
|
if (item.arc) {
|
|||
|
this.drawImageArc(item);
|
|||
|
} else {
|
|||
|
this.drawImage(item);
|
|||
|
}
|
|||
|
};
|
|||
|
// #endif
|
|||
|
},
|
|||
|
// 圆形图片另外绘制canvas,png格式
|
|||
|
drawImageArc (item) {
|
|||
|
this.canvasArc.clearRect(0, 0, this.canvasArcWidth, this.canvasArcHeight);
|
|||
|
this.canvasArcWidth = item.arcR * 2;
|
|||
|
this.canvasArcHeight = item.arcR * 2;
|
|||
|
this.canvasArc.save();
|
|||
|
let arcT = setTimeout(() => {
|
|||
|
clearTimeout(arcT);
|
|||
|
this.canvasArc.arc(item.arcR, item.arcR, item.arcR, 0, 2 * Math.PI);
|
|||
|
this.canvasArc.clip();
|
|||
|
// this.canvasArc.closePath();
|
|||
|
|
|||
|
this.canvasArc.drawImage(
|
|||
|
item.content,
|
|||
|
item.arcX,
|
|||
|
item.arcY,
|
|||
|
item.width,
|
|||
|
item.height
|
|||
|
);
|
|||
|
this.canvasArc.draw(false, setTimeout(() => {
|
|||
|
let t = setTimeout(() => {
|
|||
|
clearTimeout(t);
|
|||
|
uni.canvasToTempFilePath({
|
|||
|
x: 0,
|
|||
|
y: 0,
|
|||
|
width: item.arcR * 2,
|
|||
|
height: item.arcR * 2,
|
|||
|
fileType: 'png',
|
|||
|
canvasId: 'canvas-arc',
|
|||
|
success: (res) => {
|
|||
|
item.width = item.arcR * 2;
|
|||
|
item.height = item.arcR * 2;
|
|||
|
item.content = res.tempFilePath;
|
|||
|
this.drawImage(item);
|
|||
|
},
|
|||
|
fail: (res) => {
|
|||
|
// console.log(res);
|
|||
|
},
|
|||
|
complete: () => {
|
|||
|
this.canvasArc.restore();
|
|||
|
this.canvasArc.fillRect(0, 0, 0, 0);
|
|||
|
this.canvasArc.clearRect(0, 0, this.canvasArcWidth, this.canvasArcHeight);
|
|||
|
}
|
|||
|
}, this);
|
|||
|
}, 100);
|
|||
|
}));
|
|||
|
}, 100);
|
|||
|
},
|
|||
|
// 图片绘制
|
|||
|
drawImage (item) {
|
|||
|
this.canvas.globalAlpha = item.hasOwnProperty('globalAlpha') ? item.globalAlpha : 1;
|
|||
|
this.canvas.drawImage(
|
|||
|
item.content,
|
|||
|
item.x,
|
|||
|
item.y,
|
|||
|
item.hasOwnProperty('width') ? item.width : this.width,
|
|||
|
item.hasOwnProperty('height') ? item.height : this.height
|
|||
|
);
|
|||
|
this.checkDrawOver();
|
|||
|
},
|
|||
|
// 文本绘制
|
|||
|
drawText (item) {
|
|||
|
this.canvas.setFillStyle(item.hasOwnProperty('color') ? item.color : '#000000');
|
|||
|
this.canvas.setFontSize(item.hasOwnProperty('size')? item.size : 20);
|
|||
|
this.canvas.setTextAlign(item.hasOwnProperty('align') ? item.align: 'left');
|
|||
|
this.canvas.globalAlpha = item.hasOwnProperty('globalAlpha') ? item.globalAlpha : 1;
|
|||
|
|
|||
|
if (item.maxWidth) {
|
|||
|
this.canvas.fillText(item.content, item.x, item.y, item.maxWidth);
|
|||
|
} else {
|
|||
|
this.canvas.fillText(item.content, item.x, item.y);
|
|||
|
}
|
|||
|
this.checkDrawOver();
|
|||
|
},
|
|||
|
|
|||
|
// 矩形(线条)绘制
|
|||
|
drawRect (item) {
|
|||
|
this.canvas.setFillStyle(item.hasOwnProperty('color') ? item.color : '#000000');
|
|||
|
this.canvas.globalAlpha = item.hasOwnProperty('globalAlpha') ? item.globalAlpha : 1;
|
|||
|
this.canvas.fillRect(item.x, item.y, item.width, item.height);
|
|||
|
this.checkDrawOver();
|
|||
|
},
|
|||
|
|
|||
|
// 圆形绘制
|
|||
|
drawArc (item) {
|
|||
|
this.canvas.arc(item.arcX, item.arcY, item.arcR, 0, 2 * Math.PI);
|
|||
|
this.canvas.setFillStyle(item.hasOwnProperty('color') ? item.color : '#000000');
|
|||
|
this.canvas.globalAlpha = item.hasOwnProperty('globalAlpha') ? item.globalAlpha : 1;
|
|||
|
this.canvas.fill();
|
|||
|
this.canvas.closePath();
|
|||
|
this.checkDrawOver();
|
|||
|
},
|
|||
|
|
|||
|
// 二维码绘制
|
|||
|
drawQR (item) {
|
|||
|
item['qr'] = QR.createQrCodeImg(item.content, {
|
|||
|
size: parseInt(300)
|
|||
|
});
|
|||
|
this.canvas.globalAlpha = item.hasOwnProperty('globalAlpha') ? item.globalAlpha : 1;
|
|||
|
this.canvas.drawImage(
|
|||
|
item.qr,
|
|||
|
item.x,
|
|||
|
item.y,
|
|||
|
item.hasOwnProperty('width') ? item.width : this.width,
|
|||
|
item.hasOwnProperty('height') ? item.height : this.height
|
|||
|
);
|
|||
|
this.checkDrawOver();
|
|||
|
},
|
|||
|
|
|||
|
|
|||
|
// 判断是否绘制完
|
|||
|
checkDrawOver () {
|
|||
|
if (this.listsIndex < this.listsLength) { // lists未画完
|
|||
|
this.listsIndex++;
|
|||
|
this.dataDrawCanvas();
|
|||
|
} else {
|
|||
|
this.canvasImage();
|
|||
|
}
|
|||
|
},
|
|||
|
|
|||
|
// 绘制到画布并生成图片
|
|||
|
canvasImage () {
|
|||
|
this.listsIndex = 0;
|
|||
|
this.canvas.draw(false, setTimeout(() => {
|
|||
|
setTimeout(() => {
|
|||
|
uni.canvasToTempFilePath({
|
|||
|
x: 0,
|
|||
|
y: 0,
|
|||
|
width: Number(this.width),
|
|||
|
height: Number(this.height),
|
|||
|
fileType: this.imgType,
|
|||
|
canvasId: 'canvas',
|
|||
|
success: (res) => {
|
|||
|
this.$emit('canvasImage', res.tempFilePath);
|
|||
|
if (this.showPreview) {
|
|||
|
this.showPreviewFn(res.tempFilePath);
|
|||
|
}
|
|||
|
},
|
|||
|
fail: (res) => {
|
|||
|
// console.log(res);
|
|||
|
},
|
|||
|
complete: () => {
|
|||
|
// uni.hideLoading();
|
|||
|
}
|
|||
|
}, this);
|
|||
|
}, 500);
|
|||
|
}));
|
|||
|
},
|
|||
|
// 预览图
|
|||
|
showPreviewFn (img) {
|
|||
|
uni.previewImage({
|
|||
|
current: 0,
|
|||
|
urls: [img]
|
|||
|
});
|
|||
|
},
|
|||
|
// 清空画布
|
|||
|
clearCanvas () {
|
|||
|
this.canvas.clearRect(0, 0, this.width, this.height);
|
|||
|
},
|
|||
|
|
|||
|
}
|
|||
|
};
|
|||
|
</script>
|
|||
|
|
|||
|
<style lang='scss' scoped>
|
|||
|
.mosowe-canvas-image{
|
|||
|
overflow: hidden;
|
|||
|
.canvas-wrap-box{
|
|||
|
overflow: hidden;
|
|||
|
height: 0;
|
|||
|
width: 0;
|
|||
|
position: fixed;
|
|||
|
left:200%;
|
|||
|
top: 0;
|
|||
|
}
|
|||
|
.canvas-wrap {
|
|||
|
overflow: hidden;
|
|||
|
height: 0;
|
|||
|
width: 0;
|
|||
|
}
|
|||
|
}
|
|||
|
</style>
|