diff --git a/packages/g-plugin-canvas-renderer/src/CanvasRendererPlugin.ts b/packages/g-plugin-canvas-renderer/src/CanvasRendererPlugin.ts index 95312fe9f..d7c8190db 100644 --- a/packages/g-plugin-canvas-renderer/src/CanvasRendererPlugin.ts +++ b/packages/g-plugin-canvas-renderer/src/CanvasRendererPlugin.ts @@ -98,7 +98,10 @@ export class CanvasRendererPlugin implements RenderingPlugin { private vpMatrix = mat4.create(); private dprMatrix = mat4.create(); private tmpMat4 = mat4.create(); - private tmpVec3 = vec3.create(); + private vec3a = vec3.create(); + private vec3b = vec3.create(); + private vec3c = vec3.create(); + private vec3d = vec3.create(); apply(renderingService: RenderingService) { const canvas = this.renderingContext.root.ownerDocument.defaultView; @@ -211,17 +214,24 @@ export class CanvasRendererPlugin implements RenderingPlugin { const dirtyRect = this.convertAABB2Rect(dirtyRenderBounds); const { x, y, width, height } = dirtyRect; - const tl = vec3.transformMat4(this.tmpVec3, vec3.fromValues(x, y, 0), this.vpMatrix); + const tl = vec3.transformMat4(this.vec3a, vec3.fromValues(x, y, 0), this.vpMatrix); + const tr = vec3.transformMat4(this.vec3b, vec3.fromValues(x + width, y, 0), this.vpMatrix); + const bl = vec3.transformMat4(this.vec3c, vec3.fromValues(x, y + height, 0), this.vpMatrix); const br = vec3.transformMat4( - vec3.create(), + this.vec3d, vec3.fromValues(x + width, y + height, 0), this.vpMatrix, ); - const ix = Math.floor(tl[0]); - const iy = Math.floor(tl[1]); - const iwidth = Math.ceil(br[0] - tl[0]); - const iheight = Math.ceil(br[1] - tl[1]); + const minx = Math.min(tl[0], tr[0], br[0], bl[0]); + const miny = Math.min(tl[1], tr[1], br[1], bl[1]); + const maxx = Math.max(tl[0], tr[0], br[0], bl[0]); + const maxy = Math.max(tl[1], tr[1], br[1], bl[1]); + + const ix = Math.floor(minx); + const iy = Math.floor(miny); + const iwidth = Math.ceil(maxx - minx); + const iheight = Math.ceil(maxy - miny); context.save(); this.clearRect(context, ix, iy, iwidth, iheight); @@ -244,7 +254,12 @@ export class CanvasRendererPlugin implements RenderingPlugin { if (enableDirtyRectangleRenderingDebug) { canvas.dispatchEvent( new CustomEvent(CanvasEvent.DIRTY_RECTANGLE, { - dirtyRect, + dirtyRect: { + x: ix, + y: iy, + width: iwidth, + height: iheight, + }, }), ); } @@ -507,19 +522,19 @@ export class CanvasRendererPlugin implements RenderingPlugin { // apply clip shape's RTS if (matrix) { mat4.copy(this.tmpMat4, object.getLocalTransform()); - this.tmpVec3[0] = tx; - this.tmpVec3[1] = ty; - this.tmpVec3[2] = 0; - mat4.translate(this.tmpMat4, this.tmpMat4, this.tmpVec3); + this.vec3a[0] = tx; + this.vec3a[1] = ty; + this.vec3a[2] = 0; + mat4.translate(this.tmpMat4, this.tmpMat4, this.vec3a); mat4.multiply(this.tmpMat4, matrix, this.tmpMat4); mat4.multiply(this.tmpMat4, this.vpMatrix, this.tmpMat4); } else { // apply RTS transformation in world space mat4.copy(this.tmpMat4, object.getWorldTransform()); - this.tmpVec3[0] = tx; - this.tmpVec3[1] = ty; - this.tmpVec3[2] = 0; - mat4.translate(this.tmpMat4, this.tmpMat4, this.tmpVec3); + this.vec3a[0] = tx; + this.vec3a[1] = ty; + this.vec3a[2] = 0; + mat4.translate(this.tmpMat4, this.tmpMat4, this.vec3a); mat4.multiply(this.tmpMat4, this.vpMatrix, this.tmpMat4); } diff --git a/packages/site/docs/api/renderer/canvas.en.md b/packages/site/docs/api/renderer/canvas.en.md index 03ab0bbd4..d196a697b 100644 --- a/packages/site/docs/api/renderer/canvas.en.md +++ b/packages/site/docs/api/renderer/canvas.en.md @@ -97,14 +97,13 @@ canvas.addEventListener(CanvasEvent.DIRTY_RECTANGLE, (e) => { const { dirtyRect } = e.detail; const { x, y, width, height } = dirtyRect; - // convert from canvas coords to viewport - const tl = canvas.canvas2Viewport({ x, y }); - const br = canvas.canvas2Viewport({ x: x + width, y: y + height }); + const dpr = window.devicePixelRatio; - $dirtyRectangle.style.left = `${tl.x}px`; - $dirtyRectangle.style.top = `${tl.y}px`; - $dirtyRectangle.style.width = `${br.x - tl.x}px`; - $dirtyRectangle.style.height = `${br.y - tl.y}px`; + // convert from canvas coords to viewport + $dirtyRectangle.style.left = `${x / dpr}px`; + $dirtyRectangle.style.top = `${y / dpr}px`; + $dirtyRectangle.style.width = `${width / dpr}px`; + $dirtyRectangle.style.height = `${height / dpr}px`; }); ``` diff --git a/packages/site/docs/api/renderer/canvas.zh.md b/packages/site/docs/api/renderer/canvas.zh.md index a90d03932..ff8294d08 100644 --- a/packages/site/docs/api/renderer/canvas.zh.md +++ b/packages/site/docs/api/renderer/canvas.zh.md @@ -97,14 +97,13 @@ canvas.addEventListener(CanvasEvent.DIRTY_RECTANGLE, (e) => { const { dirtyRect } = e.detail; const { x, y, width, height } = dirtyRect; - // convert from canvas coords to viewport - const tl = canvas.canvas2Viewport({ x, y }); - const br = canvas.canvas2Viewport({ x: x + width, y: y + height }); + const dpr = window.devicePixelRatio; - $dirtyRectangle.style.left = `${tl.x}px`; - $dirtyRectangle.style.top = `${tl.y}px`; - $dirtyRectangle.style.width = `${br.x - tl.x}px`; - $dirtyRectangle.style.height = `${br.y - tl.y}px`; + // convert from canvas coords to viewport + $dirtyRectangle.style.left = `${x / dpr}px`; + $dirtyRectangle.style.top = `${y / dpr}px`; + $dirtyRectangle.style.width = `${width / dpr}px`; + $dirtyRectangle.style.height = `${height / dpr}px`; }); ``` diff --git a/packages/site/examples/event/demo/coordinates.js b/packages/site/examples/event/demo/coordinates.js index c0c048eb1..ad8d993e2 100644 --- a/packages/site/examples/event/demo/coordinates.js +++ b/packages/site/examples/event/demo/coordinates.js @@ -8,7 +8,9 @@ import * as lil from 'lil-gui'; import Stats from 'stats.js'; // create a renderer -const canvasRenderer = new CanvasRenderer(); +const canvasRenderer = new CanvasRenderer({ + enableDirtyRectangleRenderingDebug: true, +}); const webglRenderer = new WebGLRenderer(); const svgRenderer = new SVGRenderer(); const canvaskitRenderer = new CanvaskitRenderer({ @@ -123,6 +125,27 @@ canvas.addEventListener(CanvasEvent.READY, () => { } }); + // display dirty rectangle + const $dirtyRectangle = document.createElement('div'); + $dirtyRectangle.style.cssText = ` + position: absolute; + pointer-events: none; + background: rgba(255, 0, 0, 0.5); + `; + $wrapper.appendChild($dirtyRectangle); + + canvas.addEventListener(CanvasEvent.DIRTY_RECTANGLE, (e) => { + const { dirtyRect } = e.detail; + const { x, y, width, height } = dirtyRect; + const dpr = window.devicePixelRatio; + + // convert from canvas coords to viewport + $dirtyRectangle.style.left = `${x / dpr}px`; + $dirtyRectangle.style.top = `${y / dpr}px`; + $dirtyRectangle.style.width = `${width / dpr}px`; + $dirtyRectangle.style.height = `${height / dpr}px`; + }); + // GUI const gui = new lil.GUI({ autoPlace: false }); $wrapper.appendChild(gui.domElement); diff --git a/packages/site/examples/perf/demo/canvas-dirty-rectangle.js b/packages/site/examples/perf/demo/canvas-dirty-rectangle.js index f4d2510e7..84c0d39a9 100644 --- a/packages/site/examples/perf/demo/canvas-dirty-rectangle.js +++ b/packages/site/examples/perf/demo/canvas-dirty-rectangle.js @@ -110,12 +110,11 @@ $wrapper.appendChild($dirtyRectangle); canvas.addEventListener(CanvasEvent.DIRTY_RECTANGLE, (e) => { const { dirtyRect } = e.detail; const { x, y, width, height } = dirtyRect; + const dpr = window.devicePixelRatio; - const tl = canvas.canvas2Viewport({ x, y }); - const br = canvas.canvas2Viewport({ x: x + width, y: y + height }); - - $dirtyRectangle.style.left = `${tl.x}px`; - $dirtyRectangle.style.top = `${tl.y}px`; - $dirtyRectangle.style.width = `${br.x - tl.x}px`; - $dirtyRectangle.style.height = `${br.y - tl.y}px`; + // convert from canvas coords to viewport + $dirtyRectangle.style.left = `${x / dpr}px`; + $dirtyRectangle.style.top = `${y / dpr}px`; + $dirtyRectangle.style.width = `${width / dpr}px`; + $dirtyRectangle.style.height = `${height / dpr}px`; });