angular2-nvd3
Version:
Angular2 module for NVD3 chart
206 lines (175 loc) • 7.47 kB
text/typescript
import * as d3 from 'd3';
import * as nv from 'nvd3';
export namespace Angular2NvD3 {
export class NgNvD3 {
private el: any;
private chart: any;
private svg: any;
private viewInitialize: boolean = false;
constructor(el) {
this.el = el;
}
public isViewInitialize(value: boolean) {
this.viewInitialize = value;
}
public updateWithOptions(options: any, data: any) {
// Exit if options are not yet bound
if (!this.viewInitialize || !options) { return; };
let self = this;
// Clearing
this.clearElement();
// Initialize chart with specific type
this.chart = nv.models[options.chart.type]();
// Generate random chart ID
this.chart.id = Math.random().toString(36).substr(2, 15);
for (let key in this.chart) {
if (!this.chart.hasOwnProperty(key)) { continue; }
if (key[0] === '_') {
} else if ([
'clearHighlights',
'highlightPoint',
'id',
'options',
'resizeHandler',
'state',
'open',
'close',
'tooltipContent'
].indexOf(key) >= 0) {
} else if (key === 'dispatch') {
this.configureEvents(this.chart[key], options.chart[key]);
} else if ([
'bars',
'bars1',
'bars2',
'boxplot',
'bullet',
'controls',
'discretebar',
'distX',
'distY',
'interactiveLayer',
'legend',
'lines',
'lines1',
'lines2',
'multibar',
'pie',
'scatter',
'scatters1',
'scatters2',
'sparkline',
'stack1',
'stack2',
'sunburst',
'tooltip',
'x2Axis',
'xAxis',
'y1Axis',
'y2Axis',
'y3Axis',
'y4Axis',
'yAxis',
'yAxis1',
'yAxis2'
].indexOf(key) >= 0 ||
// stacked is a component for stackedAreaChart, but a boolean for multiBarChart and multiBarHorizontalChart
(key === 'stacked' && options.chart.type === 'stackedAreaChart')) {
this.configure(this.chart[key], options.chart[key], options.chart.type);
} else if ((key === 'xTickFormat' || key === 'yTickFormat') && options.chart.type === 'lineWithFocusChart') {
// TODO: need to fix bug in nvd3
} else if ((key === 'tooltips') && options.chart.type === 'boxPlotChart') {
} else if ((key === 'tooltipXContent' || key === 'tooltipYContent') && options.chart.type === 'scatterChart') {
} else if (options.chart[key] === undefined || options.chart[key] === null) {
} else { this.chart[key](options.chart[key]); }
}
this.updateWithData(data, options);
nv.addGraph(() => {
if (!self.chart) { return; }
// Remove resize handler. Due to async execution should be placed here, not in the clearElement
if (self.chart.resizeHandler) { self.chart.resizeHandler.clear(); }
// Update the chart when window resizes
self.chart.resizeHandler = nv.utils.windowResize(() => {
if (self.chart && self.chart.update) { self.chart.update(); }
});
return self.chart;
}, options.chart['callback']);
}
private updateWithData(data: any, options: any) {
if (data) {
// remove whole svg element with old data
d3.select(this.el.nativeElement).select('svg').remove();
let h, w;
// Select the current element to add <svg> element and to render the chart in
this.svg = d3.select(this.el.nativeElement).append('svg');
if (h = options.chart.height) {
if (!isNaN(+h)) { h += 'px'; }
this.svg.attr('height', h).style({height: h});
}
if (w = options.chart.width) {
if (!isNaN(+w)) { w += 'px'; }
this.svg.attr('width', w).style({width: w});
} else {
this.svg.attr('width', '100%').style({width: '100%'});
}
this.svg.datum(data).call(this.chart);
}
}
private configure(chart, options, chartType) {
if (chart && options) {
for (let key in chart) {
if (!chart.hasOwnProperty(key)) { continue; }
let value = chart[key];
if (key[0] === '_') {
} else if (key === 'dispatch') {
this.configureEvents(value, options[key]);
} else if (key === 'tooltip') {
this.configure(chart[key], options[key], chartType);
} else if (key === 'contentGenerator') {
if (options[key]) { chart[key](options[key]); }
} else if ([
'axis',
'clearHighlights',
'defined',
'highlightPoint',
'nvPointerEventsClass',
'options',
'rangeBand',
'rangeBands',
'scatter',
'open',
'close'
].indexOf(key) === -1) {
if (options[key] === undefined || options[key] === null) {
} else {
chart[key](options[key]);
}
}
}
}
}
private configureEvents(dispatch, options) {
if (dispatch && options) {
for (let key in dispatch) {
if (!dispatch.hasOwnProperty(key)) { continue; }
if (options[key] === undefined || options[key] === null) {
} else {
dispatch.on(key + '._', options[key]);
}
}
}
}
private clearElement() {
this.el.nativeElement.innerHTML = '';
// remove tooltip if exists
if (this.chart && this.chart.tooltip && this.chart.tooltip.id) {
d3.select('#' + this.chart.tooltip.id()).remove();
}
if (nv.tooltip && nv.tooltip.cleanup) {
nv.tooltip.cleanup();
}
if (this.chart && this.chart.resizeHandler) { this.chart.resizeHandler.clear(); }
this.chart = null;
}
}
}