Loading...
Use CanvasRenderingContext2D to draw 2D graphics. A <canvas>
element will be created in the container.
As with @antv/g
, there are two ways to use it.
After installing @antv/g-canvas
you can get the renderer from it.
import { Canvas } from '@antv/g';import { Renderer } from '@antv/g-canvas';const canvasRenderer = new Renderer();const canvas = new Canvas({container: 'container',width: 600,height: 500,renderer: canvasRenderer,});
<scriptsrc="https://unpkg.com/@antv/g-canvas/dist/index.umd.min.js"type="application/javascript">
The renderer can be obtained from the G.Canvas2D
namespace under.
const canvasRenderer = new window.G.Canvas2D.Renderer();
When creating a renderer, you can pass in some initialization configuration items, such as.
import { Renderer } from '@antv/g-canvas';const renderer = new Renderer({enableDirtyRectangleRendering: true,});
Indicates if "dirty rectangle" rendering is enabled. Enabled will improve the rendering performance in Canvas2D environment significantly. Enabled by default.
A common interaction is to highlight a shape with the mouse. In this case, only a small part of the scene has changed, so erasing the entire canvas and redrawing it is unnecessary. In analogy to the React diff algorithm that finds the smallest part of the scene that has really changed, "dirty rectangle" rendering reuses the previous frame's rendering as much as possible, drawing only the part that has changed, which is especially suitable for the Canvas2D API.
The following diagram illustrates this idea.
In the above intersection and region query, we can reuse the optimizations in the culling scheme, such as the acceleration structure. In the implementation we use RBush.
Obviously, when the number of dynamically changing objects is too large, this optimization becomes meaningless, as the "dirty rectangle" is almost equal to the whole canvas after some calculations, so it is better to just empty and redraw all objects. So 2D game rendering engines like Pixi.js, for example, are not considered built-in.
But it makes sense in relatively static scenarios like visualization, where for example only parts of the chart are updated after triggering a pickup, and the rest remains unchanged.
Used for debug, disabled by default, when enabled the canvas will trigger CanvasEvent.DIRTY_RECTANGLE
event and carry dirty rectangle information which can be used for subsequent visualization.
In this example, the current dirty rectangle that needs to be cleared is displayed as the mouse passes over the individual circles, and the current frame will only redraw the area.
Note that the coordinates of the dirty rectangle are under the Canvas coordinate system, so if you want to draw the floating layer using HTML, you need to use the coordinate system conversion method.
// display dirty rectangleconst $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`;});
The renderer has the following plug-ins built in.
In addition to the built-in plug-ins, the following optional plug-ins are available.
Use the Canvas version of rough.js for hand-drawn style rendering.
We provide g-plugin-rough-canvas-renderer plugin, which will replace g-plugin-canvas-renderer for partial 2D graphics rendering capability after registration.
This renderer relies on CanvasRenderingContext2D rendering capabilities and is not limited to the browser side, so you can also use node-canvas for server-side rendering.
In our integration test, it will be paired with node-canvas on the Node side Automattic/node-canvas) to render the result image and compare it with the baseline image. Other server-side rendering scenarios can also follow the following steps.
Canvas
object to be passed into the canvas via the canvas propertyhttps://github.com/antvis/g/blob/next/integration/nodetests__/canvas/circle.spec.js
const { createCanvas } = require('canvas');const { Circle, Canvas } = require('@antv/g');const { Renderer } = require('@antv/g-canvas');// create a node-canvasconst nodeCanvas = createCanvas(200, 200);// create a renderer, unregister plugin relative to DOMconst renderer = new Renderer();const domInteractionPlugin = renderer.getPlugin('dom-interaction');renderer.unregisterPlugin(domInteractionPlugin);const canvas = new Canvas({width: 200,height: 200,canvas: nodeCanvas, // use node-canvasrenderer,});const circle = new Circle({style: {r: 10,fill: 'red',},});canvas.appendChild(circle);// output imageconst out = fs.createWriteStream(__dirname + RESULT_IMAGE);const stream = nodeCanvas.createPNGStream();stream.pipe(out);out.on('finish', () => {});
If you want to use CanvasRenderingContext2D to continue drawing after G has drawn, you can get the context at CanvasEvent. AFTER_RENDER
to get the context when G has finished drawing, but since it is set to be transformable in the context, it needs to be cleared before drawing, and then you can draw in the Canvas native coordinate system:
// 在 G 绘制完接着画canvas.addEventListener(CanvasEvent.AFTER_RENDER, () => {// 获取原生 Canvas2DContextconst context = canvas.getContextService().getContext();// 重置 transformcontext.resetTransform();// 绘制context.fillStyle = 'red';context.fillRect(200, 200, 100, 100);});