Filter by a Product in JavaScript
Using ApexCharts with JavaScript
This Filter by a Product example uses ApexCharts.js directly in JavaScript, with no wrapper component.
Install it with npm install apexcharts, then mount the chart with new ApexCharts(element, options).render().
// Shared by the vanilla-js, React and Vue builds.
//
// Revenue ($k) per product, region and quarter. The left chart sums it per
// product; the right one per region and quarter. Clicking a product filters
// the right chart BY it without dropping anything: every column keeps its
// full revenue, faded, and the product's share is drawn solid in front.
var PRODUCTS = ['Laptops', 'Phones', 'Tablets', 'Audio']
var REGIONS = ['North', 'South']
var QUARTERS = ['Q1', 'Q2', 'Q3', 'Q4']
var REVENUE = {
Laptops: { North: [42, 38, 45, 61], South: [30, 28, 33, 44] },
Phones: { North: [55, 49, 52, 70], South: [48, 51, 47, 66] },
Tablets: { North: [18, 15, 17, 26], South: [22, 19, 21, 25] },
Audio: { North: [12, 14, 13, 21], South: [9, 11, 10, 16] },
}
function sum(a) {
return a.reduce(function (s, v) {
return s + v
}, 0)
}
function productTotal(p) {
return sum(
REGIONS.map(function (r) {
return sum(REVENUE[p][r])
}),
)
}
function regionQuarters(r, onlyProduct) {
return QUARTERS.map(function (q, k) {
return sum(
PRODUCTS.filter(function (p) {
return !onlyProduct || p === onlyProduct
}).map(function (p) {
return REVENUE[p][r][k]
}),
)
})
}
// The picked product, or null.
var picked = null
function productSeries() {
var totals = PRODUCTS.map(productTotal)
var s = { name: 'Revenue', data: totals }
// On the source chart the pick is the whole of its own column, so it stays
// solid while the others fade.
if (picked) {
s.highlightData = PRODUCTS.map(function (p, j) {
return p === picked ? totals[j] : null
})
}
return [s]
}
function quarterSeries() {
return REGIONS.map(function (r) {
var s = { name: r, data: regionQuarters(r) }
if (picked) s.highlightData = regionQuarters(r, picked)
return s
})
}
function pickProduct(index) {
var product = PRODUCTS[index]
picked = picked === product ? null : product
var readout = document.getElementById('readout')
if (readout) {
readout.innerHTML = picked
? 'Filtered by <b>' + picked + '</b>. Click it again to clear.'
: 'Click a product to filter the quarters by it.'
}
// Let the click handler unwind before both charts redraw.
Promise.resolve().then(function () {
ApexCharts.getChartByID('products').updateSeries(productSeries())
ApexCharts.getChartByID('quarters').updateSeries(quarterSeries())
})
}
var options = {
series: productSeries(),
chart: {
id: 'products',
type: 'bar',
height: 320,
toolbar: { show: false },
events: {
dataPointSelection: function (e, ctx, opts) {
pickProduct(opts.dataPointIndex)
},
},
},
colors: ['#0f766e'],
plotOptions: {
bar: { horizontal: true, barHeight: '64%', borderRadius: 3 },
},
states: { active: { filter: { type: 'none' } } },
dataLabels: { enabled: false },
xaxis: {
categories: PRODUCTS,
tickAmount: 3,
labels: {
formatter: function (v) {
return '$' + v + 'k'
},
},
},
// On the source chart the pick is its own column, so a tooltip row for the
// part would only repeat the total.
highlightFilter: {
tooltip: { show: false },
dataLabels: { value: 'whole' },
},
legend: { show: false },
title: { text: 'Revenue by product', style: { fontSize: '13px' } },
tooltip: {
y: {
formatter: function (v) {
return '$' + v + 'k'
},
},
},
}
var chart = new ApexCharts(document.querySelector('#chart'), options)
chart.render()
var options1 = {
series: quarterSeries(),
chart: {
id: 'quarters',
type: 'bar',
height: 320,
toolbar: { show: false },
},
colors: ['#2563eb', '#f59e0b'],
plotOptions: {
bar: { columnWidth: '70%', borderRadius: 3 },
},
dataLabels: { enabled: false },
stroke: { show: true, width: 1, colors: ['transparent'] },
xaxis: { categories: QUARTERS },
yaxis: {
labels: {
formatter: function (v) {
return '$' + v + 'k'
},
},
},
legend: { position: 'bottom' },
title: { text: 'Revenue by quarter', style: { fontSize: '13px' } },
tooltip: {
shared: true,
intersect: false,
y: {
formatter: function (v) {
return '$' + v + 'k'
},
},
},
}
var chart1 = new ApexCharts(document.querySelector('#chart2'), options1)
chart1.render()