open-nomad/ui/app/components/gauge-chart.js

94 lines
2.1 KiB
JavaScript

import Component from '@ember/component';
import { computed } from '@ember/object';
import { assert } from '@ember/debug';
import { guidFor } from '@ember/object/internals';
import { run } from '@ember/runloop';
import d3Shape from 'd3-shape';
import WindowResizable from 'nomad-ui/mixins/window-resizable';
import { classNames } from '@ember-decorators/component';
import classic from 'ember-classic-decorator';
@classic
@classNames('chart', 'gauge-chart')
export default class GaugeChart extends Component.extend(WindowResizable) {
value = null;
complement = null;
total = null;
chartClass = 'is-info';
width = 0;
height = 0;
@computed('value', 'complement', 'total')
get percent() {
assert(
'Provide complement OR total to GaugeChart, not both.',
this.complement != null || this.total != null
);
if (this.complement != null) {
return this.value / (this.value + this.complement);
}
return this.value / this.total;
}
@computed
get fillId() {
return `gauge-chart-fill-${guidFor(this)}`;
}
@computed
get maskId() {
return `gauge-chart-mask-${guidFor(this)}`;
}
@computed('width')
get radius() {
return this.width / 2;
}
weight = 4;
@computed('radius', 'weight')
get backgroundArc() {
const { radius, weight } = this;
const arc = d3Shape
.arc()
.outerRadius(radius)
.innerRadius(radius - weight)
.cornerRadius(weight)
.startAngle(-Math.PI / 2)
.endAngle(Math.PI / 2);
return arc();
}
@computed('radius', 'weight', 'percent')
get valueArc() {
const { radius, weight, percent } = this;
const arc = d3Shape
.arc()
.outerRadius(radius)
.innerRadius(radius - weight)
.cornerRadius(weight)
.startAngle(-Math.PI / 2)
.endAngle(-Math.PI / 2 + Math.PI * percent);
return arc();
}
didInsertElement() {
super.didInsertElement(...arguments);
this.updateDimensions();
}
updateDimensions() {
const width = this.element.querySelector('svg').clientWidth;
this.setProperties({ width, height: width / 2 });
}
windowResizeHandler() {
run.once(this, this.updateDimensions);
}
}