Vue - Rank Speedo

by Sarah Godoshian

HTML

<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/highcharts-more.js"></script>
<script src="https://code.highcharts.com/modules/solid-gauge.js"></script>
<template id="high-chart">
  <div class="high-chart" :id="id"></div>
</template>

<template id="rank-speedometer"> 
  <div class="root">
    <div>
      <div class="title">{{metricName}}</div>
      <div class="fixed-ratio-wrap">
        <high-chart 
                    style="position:absolute; top:0; bottom:0; left:0; right:0;"
                    :options="options"
                    ></high-chart>
      </div>
      <div class="subtitle">Rank: {{rank}} of {{maxRank}}</div>
    </div>
  </div>
</template>

<div id="app">
  <rank-speedometer
    :metric-name="metric.name"
    :metric-value="metric.value"
    :reverse="metric.reverse"
    :rank-colors="rankColors"
    :rank="metric.rank"
    :max-rank="maxRank"
  ></rank-speedometer>
</div>

SCSS

$medium-gray: #97a0a5;

.root {
  font-family: "Source Sans Pro", Helvetica, Roboto, Arial, sans-serif;
  .title {
    text-align: center;
    font-weight: bold;
  }
  .subtitle {
    text-align: center;
    color: $medium-gray !important;
    font-weight: bold;
  }
  > * {
    max-width: 250px;
    // min-width: 225px;
    margin: 0 auto;
    > .fixed-ratio-wrap {
      position: relative;
      padding-bottom: 50%;
    }
  } 
}

Vue

const METRIC = {
	name: 'Income Growth',
  value: '3.2%',
  rank: 22,
  reverse: false, // to reverse the rank coloring, set to true
};
const MAX_RANK = 50;

/**
 * DO NOT EDIT BELOW :)
 * Code updated: Feb 15 2019
 */

const RANK_COLORS = [
	"rgb(85, 155, 35)",
  "rgb(187, 215, 167)",
  "rgb(255, 222, 47)",
  "rgb(255, 153, 0)",
  "rgb(167, 25, 59)"
];

let bus = new Vue();

// high_charts_gauge.js
let gaugeOptions = {
	chart: {
    type: 'solidgauge',
    backgroundColor: 'none'
  },
  
  title: null,
  
  pane: {
    center: ['50%', '100%'],
    size: '200%',
    startAngle: -90,
    endAngle: 90,
    background: {
      backgroundColor: '#EEE',
      innerRadius: '60%',
      outerRadius: '100%',
      shape: 'arc'
    }
  },

  tooltip: {
    enabled: false
  },

  yAxis: {
    stops: [
      [0.2, 'rgb(167, 25, 59)'], // red
      [0.201, 'rgb(231, 130, 22)'], // orange
      [0.4, 'rgb(231, 130, 22)'],
      [0.401, 'rgb(255, 222, 47)'], // yellow
      [0.6, 'rgb(255, 222, 47)'],
      [0.601, 'rgb(204, 225, 189)'], // light green  
      [0.8, 'rgb(204, 225, 189)'],
      [0.801, 'rgb(102, 165, 57)'], // dark green
    ],
    lineWidth: 0,
    tickColor: 'rgba(0,0,0,0)',
    title: {
      y: -60
    },
    labels: {
      enabled: false
    },
    minorTickLength: 0,
    tickLength: 0
  },

  plotOptions: {
    solidgauge: {
      dataLabels: {
        y: 15,
        borderWidth: 0,
        useHTML: true
      }
    }
  },

  credits: {
      enabled: false
  },
};

// high-chart.vue + has-random-id.js
let HighChart = Vue.extend({
	template: '#high-chart',
  beforeCreate() {
    this.id = ('' + Math.random()).replace('0.', '');
  },
  data() {
    return {
      id: this.id
    };
  },
  props: {
    options: Object
  },
  watch: {
    'options.series': function() {
      this.renderChart();
    }
  },
  mounted() {
    this.renderChart();
    bus.$on('appWidthChange', () => {
      this.chart.reflow();
    });    
  },
  methods: {
    renderChart:...