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" />.

Vue charts guide
<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>