Honeycomb (Hexagon Cells) in Vue
Using ApexCharts with Vue
This Honeycomb (Hexagon Cells) example wires ApexCharts into Vue through the vue3-apexcharts component.
Install it with npm install vue3-apexcharts apexcharts, then mount the chart with <apexchart type="..." :options="options" :series="series" />.
<template>
<div>
<div id="chart">
<apexchart
type="heatmap"
height="420"
:options="chartOptions"
:series="series"
></apexchart>
</div>
</div>
</template>
<script>
import VueApexCharts from 'vue-apexcharts'
// Seeded PRNG so the honeycomb is identical on every load (stable snapshots).
var __seed = 0x51ab3c21
function rand() {
__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
}
// Signal strength across the floor: distance falloff from two access points
// plus gentle noise, so the color bands form contiguous regions instead of
// random speckle.
var ROWS = 12
var COLS = 20
var accessPoints = [
{ col: 4, row: 3 },
{ col: 14, row: 8 },
]
function coverage(col, row) {
var best = 0
for (var k = 0; k < accessPoints.length; k++) {
var dx = col - accessPoints[k].col
var dy = (row - accessPoints[k].row) * 1.6
var d = Math.sqrt(dx * dx + dy * dy)
best = Math.max(best, 96 - d * 7.5)
}
return Math.max(8, Math.min(100, Math.round(best + (rand() - 0.5) * 10)))
}
// First series renders as the bottom row, so build L..A to read A..L top-down.
function generateFloor() {
var series = []
for (var r = ROWS - 1; r >= 0; r--) {
var data = []
for (var c = 0; c < COLS; c++) {
data.push({ x: String(c + 1), y: coverage(c, r) })
}
series.push({ name: String.fromCharCode(65 + r), data: data })
}
return series
}
export default {
components: {
apexchart: VueApexCharts,
},
data: function () {
return {
series: generateFloor(),
chartOptions: {
chart: {
height: 420,
type: 'heatmap',
},
plotOptions: {
heatmap: {
shape: 'hexagon',
enableShades: false,
colorScale: {
ranges: [
{
from: 0,
to: 39,
name: 'Weak',
color: '#A7E0F4',
},
{
from: 40,
to: 59,
name: 'Fair',
color: '#64C6E8',
},
{
from: 60,
to: 79,
name: 'Good',
color: '#2296CB',
},
{
from: 80,
to: 100,
name: 'Excellent',
color: '#0B6E9E',
},
],
},
},
},
stroke: {
width: 2,
colors: ['#fff'],
},
dataLabels: {
enabled: false,
},
tooltip: {
y: {
title: {
// The honeycomb offsets shift each row a quarter cell off its column
// tick, so name both coordinates in the tooltip: "Zone 7 · Row D: 78"
formatter: function (seriesName, opts) {
return (
'Zone ' +
opts.w.globals.labels[opts.dataPointIndex] +
' · Row ' +
seriesName +
':'
)
},
},
},
},
xaxis: {
type: 'category',
},
title: {
text: 'Office Wi-Fi Coverage by Floor Zone',
},
},
}
},
}
</script>
<style>
#chart {
max-width: 650px;
margin: 35px auto;
}
</style>