Advanced chart
Note
This feature is only available with the Business service plan.
With this type of visualization, you can create HTML with secure markup using the Editor.generateHtml(args) function and flexible SVG visualizations using the d3
, d3-chord
, and d3-sankey
libraries.
On the Prepare tab, you need to create a structure:
module.exports = {
render: Editor.wrapFn(...),
};
Learn more about the Editor.wrapFn method.
Note
Advanced charts are slower than other visualizations. We recommend using them only when required, e.g., where regular charts fall short.
Getting started with an advanced chart
-
To render a chart, define the
render
function:module.exports = { render: Editor.wrapFn({ fn: function() { return 'Hello, world!'; }, }) };
-
Add the required markup:
module.exports = { render: Editor.wrapFn({ fn: function() { const content = 'Hello, world!'; return Editor.generateHtml(` <div style="display: flex; background: black;"> ${content} </div> `); }, }) };
-
To use data from the server, set up the arguments and provide them to the function:
// Prepare the data for chart rendering. const content = 'Hello, world!'; module.exports = { render: Editor.wrapFn({ // The first argument will always contain the chart parameters. // The variables from `args` come next. fn: function(options, content) { const {width, height} = options; return Editor.generateHtml(` <div style="width: ${width}; height: ${height}"> ${content} </div> `); }, args: [content], }) };
To reduce the client's browser load, we recommend sorting and grouping data before sending it to the render
function.
Connecting third-party libraries
You can add third-party libraries to the chart function using the libs
parameter in wrapFn
:
module.exports = {
render: Editor.wrapFn({
fn: function(options) {
const {width, height} = options;
const element = d3.create('svg')
.attr('width', width)
.attr('height', height);
element
.append('g')
.append('text')
.text('Hello, world!')
.style('alignment-baseline', 'before-edge');
return Editor.generateHtml(element.node());
},
libs: ['d3'],
})
};
Available libraries:
'date-utils@2.3.0'
'date-utils@2.5.3' (alias: 'date-utils')
'd3@7.9.0' (alias: 'd3')
'd3-chord@3.0.1' (alis: 'd3-chord')
'd3-sankey@0.12.3' (alias: 'd3-sankey')
Available methods
The entire advanced chart code runs in a QuickJs-based sandbox, limiting access to browser API methods and the DOM. Synthetic document
elements which are not connected to the external environment are available to work with the element tree.
To facilitate data management internally, extra methods are supported:
// Equivalent of browser `console.log` for code debugging
console.log(..args: unknown[])
/ Equivalent of browser `setTimeout` and `clearTimeout`
setTimeout: (handler: TimerHandler, timeout: number)
clearTimeout(timeoutId)
// For working with HTML
// When returning a string from a function without wrapping it in `generateHtml`, the data will be escaped.
Editor.generateHtml(value: string | object)
// In a chart, you can declare additional parameters that will affect the display, e.g., when working with events.
// State management methods:
// Getting the chart state
Chart.getState()
// Updating the chart state
// Calling the method will run the `render` method. To update the state without re-rendering, include {silent: true} as the second argument.
Chart.setState(state: object, options?: {silent: boolean})
// Setting cross-filtering parameters. To learn more, see the chart cross-filtering section.
Editor.updateActionParams(params)
Events
Available events:
events: {
click: Editor.wrapFn({
fn: function(event) {
...
},
}),
keydown: Editor.wrapFn({
fn: function(event) {
...
},
}),
},
Tooltip
For example:
module.exports = {
render: Editor.wrapFn({
fn: function() {
...
},
}),
tooltip: {
renderer: Editor.wrapFn({
fn: function(event, config) {
const name = event.target?.getAttribute('data-id');
if (!name) {
return null;
}
const item = config.chartData.data.find((d) => d.name === name);
return Editor.generateHtml(`<div style="padding: 20px;">${item.name}</div>`);
},
args: [chartConfig],
}),
}
};
Chart cross-filtering
For example:
const chartData = [{id: '1', OrderYear: '2024'}];
render: Editor.wrapFn({
fn: function(dimensions, data) {
...
svg.append("g")
.selectAll()
.data(data)
.enter().append('rect')
.attr('data-id', (d) => d.id)
...
},
args: [chartData],
libs: ['d3'],
}),
events: {
click: Editor.wrapFn({
fn: function(event, data) {
const dataId = event.target.getAttribute('data-id');
const selectedItem = data.find(d => d.id === dataId);
if (selectedItem) {
Chart.updateActionParams({OrderYear: selectedItem.OrderYear});
}
},
args: [chartData],
}),
},
...
Examples
Examples on the demo dashboard