import React from 'react'
import ReactApexChart from 'react-apexcharts'
import ApexCharts from 'apexcharts'
import './styles.css'
// Shared by the vanilla-js, React and Vue builds.
//
// One dataset, two partitions of it. The sunburst reads the hierarchy; the
// treemap reads the leaves, which are the level the two views have in common.
//
// Colour carries the identity across the switch: a team keeps its colour, so
// the tile you were looking at is the arc you end up looking at. Each branch
// owns a hue and its teams are progressively lighter shades of it.
var TREE = [
{
data: [
{
x: 'Engineering',
y: 88,
color: '#008FFB',
children: [
{ x: 'Platform', y: 34, color: '#008FFB' },
{ x: 'Product', y: 30, color: '#29A1FC' },
{ x: 'Data', y: 24, color: '#52B3FC' },
],
},
{
x: 'Design',
y: 34,
color: '#00E396',
children: [
{ x: 'Research', y: 12, color: '#00E396' },
{ x: 'Brand', y: 10, color: '#29E7A7' },
{ x: 'Systems', y: 12, color: '#52ECB8' },
],
},
{
x: 'Go to market',
y: 52,
color: '#FEB019',
children: [
{ x: 'Sales', y: 26, color: '#FEB019' },
{ x: 'Marketing', y: 15, color: '#FEBD3E' },
{ x: 'Support', y: 11, color: '#FEC963' },
],
},
],
},
]
// The leaves, flattened: a treemap has no hierarchy, so it draws the level the
// two charts share. That is also the level the morph pairs up, tile for arc.
var LEAVES = [
{
data: TREE[0].data.reduce(function (acc, parent) {
return acc.concat(
parent.children.map(function (c) {
return { x: c.x, y: c.y }
}),
)
}, []),
},
]
// A sunburst colours per node, so its colours travel with the data above. A
// treemap colours from the palette instead, one entry per tile once
// `distributed` is on, so hand it the same colours in the same order.
var LEAF_COLORS = TREE[0].data.reduce(function (acc, parent) {
return acc.concat(
parent.children.map(function (c) {
return c.color
}),
)
}, [])
function wirePartitionToggle(chart) {
var buttons = [].slice.call(document.querySelectorAll('[data-view]'))
function apply(view) {
buttons.forEach(function (b) {
b.className = b.getAttribute('data-view') === view ? 'on' : ''
})
chart.updateOptions({
chart: { type: view === 'sunburst' ? 'sunburst' : 'treemap' },
series: view === 'sunburst' ? TREE : LEAVES,
})
}
buttons.forEach(function (b) {
b.addEventListener('click', function () {
apply(b.getAttribute('data-view'))
})
})
}
const ApexChart = () => {
const [state, setState] = React.useState({
series: LEAVES,
options: {
chart: {
id: 'partition',
type: 'treemap',
width: 700,
height: 460,
toolbar: {
show: false,
},
animations: {
enabled: true,
chartTypeMorph: {
enabled: true,
speed: 900,
},
},
},
colors: LEAF_COLORS,
legend: {
show: false,
},
dataLabels: {
enabled: true,
style: {
fontSize: '12px',
},
},
plotOptions: {
treemap: {
// One palette entry per tile, taken straight from the data above, so a
// tile and the arc it becomes are the same colour. Shading is off because
// it would recolour tiles by value and break that pairing.
distributed: true,
enableShades: false,
},
sunburst: {
innerSize: '22%',
borderRadius: 2,
spacing: 1,
},
},
},
})
React.useEffect(() => {
// The react-apexcharts wrapper owns the render, so reach the live instance
// by its chart.id before wiring the toggle.
const timer = window.setInterval(() => {
const chart = ApexCharts.getChartByID('partition')
if (!chart) return
window.clearInterval(timer)
wirePartitionToggle(chart)
}, 50)
return () => window.clearInterval(timer)
}, [])
return (
<div>
<div className="wrap">
<h1>Two views of one partition</h1>
<p>
A treemap tile and a sunburst arc are both exactly one mark per row,
so switching between them is a shape change rather than a redraw: each
rectangle unrolls into the arc that holds the same team, and back.
Every team keeps its colour, so you can pick one and follow it across.
The sunburst adds the level a treemap cannot show, the parent rings,
which sweep in behind the leaves.
</p>
<div className="actions">
<button data-view="treemap" className="on">
Treemap
</button>
<button data-view="sunburst">Sunburst</button>
</div>
<div className="chart-wrap">
<div id="chart">
<ReactApexChart
options={state.options}
series={state.series}
type="treemap"
height={460}
width={700}
/>
</div>
</div>
</div>
</div>
)
}
export default ApexChart