UNPKG

ng-d3-graphs

Version:

<img src="./assets/ng-d3.png" alt="drawing" width="250" height="250"/>

1,275 lines (1,253 loc) 51.6 kB
import { __spread, __decorate, __assign, __param, __values } from 'tslib'; import { ɵɵdefineInjectable, Injectable, ElementRef, Input, HostListener, Component, ViewEncapsulation, NgModule, ChangeDetectionStrategy, Inject } from '@angular/core'; import { CommonModule } from '@angular/common'; import { axisLeft, axisBottom, axisRight, axisTop, line, scaleLinear, extent, scaleBand, timeFormat, select, timeParse, scaleTime, min, max, curveStep, area, utcParse, schemeSet2, scaleOrdinal, pie, entries, arc, interpolateCool } from 'd3'; import { Subject } from 'rxjs'; import { debounceTime } from 'rxjs/operators'; var axisConfig = { color: 'lightgrey', opacity: 1, rendering: 'crispEdges', strokeWidth: '1px', xAxisTimeParser: '%Y-%m-%dT%H:%M:%S.%LZ', xAxisTimeFormat: '%m/%d/%y', xAxisTicks: 5, }; var AxisDirection; (function (AxisDirection) { AxisDirection["top"] = "top"; AxisDirection["right"] = "right"; AxisDirection["bottom"] = "bottom"; AxisDirection["left"] = "left"; })(AxisDirection || (AxisDirection = {})); var D3Service = /** @class */ (function () { function D3Service() { } D3Service.prototype.translate = function (x, y) { return "translate(" + x + ", " + y + ")"; }; D3Service.prototype.factoryAxis = function (scale, direction) { switch (direction) { case AxisDirection.top: return axisTop(scale); case AxisDirection.right: return axisRight(scale); case AxisDirection.bottom: return axisBottom(scale); case AxisDirection.left: return axisLeft(scale); default: return new Error('No axis Direction Provided'); } }; D3Service.prototype.factoryLine = function () { return line().x(function (d) { return d.x; }).y(function (d) { return d.y; }); }; // ==== Axis ===== D3Service.prototype.scaleLinearX = function (labels, width) { return scaleLinear() .domain(extent(labels)) // does the magic for adjustable axis .range([0, width]); }; D3Service.prototype.scaleLinearY = function (data, height) { return scaleLinear() .domain(extent(data)) // does the magic for adjustable axis .range([height, 0]); }; D3Service.prototype.scaleBandX = function (labels, width) { return scaleBand().domain(labels).rangeRound([0, width]).padding(0.1); }; D3Service.prototype.scaleLinearYRangeRound = function (data, height) { return scaleLinear().domain([0, Math.max.apply(Math, __spread(data))]).rangeRound([ height, 0 ]); }; D3Service.prototype.addLabelAxisY = function (svg, height, options) { svg.append('text') .attr('transform', 'rotate(-90)') .attr('y', 0 - options.margin.left) .attr('x', 0 - height / 2) .attr('dy', '1em') .style('text-anchor', 'middle') .text(options.yAxisLabel); }; D3Service.prototype.addLabelAxisX = function (svg, width, height, options) { svg.append('text') .attr('transform', 'translate(' + width / 2 + ' ,' + (height + options.margin.top) + ')') .style('text-anchor', 'middle') .text(options.xAxisLabel); }; D3Service.prototype.getViewBoxDefault = function (options) { var res = { minX: -options.margin.left, minY: -25, width: options.width, height: options.height - options.margin.top, }; return res; }; D3Service.prototype.removeAxisTicks = function (axis) { axis.selectAll('.tick').selectAll('line').remove(); }; D3Service.prototype.changeAxisColor = function (axis, config) { axis.select('path') .attr('color', config.color) .attr('opacity', config.opacity) .attr('rendering', config.rendering) .attr('stroke-width', config.strokeWidth); }; D3Service.prototype.getXaxisTime = function (svg, height, x, timeFormat$1, xAxisTicks) { return svg.append('g') .attr('transform', "translate(0," + height + ")") .call(axisBottom(x) .tickFormat(timeFormat(timeFormat$1)) .ticks(xAxisTicks)); }; D3Service.prototype.hideTooltip = function (tooltipText, tooltip) { tooltipText.selectAll('tspan').remove(); tooltip.attr('visibility', 'hidden'); }; D3Service.prototype.showTooltip = function (d, xScale, yScale, tooltip, tooltipRect, tooltipText, formatTime) { var xPos = xScale(d.x) - 150 / 2; var yPos = yScale(d.y) + 10; tooltip.attr('transform', "translate(" + xPos + ", " + yPos + ")") .attr('is', true) .attr('visibility', 'visible'); tooltipRect.attr('opacity', 0.7); tooltipText.attr('tranform', 'translate(75,30)') .attr('fill', 'white') .attr('font-size', 10) .attr('font-family', "'Roboto', 'sans-serif'"); tooltipText.append('tspan') .attr('text-anchor', 'middle') .attr('is', true) .attr('x', 25) .attr('y', -5) .text("" + formatTime(d.x)); tooltipText.append('tspan') .attr('text-anchor', 'middle') .attr('is', true) .attr('x', 20) .attr('dy', 15) .text("" + d.y); }; D3Service.prototype.addTooltip = function (container) { var tooltipConfig = { width: 100, height: 40, fill: '#333', opacity: 0.7, rx: 15, text: { translateX: 10, translateY: 20, }, }; var tooltip = select(container.nativeElement).select('svg').append('g'); var tooltipRect = tooltip.append('rect') .attr('width', tooltipConfig.width) .attr('height', tooltipConfig.height) .attr('fill', tooltipConfig.fill) .attr('opacity', 0) .attr('rx', tooltipConfig.rx); var tooltipText = tooltip.append('text').attr('transform', "translate(\n " + tooltipConfig.text.translateX + ",\n " + tooltipConfig.text.translateY + ")"); return { tooltip: tooltip, tooltipRect: tooltipRect, tooltipText: tooltipText, tooltipConfig: tooltipConfig }; }; D3Service.ngInjectableDef = ɵɵdefineInjectable({ factory: function D3Service_Factory() { return new D3Service(); }, token: D3Service, providedIn: "root" }); D3Service = __decorate([ Injectable({ providedIn: 'root' }) ], D3Service); return D3Service; }()); var BandComponent = /** @class */ (function () { function BandComponent(container, d3Service) { this.container = container; this.d3Service = d3Service; this.data = []; this.labels = []; this.options = {}; this.labelsAndData = []; this.viewBox = {}; this._options = { width: 879, height: 804, margin: { top: 50, right: 50, bottom: 50, left: 50 }, yAxisLabel: '', gridTicks: 0, timeParser: axisConfig.xAxisTimeParser, timeFormat: axisConfig.xAxisTimeFormat, xAxisTicks: axisConfig.xAxisTicks, }; this.parseTime = timeParse(this.options.timeParser); this.formatTime = timeFormat(this.options.timeFormat); this.onResize$ = new Subject(); } BandComponent.prototype.onResize = function () { this.onResize$.next(); }; BandComponent.prototype.ngOnInit = function () { this.options = __assign({}, this._options, this.options); this.viewBox = { minX: -this.options.margin.left, minY: -10, width: this.options.width + this.options.margin.left + this.options.margin.right, height: this.options.height + this.options.margin.top, }; this.parseTime = timeParse(this.options.timeParser); this.formatTime = timeFormat(this.options.timeFormat); this.labels = this.formatLabels(); this.labelsAndData = this.combineLabelsDataToOne(); this.onResizeEvent(); this.render(); }; BandComponent.prototype.formatLabels = function () { var _this = this; return this.labels.map(function (d) { return _this.parseTime(d); }); }; BandComponent.prototype.combineLabelsDataToOne = function () { var N = this.labels.length; var result = []; for (var index = 0; index < N; index++) { result.push({ x: this.labels[index], low: this.data[index].low, high: this.data[index].high, }); } return result; }; BandComponent.prototype.render = function () { var currentWidth = parseInt(select(this.container.nativeElement).select('div').style('width'), 10); var currentHeight = parseInt(select(this.container.nativeElement).select('div').style('height'), 10); var width = this.options.width - this.options.margin.left - this.options.margin.right; var height = this.options.height - this.options.margin.top - this.options.margin.bottom; this.viewBox = { minX: -this.options.margin.left, minY: -10, width: this.options.width, height: this.options.height - this.options.margin.top, }; var svg = select(this.container.nativeElement) .select('div') .append('svg') .attr('width', currentWidth) .attr('height', currentHeight) .attr('viewBox', this.viewBox.minX + " " + this.viewBox.minY + " " + this.viewBox.width + " " + this.viewBox.height) .classed('svg-content', true) .append('g'); var x = scaleTime() .domain(extent(this.labels, function (d) { return new Date(d); })) .range([0, width]); var y = scaleLinear() .domain([ min(this.data, function (d) { return d.low; }), max(this.data, function (d) { return d.high; }) ]) .nice(this.options.gridTicks) .range([height, 0]); // add the X gridlines svg.append('g') .attr('class', 'grid') .call(this.make_x_gridlines(x).tickSize(height) // .tickFormat('') ); // add the Y gridlines svg.append('g') .attr('class', 'grid') .call(this.make_y_gridlines(y).tickSize(-width) // .tickFormat('') ); var xAxis = this.d3Service.getXaxisTime(svg, height, x, this.options.timeFormat, this.options.xAxisTicks); var yAxis = function (g) { return g.attr('transform', "translate(" + 0 + ",0)").call(axisLeft(y)); }; var curve = curveStep; var area$1 = area() .curve(curve) .x(function (d) { return x(d.x); }) .y0(function (d) { return y(d.low); }) .y1(function (d) { return y(d.high); }); var _yAxis = svg.append('g').call(yAxis); // this.d3Service.addLabelAxisX(svg, width, height, this.options); // text label for the x axis this.addLabelAxisX(svg, width, height); // text label for the y axis this.addLabelAxisY(svg, height); svg.append('path') .datum(this.labelsAndData) .attr('fill', 'steelblue') .attr('d', area$1); this.removeAxisTicks(xAxis); this.removeAxisTicks(_yAxis); this.changeAxisColor(xAxis, axisConfig); this.changeAxisColor(_yAxis, axisConfig); }; BandComponent.prototype.changeAxisColor = function (axis, config) { this.d3Service.changeAxisColor(axis, config); }; BandComponent.prototype.removeAxisTicks = function (axis) { this.d3Service.removeAxisTicks(axis); }; BandComponent.prototype.addLabelAxisY = function (svg, height) { svg.append('text') .attr('transform', 'rotate(0)') .attr('y', 0 - this.options.margin.top / 2) .attr('x', 0) .attr('dy', '1em') .style('text-anchor', 'start') .text(this.options.yAxisLabel); }; BandComponent.prototype.addLabelAxisX = function (svg, width, height) { svg.append('text') .attr('transform', 'translate(' + width / 2 + ' ,' + (height + this.options.margin.top - 15) + ')') .style('text-anchor', 'middle') .text(this.options.xAxisLabel); }; // gridlines in x axis function BandComponent.prototype.make_x_gridlines = function (x) { return axisBottom(x).ticks(this.options.gridTicks); }; // gridlines in y axis function BandComponent.prototype.make_y_gridlines = function (y) { return axisLeft(y).ticks(this.options.gridTicks); }; BandComponent.prototype.onResizeEvent = function () { var _this = this; this.onResize$.pipe(debounceTime(200)).subscribe(function () { var svgExist = select(_this.container.nativeElement).select('svg'); if (svgExist) { svgExist.remove(); } _this.render(); }); }; BandComponent.ctorParameters = function () { return [ { type: ElementRef }, { type: D3Service } ]; }; __decorate([ Input() ], BandComponent.prototype, "data", void 0); __decorate([ Input() ], BandComponent.prototype, "labels", void 0); __decorate([ Input() ], BandComponent.prototype, "options", void 0); __decorate([ HostListener('window:resize') ], BandComponent.prototype, "onResize", null); BandComponent = __decorate([ Component({ selector: 'ng-band', template: "<div class=\"svg-container\"></div>\n", encapsulation: ViewEncapsulation.None, styles: [".svg-container{display:inline-block;position:relative;width:100%;height:100%;padding-bottom:100%;vertical-align:top;overflow:hidden}.svg-content{display:inline-block;position:absolute;top:0;left:0}.grid line{stroke:#d3d3d3;stroke-opacity:.4;shape-rendering:crispEdges}.grid path{stroke-width:0}.grid text{display:none}.area{fill:#4682b4}"] }) ], BandComponent); return BandComponent; }()); var BandModule = /** @class */ (function () { function BandModule() { } BandModule = __decorate([ NgModule({ declarations: [BandComponent], imports: [ CommonModule ], exports: [BandComponent], }) ], BandModule); return BandModule; }()); var BarComponent = /** @class */ (function () { function BarComponent(container, d3Service) { this.container = container; this.d3Service = d3Service; this.data = []; this.labels = []; this.options = {}; this.graph = { xAxis: [], yAxis: [], xAxisPath: '', yAxisPath: '', rectanglesData: [], }; this.labelsAndData = []; this.parseTime = timeParse('%d-%b-%y'); this._options = { width: 879, height: 804, margin: { top: 50, right: 50, bottom: 50, left: 50 }, gridTicks: 0, }; this.viewBox = {}; this.onResize$ = new Subject(); } BarComponent.prototype.onResize = function () { this.onResize$.next(); }; BarComponent.prototype.ngOnInit = function () { this.options = __assign({}, this._options, this.options); this.viewBox = { minX: -this.options.margin.left, minY: -10, width: this.options.width + this.options.margin.left + this.options.margin.right, height: this.options.height + this.options.margin.top, }; this.labelsAndData = this.combineLabelsDataToOne(); this.onResizeEvent(); this.render(); }; BarComponent.prototype.render = function () { var currentWidth = parseInt(select(this.container.nativeElement).select('div').style('width'), 10); var currentHeight = parseInt(select(this.container.nativeElement).select('div').style('height'), 10); var width = this.options.width - this.options.margin.left - this.options.margin.right; var height = this.options.height - this.options.margin.top - this.options.margin.bottom; this.viewBox = { minX: -this.options.margin.left, minY: -10, width: this.options.width, height: this.options.height - this.options.margin.top, }; var svg = select(this.container.nativeElement) .select('div') .append('svg') .attr('width', currentWidth) .attr('height', currentHeight) .attr('viewBox', this.viewBox.minX + " " + this.viewBox.minY + " " + this.viewBox.width + " " + this.viewBox.height) .classed('svg-content', true) .append('g'); var x = scaleBand().rangeRound([0, width]).padding(0.1).domain(this.labels); var y = scaleLinear().rangeRound([height, 0]).domain([ 0, Math.max.apply(Math, __spread(this.data.map(function (d) { return Number(d); }))) ]); var xAxis = function (g) { return g.call(axisBottom(x)) .attr('transform', 'translate(0,' + height + ')'); }; var yAxis = function (g) { return g.call(axisLeft(y)); }; // add the X gridlines svg.append('g') .attr('class', 'grid') .call(this.make_x_gridlines(x).tickSize(height) // .tickFormat('') ); // add the Y gridlines svg.append('g') .attr('class', 'grid') .call(this.make_y_gridlines(y).tickSize(-width) // .tickFormat('') ); svg.selectAll('.bar') .data(this.labelsAndData) .enter() .append('rect') .attr('class', 'bar') .attr('x', function (d) { return x(d.x); }) .attr('y', function (d) { return y(Number(d.y)); }) .attr('width', x.bandwidth()) .attr('height', function (d) { return height - y(Number(d.y)); }); var _xAxis = svg.append('g').call(xAxis); // text label for the x axis this.addLabelAxisX(svg, width, height); var _yAxis = svg.append('g').call(yAxis); // text label for the y axis this.addLabelAxisY(svg, height); this.removeAxisTicks(_xAxis); this.removeAxisTicks(_yAxis); this.changeAxisColor(_xAxis, axisConfig); this.changeAxisColor(_yAxis, axisConfig); }; BarComponent.prototype.changeAxisColor = function (axis, config) { this.d3Service.changeAxisColor(axis, config); }; BarComponent.prototype.removeAxisTicks = function (axis) { this.d3Service.removeAxisTicks(axis); }; BarComponent.prototype.addLabelAxisY = function (svg, height) { svg.append('text') .attr('transform', 'rotate(0)') .attr('y', 0 - this.options.margin.top / 2) .attr('x', 0) .attr('dy', '1em') .style('text-anchor', 'start') .text(this.options.yAxisLabel); }; BarComponent.prototype.addLabelAxisX = function (svg, width, height) { svg.append('text') .attr('transform', 'translate(' + width / 2 + ' ,' + (height + this.options.margin.top - 15) + ')') .style('text-anchor', 'middle') .text(this.options.xAxisLabel); }; BarComponent.prototype.combineLabelsDataToOne = function () { var result = []; var N = this.data.length; for (var index = 0; index < N; index++) { result.push({ x: this.labels[index], y: this.data[index] }); } return result; }; // gridlines in x axis function BarComponent.prototype.make_x_gridlines = function (x) { return axisBottom(x).ticks(this.options.gridTicks); }; // gridlines in y axis function BarComponent.prototype.make_y_gridlines = function (y) { return axisLeft(y).ticks(this.options.gridTicks); }; BarComponent.prototype.onResizeEvent = function () { var _this = this; this.onResize$.pipe(debounceTime(200)).subscribe(function () { var svgExist = select(_this.container.nativeElement).select('svg'); if (svgExist) { svgExist.remove(); } _this.render(); }); }; BarComponent.ctorParameters = function () { return [ { type: ElementRef }, { type: D3Service } ]; }; __decorate([ Input() ], BarComponent.prototype, "data", void 0); __decorate([ Input() ], BarComponent.prototype, "labels", void 0); __decorate([ Input() ], BarComponent.prototype, "options", void 0); __decorate([ HostListener('window:resize') ], BarComponent.prototype, "onResize", null); BarComponent = __decorate([ Component({ selector: 'ng-bar', template: "\n<div class=\"svg-container\"></div>\n", encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".svg-container{display:inline-block;position:relative;width:100%;height:100%;padding-bottom:100%;vertical-align:top;overflow:hidden}.svg-content{display:inline-block;position:absolute;top:0;left:0}.grid line{stroke:#d3d3d3;stroke-opacity:.4;shape-rendering:crispEdges}.grid path{stroke-width:0}.grid text{display:none}.bar{fill:#4682b4}.bar:hover{fill:brown}"] }) ], BarComponent); return BarComponent; }()); var BarService = /** @class */ (function () { function BarService() { } BarService = __decorate([ Injectable() ], BarService); return BarService; }()); var BarModule = /** @class */ (function () { function BarModule() { } BarModule = __decorate([ NgModule({ declarations: [BarComponent], imports: [ CommonModule ], providers: [ BarService ], exports: [BarComponent] }) ], BarModule); return BarModule; }()); var LineComponent = /** @class */ (function () { function LineComponent(container, d3Service) { this.container = container; this.d3Service = d3Service; this.data = []; this.labels = []; this.options = {}; this._options = { width: 879, height: 804, margin: { top: 50, right: 50, bottom: 50, left: 50 }, gridTicks: 0, yAxisLabel: '', xAxisLabel: '', timeParser: axisConfig.xAxisTimeParser, timeFormat: axisConfig.xAxisTimeFormat, xAxisTicks: axisConfig.xAxisTicks, }; this.parseTime = timeParse(this.options.timeParser); this.formatTime = timeFormat(this.options.timeFormat); this.viewBox = {}; this.labelsAndData = []; this.AxisDataX = []; this.onResize$ = new Subject(); } LineComponent.prototype.onResize = function () { this.onResize$.next(); }; LineComponent.prototype.ngOnInit = function () { var _this = this; this.options = __assign({}, this._options, this.options); this.viewBox = this.d3Service.getViewBoxDefault(this.options); this.parseTime = timeParse(this.options.timeParser); this.formatTime = timeFormat(this.options.timeFormat); this.labels = this.labels.map(function (d) { return _this.parseTime(d); }); this.labelsAndData = this.combineLabelsDataToOne(); this.onResizeEvent(); this.render(); }; LineComponent.prototype.render = function () { var currentWidth = parseInt(select(this.container.nativeElement).select('div').style('width'), 10); var currentHeight = parseInt(select(this.container.nativeElement).select('div').style('height'), 10); var width = this.options.width - this.options.margin.left - this.options.margin.right; var height = this.options.height - this.options.margin.top - this.options.margin.bottom; this.viewBox = { minX: -this.options.margin.left, minY: -10, width: this.options.width, height: this.options.height - this.options.margin.top, }; var svg = select(this.container.nativeElement) .select('div') .append('svg') .attr('width', currentWidth) .attr('height', currentHeight) .attr('viewBox', this.viewBox.minX + " " + this.viewBox.minY + " " + this.viewBox.width + " " + this.viewBox.height) .classed('svg-content', true) .append('g'); var x = scaleTime().range([0, width]); var y = scaleLinear().range([height, 0]).nice(); var valueline = line().x(function (d) { return x(d.x); }).y(function (d) { return y(d.y); }); x.domain(extent(this.labels, function (d) { return (d); })); y.domain([0, max(this.data, function (d) { return d; })]); // add the X gridlines svg.append('g') .attr('class', 'grid') .call(this.make_x_gridlines(x).tickSize(height) // .tickFormat('') ); // add the Y gridlines svg.append('g') .attr('class', 'grid') .call(this.make_y_gridlines(y).tickSize(-width) // .tickFormat('') ); svg.append('path') .datum(this.labelsAndData) .attr('class', 'line') .attr('d', valueline); // add the X Axis var xAxis = this.d3Service.getXaxisTime(svg, height, x, this.options.timeFormat, this.options.xAxisTicks); // text label for the x axis this.addLabelAxisX(svg, width, height); // add the Y Axis var yAxis = svg.append('g').call(axisLeft(y)); // text label for the y axis this.addLabelAxisY(svg, height); this.removeAxisTicks(xAxis); this.removeAxisTicks(yAxis); this.changeAxisColor(xAxis, axisConfig); this.changeAxisColor(yAxis, axisConfig); this.addDots(svg, x, y); }; LineComponent.prototype.addDots = function (svg, x, y) { var _this = this; var dotRadius = 3; var dotColor = '#4682b4'; // add tootlip var _a = this.d3Service.addTooltip(this.container), tooltip = _a.tooltip, tooltipRect = _a.tooltipRect, tooltipText = _a.tooltipText, tooltipConfig = _a.tooltipConfig; svg.selectAll('dot') .data(this.labelsAndData) .enter() .append('circle') .attr('r', dotRadius) .attr('fill', dotColor) .attr('cx', function (d) { return x(d.x); }) .attr('cy', function (d) { return y(d.y); }) .on('mouseover', function (d) { _this.onMouseOver(d, x, y, tooltip, tooltipRect, tooltipText); }) .on('mouseout', function (d) { _this.onMouseOut(d, tooltip, tooltipText, tooltipConfig); }); }; LineComponent.prototype.onMouseOver = function (d, xScale, yScale, tooltip, tooltipRect, tooltipText) { // show tooltip if (tooltip) { this.d3Service.showTooltip(d, xScale, yScale, tooltip, tooltipRect, tooltipText, this.formatTime); } }; LineComponent.prototype.onMouseOut = function (d, tooltip, tooltipText, tooltipConfig) { // hide tooltip if (tooltip) { this.d3Service.hideTooltip(tooltipText, tooltip); } }; LineComponent.prototype.changeAxisColor = function (axis, config) { this.d3Service.changeAxisColor(axis, config); }; LineComponent.prototype.removeAxisTicks = function (axis) { this.d3Service.removeAxisTicks(axis); }; LineComponent.prototype.addLabelAxisY = function (svg, height) { svg.append('text') .attr('transform', 'rotate(0)') .attr('y', 0 - this.options.margin.top / 2) .attr('x', 0) .attr('dy', '1em') .style('text-anchor', 'start') .text(this.options.yAxisLabel); }; LineComponent.prototype.addLabelAxisX = function (svg, width, height) { svg.append('text') .attr('transform', 'translate(' + width / 2 + ' ,' + (height + this.options.margin.top - 15) + ')') .style('text-anchor', 'middle') .text(this.options.xAxisLabel); }; LineComponent.prototype.combineLabelsDataToOne = function () { var result = []; var N = this.data.length; for (var index = 0; index < N; index++) { result.push({ x: this.labels[index], y: this.data[index] }); } return result; }; // gridlines in x axis function LineComponent.prototype.make_x_gridlines = function (x) { return axisBottom(x).ticks(this.options.gridTicks); }; // gridlines in y axis function LineComponent.prototype.make_y_gridlines = function (y) { return axisLeft(y).ticks(this.options.gridTicks); }; LineComponent.prototype.onResizeEvent = function () { var _this = this; this.onResize$.pipe(debounceTime(200)).subscribe(function () { var svgExist = select(_this.container.nativeElement).select('svg'); if (svgExist) { svgExist.remove(); } _this.render(); }); }; LineComponent.ctorParameters = function () { return [ { type: ElementRef }, { type: D3Service } ]; }; __decorate([ Input() ], LineComponent.prototype, "data", void 0); __decorate([ Input() ], LineComponent.prototype, "labels", void 0); __decorate([ Input() ], LineComponent.prototype, "options", void 0); __decorate([ HostListener('window:resize') ], LineComponent.prototype, "onResize", null); LineComponent = __decorate([ Component({ selector: 'ng-line', template: "<div class=\"svg-container\"></div>\n", encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".svg-container{display:inline-block;position:relative;width:100%;height:100%;padding-bottom:100%;vertical-align:top;overflow:hidden}.svg-content{display:inline-block;position:absolute;top:0;left:0}.grid line{stroke:#d3d3d3;stroke-opacity:.4;shape-rendering:crispEdges}.grid path{stroke-width:0}.grid text{display:none}.line{fill:none;stroke:#4682b4;stroke-width:2px}div.tooltip{position:absolute;text-align:center;min-width:60px;min-height:28px;padding:5px;font:12px sans-serif;background:#b0c4de;border:0;border-radius:5px;pointer-events:none;color:#000}"] }) ], LineComponent); return LineComponent; }()); var LineService = /** @class */ (function () { function LineService(config) { this.config = config; } LineService.prototype.showConfig = function () { console.log(this.config); }; LineService.ctorParameters = function () { return [ { type: undefined, decorators: [{ type: Inject, args: ['config',] }] } ]; }; LineService = __decorate([ Injectable(), __param(0, Inject('config')) ], LineService); return LineService; }()); var LineModule = /** @class */ (function () { function LineModule() { } LineModule_1 = LineModule; LineModule.forRoot = function (config) { return { ngModule: LineModule_1, providers: [ LineService, { provide: 'config', useValue: config }, ] }; }; var LineModule_1; LineModule = LineModule_1 = __decorate([ NgModule({ declarations: [LineComponent,], imports: [ CommonModule ], exports: [LineComponent], providers: [ LineService ] }) ], LineModule); return LineModule; }()); var MultilineComponent = /** @class */ (function () { function MultilineComponent(container, d3Service) { this.container = container; this.d3Service = d3Service; this.data = []; this.labels = []; this.options = {}; this.labelsAndData = []; this.utcParse = utcParse('%Y-%m'); this.viewBox = {}; this._options = { width: 879, height: 804, yAxisLabel: '', xAxisLabel: '', margin: { top: 50, right: 50, bottom: 50, left: 50 }, timeParser: axisConfig.xAxisTimeParser, timeFormat: axisConfig.xAxisTimeFormat, xAxisTicks: axisConfig.xAxisTicks, }; this.parseTime = timeParse(this.options.timeParser); this.formatTime = timeFormat(this.options.timeFormat); this.onResize$ = new Subject(); } MultilineComponent.prototype.onResize = function () { this.onResize$.next(); }; MultilineComponent.prototype.ngOnInit = function () { this.options = __assign({}, this._options, this.options); this.viewBox = { minX: -this.options.margin.left, minY: -25, width: this.options.width + this.options.margin.left + this.options.margin.right, height: this.options.height + this.options.margin.top, }; this.parseTime = timeParse(this.options.timeParser); this.formatTime = timeFormat(this.options.timeFormat); this.labels = this.formatData(); this.labelsAndData = this.combineLabelsDataToOne(); this.onResizeEvent(); this.render(); }; MultilineComponent.prototype.formatData = function () { var _this = this; return this.labels.map(function (d) { return _this.parseTime(d); }); }; MultilineComponent.prototype.combineLabelsDataToOne = function () { var result = []; var N = this.data.length; for (var index = 0; index < N; index++) { result.push({ x: this.labels, y: this.data[index] }); } return result; }; MultilineComponent.prototype.render = function () { var _this = this; var currentWidth = parseInt(select(this.container.nativeElement).select('div').style('width'), 10); var currentHeight = parseInt(select(this.container.nativeElement).select('div').style('height'), 10); var width = this.options.width - this.options.margin.left - this.options.margin.right; var height = this.options.height - this.options.margin.top - this.options.margin.bottom; this.viewBox = { minX: -this.options.margin.left, minY: -10, width: this.options.width, height: this.options.height - this.options.margin.top, }; var svg = select(this.container.nativeElement) .select('div') .append('svg') .attr('width', currentWidth) .attr('height', currentHeight) .attr('viewBox', this.viewBox.minX + " " + this.viewBox.minY + " " + this.viewBox.width + " " + this.viewBox.height) .classed('svg-content', true) .append('g'); var xDomain = this.getXdomain(); var x = scaleTime().domain(xDomain).range([0, width]); var y = scaleLinear() .domain([0, max(this.data, function (d) { return max(d.values); })]) .range([height, 0]) .nice(); // const xAxis = (g) => // g.attr('transform', `translate(0,${height})`).call(d3.axisBottom(x)); var xAxis = this.d3Service.getXaxisTime(svg, height, x, this.options.timeFormat, this.options.xAxisTicks); var yAxis = function (g) { return g.call(axisLeft(y)); }; var line$1 = line() .defined(function (d) { return !isNaN(d); }) .x(function (d, i) { return x(_this.labels[i]); }) .y(function (d) { return y(d); }); // add the X gridlines svg.append('g') .attr('class', 'grid') .call(this.make_x_gridlines(x).tickSize(height) // .tickFormat('') ); // add the Y gridlines svg.append('g') .attr('class', 'grid') .call(this.make_y_gridlines(y).tickSize(-width) // .tickFormat('') ); var _yAxis = svg.append('g').call(yAxis); // text label for the x axis this.addLabelAxisX(svg, width, height); // text label for the y axis this.addLabelAxisY(svg, height); var path = svg.append('g') .attr('fill', 'none') .attr('stroke', 'steelblue') .attr('stroke-width', 1.5) .attr('stroke-linejoin', 'round') .attr('stroke-linecap', 'round') .selectAll('path') .data(this.data) .join('path') .style('mix-blend-mode', 'multiply') .attr('d', function (d) { return line$1(d.values); }) .text('this is '); this.removeAxisTicks(xAxis); this.removeAxisTicks(_yAxis); this.changeAxisColor(xAxis, axisConfig); this.changeAxisColor(_yAxis, axisConfig); // TODO: comment in when issue #61 is fixed /* svg.call(hover, path, this); function hover(svg, path, _this) { if ('ontouchstart' in document) { svg.style('-webkit-tap-highlight-color', 'transparent') .on('touchmove', moved) .on('touchstart', entered) .on('touchend', left); } else { svg.on('mousemove', moved) .on('mouseenter', entered) .on('mouseleave', left); } const dot = svg.append('g').attr('display', 'none'); dot.append('circle').attr('r', 2.5); dot.append('text') .attr('font-family', 'sans-serif') .attr('font-size', 10) .attr('text-anchor', 'middle') .attr('y', -8); function moved() { d3.event.preventDefault(); const ym = y.invert(d3.event.layerY) as any; const xm = x.invert(d3.event.layerX) as any; const i1 = d3.bisectLeft(_this.labels, xm, 1); const i0 = i1 - 1; const i = xm - _this.labels[i0] > _this.labels[i1] - xm ? i1 : i0; // const s = d3.least(_this.data, d => Math.abs(d.values[i] - ym)); const s = _this.least(_this.data, d => Math.abs(d.values[i] - ym), i, ym); path.attr('stroke', d => d === s ? null : '#ddd') .filter(d => d === s) .raise(); dot.attr( 'transform', `translate(${x(_this.labels[i])},${y(s.values[i])})`); dot.select('text').text(s.name); } function entered() { path.style('mix-blend-mode', null).attr('stroke', '#ddd'); dot.attr('display', null); } function left() { path.style('mix-blend-mode', 'multiply').attr('stroke', null); dot.attr('display', 'none'); } } */ }; MultilineComponent.prototype.changeAxisColor = function (axis, config) { this.d3Service.changeAxisColor(axis, config); }; MultilineComponent.prototype.removeAxisTicks = function (axis) { this.d3Service.removeAxisTicks(axis); }; MultilineComponent.prototype.addLabelAxisY = function (svg, height) { svg.append('text') .attr('transform', 'rotate(0)') .attr('y', 0 - this.options.margin.top / 2) .attr('x', 0) .attr('dy', '1em') .style('text-anchor', 'start') .text(this.options.yAxisLabel); }; MultilineComponent.prototype.addLabelAxisX = function (svg, width, height) { svg.append('text') .attr('transform', 'translate(' + width / 2 + ' ,' + (height + this.options.margin.top - 15) + ')') .style('text-anchor', 'middle') .text(this.options.xAxisLabel); }; MultilineComponent.prototype.getXdomain = function () { var domainExtent = extent(this.labels, function (d) { return d; }); return domainExtent.map(function (d) { return new Date(d); }); }; MultilineComponent.prototype.least = function (arr, filterFun, pos, ym) { var tempValues = arr.map(function (d) { return filterFun(d); }); var minNum = Math.min.apply(Math, __spread(tempValues)); var graphHovered; var minimax = tempValues[0]; var minPos = 0; for (var i = 1; i < tempValues.length; i++) { var element = tempValues[i]; if (element >= minimax) { minPos = i; minimax = element; } } graphHovered = arr[minPos]; return graphHovered; }; // gridlines in x axis function MultilineComponent.prototype.make_x_gridlines = function (x) { return axisBottom(x).ticks(this.options.gridTicks); }; // gridlines in y axis function MultilineComponent.prototype.make_y_gridlines = function (y) { return axisLeft(y).ticks(this.options.gridTicks); }; MultilineComponent.prototype.onResizeEvent = function () { var _this = this; this.onResize$.pipe(debounceTime(200)).subscribe(function () { var svgExist = select(_this.container.nativeElement).select('svg'); if (svgExist) { svgExist.remove(); } _this.render(); }); }; MultilineComponent.ctorParameters = function () { return [ { type: ElementRef }, { type: D3Service } ]; }; __decorate([ Input() ], MultilineComponent.prototype, "data", void 0); __decorate([ Input() ], MultilineComponent.prototype, "labels", void 0); __decorate([ Input() ], MultilineComponent.prototype, "options", void 0); __decorate([ HostListener('window:resize') ], MultilineComponent.prototype, "onResize", null); MultilineComponent = __decorate([ Component({ selector: 'ng-multiline', template: "<div class=\"svg-container\"></div>\n", encapsulation: ViewEncapsulation.None, styles: [".svg-container{display:inline-block;position:relative;width:100%;height:100%;padding-bottom:100%;vertical-align:top;overflow:hidden}.svg-content{display:inline-block;position:absolute;top:0;left:0}.grid line{stroke:#d3d3d3;stroke-opacity:.4;shape-rendering:crispEdges}.grid path{stroke-width:0}.grid text{display:none}"] }) ], MultilineComponent); return MultilineComponent; }()); var MultilineModule = /** @class */ (function () { function MultilineModule() { } MultilineModule = __decorate([ NgModule({ declarations: [MultilineComponent], imports: [ CommonModule, ], exports: [MultilineComponent], }) ], MultilineModule); return MultilineModule; }()); var PieComponent = /** @class */ (function () { function PieComponent(container) { this.container = container; this.labels = []; this.data = []; this.backgroundColors = schemeSet2; this.radius = 100; this.options = {}; this.color = this.interpolateColor(); // range [0,1] -> builtin range of colors. this.defaultSliceColor = 'steerblue'; this.labelsAndData = []; this.viewBox = {}; this._options = { width: 300, height: 300, margin: { top: 50, right: 50, bottom: 50, left: 50 }, }; this.onResize$ = new Subject(); } PieComponent.prototype.onResize = function () { this.onResize$.next(); }; PieComponent.prototype.ngOnInit = function () { this.options = __assign({}, this._options, this.options); this.viewBox = { minX: -this.options.margin.left, minY: 0, width: Number(this.options.width) + Number(this.options.margin.left) + Number(this.options.margin.right), height: this.options.height, }; this.onBgdColorUndefined(); this.onResizeEvent(); this.render(); }; PieComponent.prototype.onBgdColorUndefined = function () { var e_1, _a; if (this.backgroundColors.length === 0) { try { // TODO: check linter // for (let index = 0; index < this.data.length; index++) { // this.backgroundColors.push(this.defaultSliceColor); // } for (var _b = __values(this.data), _c = _b.next(); !_c.done; _c = _b.next()) { var iterator = _c.value; this.backgroundColors.push(this.defaultSliceColor); } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (_c && !_c.done && (_a = _b.return)) _a.call(_b); } finally { if (e_1) throw e_1.error; } } } }; PieComponent.prototype.render = function () { var _this = this; var currentWidth = parseInt(select(this.container.nativeElement).select('div').style('width'), 10); var currentHeight = parseInt(select(this.container.nativeElement).select('div').style('height'), 10); var radius = Math.min(this.options.width, this.options.height) / 2 - this.options.margin.top; var svg = select(this.container.nativeElement) .select('div') .append('svg') .attr('width', currentWidth) .attr('height', currentHeight) .attr('viewBox', this.viewBox.minX + " " + this.viewBox.minY + " " + this.viewBox.width + " " + this.viewBox.height) .classed('svg-content', true) .append('g') .attr('transform', 'translate(' + this.options.width / 2 + ',' + this.options.height / 2 + ')'); var color = scaleOrdinal().domain(this.data).range(this.backgroundColors); var pie$1 = pie().value(function (d) { return d.value; }); var pieData = pie$1(entries(this.data)); var arcGenerator = arc().innerRadius(0).outerRadius(radius); svg .selectAll('slices') .data(pieData) .enter() .append('path') .attr('d', arcGenerator) .attr('fill', function (d) { return _this.backgroundColors[d.index]; }) .attr('stroke', 'black') .style('stroke-width', '2px') .style('opacity', 0.7); svg .selectAll('slices') .data(pieData) .enter() .append('text') .text(function (d) { return _this.labels[d.index]; }) .attr('transform', function (d) { return ('translate(' + arcGenerator.centroid({ startAngle: d.startAngle, endAngle: d.endAngle, }) + ')'); }) .style('text-anchor', 'middle') .style('font-size', 17); this.addLabelAxisX(svg, this.options.width, this.options.height); }; PieComponent.prototype.addLabelAxisX = function (svg, width, height) { svg .append('text') .attr('transform', "translate(" + 0 + ", " + this.options.margin.top * 2.5 + ")") .style('text-anchor', 'middle') .text(this.options.xAxisLabel); }; /** * range [0, 1] */ PieComponent.prototype.interpolateColor = function () { return interpolateCool; }; PieComponent.prototype.combineLabelsDataToOne = function () { var result = []; var N = this.data.length; for (var index = 0; index < N; index++) { result.push({ x: this.labels[index], y: this.data[index] }); } return result; }; PieComponent.prototype.onResizeEvent = function () { var _this = this; this.onResize$.pipe(debounceTime(200)).subscribe(function () { var svgExist = select(_this.container.nativeElement).select('svg'); if (svgExist) { svgExist.remove(); } _this.render(); }); }; PieComponent.ctorParameters = function () { return [ { type: ElementRef } ]; }; __decorate([ Input() ], PieComponent.prototype, "labels", void 0); __decorate([ Input() ], PieComponent.prototype, "data", void 0); __decorate([ Input() ], PieComponent.prototype, "backgroundColors", void 0); __decorate([ Input() ], PieComponent.prototype, "radius", void 0); __decorate([ Input() ], PieComponent.prototype, "options", void 0); __decorate([ HostListener('window:resize') ], PieComponent.prototype, "onResize", null); PieComponent = __decorate([ Component({ selector: 'ng-pie',