PainterCore/lib/pen.js

172 lines
5.0 KiB
JavaScript
Raw Normal View History

2018-07-05 15:27:12 +08:00
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;
}
}