diff --git a/packages/board/src/index.ts b/packages/board/src/index.ts index a490983..79cc41a 100644 --- a/packages/board/src/index.ts +++ b/packages/board/src/index.ts @@ -405,9 +405,9 @@ export class Board { const { width, height, devicePixelRatio } = newViewSize; const { boardContent } = this.#opts; boardContent.viewContext.$resize({ width, height, devicePixelRatio }); - boardContent.helperContext.$resize({ width, height, devicePixelRatio }); + boardContent.overlayContext.$resize({ width, height, devicePixelRatio }); boardContent.boardContext.$resize({ width, height, devicePixelRatio }); - boardContent.underContext.$resize({ width, height, devicePixelRatio }); + boardContent.underlayContext.$resize({ width, height, devicePixelRatio }); this.#viewer.drawFrame(); this.#watcher.trigger('resize', viewSize); this.#sharer.setActiveViewSizeInfo(newViewSize); @@ -415,9 +415,9 @@ export class Board { clear() { const { boardContent } = this.#opts; - const { underContext, helperContext, viewContext, boardContext } = boardContent; - underContext.clearRect(0, 0, underContext.canvas.width, underContext.canvas.height); - helperContext.clearRect(0, 0, helperContext.canvas.width, helperContext.canvas.height); + const { underlayContext, overlayContext, viewContext, boardContext } = boardContent; + underlayContext.clearRect(0, 0, underlayContext.canvas.width, underlayContext.canvas.height); + overlayContext.clearRect(0, 0, overlayContext.canvas.width, overlayContext.canvas.height); viewContext.clearRect(0, 0, viewContext.canvas.width, viewContext.canvas.height); boardContext.clearRect(0, 0, boardContext.canvas.width, boardContext.canvas.height); this.#handleClear(); diff --git a/packages/board/src/lib/viewer.ts b/packages/board/src/lib/viewer.ts index 6395017..e57242e 100644 --- a/packages/board/src/lib/viewer.ts +++ b/packages/board/src/lib/viewer.ts @@ -172,17 +172,17 @@ export class Viewer extends EventEmitter implements BoardVi const newViewSize = { ...originViewSize, ...viewSize }; const { width, height, devicePixelRatio } = newViewSize; - const { underContext, boardContext, helperContext, viewContext } = this.#opts.boardContent; + const { underlayContext, boardContext, overlayContext, viewContext } = this.#opts.boardContent; boardContext.canvas.width = width * devicePixelRatio; boardContext.canvas.height = height * devicePixelRatio; boardContext.canvas.style.width = `${width}px`; boardContext.canvas.style.height = `${height}px`; - underContext.canvas.width = width * devicePixelRatio; - underContext.canvas.height = height * devicePixelRatio; + underlayContext.canvas.width = width * devicePixelRatio; + underlayContext.canvas.height = height * devicePixelRatio; - helperContext.canvas.width = width * devicePixelRatio; - helperContext.canvas.height = height * devicePixelRatio; + overlayContext.canvas.width = width * devicePixelRatio; + overlayContext.canvas.height = height * devicePixelRatio; viewContext.canvas.width = width * devicePixelRatio; viewContext.canvas.height = height * devicePixelRatio; diff --git a/packages/core/src/middleware/info/index.ts b/packages/core/src/middleware/info/index.ts index fc566ea..590ddf6 100644 --- a/packages/core/src/middleware/info/index.ts +++ b/packages/core/src/middleware/info/index.ts @@ -11,7 +11,7 @@ const infoLineHeight = 16; export const MiddlewareInfo: BoardMiddleware = (opts) => { const { boardContent, calculator } = opts; - const { helperContext } = boardContent; + const { overlayContext } = boardContent; return { name: '@middleware/info', @@ -76,7 +76,7 @@ export const MiddlewareInfo: BoardMiddleware = (opts) => const h = formatNumber(elem.h, { decimalPlaces: 2 }); // // test start ---- - // const ctx = helperContext; + // const ctx = overlayContext; // ctx.beginPath(); // ctx.moveTo(rectInfo.topLeft.x, rectInfo.topLeft.y); // ctx.lineTo(rectInfo.topRight.x, rectInfo.topRight.y); @@ -91,7 +91,7 @@ export const MiddlewareInfo: BoardMiddleware = (opts) => const whText = `${formatNumber(w, { decimalPlaces: 0 })}x${formatNumber(h, { decimalPlaces: 0 })}`; const angleText = `${formatNumber(elem.angle || 0, { decimalPlaces: 0 })}°`; - drawSizeInfoText(helperContext, { + drawSizeInfoText(overlayContext, { point: { x: rectInfo.bottom.x, y: rectInfo.bottom.y + infoFontSize @@ -105,7 +105,7 @@ export const MiddlewareInfo: BoardMiddleware = (opts) => background: infoBackground }); - drawPositionInfoText(helperContext, { + drawPositionInfoText(overlayContext, { point: { x: rectInfo.topLeft.x, y: rectInfo.topLeft.y - infoFontSize * 2 @@ -119,7 +119,7 @@ export const MiddlewareInfo: BoardMiddleware = (opts) => background: infoBackground }); - drawAngleInfoText(helperContext, { + drawAngleInfoText(overlayContext, { point: { x: rectInfo.top.x + infoFontSize, y: rectInfo.top.y - infoFontSize * 2 diff --git a/packages/core/src/middleware/layout-selector/index.ts b/packages/core/src/middleware/layout-selector/index.ts index 9351a68..534efbb 100644 --- a/packages/core/src/middleware/layout-selector/index.ts +++ b/packages/core/src/middleware/layout-selector/index.ts @@ -8,7 +8,7 @@ import { eventChange } from '../../config'; export const MiddlewareLayoutSelector: BoardMiddleware = (opts) => { const { sharer, boardContent, calculator, viewer, eventHub } = opts; - const { helperContext } = boardContent; + const { overlayContext } = boardContent; let prevPoint: Point | null = null; @@ -244,7 +244,7 @@ export const MiddlewareLayoutSelector: BoardMiddleware = (opts) => { const { boardContent, viewer, eventHub, calculator } = opts; - const { helperContext, underContext } = boardContent; + const { overlayContext, underlayContext } = boardContent; let show: boolean = true; let showGrid: boolean = true; @@ -36,18 +36,20 @@ export const MiddlewareRuler: BoardMiddleware nextUnit) { + continue; + } + if (unit === thisUnit) { + return unit; + } + if (unit === nextUnit) { + return unit; + } + + const mid = (thisUnit + nextUnit) / 2; + if (unit <= mid) { + return thisUnit; + } + return nextUnit; + } + return unit; +} + +function calcRulerScaleList(opts: { axis: 'X' | 'Y'; scale: number; viewLength: number; viewOffset: number }): { list: RulerScale[]; rulerUnit: number } { const { scale, viewLength, viewOffset } = opts; const list: RulerScale[] = []; let rulerUnit = 10; rulerUnit = formatNumber(rulerUnit / scale, { decimalPlaces: 0 }); - rulerUnit = Math.max(10, Math.min(rulerUnit, 1000)); - + // rulerUnit = Math.max(10, Math.min(rulerUnit, 1000)); + rulerUnit = limitRulerUnit(rulerUnit); const rulerKeyUnit = rulerUnit * 10; const rulerSubKeyUnit = rulerUnit * 5; @@ -46,6 +72,7 @@ function calcRulerScaleList(opts: { axis: 'X' | 'Y'; scale: number; viewLength: const remainderNum = startNum % viewUnit; const firstNum = (startNum - remainderNum + viewUnit) / scale; const firstPosition = startPosition + (viewUnit - remainderNum); + while (firstPosition + index * viewUnit < viewLength) { const num = formatNumber(firstNum + index * rulerUnit, { decimalPlaces: 0 }); const position = formatNumber(firstPosition + index * viewUnit, { decimalPlaces: 0 }); @@ -60,10 +87,10 @@ function calcRulerScaleList(opts: { axis: 'X' | 'Y'; scale: number; viewLength: index++; } - return list; + return { list, rulerUnit }; } -export function calcXRulerScaleList(opts: { viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo }): RulerScale[] { +export function calcXRulerScaleList(opts: { viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo }): { list: RulerScale[]; rulerUnit: number } { const { viewScaleInfo, viewSizeInfo } = opts; const { scale, offsetLeft } = viewScaleInfo; const { width } = viewSizeInfo; @@ -75,7 +102,7 @@ export function calcXRulerScaleList(opts: { viewScaleInfo: ViewScaleInfo; viewSi }); } -export function calcYRulerScaleList(opts: { viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo }): RulerScale[] { +export function calcYRulerScaleList(opts: { viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo }): { list: RulerScale[]; rulerUnit: number } { const { viewScaleInfo, viewSizeInfo } = opts; const { scale, offsetTop } = viewScaleInfo; const { height } = viewSizeInfo; @@ -195,7 +222,7 @@ export function drawRulerBackground( ctx.stroke(); } -export function drawUnderGrid( +export function drawGrid( ctx: ViewContext2D, opts: { xList: RulerScale[]; diff --git a/packages/core/src/middleware/scroller/index.ts b/packages/core/src/middleware/scroller/index.ts index 2ed6d75..ae854e9 100644 --- a/packages/core/src/middleware/scroller/index.ts +++ b/packages/core/src/middleware/scroller/index.ts @@ -6,7 +6,7 @@ import type { DeepScrollerSharedStorage } from './types'; export const MiddlewareScroller: BoardMiddleware = (opts) => { const { viewer, boardContent, sharer } = opts; - const { helperContext } = boardContent; + const { overlayContext } = boardContent; sharer.setSharedStorage(keyXThumbRect, null); // null | ElementSize sharer.setSharedStorage(keyYThumbRect, null); // null | ElementSize @@ -48,7 +48,7 @@ export const MiddlewareScroller: BoardMiddleware = (o }; const getThumbType = (p: Point) => { - return isPointInScrollThumb(helperContext, p, { + return isPointInScrollThumb(overlayContext, p, { xThumbRect: sharer.getSharedStorage(keyXThumbRect), yThumbRect: sharer.getSharedStorage(keyYThumbRect) }); @@ -97,7 +97,7 @@ export const MiddlewareScroller: BoardMiddleware = (o } }, beforeDrawFrame({ snapshot }) { - const { xThumbRect, yThumbRect } = drawScroller(helperContext, { snapshot }); + const { xThumbRect, yThumbRect } = drawScroller(overlayContext, { snapshot }); sharer.setSharedStorage(keyXThumbRect, xThumbRect); sharer.setSharedStorage(keyYThumbRect, yThumbRect); } diff --git a/packages/core/src/middleware/scroller/util.ts b/packages/core/src/middleware/scroller/util.ts index 8bbc870..e45450c 100644 --- a/packages/core/src/middleware/scroller/util.ts +++ b/packages/core/src/middleware/scroller/util.ts @@ -15,8 +15,8 @@ const scrollConfig = { showScrollBar: false }; -function isPointAtRect(helperContext: ViewContext2D, p: Point, rect: ElementSize): boolean { - const ctx = helperContext; +function isPointAtRect(overlayContext: ViewContext2D, p: Point, rect: ElementSize): boolean { + const ctx = overlayContext; const { x, y, w, h } = rect; ctx.beginPath(); ctx.rect(x, y, w, h); @@ -28,7 +28,7 @@ function isPointAtRect(helperContext: ViewContext2D, p: Point, rect: ElementSize } export function isPointInScrollThumb( - helperContext: ViewContext2D, + overlayContext: ViewContext2D, p: Point, opts: { xThumbRect?: ElementSize | null; @@ -37,9 +37,9 @@ export function isPointInScrollThumb( ): ScrollbarThumbType | null { let thumbType: ScrollbarThumbType | null = null; const { xThumbRect, yThumbRect } = opts; - if (xThumbRect && isPointAtRect(helperContext, p, xThumbRect)) { + if (xThumbRect && isPointAtRect(overlayContext, p, xThumbRect)) { thumbType = 'X'; - } else if (yThumbRect && isPointAtRect(helperContext, p, yThumbRect)) { + } else if (yThumbRect && isPointAtRect(overlayContext, p, yThumbRect)) { thumbType = 'Y'; } return thumbType; @@ -194,8 +194,8 @@ function drawScrollerThumb( ctx.restore(); } -function drawScrollerInfo(helperContext: ViewContext2D, opts: { viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo; scrollInfo: ScrollInfo }) { - const ctx = helperContext; +function drawScrollerInfo(overlayContext: ViewContext2D, opts: { viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo; scrollInfo: ScrollInfo }) { + const ctx = overlayContext; const { viewScaleInfo, viewSizeInfo, scrollInfo } = opts; const { activeThumbType, prevPoint, activePoint } = scrollInfo; const { width, height } = viewSizeInfo; diff --git a/packages/core/src/middleware/selector/index.ts b/packages/core/src/middleware/selector/index.ts index 39beb4c..d0e3476 100644 --- a/packages/core/src/middleware/selector/index.ts +++ b/packages/core/src/middleware/selector/index.ts @@ -83,7 +83,7 @@ export { middlewareEventSelect, middlewareEventSelectClear, middlewareEventSelec export const MiddlewareSelector: BoardMiddleware = (opts) => { const { viewer, sharer, boardContent, calculator, eventHub } = opts; - const { helperContext } = boardContent; + const { overlayContext } = boardContent; let prevPoint: Point | null = null; let inBusyMode: 'resize' | 'drag' | 'drag-list' | 'area' | null = null; @@ -146,7 +146,7 @@ export const MiddlewareSelector: BoardMiddleware { return { - ctx: helperContext, + ctx: overlayContext, calculator, data: sharer.getActiveStorage('data'), selectedElements: getActiveElements(), @@ -249,7 +249,7 @@ export const MiddlewareSelector: BoardMiddleware 0) { // in group const isInActiveGroup = isPointInViewActiveGroup(e.point, { - ctx: helperContext, + ctx: overlayContext, viewScaleInfo: sharer.getActiveViewScaleInfo(), viewSizeInfo: sharer.getActiveViewSizeInfo(), groupQueue: sharer.getSharedStorage(keyGroupQueue) @@ -350,7 +350,7 @@ export const MiddlewareSelector: BoardMiddleware 0) { if ( isPointInViewActiveGroup(e.point, { - ctx: helperContext, + ctx: overlayContext, viewScaleInfo: sharer.getActiveViewScaleInfo(), viewSizeInfo: sharer.getActiveViewSizeInfo(), groupQueue @@ -750,10 +750,10 @@ export const MiddlewareSelector: BoardMiddleware 0) { // in group - drawGroupQueueVertexesWrappers(helperContext, groupQueueVertexesList, drawBaseOpts); + drawGroupQueueVertexesWrappers(overlayContext, groupQueueVertexesList, drawBaseOpts); if (hoverElement && actionType !== 'drag') { if (isLock) { - drawLockVertexesWrapper(helperContext, hoverElementVertexes, { + drawLockVertexesWrapper(overlayContext, hoverElementVertexes, { ...drawBaseOpts, controller: calcElementSizeController(hoverElement, { groupQueue, @@ -762,11 +762,11 @@ export const MiddlewareSelector: BoardMiddleware, opts: RendererDrawElementOptions) { - const content = opts.loader.getContent(elem); + const content: LoadContent | HTMLCanvasElement | OffscreenCanvas | null = opts.loader.getContent(elem); const { viewScaleInfo, viewSizeInfo, parentOpacity } = opts; - const { x, y, w, h, angle } = calcViewElementSize(elem, { viewScaleInfo, viewSizeInfo }) || elem; + const { x, y, w, h, angle } = calcViewElementSize(elem, { viewScaleInfo }) || elem; const viewElem = { ...elem, ...{ x, y, w, h, angle } }; rotateElement(ctx, { x, y, w, h, angle }, () => { @@ -29,6 +29,10 @@ export function drawImage(ctx: ViewContext2D, elem: Element<'image'>, opts: Rend viewScaleInfo, viewSizeInfo }); + const { detail } = elem; + const { scaleMode, originW = 0, originH = 0 } = detail; + const imageW = ctx.$undoPixelRatio(originW); + const imageH = ctx.$undoPixelRatio(originH); ctx.save(); ctx.fillStyle = 'transparent'; @@ -41,7 +45,56 @@ export function drawImage(ctx: ViewContext2D, elem: Element<'image'>, opts: Rend ctx.closePath(); ctx.fill(); ctx.clip(); - ctx.drawImage(content, x, y, w, h); + + if (scaleMode && originH && originW) { + let sx = 0; + let sy = 0; + let sWidth = imageW; + let sHeight = imageH; + const dx = x; + const dy = y; + const dWidth = w; + const dHeight = h; + + if (imageW > elem.w || imageH > elem.h) { + if (scaleMode === 'fill') { + const sourceScale = Math.max(elem.w / imageW, elem.h / imageH); + const newImageWidth = imageW * sourceScale; + const newImageHeight = imageH * sourceScale; + sx = (newImageWidth - elem.w) / 2 / sourceScale; + sy = (newImageHeight - elem.h) / 2 / sourceScale; + sWidth = elem.w / sourceScale; + sHeight = elem.h / sourceScale; + } else if (scaleMode === 'tile') { + sx = 0; + sy = 0; + sWidth = elem.w; + sHeight = elem.h; + } else if (scaleMode === 'fit') { + const sourceScale = Math.min(elem.w / imageW, elem.h / imageH); + sx = (imageW - elem.w / sourceScale) / 2; + sy = (imageH - elem.h / sourceScale) / 2; + sWidth = elem.w / sourceScale; + sHeight = elem.h / sourceScale; + } + } + + ctx.drawImage(content, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight); + } else { + ctx.drawImage(content, x, y, w, h); + + // const sx = 0; + // const sy = 0; + // const sWidth = imageW; + // const sHeight = imageH; + // const dx = x; + // const dy = y; + // const dWidth = w; + // const dHeight = h; + // ctx.drawImage(content, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight); + } + // content = null; + ctx.globalAlpha = parentOpacity; ctx.restore(); } diff --git a/packages/renderer/src/draw/path.ts b/packages/renderer/src/draw/path.ts index b8bcc72..e27c857 100644 --- a/packages/renderer/src/draw/path.ts +++ b/packages/renderer/src/draw/path.ts @@ -4,7 +4,7 @@ import { drawBox, drawBoxShadow } from './box'; export function drawPath(ctx: ViewContext2D, elem: Element<'path'>, opts: RendererDrawElementOptions) { const { detail } = elem; - const { originX, originY, originW, originH } = detail; + const { originX, originY, originW, originH, fillRule } = detail; const { viewScaleInfo, viewSizeInfo, parentOpacity } = opts; const { x, y, w, h, angle } = calcViewElementSize(elem, { viewScaleInfo }) || elem; const scaleW = w / originW; @@ -43,7 +43,7 @@ export function drawPath(ctx: ViewContext2D, elem: Element<'path'>, opts: Render const path2d = new Path2D(pathStr); if (detail.fill) { ctx.fillStyle = detail.fill; - ctx.fill(path2d); + ctx.fill(path2d, fillRule as CanvasFillRule); } if (detail.stroke && detail.strokeWidth !== 0) { diff --git a/packages/types/src/lib/element.ts b/packages/types/src/lib/element.ts index a3811ec..33295e6 100644 --- a/packages/types/src/lib/element.ts +++ b/packages/types/src/lib/element.ts @@ -121,6 +121,9 @@ export interface ElementHTMLDetail extends ElementBaseDetail { export interface ElementImageDetail extends ElementBaseDetail { src: string; + originW?: number; + originH?: number; + scaleMode?: 'auto' | 'fill' | 'fit' | 'tile'; } export interface ElementSVGDetail extends ElementBaseDetail { @@ -144,6 +147,7 @@ export interface ElementPathDetail extends ElementBaseDetail { stroke?: string; strokeWidth?: number; strokeLineCap?: 'butt' | 'round' | 'square'; + fillRule?: string; // "evenodd" | "nonzero" } export interface ElementDetailMap { diff --git a/packages/types/src/lib/view.ts b/packages/types/src/lib/view.ts index 4a2e294..3f6ee5b 100644 --- a/packages/types/src/lib/view.ts +++ b/packages/types/src/lib/view.ts @@ -26,8 +26,8 @@ export interface ViewSizeInfo extends ViewContextSize { export interface BoardContent { boardContext: ViewContext2D; viewContext: ViewContext2D; - helperContext: ViewContext2D; - underContext: ViewContext2D; + overlayContext: ViewContext2D; + underlayContext: ViewContext2D; drawView: () => void; } diff --git a/packages/util/src/lib/canvas.ts b/packages/util/src/lib/canvas.ts index 87ceaef..39cf9c3 100644 --- a/packages/util/src/lib/canvas.ts +++ b/packages/util/src/lib/canvas.ts @@ -50,26 +50,26 @@ export function createBoardContent( if (createCustomContext2D) { // TODO const viewContext = createCustomContext2D(ctxOpts); - const helperContext = createCustomContext2D(ctxOpts); - const underContext = createCustomContext2D(ctxOpts); + const overlayContext = createCustomContext2D(ctxOpts); + const underlayContext = createCustomContext2D(ctxOpts); const boardContext = createContext2D({ ctx, ...ctxOpts }); const drawView = () => { const { width: w, height: h } = viewContext.$getSize(); boardContext.clearRect(0, 0, w, h); - boardContext.drawImage(underContext.canvas, 0, 0, w, h); + boardContext.drawImage(underlayContext.canvas, 0, 0, w, h); boardContext.drawImage(viewContext.canvas, 0, 0, w, h); - boardContext.drawImage(helperContext.canvas, 0, 0, w, h); - underContext.clearRect(0, 0, w, h); + boardContext.drawImage(overlayContext.canvas, 0, 0, w, h); + underlayContext.clearRect(0, 0, w, h); viewContext.clearRect(0, 0, w, h); - helperContext.clearRect(0, 0, w, h); + overlayContext.clearRect(0, 0, w, h); }; const content: BoardContent = { - underContext, + underlayContext, viewContext, - helperContext, + overlayContext, boardContext, drawView }; @@ -79,26 +79,26 @@ export function createBoardContent( if (offscreen === true) { // const ctx = canvas.getContext('2d') as CanvasRenderingContext2D; const viewContext = createOffscreenContext2D(ctxOpts); - const helperContext = createOffscreenContext2D(ctxOpts); - const underContext = createOffscreenContext2D(ctxOpts); + const overlayContext = createOffscreenContext2D(ctxOpts); + const underlayContext = createOffscreenContext2D(ctxOpts); const boardContext = createContext2D({ ctx, ...ctxOpts }); const drawView = () => { const { width: w, height: h } = viewContext.$getSize(); boardContext.clearRect(0, 0, w, h); - boardContext.drawImage(underContext.canvas, 0, 0, w, h); + boardContext.drawImage(underlayContext.canvas, 0, 0, w, h); boardContext.drawImage(viewContext.canvas, 0, 0, w, h); - boardContext.drawImage(helperContext.canvas, 0, 0, w, h); - underContext.clearRect(0, 0, w, h); + boardContext.drawImage(overlayContext.canvas, 0, 0, w, h); + underlayContext.clearRect(0, 0, w, h); viewContext.clearRect(0, 0, w, h); - helperContext.clearRect(0, 0, w, h); + overlayContext.clearRect(0, 0, w, h); }; const content: BoardContent = { - underContext, + underlayContext, viewContext, - helperContext, + overlayContext, boardContext, drawView }; @@ -106,24 +106,24 @@ export function createBoardContent( } else { // const ctx = canvas.getContext('2d') as CanvasRenderingContext2D; const viewContext = createContext2D(ctxOpts); - const helperContext = createContext2D(ctxOpts); - const underContext = createContext2D(ctxOpts); + const overlayContext = createContext2D(ctxOpts); + const underlayContext = createContext2D(ctxOpts); const boardContext = createContext2D({ ctx, ...ctxOpts }); const drawView = () => { boardContext.clearRect(0, 0, width, height); - boardContext.drawImage(underContext.canvas, 0, 0, width, height); + boardContext.drawImage(underlayContext.canvas, 0, 0, width, height); boardContext.drawImage(viewContext.canvas, 0, 0, width, height); - boardContext.drawImage(helperContext.canvas, 0, 0, width, height); - underContext.clearRect(0, 0, width, height); + boardContext.drawImage(overlayContext.canvas, 0, 0, width, height); + underlayContext.clearRect(0, 0, width, height); viewContext.clearRect(0, 0, width, height); - helperContext.clearRect(0, 0, width, height); + overlayContext.clearRect(0, 0, width, height); }; const content: BoardContent = { - underContext, + underlayContext, viewContext, - helperContext, + overlayContext, boardContext, drawView };