181 lines
4.3 KiB
Vue
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>
|