<template>
  <div>
    <div class="mz-wrap">
      <div class="mz-bar">
        <button id="mz-clear">Clear</button>
        <span class="readout" id="mz-readout"
          >The ruler tool is pre-selected in the toolbar. Drag from A to B on
          the chart.</span
        >
      </div>

      <div id="chart">
        <apexchart
          type="area"
          height="380"
          :options="chartOptions"
          :series="series"
        ></apexchart>
      </div>

      <div class="mz-note">
        The ruler is a built-in <b>toolbar tool</b>, pre-selected here with
        <code>toolbar.autoSelected: 'measure'</code>. Drag across the plot: a
        shaded band spans the two points and a readout shows the <b>change</b>,
        the <b>% change</b> and the <b>range</b> between them, with the
        endpoints snapped to the price line (the finance-style default,
        <code>measure.mode: 'span'</code>). Green means the move is up, red
        means down. Release to pin it; a pinned ruler is stored in data
        coordinates, so it stays glued when you zoom or resize. Click the ruler
        icon again to deselect it and hand the plot back to zoom; the
        <code>m</code> key still works too. Fires the
        <code>measured</code> event. Set <code>measure.mode: 'free'</code> for a
        diagonal ruler between any two points. Needs the
        <code>measure</code> feature. <b>Clear</b> removes all rulers.
      </div>
    </div>
  </div>
</template>

<script>
import VueApexCharts from 'vue-apexcharts'
import ApexCharts from 'apexcharts'

function series() {
  var out = []
  var v = 100
  for (var i = 0; i < 60; i++) {
    v += 2 + Math.sin(i / 5) * 3
    out.push([i, Math.round(v)])
  }
  return out
}

export default {
components: {
apexchart: VueApexCharts,
},
data: function () {
return {
series: [
  { name: 'Price', data: series() }
],
chartOptions: {
chart: {
  id: 'price',
  type: 'area',
  height: 380,
  fontFamily: 'Helvetica, Arial, sans-serif',
  animations: { enabled: false },
  measure: { enabled: true, pinOnRelease: true },
  toolbar: { show: true, autoSelected: 'measure' },
  zoom: { enabled: true, type: 'x' },
},
stroke: { width: 2, curve: 'straight' },
dataLabels: { enabled: false },
title: { text: 'Price (measure any move)', align: 'left' },
xaxis: { type: 'numeric', title: { text: 'Session' } },
yaxis: { title: { text: 'Price' }, decimalsInFloat: 0 },
},
pollTimer: null,
}
},
mounted: function () {
  // The vue-apexcharts wrapper owns the render, so reach the live instance by
  // its chart.id, then wire the same handlers the vanilla build does.
  // (series() lives in the shared head script.)
  var me = this
  me.pollTimer = window.setInterval(function () {
    var chart = ApexCharts.getChartByID('price')
    if (!chart) return
    window.clearInterval(me.pollTimer)
    me.pollTimer = null

    var readout = document.getElementById('mz-readout')

    document.getElementById('mz-clear').addEventListener('click', function () {
      chart.clearMeasures()
    })

    chart.addEventListener('measured', function (c, o) {
      readout.textContent =
        'dx=' + Number(o.dx).toFixed(2) +
        '  dy=' + Number(o.dy).toFixed(2) +
        '  (' + (o.percentChange >= 0 ? '+' : '') + Number(o.percentChange).toFixed(1) + '%)'
    })
  }, 50)
},
beforeDestroy: function () {
  if (this.pollTimer) window.clearInterval(this.pollTimer)
},,
}
</script>

<style>
.mz-wrap {
  max-width: 820px;
  margin: 12px auto;
  font-family: Helvetica, Arial, sans-serif;
}
.mz-bar {
  display: flex;
  gap: 10px;
  align-items: center;
  flex-wrap: wrap;
  margin: 4px 6px 10px;
}
.mz-bar button {
  padding: 6px 13px;
  cursor: pointer;
  border: 1px solid #0ea5e9;
  color: #0369a1;
  background: #fff;
  border-radius: 6px;
  font-size: 13px;
  font-weight: 600;
}
.mz-bar button.active {
  background: #0ea5e9;
  color: #fff;
}
.mz-bar .readout {
  font-family: monospace;
  font-size: 13px;
  color: #445;
}
.mz-note {
  background: #f0f9ff;
  border-left: 3px solid #0ea5e9;
  padding: 11px 15px;
  font-size: 13px;
  color: #234;
  border-radius: 2px;
  line-height: 1.6;
  margin: 12px 6px;
}
.mz-note code {
  background: #dceafb;
  padding: 1px 5px;
  border-radius: 3px;
}
</style>
Measure Ruler - Vue Interactivity | ApexCharts.js | ApexCharts.js