Connecting charts
One of the key requirements of a dashboard is the ability to connect charts to your model. VisuallyJs makes this a snap. On this page we'll run through various basic scenarios, to give you a feel for what's possible.
Series based charts
We'll start with a simple example - in this canvas we have a set of nodes that display a value they are tracking.
- Click the +/- buttons to increment/decrement the value.
- Click in whitespace to add a new node at the location you clicked, with a random new value between 0 and 15.
Column chart
There are 3 parts to this currently - the component we use to render each node, the component for the app, and then the wrapper for the app.
- Component
- Node
- App
The component uses a DashboardExampleNode to render each node, and sets zoomToFit:true, to fit all the nodes in the canvas on load. Then it registers a canvasClick event handler, which adds a new node with a random value at the location the user clicked.
export default function DashboardExampleSurface1() {
<SurfaceComponent viewOptions={{
nodes: {
default: {
jsx: DashboardExampleNode
}
}
}} data={data1} renderOptions={{
zoomToFit: true,
events: {
"canvasClick": (s, e) => {
const pos = s.mapEventLocation(e)
s.model.addNode({
left: pos.x,
top: pos.y,
id: (uuid()).substring(0, 6),
value: Math.floor(Math.random() * 15)
})
}
}
}}>
<ControlsComponent style={{zIndex: "50"}}/>
<GridBackgroundComponent/>
</SurfaceComponent>
}
The node component shows the node id and value, plus the +/- buttons to adjust the value. These buttons call updateNode to adjust the current value.
export default function DashboardExampleNode({data, obj, model}) {
return <div className="vjs-dashboard-node">
<span className="vjs-dashboard-id">{data.id}</span>
<div className="df aic w-100" style={{justifyContent: "center"}}>
<button onClick={() => model.updateNode(obj, {value:Math.max(0, data.value - 1)})}>-</button>
<span className="vjs-dashboard-value">{data.value}</span>
<button onClick={() => model.updateNode(obj, {value:data.value + 1})}>+</button>
</div>
</div>
}
The code for the component itself is in the 'Component' tab. We've written
<div className="vjs-dashboard-example-1">
<DashboardExampleSurface1/>
</div>
Node data
The data for each node in this app looks like this:
{
id:"1",
left:50,
top:190,
label:"One",
value:5
}
Adding the chart
To help users make sense of what they're seeing, we're going to add a column chart to this UI, plotting the value field of each node.
To do this, we introduced a SurfaceProvider to our wrapper:
<div className="vjs-dashboard-example-1">
<SurfaceProvider>
<DashboardExampleSurface1/>
<DashboardExampleChart1/>
</SurfaceProvider>
</div>
and the code for DashboardExampleChart1 looks like this:
export default function DashboardExampleChart1() {
return <ColumnChartComponent options={{
title: { text: "Node Values" },
categoryAxis: {
title: { text: "Node Id" }
},
valueAxis: {
title: { text: "Value" }
},
series: [{ valueField: "value", color:"midnightblue" }],
tooltip: { format: "{{category}}:{{point.value}}" }
}}/>
}
The key points to note are:
- The column chart component is context aware, and finds the surface (and its model) to attach to automatically
- The
valueField:"value"chart option is what tells the chart where to find the values to display.
Now whenever there are changes to the model, the chart is repainted. Try clicking the +/- buttons and seeing how the chart redraws, or clicking into whitespace to add a new node. The chart is also fully integrated with the undo/redo buttons.
Pie Chart
The above example uses a column chart, but there are a number of series based charts in VisuallyJs, each of which can be dropped in for the column chart above. For example, we'll use this code for the chart instead, to show a pie chart comparing the value field in each node:
<div className="vjs-dashboard-example-1">
<SurfaceProvider>
<DashboardExampleSurface1/>
<PieChartComponent options={{
colors:["#456789"],
title: { text: "Node Values" },
series: [{ valueField: "value" }],
tooltip: { format: "{{category}}:{{point.value}}" }
}}/>
</SurfaceProvider>
</div>
Dual value axis charts
Charts with two value axes - such as bubble and scatter charts - are easily integrated too.
Scatter Chart
Here's a scatter chart which tracks the location of the nodes on the canvas (perhaps not the most useful application, but fun!):
This is the code:
<SurfaceProvider>
<DashboardExampleSurface1/>
<ScatterChartComponent options={{
title:{ text:"Node location" },
series:[{
xAxisField:"left",
yAxisField:"top",
color:"#569934"
}],
yAxis:{
inverted:true
},
tooltip:{
format:"<b>Node: </b>{{point.id}}<b>Value: </b>{{point.value}}<b>Left: </b>{{point.left}}<b>Top: </b>{{point.top}}"
}}}/>
</SurfaceProvider>
Points to note are:
- We map
xAxisFieldtoleftandyAxisFieldtotop- these are the properties used to position nodes on the canvas. - We mark
yAxisasinverted:true. By default, the Y axis in a dual value chart has its minimum value in the lower left corner, but that is the opposite way to the way that browsers measure Y. So marking the y axisinvertedmeans that the scatter points correctly map the Y axis of the nodes in the canvas.
Bubble Chart
This bubble chart extends the view provided by the scatter chart above to map the value field from each node to the bubble size:
- As with the scatter chart, we map
xAxisFieldtoleftandyAxisFieldtotop - We mark
yAxisasinverted:true- see discussion for scatter chart above - We map
valueFieldtovalue, meaning that the size of each bubble is proportional to thevaluein the node it represents.
Bubble charts have a default maximum bubble size of 50 pixels and a default minimum size of 8 pixels. This is to prevent large discrepancies in data values from resulting in bubbles of widely different sizes in the chart. This maximum and minimum can be changed in the chart options.