1
0
Fork 0
mirror of https://git.rwth-aachen.de/acs/public/villas/web/ synced 2025-03-09 00:00:01 +01:00

Add d3 library and d3-gauge component

This commit is contained in:
Markus Grigull 2015-10-22 10:13:24 -04:00
parent 3108592bac
commit cc7eb9ccd9
7 changed files with 291 additions and 1 deletions

257
app/components/d3-gauge.js vendored Normal file
View file

@ -0,0 +1,257 @@
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");
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];
console.log(zone);
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.round(value));
var pointer = pointerContainer.selectAll("path");
var _this = this;
pointer.transition()
.duration(transitionDuration)
.attrTween("transform", function() {
var pointerValue = value;
if (value > _this.maxValue) {
pointerValue = _this.maxValue + 0.02 * (_this.maxValue - _this.minValue);
} else if (value < _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);
}
});

View file

@ -2,6 +2,8 @@ import Ember from 'ember';
export default Ember.Controller.extend({
state: 1,
redZone: [{from: 50, to: 60}],
yellowZone: [{from: 40, to: 50}],
dataSetOne: [
{

View file

@ -0,0 +1 @@
{{yield}}

View file

@ -32,6 +32,8 @@
<li>Electric power capacity: 8458 MW</li>
</ul>
</p>
{{d3-gauge label="Frequency" value=23 maxValue=60 minorTicks=4 redZones=redZone yellowZones=yellowZone}}
</td>
<td style="width: 25%">
<img src={{"assets/images/TS_section/TS_fig1.svg"}} class="svg-image" />

View file

@ -17,7 +17,8 @@
"Faker": "~3.0.0",
"bootstrap": "~3.3.2",
"flot": "*",
"normalize.css": "3.0.3"
"normalize.css": "3.0.3",
"d3": "~3.5.6"
},
"resolutions": {
"ember": "^2.0.0"

View file

@ -20,6 +20,7 @@ module.exports = function(defaults) {
// along with the exports of each module as its value.
app.import('bower_components/flot/jquery.flot.time.js');
app.import('bower_components/d3/d3.js');
return app.toTree();
};

View file

@ -0,0 +1,26 @@
import { moduleForComponent, test } from 'ember-qunit';
import hbs from 'htmlbars-inline-precompile';
moduleForComponent('d3-gauge', 'Integration | Component | d3 gauge', {
integration: true
});
test('it renders', function(assert) {
assert.expect(2);
// Set any properties with this.set('myProperty', 'value');
// Handle any actions with this.on('myAction', function(val) { ... });
this.render(hbs`{{d3-gauge}}`);
assert.equal(this.$().text().trim(), '');
// Template block usage:
this.render(hbs`
{{#d3-gauge}}
template block text
{{/d3-gauge}}
`);
assert.equal(this.$().text().trim(), 'template block text');
});