Activity by Location in JavaScript
Using ApexCharts with JavaScript
This Activity by Location 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().
// Six locations, each a real heatmap of day x hour check-ins, all six drawn
// against ONE colour scale derived from the union of every panel's values.
// That is the whole point of the grid: the same fill means the same count
// everywhere, so the quiet sites read as quiet. Six independently shaded
// heatmaps would give every panel its own darkest cell and the comparison
// would be a lie.
//
// Deterministic counts so the e2e snapshot is stable.
function mulberry32(seed) {
return function () {
seed |= 0
seed = (seed + 0x6d2b79f5) | 0
var t = Math.imul(seed ^ (seed >>> 15), 1 | seed)
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t
return ((t ^ (t >>> 14)) >>> 0) / 4294967296
}
}
var DAYS = ['Sun', 'Sat', 'Fri', 'Thu', 'Wed', 'Tue', 'Mon']
var HOURS = ['6a', '8a', '10a', '12p', '2p', '4p', '6p', '8p']
// Each location has its own rhythm AND its own overall volume: the commuter
// sites are busiest, the campus site is a midday hump, the lakeside site is
// small and evening-heavy. Volume differences are the point of one scale.
var LOCATIONS = [
{
name: 'Central Station',
seed: 7,
volume: 1.0,
peaks: [1, 6],
weekend: 0.45,
},
{ name: 'Harbor Point', seed: 19, volume: 0.82, peaks: [1, 6], weekend: 0.6 },
{
name: 'University Campus',
seed: 31,
volume: 0.66,
peaks: [3, 4],
weekend: 0.3,
},
{
name: 'Riverside Mall',
seed: 43,
volume: 0.58,
peaks: [4, 5],
weekend: 1.15,
},
{
name: 'Airport North',
seed: 59,
volume: 0.74,
peaks: [0, 7],
weekend: 0.95,
},
{
name: 'Lakeside Park',
seed: 71,
volume: 0.31,
peaks: [5, 6],
weekend: 1.4,
},
]
function hourlyRow(rand, loc, dayIndex) {
// DAYS runs Sun..Mon top to bottom, so weekend factor keys off the ends.
var isWeekend = dayIndex === 0 || dayIndex === 1
var dayFactor = isWeekend ? loc.weekend : 0.85 + rand() * 0.3
return HOURS.map(function (hour, hi) {
var near = Math.min(
Math.abs(hi - loc.peaks[0]),
Math.abs(hi - loc.peaks[1]),
)
var shape = Math.max(0.12, 1 - near * 0.28)
var v = 130 * loc.volume * dayFactor * shape * (0.85 + rand() * 0.3)
return { x: hour, y: Math.round(v) }
})
}
var activitySeries = []
LOCATIONS.forEach(function (loc) {
var rand = mulberry32(loc.seed)
DAYS.forEach(function (day, di) {
activitySeries.push({
name: day,
location: loc.name,
data: hourlyRow(rand, loc, di),
})
})
})
var options = {
series: activitySeries,
chart: {
id: 'activityTrellis',
type: 'heatmap',
height: 620,
animations: {
enabled: false,
},
},
trellis: {
by: 'location',
columns: 3,
minPanelWidth: 300,
gap: 14,
},
colors: ['#0E7490'],
plotOptions: {
heatmap: {
radius: 2,
enableShades: true,
shadeIntensity: 0.55,
colorScale: {
gradientLegend: {
formatter: function (val) {
return Math.round(Number(val)) + ' check-ins'
},
},
},
},
},
dataLabels: {
enabled: false,
},
stroke: {
width: 1,
colors: ['#fff'],
},
xaxis: {
type: 'category',
},
tooltip: {
compact: true,
y: {
formatter: function (val) {
return val + ' check-ins'
},
},
},
}
var chart = new ApexCharts(document.querySelector('#chart'), options)
chart.render()