UNPKG

nvd3-fork

Version:

FORK! of NVD3, a reusable charting library written in d3.js

301 lines (254 loc) 12.8 kB
nv.models.parallelCoordinatesChart = function () { "use strict"; //============================================================ // Public Variables with Default Settings //------------------------------------------------------------ var parallelCoordinates = nv.models.parallelCoordinates() var legend = nv.models.legend() var tooltip = nv.models.tooltip(); var dimensionTooltip = nv.models.tooltip(); var margin = { top: 0, right: 0, bottom: 0, left: 0 } , marginTop = null , width = null , height = null , showLegend = true , color = nv.utils.defaultColor() , state = nv.utils.state() , dimensionData = [] , displayBrush = true , defaultState = null , noData = null , nanValue = "undefined" , dispatch = d3.dispatch('dimensionsOrder', 'brushEnd', 'stateChange', 'changeState', 'renderEnd') , controlWidth = function () { return showControls ? 180 : 0 } ; //============================================================ //============================================================ // Private Variables //------------------------------------------------------------ var renderWatch = nv.utils.renderWatch(dispatch); var stateGetter = function(data) { return function() { return { active: data.map(function(d) { return !d.disabled }) }; } }; var stateSetter = function(data) { return function(state) { if(state.active !== undefined) { data.forEach(function(series, i) { series.disabled = !state.active[i]; }); } } }; tooltip.contentGenerator(function(data) { var str = '<table><thead><tr><td class="legend-color-guide"><div style="background-color:' + data.color + '"></div></td><td><strong>' + data.key + '</strong></td></tr></thead>'; if(data.series.length !== 0) { str = str + '<tbody><tr><td height ="10px"></td></tr>'; data.series.forEach(function(d){ str = str + '<tr><td class="legend-color-guide"><div style="background-color:' + d.color + '"></div></td><td class="key">' + d.key + '</td><td class="value">' + d.value + '</td></tr>'; }); str = str + '</tbody>'; } str = str + '</table>'; return str; }); //============================================================ // Chart function //------------------------------------------------------------ function chart(selection) { renderWatch.reset(); renderWatch.models(parallelCoordinates); selection.each(function(data) { var container = d3.select(this); nv.utils.initSVG(container); var that = this; var availableWidth = nv.utils.availableWidth(width, container, margin), availableHeight = nv.utils.availableHeight(height, container, margin); chart.update = function() { container.call(chart); }; chart.container = this; state.setter(stateSetter(dimensionData), chart.update) .getter(stateGetter(dimensionData)) .update(); //set state.disabled state.disabled = dimensionData.map(function (d) { return !!d.disabled }); //Keep dimensions position in memory dimensionData = dimensionData.map(function (d) {d.disabled = !!d.disabled; return d}); dimensionData.forEach(function (d, i) { d.originalPosition = isNaN(d.originalPosition) ? i : d.originalPosition; d.currentPosition = isNaN(d.currentPosition) ? i : d.currentPosition; }); if (!defaultState) { var key; defaultState = {}; for(key in state) { if(state[key] instanceof Array) defaultState[key] = state[key].slice(0); else defaultState[key] = state[key]; } } // Display No Data message if there's nothing to show. if(!data || !data.length) { nv.utils.noData(chart, container); return chart; } else { container.selectAll('.nv-noData').remove(); } //------------------------------------------------------------ // Setup containers and skeleton of chart var wrap = container.selectAll('g.nv-wrap.nv-parallelCoordinatesChart').data([data]); var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-parallelCoordinatesChart').append('g'); var g = wrap.select('g'); gEnter.append('g').attr('class', 'nv-parallelCoordinatesWrap'); gEnter.append('g').attr('class', 'nv-legendWrap'); g.select("rect") .attr("width", availableWidth) .attr("height", (availableHeight > 0) ? availableHeight : 0); // Legend if (!showLegend) { g.select('.nv-legendWrap').selectAll('*').remove(); } else { legend.width(availableWidth) .color(function (d) { return "rgb(188,190,192)"; }); g.select('.nv-legendWrap') .datum(dimensionData.sort(function (a, b) { return a.originalPosition - b.originalPosition; })) .call(legend); if (!marginTop && legend.height() !== margin.top) { margin.top = legend.height(); availableHeight = nv.utils.availableHeight(height, container, margin); } wrap.select('.nv-legendWrap') .attr('transform', 'translate( 0 ,' + (-margin.top) + ')'); } wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); // Main Chart Component(s) parallelCoordinates .width(availableWidth) .height(availableHeight) .dimensionData(dimensionData) .displayBrush(displayBrush); var parallelCoordinatesWrap = g.select('.nv-parallelCoordinatesWrap ') .datum(data); parallelCoordinatesWrap.transition().call(parallelCoordinates); //============================================================ // Event Handling/Dispatching (in chart's scope) //------------------------------------------------------------ //Display reset brush button parallelCoordinates.dispatch.on('brushEnd', function (active, hasActiveBrush) { if (hasActiveBrush) { displayBrush = true; dispatch.brushEnd(active); } else { displayBrush = false; } }); legend.dispatch.on('stateChange', function(newState) { for(var key in newState) { state[key] = newState[key]; } dispatch.stateChange(state); chart.update(); }); //Update dimensions order and display reset sorting button parallelCoordinates.dispatch.on('dimensionsOrder', function (e) { dimensionData.sort(function (a, b) { return a.currentPosition - b.currentPosition; }); var isSorted = false; dimensionData.forEach(function (d, i) { d.currentPosition = i; if (d.currentPosition !== d.originalPosition) isSorted = true; }); dispatch.dimensionsOrder(dimensionData, isSorted); }); // Update chart from a state object passed to event handler dispatch.on('changeState', function (e) { if (typeof e.disabled !== 'undefined') { dimensionData.forEach(function (series, i) { series.disabled = e.disabled[i]; }); state.disabled = e.disabled; } chart.update(); }); }); renderWatch.renderEnd('parraleleCoordinateChart immediate'); return chart; } //============================================================ // Event Handling/Dispatching (out of chart's scope) //------------------------------------------------------------ parallelCoordinates.dispatch.on('elementMouseover.tooltip', function (evt) { var tp = { key: evt.label, color: evt.color, series: [] } if(evt.values){ Object.keys(evt.values).forEach(function (d) { var dim = evt.dimensions.filter(function (dd) {return dd.key === d;})[0]; if(dim){ var v; if (isNaN(evt.values[d]) || isNaN(parseFloat(evt.values[d]))) { v = nanValue; } else { v = dim.format(evt.values[d]); } tp.series.push({ idx: dim.currentPosition, key: d, value: v, color: dim.color }); } }); tp.series.sort(function(a,b) {return a.idx - b.idx}); } tooltip.data(tp).hidden(false); }); parallelCoordinates.dispatch.on('elementMouseout.tooltip', function(evt) { tooltip.hidden(true) }); parallelCoordinates.dispatch.on('elementMousemove.tooltip', function () { tooltip(); }); //============================================================ // Expose Public Variables //------------------------------------------------------------ // expose chart's sub-components chart.dispatch = dispatch; chart.parallelCoordinates = parallelCoordinates; chart.legend = legend; chart.tooltip = tooltip; chart.options = nv.utils.optionsFunc.bind(chart); chart._options = Object.create({}, { // simple options, just get/set the necessary values width: { get: function () { return width; }, set: function (_) { width = _; } }, height: { get: function () { return height; }, set: function (_) { height = _; } }, showLegend: { get: function () { return showLegend; }, set: function (_) { showLegend = _; } }, defaultState: { get: function () { return defaultState; }, set: function (_) { defaultState = _; } }, dimensionData: { get: function () { return dimensionData; }, set: function (_) { dimensionData = _; } }, displayBrush: { get: function () { return displayBrush; }, set: function (_) { displayBrush = _; } }, noData: { get: function () { return noData; }, set: function (_) { noData = _; } }, nanValue: { get: function () { return nanValue; }, set: function (_) { nanValue = _; } }, // options that require extra logic in the setter margin: { get: function () { return margin; }, set: function (_) { if (_.top !== undefined) { margin.top = _.top; marginTop = _.top; } margin.right = _.right !== undefined ? _.right : margin.right; margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; margin.left = _.left !== undefined ? _.left : margin.left; } }, color: {get: function(){return color;}, set: function(_){ color = nv.utils.getColor(_); legend.color(color); parallelCoordinates.color(color); }} }); nv.utils.inheritOptions(chart, parallelCoordinates); nv.utils.initOptions(chart); return chart; };