Enhance your GoJS diagram with a palette for inserting nodes, grid snapping, and auto-layouts for a polished, interactive application.
Recently I’ve explained how to create a GoJS diagram, as well as how to set and style edges. In order to make the diagram fully interactive, we still need to give the option of inserting elements. To do this, we’ll create a palette built into GoJS.
A palette is a separate canvas that displays all the nodes defined in it and allows you to transfer them to the main diagram. It is configured in a manner analogical to the diagram, but through the creation of a go.Palette object. However, in order to do this, we should first add an additional div to the HTML file where the palette will be contained. We can also add a function to initialize the palette in the JS file, which we will also make available outside (initPalette). In our example, we’ll put the palette next to the diagram. Here’s how we will edit the HTML file:
<div id="palette-content" style="height: 800px; width: 200px; display: inline-block; border: 1px solid black"></div><div id="diagram-content" style="height: 800px; width: calc(100% - 220px); display: inline-block; border: 1px solid black;"></div><script>window.onload = function() {diagram.initDiagram();diagram.initPalette();};</script>
view rawindex.html hosted with ❤ by GitHub
The next step is to complete the initPalette function we’ve created. As I mentioned earlier, initialization of the palette isn’t very different from initialization of the diagram. Here we will use our getTemplates() function for the second time – when we do this, we don’t have to define the appearance of the shapes again, just for the palette. However, it should be stressed that we can create still other appearances for shapes – when moving to the diagram, what’s important is the element’s category, not its appearance. In addition, to enable transfer from the palette to the diagram, we need to add the allowDrop field to the diagram initialization and set its value to true. Here’s what the code should look like:
var initDiagram = function () {diagram = $(go.Diagram,'diagram-content', {initialContentAlignment: go.Spot.Center,allowDrop: true});// ...}var initPalette = function () {palette = $(go.Palette, 'palette-content');getTemplates().forEach(x => palette.nodeTemplateMap.add(x.category, x.template));palette.model.nodeDataArray = [{key: 1, category: 'first'},{key: 2, category: 'second'},{key: 3, category: 'third'}]}
view rawdiagram.js hosted with ❤ by GitHub
Now here’s what the application will look like:
At the end, in order to improve the appearance of the application, let’s add two more things: a grid the elements will be snapped to, and their auto-positioning.
Let's start with the grid. You’ll find it under diagram.grid, and the only thing we have to do is change its visible property to true. In order to add dragging, it has to be configured in the built-in drag tool available under diagram.toolManager.draggingTool. We can use two properties here: isGridSnapEnabled to enable dragging and gridSnapCellSize to define the size of the grid (for our example let’s define a size of 50x50). If we’re using node size modification (resizingTool), we would set analogous fields in it as well. Here’s the code that will be responsible for setting the grid:
diagram.grid.visible = true;diagram.toolManager.draggingTool.isGridSnapEnabled = true;diagram.toolManager.draggingTool.gridSnapCellSize = new go.Size(50, 50);
view rawdiagram.js hosted with ❤ by GitHub
The easiest way to position the elements is by changing the layout of the diagram. The default layout does not define any automatic arrangement of elements – it only arranges them so that they don’t overlap each other. However, this is offered by other layouts: GridLayout (placement on the grid), TreeLayout (tree), ForceDirectedLayout (graphs pushing the elements away from each other), LayeredDigraphLayout (graph arranged in columns and rows) and CircularLayout (arrangement of nodes on a circle).
We set the layout as another field during initialization of the diagram – a layout we pass a new instance of the selected layout to, along with its possible configuration. Here’s an example of how we can implement it for LayeredDigraphLayout:
diagram = $(go.Diagram,'diagram-content', {initialContentAlignment: go.Spot.Center,allowDrop: true,layout: $(go.LayeredDigraphLayout)});
view rawdiagram.js hosted with ❤ by GitHub
The effect is presented in Figure 3.
You can also check out other available layouts, but you need to keep their limitations in mind. For example, TreeLayout won’t be able to handle a situation where two edges lead to one node.
Results of the whole tutorial you can check on the GitHub repository or on Codepen:
As you’ve definitely understood reading this article, we have developed an advanced application without a lot of work, using just the functionality of the GoJS library without additional hacking. There’s a total of around 120 lines of JavaScript code, which shows clearly that we haven’t done anything difficult. GoJS allows us to save a lot of time that we would otherwise spend on creating a palette, handling elements on the canvas, or other nontrivial things like automatic positioning of elements. This library also offers other advantages, such as transparent documentation, lots of ready examples, and very good support from the producer. TypeScript users will be also satisfied because official typings are made available, as well as free extensions of the library written in TypeScript.
As much as we’d like to, it was impossible to present all the capabilities of the library in this series of articles. We strongly encourage you to go through the examples available on the developer's website.