Canvas and widgets
<Canvas />
is a main component to display a scrollable canvas for the diagram with elements, links and additional widgets.
Customizing element and link appearance
It is possible to customize how elements (nodes) and links (edges) are rendered on the canvas by providing elementTemplateResolver
(TypedElementResolver
) and/or linkTemplateResolver
(LinkTemplateResolver
) props to the <Canvas />
.
An element or link template is an object with rendering function (returning a React component to display it) and additional rendering settings such as element shape, link markers, etc.
An element template is an ElementTemplate
object with rendering function (returning a React component to display the element) and additional settings, such as element shape (rectangular or elliptical).
A link template is a LinkTemplate
object with rendering function (returning a React component to display the link) and additional settings, such as link markers (mini-shapes on its endpoints, e.g. arrowheads) and path spline type (straight or smooth).
The library provides the following built-in templates:
Template | Type | Description |
---|---|---|
StandardTemplate | element | Default (fallback) template for an element; supports single entity elements and entity groups. Uses StandardEntity and StandardEntityGroup components to render elements. |
ClassicTemplate | element | Element template component with classic "look and feel" which was used for elements before v0.8; does not support entity groups. Uses ClassicEntity component to render elements. |
RoundTemplate | element | Basic element template with an round (elliptical) shape; does not support entity groups. Uses RoundEntity component to render elements. |
DefaultLinkTemplate | link | Default (fallback) template for a link; supports single relation links and relation groups. Uses DefaultLink component to render links which uses LinkPath , LinkLabel and LinkVertices components inside to display the link connection itself, the labels and vertices (to change link geometry). |
Additionally, it is possible to override how the link are routed (how default path geometry is computed) on the canvas by providing linkRouter
(LinkRouter
) prop to the <Canvas />
. By default, the DefaultLinkRouter
is used which moves apart multiple links between same elements and displays self-links (where target is equal to source) as loops.
Element decorations
To further customize element rendering the library provides <ElementDecoration />
component to display a decoration over a canvas element. These decorations are rendered outside the element template content itself and does not contribute to the measured size of an element.
All decorations for a specific entity are rendered as children of a DOM element with reactodia-element-decorators
CSS class which immediately follows each target canvas element in the DOM. Such parent DOM elements for the decorations have transform: translate(...)
, width
and height
set to the same values as the target element to be able to layout decoration content via CSS:
/* Position decoration to the left of the target canvas element */
.my-custom-decoration {
position: absolute;
top: 50%;
left: -10px;
transform: translate(-100%,-50%);
}
/* Show decoration on hover over it or target canvas element */
.reactodia-overlaid-element:hover + .reactodia-element-decorations .my-custom-decoration,
.my-custom-decoration:hover {
opacity: 1;
}
See complete style customization example with custom element and link templates, element decorations and more.
Getting the canvas instance
useCanvas()
hook called from a canvas widget can be used to get the CanvasApi
instance from a context to read or subscribe to the canvas state or perform viewport-related effects:
function MyWidget() {
const {canvas} = Reactodia.useCanvas();
// Use canvas here
}
Alternatively, with SharedCanvasState.findAnyCanvas()
or SharedCanvasState.findAllCanvases()
methods it is possible to get canvas instance outside the canvas component:
function NonWidgetComponent {
const {view} = React.useWorkspace();
const canvas = view.findAnyCanvas();
if (canvas) {
// Use canvas here (could be any if there are several of them)
}
for (const canvas of view.findAllCanvases()) {
// Use each canvas mounted in the workspace
}
}
Canvas widgets
Canvas widget is an instance of any React component type which is marked by defineCanvasWidget() function with metadata such as its attachment layer i.e. where the component should be displayed in relation to other canvas content.
There are multiple canvas layers to place widgets on, from top one to the bottom:
Layer name | Coordinate type | Description |
---|---|---|
viewport | client (viewport) | Topmost layer, does not scale or scroll with the diagram. |
overElements | paper | Displayed over both elements and links, scales and scrolls with the diagram. |
overLinks | paper | Displayed under elements but over links, scales and scrolls with the diagram. |
Example: custom viewport widget
function CustomSelectAllWidget() { const {model} = Reactodia.useWorkspace(); return ( <Reactodia.ViewportDock dock='ne'> <button type='button' className='reactodia-btn reactodia-btn-default' onClick={() => model.setSelection([...model.elements])}> Select All </button> </Reactodia.ViewportDock> ); } Reactodia.defineCanvasWidget( CustomSelectAllWidget, element => ({element, attachment: 'viewport'}) ); function Example() { const {defaultLayout} = Reactodia.useWorker(Layouts); const {onMount} = Reactodia.useLoadedWorkspace(async ({context, signal}) => { const {model, view, performLayout} = context; model.createElement('http://example.com/entity1'); model.createElement('http://example.com/entity2'); model.createLinks({ sourceId: 'http://example.com/entity1', targetId: 'http://example.com/entity2', linkTypeId: 'http://example.com/connectedTo', properties: {}, }); await performLayout({signal}); }, []); return ( <div className='reactodia-live-editor'> <Reactodia.Workspace ref={onMount} defaultLayout={defaultLayout}> <Reactodia.DefaultWorkspace search={null} canvasWidgets={[<CustomSelectAllWidget key='select-all' />]} /> </Reactodia.Workspace> </div> ); } render(<Example />);
Exporting the canvas
It is possible to export a "snapshot" of currently rendered canvas content into an SVG (with HTML parts) or a raster image:
Canvas API method | Description |
---|---|
exportSvg() | Exports the diagram as a serialized into text SVG document with <foreignObject> HTML layers inside. (Can be opened by the browser but not with a pure SVG image editor.) |
exportRaster() | Exports the diagram as a rendered raster image (e.g. PNG, JPEG, etc) serialized into base64-encoded data URL. |
When exporting into an SVG, the resulting document would include all diagram content as well as every CSS rule which applies to any DOM element inside the diagram content.
If possible, every image referenced from <img>
elements, mask
(mask-image
) and background
(background-image
) CSS properties are fetched and embedded as base64 data URL strings. To ensure that images can be embedded (to export the diagram as a complete raster image) it is required that a used image can be loaded into a <img crossorigin="anonymous">
element.
Diagram is always exported in the light theme.
To prevent being exported a DOM element can be marked with data-reactodia-no-export
attribute or additional CSS selectors can be provided via removeByCssSelectors
options to the export methods.
Printing the diagram can be achieved by exporting an SVG, writing it into a newly opened window and printing it:
const printWindow = window.open('', undefined, 'width=1280,height=720')!;
const svg = await canvas.exportSvg();
printWindow.document.write(svg);
printWindow.document.close();
printWindow.print();
The library provides a built-in toolbar
action component <ToolbarActionExport />
as a convenient way to export or print the diagram from the UI.
Styles
The component look can be customized using the following CSS properties (see design system for more information):
Property | Description |
---|---|
--reactodia-canvas-background-color | Background color for the canvas. |
--reactodia-canvas-box-shadow | Box shadow for the UI components layered on top of the canvas. |
--reactodia-canvas-overlay-color | Semi-transparent color to place over canvas content when displaying a modal on top. |
--reactodia-canvas-underlay-color | Semi-transparent color to place under components for improved readability when they are placed on the canvas. |
--reactodia-element-background-color | Default background color for the graph elements displayed on the canvas. |
--reactodia-link-stroke-color | Default stroke color for the graph links displayed on the canvas. |
--reactodia-monochrome-icon-filter | CSS filter for the monochrome type style icons. |
--reactodia-viewport-dock-margin | Margin from the borders of the canvas for the viewport widgets. |