Files
ClassContent/历届学生/韩想/uniappStudy/components/lime-painter/index.vue
2024-09-27 02:06:13 +08:00

181 lines
4.3 KiB
Vue

<template>
<canvas :type="type" id="l-painter" :style="style" :canvas-id="canvasId"></canvas>
</template>
<script>
import { toPx, dataURItoBlob, blobToDataURL} from './utils';
import { Draw } from './draw';
import { adaptor } from './canvas'
export default {
name: 'l-painter',
props: {
board: Object,
fileType: {
type: String,
default: 'jpg'
},
pixelRatio: Number,
customStyle: String,
isRenderImage: Boolean,
isH5RenderBlob: Boolean,
type: {
type: String,
default: '',
},
},
data() {
// #ifndef MP-WEIXIN
const canvasId = `l-painter_${JSON.stringify(Math.random()).split('.')[1]}`
// #endif
// #ifdef MP-WEIXIN
const canvasId = `l-painter`
// #endif
return {
canvasId,
use2dCanvas: false ,// 微信 2.9.2 后可用canvas 2d 接口,
draw: null,
ctx: null
};
},
watch: {
board: {
handler(val) {
if (JSON.stringify(val) === '{}') return;
this.render();
},
immediate: true,
deep: true
}
},
computed: {
style() {
return `width:${this.boardWidth}px; height: ${this.boardHeight}px; ${this.customStyle}`;
},
dpr() {
return this.pixelRatio || wx.getSystemInfoSync().pixelRatio;
},
boardWidth() {
const { width = 200 } = this.board || {};
return toPx(width);
},
boardHeight() {
const { height = 200 } = this.board || {};
return toPx(height);
}
},
created() {},
mounted() {},
methods: {
render(args = {}) {
this.getContext().then(async (ctx) => {
if(!this.ctx) {
this.ctx = ctx
}
const { use2dCanvas, boardWidth, boardHeight, board, canvas, isH5RenderBlob } = this;
const {width, height} = args
if (use2dCanvas && !canvas) {
return Promise.reject(new Error('render: fail canvas has not been created'));
}
this.boundary = {
top: 0,
left: 0,
width: boardWidth || width,
height: boardHeight || height,
}
this.ctx.clearRect(0, 0, boardWidth, boardHeight);
if(!this.draw) {
this.draw = new Draw(this.ctx, canvas, use2dCanvas);
}
await this.draw.drawBoard(JSON.stringify(args) != '{}' ? args : board);
if (!use2dCanvas) {
const isDraw = await this.canvasDraw(this.ctx, this.isRenderImage);
if(isDraw && this.isRenderImage) {
this.canvasToTempFilePath()
.then(res => {
if(/^data:image\/(\w+);base64/.test(res.tempFilePath) && isH5RenderBlob) {
const img = URL.createObjectURL(dataURItoBlob(res.tempFilePath))
this.$emit('success', img)
} else {
this.$emit('success', res.tempFilePath)
}
})
.catch(err => {
this.$emit('fail', err)
new Error(JSON.stringify(err))
})
}
}
return Promise.resolve('ok');
});
},
canvasDraw(ctx, reserve) {
return new Promise(resolve => {
ctx.draw(reserve, () => {
resolve(true);
});
});
},
getContext() {
const { type, dpr, boardWidth, boardHeight } = this;
// #ifndef MP-WEIXIN
const ctx = uni.createCanvasContext(this.canvasId, this);
return Promise.resolve(ctx);
// #endif
if (type === '') {
const ctx = uni.createCanvasContext(this.canvasId, this);
return Promise.resolve(ctx);
}
return new Promise(resolve => {
uni.createSelectorQuery()
.in(this)
.select('#l-painter')
.node()
.exec(res => {
const canvas = res[0].node;
const ctx = canvas.getContext(type);
if (!this.inited) {
this.inited = true;
canvas.width = boardWidth * dpr;
canvas.height = boardHeight * dpr;
this.use2dCanvas = true;
this.canvas = canvas
ctx.scale(dpr, dpr);
}
resolve(adaptor(ctx));
});
});
},
canvasToTempFilePath(args = {}) {
const {use2dCanvas, canvasId} = this
return new Promise((resolve, reject) => {
const { top = 0, left = 0, width, height } = this.boundary
const copyArgs = {
x: left,
y: top,
width,
height,
destWidth: width * this.dpr,
destHeight: height * this.dpr,
canvasId,
fileType: args.fileType || this.fileType || 'png',
quality: args.quality || 1,
success: resolve,
fail: reject
}
if (use2dCanvas) {
delete copyArgs.canvasId
copyArgs.canvas = this.canvas
}
uni.canvasToTempFilePath(copyArgs, this)
})
}
}
};
</script>
<style></style>