UNPKG

@csn_chile/wsjs_charts

Version:

Scripts de javascript para usar websockets

369 lines (311 loc) 10.8 kB
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};