PainterCore/lib/pen.js
2018-07-05 15:27:12 +08:00

172 lines
5.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import Downloader from './downloader';
const downloader = new Downloader();
const QR = require('./qrcode.js');
export default class Painter {
constructor(ctx, data) {
this.ctx = ctx;
this.data = data;
}
paint(callback) {
this.style = {
width: this.data.width.toPx(),
height: this.data.height.toPx(),
};
this._background();
for (const view of this.data.views) {
this._drawAbsolute(view);
}
this.ctx.draw(false, () => {
callback();
});
}
_background() {
this.ctx.save();
const { width, height } = this.style;
const bg = this.data.background;
this.ctx.translate(width / 2, height / 2);
this._doBorder(this.data.borderRadius, width, height);
if (!bg) {
// 如果未设置背景,则默认使用白色
this.ctx.setFillStyle('#fff');
this.ctx.fillRect(-(width / 2), -(height / 2), width, height);
} else if (bg.startsWith('#') || bg.startsWith('rgba')) {
// 背景填充颜色
this.ctx.setFillStyle(bg);
this.ctx.fillRect(-(width / 2), -(height / 2), width, height);
} else {
// 背景填充图片
this.ctx.drawImage(bg, -(width / 2), -(height / 2), width, height);
}
this.ctx.restore();
}
_drawAbsolute(view) {
// 证明 css 为数组形式,需要合并
if (view.css.length) {
/* eslint-disable no-param-reassign */
view.css = Object.assign(...view.css);
}
switch (view.type) {
case 'image':
this._drawAbsImage(view);
break;
case 'text':
this._fillAbsText(view);
break;
case 'rect':
this._drawAbsRect(view);
break;
case 'qrcode':
this._drawQRCode(view);
break;
default:
break;
}
}
_doBorder(borderRadius, width, height) {
if (borderRadius && width && height) {
const r = Math.min(borderRadius.toPx(), width / 2, height / 2);
this.ctx.beginPath();
this.ctx.arc(-width / 2 + r, -height / 2 + r, r, 1 * Math.PI, 1.5 * Math.PI);
this.ctx.lineTo(width / 2 - r, -height / 2);
this.ctx.arc(width / 2 - r, -height / 2 + r, r, 1.5 * Math.PI, 2 * Math.PI);
this.ctx.lineTo(width / 2, height / 2 - r);
this.ctx.arc(width / 2 - r, height / 2 - r, r, 0, 0.5 * Math.PI);
this.ctx.lineTo(-width / 2 + r, height / 2);
this.ctx.arc(-width / 2 + r, height / 2 - r, r, 0.5 * Math.PI, 1 * Math.PI);
this.ctx.closePath();
this.ctx.fill();
// 在 ios 的 6.6.6 版本上 clip 有 bug禁掉此类型上的 clip也就意味着在此版本微信的 ios 设备下无法使用 border 属性
if (!(getApp().systemInfo
&& getApp().systemInfo.version <= '6.6.6'
&& getApp().systemInfo.platform === 'ios')) {
this.ctx.clip();
}
}
}
_preProcess(view) {
let width;
let height;
let x;
let y;
if (view.type === 'text') {
this.ctx.setFillStyle(view.css.color ? view.css.color : 'black');
this.ctx.setFontSize(view.css.fontSize.toPx());
/* eslint-disable prefer-destructuring */
width = this.ctx.measureText(view.text).width;
height = view.css.fontSize.toPx();
x = view.css.right ? this.style.width - width - view.css.right.toPx() : (view.css.left ? view.css.left.toPx() : 0);
y = view.css.bottom ? this.style.height - height - view.css.bottom.toPx() : (view.css.top ? view.css.top.toPx() : 0);
} else {
width = view.css.width.toPx();
height = view.css.height.toPx();
x = view.css.right ? this.style.width - width - view.css.right.toPx() : (view.css.left ? view.css.left.toPx() : 0);
y = view.css.bottom ? this.style.height - height - view.css.bottom.toPx() : (view.css.top ? view.css.top.toPx() : 0);
}
const angle = view.css.rotate ? this._getAngle(view.css.rotate) : 0;
this.ctx.translate(x + width / 2, y + height / 2);
this.ctx.rotate(angle);
this._doBorder(view.css.borderRadius, width, height);
return {
width: width, height: height, x: x, y: y,
};
}
_drawQRCode(view) {
this.ctx.save();
const {
width, height,
} = this._preProcess(view);
QR.api.draw(view.content, this.ctx, -width / 2, -height / 2, width, height, view.css.background);
this.ctx.restore();
}
_drawAbsImage(view) {
if (!view.url) {
return;
}
this.ctx.save();
const {
width, height,
} = this._preProcess(view);
this.ctx.drawImage(view.url, -(width / 2), -(height / 2), width, height);
this.ctx.restore();
}
_fillAbsText(view) {
if (!view.text) {
return;
}
this.ctx.save();
const {
width, height,
} = this._preProcess(view);
this.ctx.fillText(view.text, -(width / 2), (height / 2));
this.ctx.restore();
}
_drawAbsRect(view) {
this.ctx.save();
const {
width, height,
} = this._preProcess(view);
this.ctx.setFillStyle(view.css.color);
this.ctx.fillRect(-(width / 2), -(height / 2), width, height);
this.ctx.restore();
}
_getAngle(angle) {
return Number(angle) * Math.PI / 180;
}
}