@csn_chile/wsjs_charts
Version:
Scripts de javascript para usar websockets
369 lines (311 loc) • 10.8 kB
JavaScript
let d3 = require("d3");
let fuelGauge = null;
function initialize() {
let config = {
size: 80,
minorTicks: 1,
showPointer: false,
showValue: true,
valueFontSize: 16,
unit: '%',
redZone: {
from: 0,
to: 20
},
yellowZone: {
from: 20,
to: 60
},
greenZone: {
from: 60,
to: 100
}
};
fuelGauge = new Gauge("#fuelGaugeContainer", config);
fuelGauge.render(70);
setInterval(updateGauges, 2000);
}
function updateGauges(startNumber) {
let number = Math.random() * 100;
let theNumber = Math.round(number);
fuelGauge.redraw(theNumber);
}
function Gauge(container, configuration) {
let self = this;
configuration = configuration || {};
//default config options
this.config = {
size: 200,
label: '',
min: 0,
max: 100,
transitionDuration: 500,
majorTicks: 6,
minorTicks: 3,
showPointer: true,
showValue: true,
valueFontSize: 14,
unit: '%',
greenColor: "#72A544",
yellowColor: "#FFBE00",
redColor: "#C81922",
greyColor: "#D5D3D9"
};
this.configure = function(configuration) {
let prop, zoneRange;
for (prop in configuration) {
if (this.config.hasOwnProperty(prop)) {
this.config[prop] = configuration[prop];
}
}
//todo: add checks for valid values
this.config.radius = this.config.size / 2;
this.config.cx = this.config.size / 2;
this.config.cy = this.config.size / 2;
this.config.I = 0;
this.config.range = this.config.max - this.config.min;
zoneRange = Math.round(this.config.range / 3);
//default zone sizes
this.config.redZone = configuration.redZone || {
from: this.config.min,
to: this.config.min + zoneRange
};
this.config.yellowZone = configuration.yellowZone || {
from: this.config.redZone.to,
to: this.config.redZone.to + zoneRange
};
this.config.greenZone = configuration.greenZone || {
from: this.config.yellowZone.to,
to: this.config.max
};
};
this.render = function(value) {
let labelFontSize, major, minor, minorDelta, majorDelta, point1, point2, point;
this.body = d3.select(container)
.append("svg:svg")
.attr("class", "gauge")
.attr("width", this.config.size)
.attr("height", this.config.size);
this.drawRestBand(this.config.min, this.config.max, self.config.greyColor);
this.drawBand(this.config.min, this.config.max, self.config.greyColor);
if (this.config.label) {
labelFontSize = Math.round(this.config.size / 9);
this.body.append("svg:text")
.attr("x", this.config.cx)
.attr("y", this.config.cy / 2 + labelFontSize / 2)
.attr("dy", labelFontSize)
.attr('class', 'label')
.attr("text-anchor", "middle")
.text(this.config.label)
.style("font-size", labelFontSize + "px");
}
majorDelta = this.config.range / (this.config.majorTicks - 1);
for (major = this.config.min; major <= this.config.max; major += majorDelta) {
minorDelta = majorDelta / this.config.minorTicks;
for (minor = major + minorDelta; minor < Math.min(major + majorDelta, this.config.max); minor += minorDelta) {
point1 = this.valueToPoint(minor, 0.75);
point2 = this.valueToPoint(minor, 0.85);
this.body.append("svg:line")
.attr("class", "minorTick")
.attr("x1", point1.x)
.attr("y1", point1.y)
.attr("x2", point2.x)
.attr("y2", point2.y);
}
point1 = this.valueToPoint(major, 0.6);
point2 = this.valueToPoint(major, 0.9);
this.body.append("svg:line")
.attr("class", "majorTick")
.attr("x1", point1.x)
.attr("y1", point1.y)
.attr("x2", point2.x)
.attr("y2", point2.y);
if (major === this.config.max) {
point = this.valueToPoint(major, 0.82);
}
if (major === this.config.min) {
point = this.valueToPoint(major, 0.82);
}
}
let pointerContainer = this.body.append("svg:g").attr("class", "pointerContainer");
let midValue = (this.config.min + this.config.max) / 2;
if (this.config.showPointer) {
let pointerPath = this.buildPointerPath(midValue);
let pointerLine = d3.line()
.x(function(d) {
return d.x;
})
.y(function(d) {
return d.y;
})
.curve(d3.curveBasis);
pointerContainer.selectAll("path")
.data([pointerPath])
.enter()
.append("svg:path")
.attr("d", pointerLine)
.attr('class', 'pointerLine')
.style("fill-opacity", 1);
pointerContainer.append("svg:circle")
.attr("cx", this.config.cx)
.attr("cy", this.config.cy)
.attr("r", 0.06 * this.config.radius)
.attr('class', 'pointerCircle')
.style("opacity", 1);
}
if (this.config.showValue) {
let fontSize = this.config.valueFontSize;
pointerContainer.selectAll("text")
.data([midValue])
.enter()
.append("svg:text")
.attr("x", this.config.cx)
.attr("y", this.config.size - this.config.cy / 1.6 - fontSize)
.attr("dy", fontSize)
.attr("text-anchor", "middle")
.attr('class', 'value')
.style("font-size", fontSize + "px")
.style("stroke-width", "0px");
}
this.redraw(value || this.config.min);
};
this.isRendered = function() {
return (this.body !== undefined);
};
this.buildPointerPath = function(value) {
function valueToPoint(value, factor) {
let point = self.valueToPoint(value, factor);
point.x -= self.config.cx;
point.y -= self.config.cy;
return point;
}
let delta = this.config.range / 13;
let head = valueToPoint(value, 0.6);
let head1 = valueToPoint(value - delta, 0.12);
let head2 = valueToPoint(value + delta, 0.12);
let tailValue = value - (this.config.range * (1 / (180 / 360)) / 2);
let tail = valueToPoint(tailValue, -0.1);
let tail1 = valueToPoint(tailValue - delta, 0.12);
let tail2 = valueToPoint(tailValue + delta, 0.12);
return [head, head1, tail2, tail, tail1, head2, head];
};
this.drawBand = function(start, end, color) {
let bands, bandsdraw, theend, arc, arcs;
if (0 >= end - start) {
return;
}
function arcTween(transition, newAngle) {
transition.attrTween("d", function(d) {
let theAngle = (newAngle / 100 * 180 - (0 / 100 * 180)) * Math.PI / 180;
let interpolate = d3.interpolate(d.endAngle, theAngle);
return function(t) {
d.endAngle = interpolate(t);
self.config.I = newAngle;
return arc(d);
};
});
}
bands = this.body.select(".bands");
if (bands.empty()) {
bands = this.body.append("svg:path").attr("class", 'bands');
}
theend = this.valueToRadians(end);
arc = d3.arc()
.innerRadius(0.45 * this.config.radius)
.outerRadius(0.85 * this.config.radius)
.startAngle(0);
bandsdraw = bands.attr("transform", function() {
return "translate(" + self.config.cx + ", " + self.config.cy + ") rotate(270)";
});
if (self.config.I === 0) {
arcs = bandsdraw
.datum({
endAngle: 0
})
.style("fill", color)
.attr("d", arc);
} else {
arcs = bandsdraw
.datum({
endAngle: this.valueToRadians(self.config.I)
})
.style("fill", color)
.attr("d", arc);
}
arcs.transition().duration(this.config.transitionDuration).call(arcTween, end);
};
this.drawRestBand = function(start, end, color) {
let bands, theend, bandsdrawn, arcEnd, arcss;
if (0 >= end - start) {
return;
}
bands = this.body.select(".backbands");
if (bands.empty()) {
bands = this.body.append("svg:path").attr("class", 'backbands');
}
theend = this.valueToRadians(end);
bandsdrawn = bands.attr("transform", function() {
return "translate(" + self.config.cx + ", " + self.config.cy + ") rotate(270)";
});
arcEnd = d3.arc()
.innerRadius(0.45 * this.config.radius)
.outerRadius(0.85 * this.config.radius)
.startAngle(this.valueToRadians(start))
.endAngle(this.valueToRadians(end));
arcss = bandsdrawn
.style("fill", color)
.attr("d", arcEnd);
};
this.redraw = function(value) {
if (!this.isRendered() || !value || !(!isNaN(parseFloat(value)) && isFinite(value))) {
return;
}
let pointerContainer = this.body.select(".pointerContainer");
pointerContainer.selectAll("text").text(Math.round(value) + this.config.unit);
let pointer = pointerContainer.selectAll("path");
pointer.transition()
.duration(this.config.transitionDuration)
.attrTween("transform", function() {
let pointerValue = value;
if (value > self.config.max) {
pointerValue = self.config.max + 0.02 * self.config.range;
} else if (value < self.config.min) {
pointerValue = self.config.min - 0.02 * self.config.range;
}
let targetRotation = (self.valueToDegrees(pointerValue) - 90);
let currentRotation = self._currentRotation || targetRotation;
self._currentRotation = targetRotation;
return function(step) {
let rotation = currentRotation + (targetRotation - currentRotation) * step;
return "translate(" + self.config.cx + ", " + self.config.cy + ") rotate(" + rotation + ")";
};
});
//todo: make color ranges configurable
if (value >= this.config.redZone.from && value < this.config.redZone.to) {
this.drawBand(0, value, this.config.redColor);
} else if (value >= this.config.yellowZone.from && value <= this.config.yellowZone.to) {
this.drawBand(0, value, this.config.yellowColor);
} else if (value >= this.config.greenZone.from && value <= this.config.greenZone.to) {
this.drawBand(0, value, this.config.greenColor);
} else {
this.drawBand(0, value, this.config.greyColor);
}
this.drawRestBand(0, 100, this.config.greyColor);
};
this.valueToDegrees = function(value) {
return value / this.config.range * 180 - (this.config.min / this.config.range * 180);
};
this.valueToRadians = function(value) {
return this.valueToDegrees(value) * Math.PI / 180;
};
this.valueToPoint = function(value, factor) {
return {
x: this.config.cx - this.config.radius * factor * Math.cos(this.valueToRadians(value)),
y: this.config.cy - this.config.radius * factor * Math.sin(this.valueToRadians(value))
};
};
// initialization
this.configure(configuration);
};
initialize();
export {initialize, Gauge};