UNPKG

@swimlane/ngx-charts

Version:

Declarative Charting Framework for Angular2 and beyond!

204 lines (169 loc) 4.81 kB
import { Component, Input, Output, EventEmitter, ElementRef, OnChanges, ChangeDetectionStrategy, NgZone, ChangeDetectorRef, SimpleChanges } from '@angular/core'; import * as moment from 'moment'; import d3 from '../d3'; import { id } from '../utils/id'; @Component({ selector: 'g[ngx-charts-timeline]', template: ` <svg:g class="timeline" [attr.transform]="transform"> <svg:filter [attr.id]="filterId"> <svg:feColorMatrix in="SourceGraphic" type="matrix" values="0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1 0" /> </svg:filter> <svg:g class="embedded-chart"> <ng-content></ng-content> </svg:g> <svg:rect x="0" [attr.width]="view[0]" y="0" [attr.height]="height" class="brush-background" /> <svg:g class="brush"></svg:g> </svg:g> `, changeDetection: ChangeDetectionStrategy.OnPush }) export class Timeline implements OnChanges { @Input() view; @Input() state; @Input() results; @Input() scheme; @Input() customColors; @Input() legend; @Input() miniChart; @Input() autoScale; @Input() scaleType; @Input() height: number = 50; @Output() select = new EventEmitter(); @Output() onDomainChange = new EventEmitter(); element: HTMLElement; dims: any; xDomain: any[]; xScale: any; brush: any; transform: string; initialized: boolean = false; filterId: any; filter: any; constructor(element: ElementRef, private zone: NgZone, private cd: ChangeDetectorRef) { this.element = element.nativeElement; } ngOnChanges(changes: SimpleChanges): void { this.update(); if (!this.initialized) { this.addBrush(); this.initialized = true; } } update(): void { this.zone.run(() => { this.dims = this.getDims(); this.height = this.dims.height; let offsetY = this.view[1] - this.height; this.xDomain = this.getXDomain(); this.xScale = this.getXScale(); if (this.brush) { this.updateBrush(); } this.transform = `translate(0 , ${ offsetY })`; let pageUrl = window.location.href; this.filterId = 'filter' + id().toString(); this.filter = `url(${pageUrl}#${this.filterId})`; this.cd.markForCheck(); }); } getXDomain(): any[] { let values = []; for (let results of this.results) { for (let d of results.series){ if (!values.includes(d.name)) { values.push(d.name); } } } let domain = []; if (this.scaleType === 'time') { values = values.map(v => moment(v).toDate()); let min = Math.min(...values); let max = Math.max(...values); domain = [min, max]; } else if (this.scaleType === 'linear') { values = values.map(v => Number(v)); let min = Math.min(...values); let max = Math.max(...values); domain = [min, max]; } else { domain = values; } return domain; } getXScale() { let scale; if (this.scaleType === 'time') { scale = d3.scaleTime() .range([0, this.dims.width]) .domain(this.xDomain); } else if (this.scaleType === 'linear') { scale = d3.scaleLinear() .range([0, this.dims.width]) .domain(this.xDomain); } else if (this.scaleType === 'ordinal') { scale = d3.scalePoint() .range([0, this.dims.width]) .padding(0.1) .domain(this.xDomain); } return scale; } addBrush(): void { if (this.brush) return; const height = this.height; const width = this.view[0]; this.brush = d3.brushX() .extent([[0, 0], [width, height]]) .on('brush end', () => { this.zone.run(() => { const selection = d3.selection.event.selection || this.xScale.range(); const newDomain = selection.map(this.xScale.invert); this.onDomainChange.emit(newDomain); this.cd.markForCheck(); }); }); d3.select(this.element) .select('.brush') .call(this.brush); } updateBrush(): void { if (!this.brush) return; const height = this.height; const width = this.view[0]; this.zone.run(() => { this.brush.extent([[0, 0], [width, height]]); d3.select(this.element) .select('.brush') .call(this.brush); // clear hardcoded properties so they can be defined by CSS d3.select(this.element).select('.selection') .attr('fill', undefined) .attr('stroke', undefined) .attr('fill-opacity', undefined); this.cd.markForCheck(); }); } getDims(): any { let width = this.view[0]; let dims = { width, height: this.height }; return dims; } }