2018-07-05 15:27:12 +08:00
|
|
|
|
const QR = require('./qrcode.js');
|
2018-12-06 12:27:07 +08:00
|
|
|
|
const GD = require('./gradient.js');
|
2018-07-05 15:27:12 +08:00
|
|
|
|
|
|
|
|
|
|
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();
|
2018-07-05 18:00:45 +08:00
|
|
|
|
const {
|
|
|
|
|
|
width,
|
2018-07-10 18:24:28 +08:00
|
|
|
|
height,
|
2018-07-05 18:00:45 +08:00
|
|
|
|
} = this.style;
|
2018-07-05 15:27:12 +08:00
|
|
|
|
const bg = this.data.background;
|
|
|
|
|
|
this.ctx.translate(width / 2, height / 2);
|
|
|
|
|
|
|
2018-07-20 18:59:47 +08:00
|
|
|
|
this._doClip(this.data.borderRadius, width, height);
|
2018-07-05 15:27:12 +08:00
|
|
|
|
if (!bg) {
|
|
|
|
|
|
// 如果未设置背景,则默认使用白色
|
|
|
|
|
|
this.ctx.setFillStyle('#fff');
|
|
|
|
|
|
this.ctx.fillRect(-(width / 2), -(height / 2), width, height);
|
2018-08-11 18:27:34 +08:00
|
|
|
|
} else if (bg.startsWith('#') || bg.startsWith('rgba') || bg.toLowerCase() === 'transparent') {
|
2018-07-05 15:27:12 +08:00
|
|
|
|
// 背景填充颜色
|
|
|
|
|
|
this.ctx.setFillStyle(bg);
|
|
|
|
|
|
this.ctx.fillRect(-(width / 2), -(height / 2), width, height);
|
2019-01-04 14:41:32 +08:00
|
|
|
|
} else if (GD.api.isGradient(bg)) {
|
|
|
|
|
|
GD.api.doGradient(bg, width, height, this.ctx);
|
2018-07-05 15:27:12 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
// 背景填充图片
|
|
|
|
|
|
this.ctx.drawImage(bg, -(width / 2), -(height / 2), width, height);
|
|
|
|
|
|
}
|
|
|
|
|
|
this.ctx.restore();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_drawAbsolute(view) {
|
|
|
|
|
|
// 证明 css 为数组形式,需要合并
|
2018-08-07 15:28:35 +08:00
|
|
|
|
if (view.css && view.css.length) {
|
2018-07-05 15:27:12 +08:00
|
|
|
|
/* 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;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-07-20 18:59:47 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 根据 borderRadius 进行裁减
|
|
|
|
|
|
*/
|
|
|
|
|
|
_doClip(borderRadius, width, height) {
|
2018-07-05 15:27:12 +08:00
|
|
|
|
if (borderRadius && width && height) {
|
|
|
|
|
|
const r = Math.min(borderRadius.toPx(), width / 2, height / 2);
|
2018-07-10 19:47:41 +08:00
|
|
|
|
// 防止在某些机型上周边有黑框现象,此处如果直接设置 setFillStyle 为透明,在 Android 机型上会导致被裁减的图片也变为透明, iOS 和 IDE 上不会
|
|
|
|
|
|
// setGlobalAlpha 在 1.9.90 起支持,低版本下无效,但把 setFillStyle 设为了 white,相对默认的 black 要好点
|
|
|
|
|
|
this.ctx.setGlobalAlpha(0);
|
2018-07-10 18:24:28 +08:00
|
|
|
|
this.ctx.setFillStyle('white');
|
2018-07-05 15:27:12 +08:00
|
|
|
|
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 属性
|
2018-07-05 18:00:45 +08:00
|
|
|
|
if (!(getApp().systemInfo &&
|
|
|
|
|
|
getApp().systemInfo.version <= '6.6.6' &&
|
|
|
|
|
|
getApp().systemInfo.platform === 'ios')) {
|
2018-07-05 15:27:12 +08:00
|
|
|
|
this.ctx.clip();
|
|
|
|
|
|
}
|
2018-07-10 19:47:41 +08:00
|
|
|
|
this.ctx.setGlobalAlpha(1);
|
2018-07-05 15:27:12 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-07-20 18:59:47 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 画边框
|
|
|
|
|
|
*/
|
|
|
|
|
|
_doBorder(view, width, height) {
|
2018-08-07 15:28:35 +08:00
|
|
|
|
if (!view.css) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2018-07-20 18:59:47 +08:00
|
|
|
|
const {
|
|
|
|
|
|
borderRadius,
|
|
|
|
|
|
borderWidth,
|
|
|
|
|
|
borderColor,
|
|
|
|
|
|
} = view.css;
|
|
|
|
|
|
if (!borderWidth) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
this.ctx.save();
|
|
|
|
|
|
this._preProcess(view, true);
|
|
|
|
|
|
let r;
|
|
|
|
|
|
if (borderRadius) {
|
|
|
|
|
|
r = Math.min(borderRadius.toPx(), width / 2, height / 2);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
r = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
const lineWidth = borderWidth.toPx();
|
|
|
|
|
|
this.ctx.setLineWidth(lineWidth);
|
|
|
|
|
|
this.ctx.setStrokeStyle(borderColor || 'black');
|
|
|
|
|
|
this.ctx.beginPath();
|
|
|
|
|
|
this.ctx.arc(-width / 2 + r, -height / 2 + r, r + lineWidth / 2, 1 * Math.PI, 1.5 * Math.PI);
|
|
|
|
|
|
this.ctx.lineTo(width / 2 - r, -height / 2 - lineWidth / 2);
|
|
|
|
|
|
this.ctx.arc(width / 2 - r, -height / 2 + r, r + lineWidth / 2, 1.5 * Math.PI, 2 * Math.PI);
|
|
|
|
|
|
this.ctx.lineTo(width / 2 + lineWidth / 2, height / 2 - r);
|
|
|
|
|
|
this.ctx.arc(width / 2 - r, height / 2 - r, r + lineWidth / 2, 0, 0.5 * Math.PI);
|
|
|
|
|
|
this.ctx.lineTo(-width / 2 + r, height / 2 + lineWidth / 2);
|
|
|
|
|
|
this.ctx.arc(-width / 2 + r, height / 2 - r, r + lineWidth / 2, 0.5 * Math.PI, 1 * Math.PI);
|
|
|
|
|
|
this.ctx.closePath();
|
|
|
|
|
|
this.ctx.stroke();
|
|
|
|
|
|
this.ctx.restore();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_preProcess(view, notClip) {
|
2018-07-05 15:27:12 +08:00
|
|
|
|
let width;
|
|
|
|
|
|
let height;
|
2018-07-11 16:54:16 +08:00
|
|
|
|
let extra;
|
2018-08-07 15:28:35 +08:00
|
|
|
|
switch (view.type) {
|
|
|
|
|
|
case 'text': {
|
|
|
|
|
|
const fontWeight = view.css.fontWeight === 'bold' ? 'bold' : 'normal';
|
|
|
|
|
|
view.css.fontSize = view.css.fontSize ? view.css.fontSize : '20rpx';
|
2018-10-16 14:40:48 +08:00
|
|
|
|
this.ctx.font = `normal ${fontWeight} ${view.css.fontSize.toPx()}px ${view.css.fontFamily ? view.css.fontFamily : 'sans-serif'}`;
|
2018-08-07 15:28:35 +08:00
|
|
|
|
// this.ctx.setFontSize(view.css.fontSize.toPx());
|
|
|
|
|
|
const textLength = this.ctx.measureText(view.text).width;
|
|
|
|
|
|
width = view.css.width ? view.css.width.toPx() : textLength;
|
|
|
|
|
|
// 计算行数
|
|
|
|
|
|
const calLines = Math.ceil(textLength / width);
|
|
|
|
|
|
const lines = view.css.maxLines < calLines ? view.css.maxLines : calLines;
|
|
|
|
|
|
const lineHeight = view.css.lineHeight ? view.css.lineHeight.toPx() : view.css.fontSize.toPx();
|
|
|
|
|
|
height = lineHeight * lines;
|
|
|
|
|
|
extra = { lines: lines, lineHeight: lineHeight };
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
case 'image': {
|
|
|
|
|
|
// image 如果未设置长宽,则使用图片本身的长宽
|
|
|
|
|
|
const ratio = getApp().systemInfo.pixelRatio ? getApp().systemInfo.pixelRatio : 2;
|
|
|
|
|
|
width = view.css && view.css.width ? view.css.width.toPx() : Math.round(view.sWidth / ratio);
|
|
|
|
|
|
height = view.css && view.css.height ? view.css.height.toPx() : Math.round(view.sHeight / ratio);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
default: {
|
|
|
|
|
|
if (!(view.css.width && view.css.height)) {
|
|
|
|
|
|
console.error('You should set width and height');
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
width = view.css.width.toPx();
|
|
|
|
|
|
height = view.css.height.toPx();
|
2018-07-17 20:54:35 +08:00
|
|
|
|
}
|
2018-07-05 15:27:12 +08:00
|
|
|
|
}
|
2018-08-07 15:28:35 +08:00
|
|
|
|
const x = view.css && view.css.right ? this.style.width - view.css.right.toPx(true) : (view.css && view.css.left ? view.css.left.toPx(true) : 0);
|
|
|
|
|
|
const y = view.css && view.css.bottom ? this.style.height - height - view.css.bottom.toPx(true) : (view.css && view.css.top ? view.css.top.toPx(true) : 0);
|
|
|
|
|
|
|
|
|
|
|
|
const angle = view.css && view.css.rotate ? this._getAngle(view.css.rotate) : 0;
|
2018-07-17 20:54:35 +08:00
|
|
|
|
// 当设置了 right 时,默认 align 用 right,反之用 left
|
2018-08-07 15:28:35 +08:00
|
|
|
|
const align = view.css && view.css.align ? view.css.align : (view.css && view.css.right ? 'right' : 'left');
|
2018-07-05 18:00:45 +08:00
|
|
|
|
switch (align) {
|
|
|
|
|
|
case 'center':
|
|
|
|
|
|
this.ctx.translate(x, y + height / 2);
|
|
|
|
|
|
break;
|
2018-07-10 18:24:28 +08:00
|
|
|
|
case 'right':
|
2018-07-05 18:00:45 +08:00
|
|
|
|
this.ctx.translate(x - width / 2, y + height / 2);
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
this.ctx.translate(x + width / 2, y + height / 2);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
2018-07-05 15:27:12 +08:00
|
|
|
|
this.ctx.rotate(angle);
|
2018-08-07 15:28:35 +08:00
|
|
|
|
if (!notClip && view.css && view.css.borderRadius) {
|
2018-07-20 18:59:47 +08:00
|
|
|
|
this._doClip(view.css.borderRadius, width, height);
|
|
|
|
|
|
}
|
2019-01-21 15:03:21 +08:00
|
|
|
|
this._doShadow(view);
|
2018-07-05 15:27:12 +08:00
|
|
|
|
|
|
|
|
|
|
return {
|
2018-07-05 18:00:45 +08:00
|
|
|
|
width: width,
|
|
|
|
|
|
height: height,
|
|
|
|
|
|
x: x,
|
|
|
|
|
|
y: y,
|
2018-07-11 16:54:16 +08:00
|
|
|
|
extra: extra,
|
2018-07-05 15:27:12 +08:00
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_drawQRCode(view) {
|
|
|
|
|
|
this.ctx.save();
|
|
|
|
|
|
const {
|
2018-07-05 18:00:45 +08:00
|
|
|
|
width,
|
|
|
|
|
|
height,
|
2018-07-05 15:27:12 +08:00
|
|
|
|
} = this._preProcess(view);
|
2018-07-20 18:59:47 +08:00
|
|
|
|
QR.api.draw(view.content, this.ctx, -width / 2, -height / 2, width, height, view.css.background, view.css.color);
|
2018-07-05 15:27:12 +08:00
|
|
|
|
this.ctx.restore();
|
2018-07-20 18:59:47 +08:00
|
|
|
|
this._doBorder(view, width, height);
|
2018-07-05 15:27:12 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_drawAbsImage(view) {
|
|
|
|
|
|
if (!view.url) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
this.ctx.save();
|
|
|
|
|
|
const {
|
2018-07-05 18:00:45 +08:00
|
|
|
|
width,
|
|
|
|
|
|
height,
|
2018-07-05 15:27:12 +08:00
|
|
|
|
} = this._preProcess(view);
|
2018-07-27 14:39:36 +08:00
|
|
|
|
// 获得缩放到图片大小级别的裁减框
|
2018-11-30 16:55:10 +08:00
|
|
|
|
let rWidth = view.sWidth;
|
|
|
|
|
|
let rHeight = view.sHeight;
|
2018-07-27 14:39:36 +08:00
|
|
|
|
let startX = 0;
|
|
|
|
|
|
let startY = 0;
|
2018-11-30 16:55:10 +08:00
|
|
|
|
// 绘画区域比例
|
|
|
|
|
|
const cp = width / height;
|
|
|
|
|
|
// 原图比例
|
|
|
|
|
|
const op = view.sWidth / view.sHeight;
|
|
|
|
|
|
if (cp >= op) {
|
|
|
|
|
|
rHeight = rWidth / cp;
|
|
|
|
|
|
startY = Math.round((view.sHeight - rHeight) / 2);
|
2018-07-27 14:39:36 +08:00
|
|
|
|
} else {
|
2018-11-30 16:55:10 +08:00
|
|
|
|
rWidth = rHeight * cp;
|
2018-07-27 14:39:36 +08:00
|
|
|
|
startX = Math.round((view.sWidth - rWidth) / 2);
|
|
|
|
|
|
}
|
2018-08-07 15:28:35 +08:00
|
|
|
|
if (view.css && view.css.mode === 'scaleToFill') {
|
2018-07-27 14:39:36 +08:00
|
|
|
|
this.ctx.drawImage(view.url, -(width / 2), -(height / 2), width, height);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
this.ctx.drawImage(view.url, startX, startY, rWidth, rHeight, -(width / 2), -(height / 2), width, height);
|
|
|
|
|
|
}
|
2018-07-05 15:27:12 +08:00
|
|
|
|
this.ctx.restore();
|
2018-07-20 18:59:47 +08:00
|
|
|
|
this._doBorder(view, width, height);
|
2018-07-05 15:27:12 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_fillAbsText(view) {
|
|
|
|
|
|
if (!view.text) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
this.ctx.save();
|
|
|
|
|
|
const {
|
2018-07-05 18:00:45 +08:00
|
|
|
|
width,
|
|
|
|
|
|
height,
|
2018-07-11 16:54:16 +08:00
|
|
|
|
extra,
|
2018-07-05 15:27:12 +08:00
|
|
|
|
} = this._preProcess(view);
|
2018-07-20 18:59:47 +08:00
|
|
|
|
this.ctx.setFillStyle(view.css.color || 'black');
|
2018-07-11 16:54:16 +08:00
|
|
|
|
const { lines, lineHeight } = extra;
|
|
|
|
|
|
const preLineLength = Math.round(view.text.length / lines);
|
|
|
|
|
|
let start = 0;
|
|
|
|
|
|
let alreadyCount = 0;
|
|
|
|
|
|
for (let i = 0; i < lines; ++i) {
|
|
|
|
|
|
alreadyCount = preLineLength;
|
|
|
|
|
|
let text = view.text.substr(start, alreadyCount);
|
|
|
|
|
|
let measuredWith = this.ctx.measureText(text).width;
|
|
|
|
|
|
// 如果测量大小小于width一个字符的大小,则进行补齐,如果测量大小超出 width,则进行减除
|
|
|
|
|
|
// 如果已经到文本末尾,也不要进行该循环
|
|
|
|
|
|
while ((start + alreadyCount <= view.text.length) && (width - measuredWith > view.css.fontSize.toPx() || measuredWith > width)) {
|
|
|
|
|
|
if (measuredWith < width) {
|
|
|
|
|
|
text = view.text.substr(start, ++alreadyCount);
|
|
|
|
|
|
} else {
|
2018-07-17 17:32:33 +08:00
|
|
|
|
if (text.length <= 1) {
|
|
|
|
|
|
// 如果只有一个字符时,直接跳出循环
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
2018-07-11 16:54:16 +08:00
|
|
|
|
text = view.text.substr(start, --alreadyCount);
|
|
|
|
|
|
}
|
|
|
|
|
|
measuredWith = this.ctx.measureText(text).width;
|
|
|
|
|
|
}
|
|
|
|
|
|
start += text.length;
|
|
|
|
|
|
// 如果是最后一行了,发现还有未绘制完的内容,则加...
|
|
|
|
|
|
if (i === lines - 1 && start < view.text.length) {
|
|
|
|
|
|
while (this.ctx.measureText(`${text}...`).width > width) {
|
2018-07-17 17:32:33 +08:00
|
|
|
|
if (text.length <= 1) {
|
|
|
|
|
|
// 如果只有一个字符时,直接跳出循环
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
2018-07-11 16:54:16 +08:00
|
|
|
|
text = text.substring(0, text.length - 1);
|
|
|
|
|
|
}
|
2018-07-17 14:08:09 +08:00
|
|
|
|
text += '...';
|
2018-07-17 17:32:33 +08:00
|
|
|
|
measuredWith = this.ctx.measureText(text).width;
|
2018-07-17 13:51:36 +08:00
|
|
|
|
}
|
2018-07-25 14:54:59 +08:00
|
|
|
|
this.ctx.setTextAlign(view.css.align ? view.css.align : 'left');
|
|
|
|
|
|
let x;
|
|
|
|
|
|
switch (view.css.align) {
|
|
|
|
|
|
case 'center':
|
|
|
|
|
|
x = 0;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'right':
|
|
|
|
|
|
x = (width / 2);
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
x = -(width / 2);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
2018-07-17 13:51:36 +08:00
|
|
|
|
const y = -(height / 2) + (i === 0 ? view.css.fontSize.toPx() : (view.css.fontSize.toPx() + i * lineHeight));
|
2018-07-19 19:10:29 +08:00
|
|
|
|
if (view.css.textStyle === 'stroke') {
|
|
|
|
|
|
this.ctx.strokeText(text, x, y, measuredWith);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
this.ctx.fillText(text, x, y, measuredWith);
|
|
|
|
|
|
}
|
2018-07-17 13:51:36 +08:00
|
|
|
|
const fontSize = view.css.fontSize.toPx();
|
|
|
|
|
|
if (view.css.textDecoration) {
|
|
|
|
|
|
this.ctx.beginPath();
|
|
|
|
|
|
if (/\bunderline\b/.test(view.css.textDecoration)) {
|
|
|
|
|
|
this.ctx.moveTo(x, y);
|
|
|
|
|
|
this.ctx.lineTo(x + measuredWith, y);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (/\boverline\b/.test(view.css.textDecoration)) {
|
|
|
|
|
|
this.ctx.moveTo(x, y - fontSize);
|
|
|
|
|
|
this.ctx.lineTo(x + measuredWith, y - fontSize);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (/\bline-through\b/.test(view.css.textDecoration)) {
|
|
|
|
|
|
this.ctx.moveTo(x, y - fontSize / 3);
|
|
|
|
|
|
this.ctx.lineTo(x + measuredWith, y - fontSize / 3);
|
|
|
|
|
|
}
|
|
|
|
|
|
this.ctx.closePath();
|
|
|
|
|
|
this.ctx.setStrokeStyle(view.css.color);
|
|
|
|
|
|
this.ctx.stroke();
|
2018-07-11 16:54:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2018-07-05 15:27:12 +08:00
|
|
|
|
|
|
|
|
|
|
this.ctx.restore();
|
2018-07-20 18:59:47 +08:00
|
|
|
|
this._doBorder(view, width, height);
|
2018-07-05 15:27:12 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_drawAbsRect(view) {
|
|
|
|
|
|
this.ctx.save();
|
|
|
|
|
|
const {
|
2018-07-05 18:00:45 +08:00
|
|
|
|
width,
|
|
|
|
|
|
height,
|
2018-07-05 15:27:12 +08:00
|
|
|
|
} = this._preProcess(view);
|
2019-01-04 14:41:32 +08:00
|
|
|
|
if (GD.api.isGradient(view.css.color)) {
|
|
|
|
|
|
GD.api.doGradient(view.css.color, width, height, this.ctx);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
this.ctx.setFillStyle(view.css.color);
|
|
|
|
|
|
}
|
2018-07-05 15:27:12 +08:00
|
|
|
|
this.ctx.fillRect(-(width / 2), -(height / 2), width, height);
|
|
|
|
|
|
this.ctx.restore();
|
2018-07-20 18:59:47 +08:00
|
|
|
|
this._doBorder(view, width, height);
|
2018-07-05 15:27:12 +08:00
|
|
|
|
}
|
2019-01-21 15:03:21 +08:00
|
|
|
|
|
|
|
|
|
|
// shadow 支持 (x, y, blur, color), 不支持 spread
|
|
|
|
|
|
// shadow:0px 0px 10px rgba(0,0,0,0.1);
|
|
|
|
|
|
_doShadow(view) {
|
|
|
|
|
|
if(!view.css || !view.css.shadow){
|
2019-01-18 00:43:01 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2019-01-21 15:03:21 +08:00
|
|
|
|
let box = view.css.shadow.replace(/,\s+/g, ',').split(' ');
|
2019-01-18 00:43:01 +08:00
|
|
|
|
if(box.length > 4) {
|
2019-01-21 15:03:21 +08:00
|
|
|
|
console.error('shadow don\'t spread option');
|
2019-01-18 00:43:01 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
this.ctx.shadowOffsetX = parseInt(box[0])
|
|
|
|
|
|
this.ctx.shadowOffsetY = parseInt(box[1])
|
|
|
|
|
|
this.ctx.shadowBlur = parseInt(box[2])
|
|
|
|
|
|
this.ctx.shadowColor = box[3];
|
|
|
|
|
|
}
|
2018-07-05 15:27:12 +08:00
|
|
|
|
|
|
|
|
|
|
_getAngle(angle) {
|
|
|
|
|
|
return Number(angle) * Math.PI / 180;
|
|
|
|
|
|
}
|
2018-07-10 18:24:28 +08:00
|
|
|
|
}
|