Frontend Rendering
This guide is targeted towards developers working with Arcentry's code-base. If you are an end-user, please consult the REST-API and Api-Docs documentation instead. If you are an enterprise customer, please find information in the Enterprise section of the documentation.
Arcentry diagrams are drawn on an HTML5 Canvas element using WebGL.
Arcentry internally builds up a Scene-Graph, starting at canvas.scene and adding all elements such as 3D components, 2D planes, cameras, and lights in a hierarchical fashion.
On every browser frame (usually around 60 times a second), this scene graph is rendered and displayed as an image. This happens in the render function of arc-frontend/src/js/canvas/canvas.js. This rendering happens entirely on the GPU and is reasonably efficient in terms of performance.
2D Drawing
2D shapes, such as lines, areas, icons, labels, and images, however, are a harder problem. To draw these, Arcentry places a total of 3 planes at y=0, each responsible for a different aspect of drawing:
- the grid plane (src\js\plane\grid.js) draws the line grid
- the pixel plane (src\js\pixel\pixel-plane.js) draws long-term shapes such as lines, areas, icons, labels, and images
- the interaction plane (src\js\plane\interaction-plane.js) draws short-lived effects, such as hover and selection highlighting, selection rectangles, line drawing helpers, placement crosshairs, etc.
All drawing planes are instances of AbstractPlane (src\js\plane\abstract-plane.js). Each plane has an associated 2D Canvas element on which shapes are drawn. This canvas element's pixel data is subsequently passed to the GPU and used as a texture for the plane object in the 3D space. In terms of performance, this is a relatively expensive operation, and Arcentry takes several steps to limit this to the absolute minimum. Here's how this works:
As Arcentry's viewport can be panned and zoomed, 2D planes are pretty much infinite in size. The associated 2D canvas on which the textures are drawn however, measures only 2048x2048px.
This means that Arcentry only draws a subset of shapes onto it and updates these, based on the currently visible part of the plane and its Zoom level.
This is achieved by wrapping the Canvas drawing API in AbstractPlane into higher-level functions that keep a backlog of drawing instructions. This backlog is replayed whenever the camera moves or zooms to create crystal clear shapes at every resolution.
When and where does this drawing happen?
Drawing in Arcentry is somewhat detached from the operation that triggered it. Whenever a change occurs that requires a redraw, this change is reflected in an object's state. The class representing the object, e.g. Area (src\js\line\area.js), LineGroup (src\js\line\line-group.js) or PixelObject (src\js\pixel\pixel-object.js) for Images and Icons then calls scheduleRender() on the plane it wishes to draw upon.
Schedule render doesn't render immediately, but simply notes the need to redraw on the next browser frame. This allows for multiple operations to be performed before a redraw is triggered.
On the next browser frame, the drawing plane clears its contents and emits a 'render' event. This event is picked up by any number of renderers associated with the plane, e.g. the AreaRenderer(src\js\line\area-renderer.js), LineRenderer (src\js\line\line-renderer.js) or PixelObjectRenderer (src\js\pixel\pixel-object-renderer.js). These renderers perform the actual steps necessary to draw the shapes.
Finally, the AbstractPlane flags its texture for updating which pulls the transmits the pixel data from the canvas to the GPU and applies it as a texture the next time the scene is rendered.