// JS import { category21 } from '../javascripts/modules/colors'; import { timeFormatFactory, formatDate } from '../javascripts/modules/dates'; const d3 = require('d3'); const nv = require('nvd3'); // CSS require('../node_modules/nvd3/build/nv.d3.min.css'); require('./nvd3_vis.css'); const minBarWidth = 15; const animationTime = 1000; const addTotalBarValues = function (chart, data, stacked) { const svg = d3.select('svg'); const format = d3.format('.3s'); const countSeriesDisplayed = data.length; const totalStackedValues = stacked && data.length !== 0 ? data[0].values.map(function (bar, iBar) { const bars = data.map(function (series) { return series.values[iBar]; }); return d3.sum(bars, function (d) { return d.y; }); }) : []; const rectsToBeLabeled = svg.selectAll('g.nv-group').filter( function (d, i) { if (!stacked) { return true; } return i === countSeriesDisplayed - 1; }).selectAll('rect.positive'); const groupLabels = svg.select('g.nv-barsWrap').append('g'); rectsToBeLabeled.each( function (d, index) { const rectObj = d3.select(this); const transformAttr = rectObj.attr('transform'); const yPos = parseFloat(rectObj.attr('y')); const xPos = parseFloat(rectObj.attr('x')); const rectWidth = parseFloat(rectObj.attr('width')); const t = groupLabels.append('text') .attr('x', xPos) // rough position first, fine tune later .attr('y', yPos - 5) .text(format(stacked ? totalStackedValues[index] : d.y)) .attr('transform', transformAttr) .attr('class', 'bar-chart-label'); const labelWidth = t.node().getBBox().width; t.attr('x', xPos + rectWidth / 2 - labelWidth / 2); // fine tune }); }; function nvd3Vis(slice) { let chart; let colorKey = 'key'; const render = function () { d3.json(slice.jsonEndpoint(), function (error, payload) { slice.container.html(''); // Check error first, otherwise payload can be null if (error) { slice.error(error.responseText, error); return; } // Calculates the longest label size for stretching bottom margin function calculateStretchMargins(payloadData) { const axisLabels = payloadData.data[0].values; let stretchMargin = 0; const pixelsPerCharX = 4.5; // approx, depends on font size let maxLabelSize = 0; for (let i = 0; i < axisLabels.length; i++) { maxLabelSize = Math.max(axisLabels[i].x.length, maxLabelSize); } stretchMargin = Math.ceil(Math.max(stretchMargin, pixelsPerCharX * maxLabelSize)); return stretchMargin; } let width = slice.width(); const fd = payload.form_data; const barchartWidth = function () { let bars; if (fd.bar_stacked) { bars = d3.max(payload.data, function (d) { return d.values.length; }); } else { bars = d3.sum(payload.data, function (d) { return d.values.length; }); } if (bars * minBarWidth > width) { return bars * minBarWidth; } return width; }; const vizType = fd.viz_type; const f = d3.format('.3s'); const reduceXTicks = fd.reduce_x_ticks || false; let stacked = false; let row; nv.addGraph(function () { switch (vizType) { case 'line': if (fd.show_brush) { chart = nv.models.lineWithFocusChart(); chart.focus.xScale(d3.time.scale.utc()); chart.x2Axis .showMaxMin(fd.x_axis_showminmax) .staggerLabels(false); } else { chart = nv.models.lineChart(); } // To alter the tooltip header // chart.interactiveLayer.tooltip.headerFormatter(function(){return '';}); chart.xScale(d3.time.scale.utc()); chart.interpolate(fd.line_interpolation); chart.xAxis .showMaxMin(fd.x_axis_showminmax) .staggerLabels(false); break; case 'bar': chart = nv.models.multiBarChart() .showControls(fd.show_controls) .groupSpacing(0.1); if (!reduceXTicks) { width = barchartWidth(); } chart.width(width); chart.xAxis .showMaxMin(false) .staggerLabels(true); stacked = fd.bar_stacked; chart.stacked(stacked); if (fd.show_bar_value) { setTimeout(function () { addTotalBarValues(chart, payload.data, stacked); }, animationTime); } break; case 'dist_bar': chart = nv.models.multiBarChart() .showControls(fd.show_controls) .reduceXTicks(reduceXTicks) .rotateLabels(45) .groupSpacing(0.1); // Distance between each group of bars. chart.xAxis .showMaxMin(false); stacked = fd.bar_stacked; chart.stacked(stacked); if (fd.show_bar_value) { setTimeout(function () { addTotalBarValues(chart, payload.data, stacked); }, animationTime); } if (!reduceXTicks) { width = barchartWidth(); } chart.width(width); break; case 'pie': chart = nv.models.pieChart(); colorKey = 'x'; chart.valueFormat(f); if (fd.donut) { chart.donut(true); } chart.labelsOutside(fd.labels_outside); chart.labelThreshold(0.05) // Configure the minimum slice size for labels to show up .labelType(fd.pie_label_type); chart.cornerRadius(true); break; case 'column': chart = nv.models.multiBarChart() .reduceXTicks(false) .rotateLabels(45); break; case 'compare': chart = nv.models.cumulativeLineChart(); chart.xScale(d3.time.scale.utc()); chart.xAxis .showMaxMin(false) .staggerLabels(true); break; case 'bubble': row = (col1, col2) => `
| ` + `${p[fd.entity]} (${p.group})` + ' |