Plugins
plotOptions.sankey.plugins: a registered plugin reserves a row and draws column totals, an inline plugin adds a tooltip row, another one listens to events. Hooks: reserve, afterRender, event, tooltip, describe, destroy (the same API for every premium type).
Open the chart without page chrome ↗Drawing width at least 900 px. Scroll within the chart on smaller screens.
const options = {
"chart": {
"height": 360,
"toolbar": {
"show": false
},
"type": "sankey"
},
"series": [
{
"data": [
[
"Leads",
"Qualified",
300
],
[
"Leads",
"Lost",
500
],
[
"Qualified",
"Won",
120
],
[
"Qualified",
"Lost",
180
]
]
}
],
"plotOptions": {
"sankey": {
"plugins": [
[
{
"name": "column-totals",
"defaults": {
"label": "Total",
"color": null
},
"reserve": () => ({ bottom: 26 }),
"afterRender": (p) => {
const g = p.layer()
const cols = {}
p.api.nodes().forEach((n) => {
const b = p.api.nodeBox(n.id)
const c = (cols[n.column] = cols[n.column] || { l: b.x, r: b.x + b.width, v: 0 })
c.v += n.value
})
const y = p.area.y + p.area.height + 16
const keys = Object.keys(cols)
keys.forEach((k, i) => {
const c = cols[k]
// edge columns align to the outer side so the label stays inside the chart
const anchor = i === 0 ? 'start' : i === keys.length - 1 ? 'end' : 'middle'
const x = anchor === 'start' ? c.l : anchor === 'end' ? c.r : (c.l + c.r) / 2
p.text(g, x, y, p.options.label + ' ' + c.v.toLocaleString('en-US'), p.font(11, 600, p.options.color || p.theme.muted, { 'text-anchor': anchor }))
})
},
"describe": () => 'Column totals are shown below the diagram.'
},
{
"label": "Σ"
}
],
{
"name": "share-of-column",
"tooltip": (content, p) => {
const pl = content.payload
if (!pl || pl.kind !== 'node') return content
const col = p.api.nodes().filter((n) => n.column === pl.node.column)
const sum = col.reduce((s, n) => s + n.value, 0)
content.rows.push({ label: 'Share of column (plugin)', value: Math.round((pl.node.value / sum) * 100) + '%' })
return content
}
},
{
"name": "event-log",
"event": (name, e, o) => { if (name === 'dataPointSelection' && o && o.node) console.log('plugin saw ' + name + ': ' + o.node.name) }
}
]
}
},
"theme": {
"mode": "light",
"preset": "coastal"
}
}
const chart = new WestCoastCharts(document.querySelector('#chart'), options)
chart.render()import WestCoastCharts from 'west-coast-charts'
import types from 'west-coast-charts/types'
import premium from 'west-coast-charts/premium'
WestCoastCharts.use(types).use(premium)
const WestCoastChartsPremium = premium
WestCoastCharts.setLicenseKey(LICENCE_KEY) // paid production licence; localhost evaluation needs no key
const options = {
"chart": {
"height": 360,
"toolbar": {
"show": false
},
"type": "sankey"
},
"series": [
{
"data": [
[
"Leads",
"Qualified",
300
],
[
"Leads",
"Lost",
500
],
[
"Qualified",
"Won",
120
],
[
"Qualified",
"Lost",
180
]
]
}
],
"plotOptions": {
"sankey": {
"plugins": [
[
{
"name": "column-totals",
"defaults": {
"label": "Total",
"color": null
},
"reserve": () => ({ bottom: 26 }),
"afterRender": (p) => {
const g = p.layer()
const cols = {}
p.api.nodes().forEach((n) => {
const b = p.api.nodeBox(n.id)
const c = (cols[n.column] = cols[n.column] || { l: b.x, r: b.x + b.width, v: 0 })
c.v += n.value
})
const y = p.area.y + p.area.height + 16
const keys = Object.keys(cols)
keys.forEach((k, i) => {
const c = cols[k]
// edge columns align to the outer side so the label stays inside the chart
const anchor = i === 0 ? 'start' : i === keys.length - 1 ? 'end' : 'middle'
const x = anchor === 'start' ? c.l : anchor === 'end' ? c.r : (c.l + c.r) / 2
p.text(g, x, y, p.options.label + ' ' + c.v.toLocaleString('en-US'), p.font(11, 600, p.options.color || p.theme.muted, { 'text-anchor': anchor }))
})
},
"describe": () => 'Column totals are shown below the diagram.'
},
{
"label": "Σ"
}
],
{
"name": "share-of-column",
"tooltip": (content, p) => {
const pl = content.payload
if (!pl || pl.kind !== 'node') return content
const col = p.api.nodes().filter((n) => n.column === pl.node.column)
const sum = col.reduce((s, n) => s + n.value, 0)
content.rows.push({ label: 'Share of column (plugin)', value: Math.round((pl.node.value / sum) * 100) + '%' })
return content
}
},
{
"name": "event-log",
"event": (name, e, o) => { if (name === 'dataPointSelection' && o && o.node) console.log('plugin saw ' + name + ': ' + o.node.name) }
}
]
}
},
"theme": {
"mode": "light",
"preset": "coastal"
}
}
const chart = new WestCoastCharts(document.querySelector('#chart'), options)
await chart.render() Waiting for the chart.
Open Data & agent view to read this chart through chart.describe().
Read from the running library through its optional agent/describe module. Text, table and JSON share the same snapshot. Demo data only.
$ wcc chart export sankey-plugins.json --out sankey-plugins.svg --with-table Public agent tools 0.2.3, tested with Library 1.1.5; available from the versioned GitHub release and npm. Save a JSON spec first and check the loaded runtime and supported modules before rendering. Command reference
Loading /gallery/sankey/plugins/index.md … This example uses Premium modules. Compare licences · Embedding in a distributed product?