1
0
Fork 0
mirror of https://git.rwth-aachen.de/acs/public/villas/web/ synced 2025-03-16 00:00:03 +01:00
VILLASweb/app/components/d3-gauge.js
2015-10-26 11:22:06 -04:00

261 lines
7.3 KiB
JavaScript

import Ember from 'ember';
export default Ember.Component.extend({
tagName: 'span',
classNames: ['gauge'],
size: 120,
minValue: 0,
maxValue: 100,
value: 0,
minorTicks: 2,
majorTicks: 5,
label: '',
greenColor: '#109618',
yellowColor: '#FF9900',
redColor: '#DC3912',
greenZones: [],
yellowZones: [],
redZones: [],
didInsertElement: function() {
this._drawGauge();
},
_drawGauge: function() {
// calculate dimensions
var cx = this.size / 2;
var radius = this.size / 2 * 0.97;
var labelFontSize = Math.round(this.size / 9);
var fontSize = Math.round(this.size / 16);
var range = this.maxValue - this.minValue;
var majorDelta = range / (this.majorTicks - 1);
var minorDelta = majorDelta / this.minorTicks;
var midValue = (this.minValue + this.maxValue) / 2;
var pointerFontSize = Math.round(this.size / 10);
// create body element
var body = d3.select('#' + this.elementId)
.append("svg:svg")
.attr("width", this.size)
.attr("height", this.size);
this.set('svgBody', body);
// base circles
body.append("svg:circle")
.attr("cx", cx)
.attr("cy", cx)
.attr("r", radius)
.style("fill", "#ccc")
.style("stroke", "#000")
.style("stroke-width", "0.5px");
body.append("svg:circle")
.attr("cx", cx)
.attr("cy", cx)
.attr("r", radius * 0.9)
.style("fill", "#fff")
.style("stroke", "#e0e0e0")
.style("stroke-width", "2px");
// color zones
for (var index in this.greenZones) {
this.drawBand(this.greenZones[index].from, this.greenZones[index].to, this.greenColor);
}
for (var index in this.yellowZones) {
this.drawBand(this.yellowZones[index].from, this.yellowZones[index].to, this.yellowColor);
}
for (var index in this.redZones) {
var zone = this.redZones[index];
this.drawBand(this.redZones[index].from, this.redZones[index].to, this.redColor);
}
// label
if (this.label) {
body.append("svg:text")
.attr("x", cx)
.attr("y", cx / 2 + labelFontSize / 2)
.attr("dy", labelFontSize / 2)
.attr("text-anchor", "middle")
.text(this.label)
.style("font-size", labelFontSize + "px")
.style("fill", "#333")
.style("stroke-width", "0px");
}
// ticks
for (var major = this.minValue; major <= this.maxValue; major += majorDelta) {
for (var minor = major + minorDelta; minor < Math.min(major + majorDelta, this.maxValue); minor += minorDelta) {
var p1 = this.valueToPoint(minor, 0.75);
var p2 = this.valueToPoint(minor, 0.85);
body.append("svg:line")
.attr("x1", p1.x)
.attr("y1", p1.y)
.attr("x2", p2.x)
.attr("y2", p2.y)
.style("stroke", "#666")
.style("stroke-width", "1px");
}
var p1 = this.valueToPoint(major, 0.7);
var p2 = this.valueToPoint(major, 0.85);
body.append("svg:line")
.attr("x1", p1.x)
.attr("y1", p1.y)
.attr("x2", p2.x)
.attr("y2", p2.y)
.style("stroke", "#333")
.style("stroke-width", "2px");
if (major == this.minValue || major == this.maxValue) {
var point = this.valueToPoint(major, 0.63);
body.append("svg:text")
.attr("x", point.x)
.attr("y", point.y)
.attr("dy", fontSize / 3)
.attr("text-anchor", major == this.minValue ? "start" : "end")
.text(major)
.style("font-size", fontSize + "px")
.style("fill", "#333")
.style("stroke-width", "0px");
}
}
// pointer
var pointerContainer = body.append("svg:g").attr("class", "pointerContainer");
var pointerPath = this.buildPointerPath(midValue);
var pointerLine = d3.svg.line()
.x(function(d) { return d.x })
.y(function(d) { return d.y })
.interpolate("basis");
pointerContainer.selectAll("path")
.data([pointerPath])
.enter()
.append("svg:path")
.attr("d", pointerLine)
.style("fill", "#dc3912")
.style("stroke", "#c63310")
.style("fill-opacity", 0.7);
pointerContainer.append("svg:circle")
.attr("cx", cx)
.attr("cy", cx)
.attr("r", radius * 0.12)
.style("fill", "#4684EE")
.style("stroke", "#666")
.style("opacity", 1);
pointerContainer.selectAll("text")
.data([midValue])
.enter()
.append("svg:text")
.attr("x", cx)
.attr("y", this.size - cx / 4 - pointerFontSize)
.attr("dy", pointerFontSize / 2)
.attr("text-anchor", "middle")
.style("font-size", pointerFontSize + "px")
.style("fill", "#000")
.style("stroke-width", "0px");
this._redraw(this.value, 0);
},
_redraw: function(value, transitionDuration) {
var pointerContainer = this.svgBody.select(".pointerContainer");
pointerContainer.selectAll("text").text(Math.floor(this.value * 100) / 100);
var pointer = pointerContainer.selectAll("path");
var _this = this;
transitionDuration = 0;
pointer.transition()
.duration(transitionDuration)
.attrTween("transform", function() {
var pointerValue = _this.value;
if (pointerValue > _this.maxValue) {
pointerValue = _this.maxValue + 0.02 * (_this.maxValue - _this.minValue);
} else if (pointerValue < _this.minValue) {
pointerValue = _this.minValue - 0.02 * (_this.maxValue - _this.minValue);
}
var targetRotation = _this.valueToDegrees(pointerValue) - 90;
var currentRotation = _this._currentRotation || targetRotation;
_this._currentRotation = targetRotation;
return function(step) {
var rotation = currentRotation + (targetRotation - currentRotation) * step;
return "translate(" + (_this.size / 2) + ", " + (_this.size / 2) + ") rotate(" + rotation + ")";
}
});
}.observes('value'),
drawBand: function(start, end, color) {
if (0 >= end - start) {
return;
}
var _this = this;
this.svgBody.append("svg:path")
.style("fill", color)
.attr("d", d3.svg.arc()
.startAngle(this.valueToRadians(start))
.endAngle(this.valueToRadians(end))
.innerRadius(0.65 * (this.size / 2 * 0.97))
.outerRadius(0.85 * (this.size / 2 * 0.97)))
.attr("transform", function() {
return "translate(" + (_this.size / 2) + ", " + (_this.size / 2) + ") rotate(270)";
});
},
buildPointerPath: function(value) {
var delta = (this.maxValue - this.minValue) / 13;
var head = this.valueToPoint(value, 0.85);
var head1 = this.valueToPoint(value - delta, 0.12);
var head2 = this.valueToPoint(value + delta, 0.12);
var cx = this.size / 2;
head.x -= cx;
head.y -= cx;
head1.x -= cx;
head1.y -= cx;
head2.x -= cx;
head2.y -= cx;
var tailValue = value - ((this.maxValue - this.minValue) * (1/(270/360)) / 2);
var tail = this.valueToPoint(tailValue, 0.28);
var tail1 = this.valueToPoint(tailValue - delta, 0.12);
var tail2 = this.valueToPoint(tailValue + delta, 0.12);
tail.x -= cx;
tail.y -= cx;
tail1.x -= cx;
tail1.y -= cx;
tail2.x -= cx;
tail2.y -= cx;
return [head, head1, tail2, tail, tail1, head2, head];
},
valueToPoint: function(value, factor) {
return {
x: (this.size / 2) - (this.size / 2 * 0.97) * factor * Math.cos(this.valueToRadians(value)),
y: (this.size / 2) - (this.size / 2 * 0.97) * factor * Math.sin(this.valueToRadians(value))
};
},
valueToRadians: function(value) {
return this.valueToDegrees(value) * Math.PI / 180;
},
valueToDegrees: function(value) {
return value / (this.maxValue - this.minValue) * 270 - (this.minValue / (this.maxValue - this.minValue) * 270 + 45);
}
});