From cc0f72c90b06da53dcb136f062a9cb0b537f886a Mon Sep 17 00:00:00 2001 From: chenshenhai Date: Sat, 6 May 2023 22:13:31 +0800 Subject: [PATCH] feat: implement group element render --- packages/board/src/lib/calculator.ts | 2 +- .../src/middleware/selector/draw-wrapper.ts | 6 +- .../core/src/middleware/selector/index.ts | 4 +- packages/core/src/middleware/selector/util.ts | 1 + packages/lab/src/data.ts | 152 ++++++++++++++++- packages/renderer/src/draw/base.ts | 154 +++++++++--------- packages/renderer/src/draw/elements.ts | 7 +- packages/renderer/src/draw/group.ts | 95 +++++++++++ packages/renderer/src/draw/rect.ts | 2 +- packages/renderer/src/draw/text.ts | 6 +- packages/renderer/src/index.ts | 29 +++- packages/types/src/lib/context2d.ts | 2 + packages/types/src/lib/element.ts | 9 +- packages/types/src/lib/renderer.ts | 4 +- packages/util/src/lib/context2d.ts | 6 + packages/util/src/lib/rotate.ts | 4 +- 16 files changed, 375 insertions(+), 108 deletions(-) create mode 100644 packages/renderer/src/draw/group.ts diff --git a/packages/board/src/lib/calculator.ts b/packages/board/src/lib/calculator.ts index cfa3370..5c439c0 100644 --- a/packages/board/src/lib/calculator.ts +++ b/packages/board/src/lib/calculator.ts @@ -148,7 +148,7 @@ export class Calculator implements ViewCalculator { index: -1, element: null }; - for (let i = 0; i < data.elements.length; i++) { + for (let i = data.elements.length - 1; i >= 0; i--) { const elem = data.elements[i]; if (this.isPointInElement(p, elem, scaleInfo)) { result.index = i; diff --git a/packages/core/src/middleware/selector/draw-wrapper.ts b/packages/core/src/middleware/selector/draw-wrapper.ts index 903214d..d0781fa 100644 --- a/packages/core/src/middleware/selector/draw-wrapper.ts +++ b/packages/core/src/middleware/selector/draw-wrapper.ts @@ -5,7 +5,7 @@ import type { AreaSize, ControllerStyle, ElementSizeController } from './types'; const wrapperColor = '#1973ba'; -export function drawPointWrapper(ctx: ViewContext2D, elem: ElementSize, opts?: Omit) { +export function drawPointWrapper(ctx: ViewContext2D, elem: ElementSize) { const bw = 0; const { x, y, w, h } = elem; const { angle = 0 } = elem; @@ -35,7 +35,7 @@ export function drawPointWrapper(ctx: ViewContext2D, elem: ElementSize, opts?: O }); } -export function drawHoverWrapper(ctx: ViewContext2D, elem: ElementSize, opts?: Omit) { +export function drawHoverWrapper(ctx: ViewContext2D, elem: ElementSize) { const bw = 0; const { x, y, w, h } = elem; const { angle = 0 } = elem; @@ -85,7 +85,7 @@ function drawController(ctx: ViewContext2D, style: ControllerStyle) { export function drawElementControllers( ctx: ViewContext2D, elem: ElementSize, - opts: Omit & { sizeControllers: ElementSizeController } + opts: Omit & { sizeControllers: ElementSizeController } ) { const bw = 0; const { x, y, w, h } = elem; diff --git a/packages/core/src/middleware/selector/index.ts b/packages/core/src/middleware/selector/index.ts index 81e708c..95d8bcf 100644 --- a/packages/core/src/middleware/selector/index.ts +++ b/packages/core/src/middleware/selector/index.ts @@ -257,13 +257,13 @@ export const MiddlewareSelector: BoardMiddleware = (opts) => { const drawOpts = { calculator, scaleInfo, viewSize }; if (hoverElement && actionType !== 'drag') { const hoverElemSize = calculator.elementSize(hoverElement, scaleInfo); - drawHoverWrapper(helperContext, hoverElemSize, drawOpts); + drawHoverWrapper(helperContext, hoverElemSize); } if (elem && ['select', 'drag', 'resize'].includes(actionType)) { const selectedElemSize = calculator.elementSize(elem, scaleInfo); const sizeControllers = calcElementControllerStyle(selectedElemSize); - drawPointWrapper(helperContext, selectedElemSize, drawOpts); + drawPointWrapper(helperContext, selectedElemSize); drawElementControllers(helperContext, selectedElemSize, { ...drawOpts, sizeControllers }); } else if (actionType === 'area' && areaStart && areaEnd) { drawArea(helperContext, { start: areaStart, end: areaEnd }); diff --git a/packages/core/src/middleware/selector/util.ts b/packages/core/src/middleware/selector/util.ts index 1bf5500..608d301 100644 --- a/packages/core/src/middleware/selector/util.ts +++ b/packages/core/src/middleware/selector/util.ts @@ -432,6 +432,7 @@ export function calcSelectedElementsArea( if (elemSize.angle && (elemSize.angle > 0 || elemSize.angle < 0)) { const ves = rotateElementVertexes(elemSize); + if (ves.length === 4) { const xList = [ves[0].x, ves[1].x, ves[2].x, ves[3].x]; const yList = [ves[0].y, ves[1].y, ves[2].y, ves[3].y]; diff --git a/packages/lab/src/data.ts b/packages/lab/src/data.ts index a030a22..e9bd6bc 100644 --- a/packages/lab/src/data.ts +++ b/packages/lab/src/data.ts @@ -145,7 +145,6 @@ const data: Data = { } }, { - name: 'html-001', uuid: 'xxx-0012', x: 400, y: 200, @@ -196,11 +195,160 @@ const data: Data = {
+
` } + }, + { + uuid: 'group-001', + x: 400, + y: 400, + w: 100, + h: 100, + type: 'group', + desc: { + bgColor: '#1f1f1f', + children: [ + { + uuid: 'group-001-0014', + type: 'circle', + x: -40, + y: 0, + w: 100, + h: 100, + desc: { + bgColor: '#f44336' + } + }, + { + uuid: 'group-001-0015', + type: 'circle', + x: -20, + y: 0, + w: 100, + h: 100, + desc: { + bgColor: '#ff9800' + } + }, + { + uuid: 'group-001-0016', + type: 'circle', + x: 0, + y: 0, + w: 100, + h: 100, + desc: { + bgColor: '#ffc106' + } + }, + { + uuid: 'group-001-0017', + type: 'circle', + x: 20, + y: 0, + w: 100, + h: 100, + desc: { + bgColor: '#cddc39' + } + }, + { + uuid: 'group-001-0018', + type: 'circle', + x: 40, + y: 0, + w: 100, + h: 100, + desc: { + bgColor: '#4caf50' + } + } + ] + } + }, + { + uuid: 'group-0013', + x: 550, + y: 100, + w: 173.20508075688775, + // w: 100, + h: 100, + angle: 30, + type: 'group', + desc: { + children: [ + { + uuid: 'group-002-014', + type: 'circle', + x: -40, + y: 0, + w: 100, + h: 100, + desc: { + bgColor: '#f44336' + } + }, + { + uuid: 'group-002-0015', + type: 'circle', + x: -20, + y: 0, + w: 100, + h: 100, + desc: { + bgColor: '#ff9800' + } + }, + { + uuid: 'group-002-0016', + type: 'circle', + x: 0, + y: 0, + w: 100, + h: 100, + desc: { + bgColor: '#ffc106' + } + }, + { + uuid: 'group-002-0017', + type: 'circle', + x: 20, + y: 0, + w: 100, + h: 100, + desc: { + bgColor: '#cddc39' + } + }, + { + uuid: 'group-002-0018', + type: 'circle', + x: 40, + y: 0, + w: 100, + h: 100, + desc: { + bgColor: '#4caf50' + } + } + ] + } + }, + { + uuid: 'xxxx-0017', + type: 'image', + x: 100, + y: 400, + w: 100, + h: 100, + angle: 30, + desc: { + src: './images/lena.png?v=0017' + } } ] }; diff --git a/packages/renderer/src/draw/base.ts b/packages/renderer/src/draw/base.ts index 71dd9a6..c0d2e96 100644 --- a/packages/renderer/src/draw/base.ts +++ b/packages/renderer/src/draw/base.ts @@ -1,87 +1,81 @@ -import { ViewContext2D, Element } from '@idraw/types'; -import { is, istype, isColorStr, rotateElement } from '@idraw/util'; +import { ViewContext2D, Element, ElementType } from '@idraw/types'; +import { is, istype, isColorStr } from '@idraw/util'; -export function clearContext(ctx: ViewContext2D) { - ctx.fillStyle = '#000000'; - ctx.strokeStyle = '#000000'; - ctx.setLineDash([]); - ctx.globalAlpha = 1; - ctx.shadowColor = '#00000000'; - ctx.shadowOffsetX = 0; - ctx.shadowOffsetY = 0; - ctx.shadowBlur = 0; -} +// export function clearContext(ctx: ViewContext2D) { +// ctx.fillStyle = '#000000'; +// ctx.strokeStyle = '#000000'; +// ctx.setLineDash([]); +// ctx.globalAlpha = 1; +// ctx.shadowColor = '#00000000'; +// ctx.shadowOffsetX = 0; +// ctx.shadowOffsetY = 0; +// ctx.shadowBlur = 0; +// } -export function drawBox(ctx: ViewContext2D, elem: Element<'text' | 'rect'>, pattern: string | CanvasPattern | null): void { - clearContext(ctx); +export function drawBox(ctx: ViewContext2D, elem: Element, pattern?: string | CanvasPattern | null): void { drawBoxBorder(ctx, elem); - clearContext(ctx); - rotateElement(ctx, elem, () => { - const { x, y, w, h } = elem; - let r: number = elem.desc.borderRadius || 0; - r = Math.min(r, w / 2, h / 2); - if (w < r * 2 || h < r * 2) { - r = 0; - } - ctx.beginPath(); - ctx.moveTo(x + r, y); - ctx.arcTo(x + w, y, x + w, y + h, r); - ctx.arcTo(x + w, y + h, x, y + h, r); - ctx.arcTo(x, y + h, x, y, r); - ctx.arcTo(x, y, x + w, y, r); - ctx.closePath(); - if (typeof pattern === 'string') { - ctx.fillStyle = pattern; - } else if (['CanvasPattern'].includes(istype.type(pattern))) { - ctx.fillStyle = pattern as CanvasPattern; - } - ctx.fill(); - }); + + const { x, y, w, h } = elem; + let r: number = elem.desc.borderRadius || 0; + r = Math.min(r, w / 2, h / 2); + if (w < r * 2 || h < r * 2) { + r = 0; + } + ctx.beginPath(); + ctx.moveTo(x + r, y); + ctx.arcTo(x + w, y, x + w, y + h, r); + ctx.arcTo(x + w, y + h, x, y + h, r); + ctx.arcTo(x, y + h, x, y, r); + ctx.arcTo(x, y, x + w, y, r); + ctx.closePath(); + if (typeof pattern === 'string') { + ctx.fillStyle = pattern; + } else if (['CanvasPattern'].includes(istype.type(pattern))) { + ctx.fillStyle = pattern as CanvasPattern; + } + ctx.fill(); } -export function drawBoxBorder(ctx: ViewContext2D, elem: Element<'text' | 'rect'>): void { - clearContext(ctx); - rotateElement(ctx, elem, () => { - if (!(elem.desc.borderWidth && elem.desc.borderWidth > 0)) { - return; - } - const bw = elem.desc.borderWidth; - let borderColor = '#000000'; - if (isColorStr(elem.desc.borderColor) === true) { - borderColor = elem.desc.borderColor as string; - } - const x = elem.x - bw / 2; - const y = elem.y - bw / 2; - const w = elem.w + bw; - const h = elem.h + bw; +export function drawBoxBorder(ctx: ViewContext2D, elem: Element): void { + if (!(elem.desc.borderWidth && elem.desc.borderWidth > 0)) { + return; + } + const bw = elem.desc.borderWidth; + let borderColor = '#000000'; + if (isColorStr(elem.desc.borderColor) === true) { + borderColor = elem.desc.borderColor as string; + } + const x = elem.x - bw / 2; + const y = elem.y - bw / 2; + const w = elem.w + bw; + const h = elem.h + bw; - let r: number = elem.desc.borderRadius || 0; - r = Math.min(r, w / 2, h / 2); - if (r < w / 2 && r < h / 2) { - r = r + bw / 2; - } - const { desc } = elem; - if (desc.shadowColor !== undefined && isColorStr(desc.shadowColor)) { - ctx.shadowColor = desc.shadowColor; - } - if (desc.shadowOffsetX !== undefined && is.number(desc.shadowOffsetX)) { - ctx.shadowOffsetX = desc.shadowOffsetX; - } - if (desc.shadowOffsetY !== undefined && is.number(desc.shadowOffsetY)) { - ctx.shadowOffsetY = desc.shadowOffsetY; - } - if (desc.shadowBlur !== undefined && is.number(desc.shadowBlur)) { - ctx.shadowBlur = desc.shadowBlur; - } - ctx.beginPath(); - ctx.lineWidth = bw; - ctx.strokeStyle = borderColor; - ctx.moveTo(x + r, y); - ctx.arcTo(x + w, y, x + w, y + h, r); - ctx.arcTo(x + w, y + h, x, y + h, r); - ctx.arcTo(x, y + h, x, y, r); - ctx.arcTo(x, y, x + w, y, r); - ctx.closePath(); - ctx.stroke(); - }); + let r: number = elem.desc.borderRadius || 0; + r = Math.min(r, w / 2, h / 2); + if (r < w / 2 && r < h / 2) { + r = r + bw / 2; + } + const { desc } = elem; + if (desc.shadowColor !== undefined && isColorStr(desc.shadowColor)) { + ctx.shadowColor = desc.shadowColor; + } + if (desc.shadowOffsetX !== undefined && is.number(desc.shadowOffsetX)) { + ctx.shadowOffsetX = desc.shadowOffsetX; + } + if (desc.shadowOffsetY !== undefined && is.number(desc.shadowOffsetY)) { + ctx.shadowOffsetY = desc.shadowOffsetY; + } + if (desc.shadowBlur !== undefined && is.number(desc.shadowBlur)) { + ctx.shadowBlur = desc.shadowBlur; + } + ctx.beginPath(); + ctx.lineWidth = bw; + ctx.strokeStyle = borderColor; + ctx.moveTo(x + r, y); + ctx.arcTo(x + w, y, x + w, y + h, r); + ctx.arcTo(x + w, y + h, x, y + h, r); + ctx.arcTo(x, y + h, x, y, r); + ctx.arcTo(x, y, x + w, y, r); + ctx.closePath(); + ctx.stroke(); } diff --git a/packages/renderer/src/draw/elements.ts b/packages/renderer/src/draw/elements.ts index 06cfb32..b88b2af 100644 --- a/packages/renderer/src/draw/elements.ts +++ b/packages/renderer/src/draw/elements.ts @@ -5,6 +5,7 @@ import { drawImage } from './image'; import { drawText } from './text'; import { drawSVG } from './svg'; import { drawHTML } from './html'; +import { drawGroup } from './group'; export function drawElement(ctx: ViewContext2D, elem: Element, opts: RendererDrawElementOptions) { try { @@ -33,6 +34,10 @@ export function drawElement(ctx: ViewContext2D, elem: Element, opts drawHTML(ctx, elem as Element<'html'>, opts); break; } + case 'group': { + drawGroup(ctx, elem as Element<'group'>, opts); + break; + } default: { break; } @@ -43,7 +48,7 @@ export function drawElement(ctx: ViewContext2D, elem: Element, opts } export function drawElementList(ctx: ViewContext2D, elements: Data['elements'], opts: RendererDrawElementOptions) { - for (let i = elements.length - 1; i >= 0; i--) { + for (let i = 0; i < elements.length; i++) { const elem = elements[i]; if (!opts.calculator.isElementInView(elem, opts.scaleInfo, opts.viewSize)) { continue; diff --git a/packages/renderer/src/draw/group.ts b/packages/renderer/src/draw/group.ts new file mode 100644 index 0000000..195bb79 --- /dev/null +++ b/packages/renderer/src/draw/group.ts @@ -0,0 +1,95 @@ +import type { Element, ElementType, ElementSize, RendererDrawElementOptions, ViewContext2D } from '@idraw/types'; +import { rotateElement } from '@idraw/util'; +import { drawCircle } from './circle'; +import { drawRect } from './rect'; +import { drawImage } from './image'; +import { drawText } from './text'; +import { drawSVG } from './svg'; +import { drawHTML } from './html'; +import { drawBox } from './base'; + +export function drawElement(ctx: ViewContext2D, elem: Element, opts: RendererDrawElementOptions) { + try { + switch (elem.type) { + case 'rect': { + drawRect(ctx, elem as Element<'rect'>, opts); + break; + } + case 'circle': { + drawCircle(ctx, elem as Element<'circle'>, opts); + break; + } + case 'text': { + drawText(ctx, elem as Element<'text'>, opts); + break; + } + case 'image': { + drawImage(ctx, elem as Element<'image'>, opts); + break; + } + case 'svg': { + drawSVG(ctx, elem as Element<'svg'>, opts); + break; + } + case 'html': { + drawHTML(ctx, elem as Element<'html'>, opts); + break; + } + default: { + break; + } + } + } catch (err) { + console.error(err); + } +} + +export function drawGroup(ctx: ViewContext2D, elem: Element<'group'>, opts: RendererDrawElementOptions) { + const { calculator, scaleInfo } = opts; + const { x, y, w, h, angle } = calculator.elementSize({ x: elem.x, y: elem.y, w: elem.w, h: elem.h, angle: elem.angle }, scaleInfo); + + rotateElement(ctx, { x, y, w, h, angle }, () => { + drawBox(ctx, elem); + if (Array.isArray(elem.desc.children)) { + const { parentElementSize: parentSize } = opts; + const newParentSize: ElementSize = { + x: parentSize.x + elem.x, + y: parentSize.y + elem.y, + w: elem.w || parentSize.w, + h: elem.h || parentSize.h, + angle: elem.angle + }; + const { calculator } = opts; + ctx.save(); + + ctx.beginPath(); + ctx.moveTo(x, y); + ctx.lineTo(x + w, y); + ctx.lineTo(x + w, y + h); + ctx.lineTo(x, y + h); + ctx.closePath(); + ctx.clip(); + + for (let i = 0; i < elem.desc.children.length; i++) { + let child = elem.desc.children[i]; + child = { + ...child, + ...{ + x: newParentSize.x + child.x, + y: newParentSize.y + child.y + } + }; + if (!calculator.isElementInView(child, opts.scaleInfo, opts.viewSize)) { + continue; + } + try { + drawElement(ctx, child, opts); + } catch (err) { + console.error(err); + } + } + + ctx.restore(); + } + }); +} diff --git a/packages/renderer/src/draw/rect.ts b/packages/renderer/src/draw/rect.ts index 950e326..3e9d870 100644 --- a/packages/renderer/src/draw/rect.ts +++ b/packages/renderer/src/draw/rect.ts @@ -5,7 +5,7 @@ export function drawRect(ctx: ViewContext2D, elem: Element<'rect'>, opts: Render // const { desc } = elem; const { calculator, scaleInfo } = opts; - const { x, y, w, h, angle } = calculator.elementSize({ x: elem.x, y: elem.y, w: elem.w, h: elem.h }, scaleInfo); + const { x, y, w, h, angle } = calculator.elementSize(elem, scaleInfo); rotateElement(ctx, { x, y, w, h, angle }, () => { let r: number = (elem.desc.borderRadius || 0) * scaleInfo.scale; r = Math.min(r, w / 2, h / 2); diff --git a/packages/renderer/src/draw/text.ts b/packages/renderer/src/draw/text.ts index 316e6ed..751aada 100644 --- a/packages/renderer/src/draw/text.ts +++ b/packages/renderer/src/draw/text.ts @@ -1,12 +1,11 @@ import type { Element, RendererDrawElementOptions, ViewContext2D } from '@idraw/types'; import { rotateElement } from '@idraw/util'; import { is, isColorStr } from '@idraw/util'; -import { clearContext, drawBox } from './base'; +import { drawBox } from './base'; export function drawText(ctx: ViewContext2D, elem: Element<'text'>, opts: RendererDrawElementOptions) { - clearContext(ctx); - drawBox(ctx, elem, elem.desc.bgColor || 'transparent'); rotateElement(ctx, elem, () => { + drawBox(ctx, elem, elem.desc.bgColor || 'transparent'); const desc: Element<'text'>['desc'] = { ...{ fontSize: 12, @@ -103,7 +102,6 @@ export function drawText(ctx: ViewContext2D, elem: Element<'text'>, opts: Render } ctx.fillText(line.text, _x, _y + fontHeight * i); }); - clearContext(ctx); } // draw text stroke diff --git a/packages/renderer/src/index.ts b/packages/renderer/src/index.ts index 72a8ee6..be60f23 100644 --- a/packages/renderer/src/index.ts +++ b/packages/renderer/src/index.ts @@ -1,4 +1,4 @@ -import { EventEmitter, createOffscreenContext2D } from '@idraw/util'; +import { EventEmitter } from '@idraw/util'; import { drawElementList } from './draw'; import { Loader } from './loader'; import type { Data, BoardRenderer, RendererOptions, RendererEventMap, RendererDrawOptions } from '@idraw/types'; @@ -6,17 +6,17 @@ import type { Data, BoardRenderer, RendererOptions, RendererEventMap, RendererDr export class Renderer extends EventEmitter implements BoardRenderer { private _opts: RendererOptions; private _loader: Loader = new Loader(); - private _draftContextTop: CanvasRenderingContext2D; - private _draftContextMiddle: CanvasRenderingContext2D; - private _draftContextBottom: CanvasRenderingContext2D; + // private _draftContextTop: CanvasRenderingContext2D; + // private _draftContextMiddle: CanvasRenderingContext2D; + // private _draftContextBottom: CanvasRenderingContext2D; constructor(opts: RendererOptions) { super(); this._opts = opts; - const { width, height } = this._opts.viewContent.viewContext.canvas; - this._draftContextTop = createOffscreenContext2D({ width, height }) as CanvasRenderingContext2D; - this._draftContextMiddle = createOffscreenContext2D({ width, height }) as CanvasRenderingContext2D; - this._draftContextBottom = createOffscreenContext2D({ width, height }) as CanvasRenderingContext2D; + // const { width, height } = this._opts.viewContent.viewContext.canvas; + // this._draftContextTop = createOffscreenContext2D({ width, height }) as CanvasRenderingContext2D; + // this._draftContextMiddle = createOffscreenContext2D({ width, height }) as CanvasRenderingContext2D; + // this._draftContextBottom = createOffscreenContext2D({ width, height }) as CanvasRenderingContext2D; this._init(); } @@ -40,7 +40,18 @@ export class Renderer extends EventEmitter implements BoardRen const { calculator } = this._opts; const { viewContext } = this._opts.viewContent; viewContext.clearRect(0, 0, viewContext.canvas.width, viewContext.canvas.height); - drawElementList(viewContext, data.elements, { loader, calculator, ...opts }); + const parentElementSize = { + x: 0, + y: 0, + w: opts.viewSize.width, + h: opts.viewSize.height + }; + drawElementList(viewContext, data.elements, { + loader, + calculator, + parentElementSize, + ...opts + }); } scale(num: number) { diff --git a/packages/types/src/lib/context2d.ts b/packages/types/src/lib/context2d.ts index 2394fe3..5b4bf1c 100644 --- a/packages/types/src/lib/context2d.ts +++ b/packages/types/src/lib/context2d.ts @@ -54,4 +54,6 @@ export interface ViewContext2D { shadowOffsetY: number; ellipse(x: number, y: number, radiusX: number, radiusY: number, rotation: number, startAngle: number, endAngle: number, counterclockwise?: boolean): void; isPointInPath(x: number, y: number, fillRule?: CanvasFillRule): boolean; + clip(fillRule?: CanvasFillRule): void; + clip(path: Path2D, fillRule?: CanvasFillRule): void; } diff --git a/packages/types/src/lib/element.ts b/packages/types/src/lib/element.ts index 222c99a..bf9c897 100644 --- a/packages/types/src/lib/element.ts +++ b/packages/types/src/lib/element.ts @@ -26,7 +26,7 @@ interface ElemenTextDesc extends ElementBaseDesc { color: string; fontSize: number; lineHeight?: number; - fontWeight?: 'bold' | ''; + fontWeight?: 'bold' | string; fontFamily?: string; textAlign?: 'center' | 'left' | 'right'; verticalAlign?: 'middle' | 'top' | 'bottom'; @@ -58,6 +58,10 @@ interface ElementSVGDesc extends ElementBaseDesc { svg: string; } +interface ElementGroupDesc extends ElementBaseDesc { + children: Element[]; +} + interface ElementDescMap { rect: ElementRectDesc; circle: ElementCircleDesc; @@ -65,9 +69,10 @@ interface ElementDescMap { image: ElementImageDesc; html: ElementHTMLDesc; svg: ElementSVGDesc; + group: ElementGroupDesc; } -export type ElementType = 'text' | 'rect' | 'circle' | 'image' | 'svg' | 'html'; +export type ElementType = 'text' | 'rect' | 'circle' | 'image' | 'svg' | 'html' | 'group'; export interface ElementOperation { lock?: boolean; diff --git a/packages/types/src/lib/renderer.ts b/packages/types/src/lib/renderer.ts index e3a149e..b2fb354 100644 --- a/packages/types/src/lib/renderer.ts +++ b/packages/types/src/lib/renderer.ts @@ -1,5 +1,5 @@ import type { ViewContent, ViewScaleInfo, ViewCalculator, ViewSizeInfo } from './view'; -import type { Element } from './element'; +import type { Element, ElementSize } from './element'; import type { LoaderEventMap, LoadElementType, LoadContent } from './loader'; import type { UtilEventEmitter } from './util'; import type { StoreSharer } from './store'; @@ -31,4 +31,6 @@ export interface RendererDrawOptions { export interface RendererDrawElementOptions extends RendererDrawOptions { loader: RendererLoader; calculator: ViewCalculator; + scaleInfo: ViewScaleInfo; + parentElementSize: ElementSize; } diff --git a/packages/util/src/lib/context2d.ts b/packages/util/src/lib/context2d.ts index 66dc138..0735548 100644 --- a/packages/util/src/lib/context2d.ts +++ b/packages/util/src/lib/context2d.ts @@ -272,4 +272,10 @@ export class Context2D implements ViewContext2D { isPointInPath(x: number, y: number) { return this._ctx.isPointInPath(this.$doPixelRatio(x), this.$doPixelRatio(y)); } + + // clip(fillRule?: CanvasFillRule): void; + // clip(path: Path2D, fillRule?: CanvasFillRule): void; + clip(...args: [fillRule?: CanvasFillRule | undefined] | [path: Path2D, fillRule?: CanvasFillRule | undefined]) { + return this._ctx.clip(...(args as any[])); + } } diff --git a/packages/util/src/lib/rotate.ts b/packages/util/src/lib/rotate.ts index 7782fcb..0033002 100644 --- a/packages/util/src/lib/rotate.ts +++ b/packages/util/src/lib/rotate.ts @@ -85,9 +85,9 @@ function calcLineRadian(center: PointSize, p: PointSize): number { } else if (x > 0 && y > 0) { return Math.PI - Math.atan(Math.abs(x) / Math.abs(y)); } else if (x < 0 && y > 0) { - return Math.PI + Math.atan(Math.abs(y) / Math.abs(x)); + return Math.PI + Math.atan(Math.abs(x) / Math.abs(y)); } else if (x < 0 && y < 0) { - return 2 * Math.PI - Math.atan(Math.abs(y) / Math.abs(x)); + return 2 * Math.PI - Math.atan(Math.abs(x) / Math.abs(y)); } return 0;