import Shape from './shape'; import { RectOptions } from '../models/painter'; import { Decal } from '@utils/decal'; // 为了处理radius 大于 width 或 height 的场景 function parseRadius(radius: number[], width, height) { // 都为0 if (!radius[0] && !radius[1] && !radius[2] && !radius[3]) { return radius; } const minWidth = Math.max(radius[0] + radius[1], radius[2] + radius[3]); const minHeight = Math.max(radius[0] + radius[3], radius[1] + radius[2]); const scale = Math.min(width / minWidth, height / minHeight); if (scale < 1) { return radius.map(r => r * scale); } return radius; } function setBoxShadow(ctx, boxShadow) { // 阴影的x偏移 ctx.shadowOffsetX = boxShadow.offsetX; // 阴影的y偏移 ctx.shadowOffsetY = boxShadow.offsetY; // 阴影颜色 ctx.shadowColor = boxShadow.color; // 阴影的模糊半径 ctx.shadowBlur = boxShadow.blur; } class Rect extends Shape { draw(): void { const { ctx } = this; const { x: rawX = 0, // 原点x坐标 左下角 y: rawY = 0, // 原点y坐标 左下角 width = 0, height = 0, fillStyle, strokeStyle = 'rgba(256, 256, 256, 0)', boxShadow, blur, decal, } = this.config as RectOptions; // 原点 映射到 左上角 const { x, y } = { x: rawX, y: rawY - height, }; let { radius = [0, 0, 0, 0] } = this.config as RectOptions; const [tl = 0, tr = 0, br = 0, bl = 0] = radius; const isRadiusRect = radius.length > 0 && radius.some(r => r > 0); const decalObj = new Decal(); decalObj.init(decal); if (decalObj.isValid()) { this.ctx.save(); decalObj.fillRect(this.ctx, { x, y, width, height }, fillStyle); if (strokeStyle) { this.ctx.beginPath(); this.ctx.rect(x, y, width, height); this.ctx.closePath(); this.ctx.strokeStyle = strokeStyle; this.ctx.stroke(); } this.ctx.restore(); } else { this.ctx.save(); this.ctx.beginPath(); boxShadow && setBoxShadow(ctx, boxShadow); this.ctx.fillStyle = fillStyle; if (isRadiusRect) { // 圆角矩形 TODO:这里目前和bar图的坐标体系不匹配,后续bar修改坐标映射后,此处即可接入 radius = parseRadius(radius, width, height); this.ctx.moveTo(x + tl, y); this.ctx.lineTo(x + width - tr, y); this.ctx.arc(x + width - tr, y + tr, tr, -Math.PI / 2, 0, false); this.ctx.lineTo(x + width, y + height - br); this.ctx.arc(x + width - br, y + height - br, br, 0, Math.PI / 2, false); this.ctx.lineTo(x + bl, y + height); this.ctx.arc(x + bl, y + height - bl, bl, Math.PI / 2, Math.PI, false); this.ctx.lineTo(x, y + tl); this.ctx.arc(x + tl, y + tl, tl, Math.PI, Math.PI * 3 / 2, false); this.ctx.fill(); } else { // 直角矩形 this.ctx.fillRect(x, y, width, height); } this.ctx.closePath(); this.ctx.strokeStyle = strokeStyle; this.ctx.filter = blur; this.ctx.stroke(); this.ctx.restore(); } } } export default Rect;