178 lines
5.4 KiB
JavaScript
178 lines
5.4 KiB
JavaScript
|
|
||
|
/***
|
||
|
* This chart treats the X position as the INDEX, not the value
|
||
|
* Each series at the same index MUST be the same x value for a valid representation
|
||
|
* This is needed specifically for daily data where the gap between Friday and Monday
|
||
|
* should be equal to the gap from Monday to Tuesday. (and of course, holidays can be
|
||
|
* omitted without issue, as long as ALL series omit the same days).
|
||
|
* An intentional side effect is that ALL ticks will land on actual data points,
|
||
|
* so this visualization can also be used for Month End data points, showing Month End
|
||
|
* ticks on the X axis
|
||
|
***/
|
||
|
|
||
|
nv.charts.stackedAreaChart = function() {
|
||
|
var selector = null,
|
||
|
data = [],
|
||
|
duration = 500,
|
||
|
tooltip = function(key, x, y, e, graph) {
|
||
|
return '<h3>' + key + '</h3>' +
|
||
|
'<p>' + y + ' at ' + x + '</p>'
|
||
|
};
|
||
|
|
||
|
|
||
|
var graph = nv.models.stackedAreaWithLegend()
|
||
|
.x(function(d,i) { return i }),
|
||
|
showTooltip = function(e) {
|
||
|
var offsetElement = document.getElementById(selector.substr(1)),
|
||
|
left = e.pos[0] + offsetElement.offsetLeft,
|
||
|
top = e.pos[1] + offsetElement.offsetTop,
|
||
|
formatX = graph.xAxis.tickFormat(),
|
||
|
formatY = graph.yAxis.tickFormat(),
|
||
|
x = formatX(graph.x()(e, e.pointIndex)),
|
||
|
//x = formatX(graph.x()(e.point)),
|
||
|
y = formatY(graph.y()(e.point)),
|
||
|
content = tooltip(e.series.key, x, y, e, graph);
|
||
|
|
||
|
nv.tooltip.show([left, top], content);
|
||
|
};
|
||
|
|
||
|
//setting component defaults
|
||
|
//graph.xAxis.tickFormat(d3.format(',r'));
|
||
|
graph.xAxis.tickFormat(function(d) {
|
||
|
//return d3.time.format('%x')(new Date(d))
|
||
|
//log(d, data[0].values[d]);
|
||
|
return d3.time.format('%x')(new Date(data[0].values[d].x))
|
||
|
});
|
||
|
|
||
|
//graph.yAxis.tickFormat(d3.format(',.2f'));
|
||
|
graph.yAxis.tickFormat(d3.format(',.2%'));
|
||
|
|
||
|
|
||
|
//TODO: consider a method more similar to how the models are built
|
||
|
function chart() {
|
||
|
if (!selector || !data.length) return chart; //do nothing if you have nothing to work with
|
||
|
|
||
|
d3.select(selector).select('svg')
|
||
|
.datum(data)
|
||
|
.transition().duration(duration)
|
||
|
.call(graph); //consider using transition chaining like in the models
|
||
|
|
||
|
return chart;
|
||
|
}
|
||
|
|
||
|
|
||
|
// This should always only be called once, then update should be used after,
|
||
|
// in which case should consider the 'd3 way' and merge this with update,
|
||
|
// but simply do this on enter... should try anoter example that way
|
||
|
chart.build = function() {
|
||
|
if (!selector || !data.length) return chart; //do nothing if you have nothing to work with
|
||
|
|
||
|
nv.addGraph({
|
||
|
generate: function() {
|
||
|
var container = d3.select(selector),
|
||
|
width = function() { return parseInt(container.style('width')) },
|
||
|
height = function() { return parseInt(container.style('height')) },
|
||
|
svg = container.append('svg');
|
||
|
|
||
|
graph
|
||
|
.width(width)
|
||
|
.height(height);
|
||
|
|
||
|
svg
|
||
|
.attr('width', width())
|
||
|
.attr('height', height())
|
||
|
.datum(data)
|
||
|
.transition().duration(duration)
|
||
|
.call(graph);
|
||
|
|
||
|
return graph;
|
||
|
},
|
||
|
callback: function(graph) {
|
||
|
graph.dispatch.on('tooltipShow', showTooltip);
|
||
|
graph.dispatch.on('tooltipHide', nv.tooltip.cleanup);
|
||
|
|
||
|
//TODO: create resize queue and have nv core handle resize instead of binding all to window resize
|
||
|
window.onresize =
|
||
|
function() {
|
||
|
// now that width and height are functions, should be automatic..of course you can always override them
|
||
|
d3.select(selector + ' svg')
|
||
|
.attr('width', graph.width()()) //need to set SVG dimensions, chart is not aware of the SVG component
|
||
|
.attr('height', graph.height()())
|
||
|
.call(graph);
|
||
|
};
|
||
|
}
|
||
|
});
|
||
|
|
||
|
return chart;
|
||
|
};
|
||
|
|
||
|
|
||
|
/*
|
||
|
// moved to chart()
|
||
|
chart.update = function() {
|
||
|
if (!selector || !data.length) return chart; //do nothing if you have nothing to work with
|
||
|
|
||
|
d3.select(selector).select('svg')
|
||
|
.datum(data)
|
||
|
.transition().duration(duration).call(graph);
|
||
|
|
||
|
return chart;
|
||
|
};
|
||
|
*/
|
||
|
|
||
|
chart.data = function(_) {
|
||
|
if (!arguments.length) return data;
|
||
|
data = _;
|
||
|
return chart;
|
||
|
};
|
||
|
|
||
|
chart.selector = function(_) {
|
||
|
if (!arguments.length) return selector;
|
||
|
selector = _;
|
||
|
return chart;
|
||
|
};
|
||
|
|
||
|
chart.duration = function(_) {
|
||
|
if (!arguments.length) return duration;
|
||
|
duration = _;
|
||
|
return chart;
|
||
|
};
|
||
|
|
||
|
chart.tooltip = function(_) {
|
||
|
if (!arguments.length) return tooltip;
|
||
|
tooltip = _;
|
||
|
return chart;
|
||
|
};
|
||
|
|
||
|
chart.xTickFormat = function(_) {
|
||
|
if (!arguments.length) return graph.xAxis.tickFormat();
|
||
|
graph.xAxis.tickFormat(typeof _ === 'function' ? _ : d3.format(_));
|
||
|
return chart;
|
||
|
};
|
||
|
|
||
|
chart.yTickFormat = function(_) {
|
||
|
if (!arguments.length) return graph.yAxis.tickFormat();
|
||
|
graph.yAxis.tickFormat(typeof _ === 'function' ? _ : d3.format(_));
|
||
|
return chart;
|
||
|
};
|
||
|
|
||
|
chart.xAxisLabel = function(_) {
|
||
|
if (!arguments.length) return graph.xAxis.axisLabel();
|
||
|
graph.xAxis.axisLabel(_);
|
||
|
return chart;
|
||
|
};
|
||
|
|
||
|
chart.yAxisLabel = function(_) {
|
||
|
if (!arguments.length) return graph.yAxis.axisLabel();
|
||
|
graph.yAxis.axisLabel(_);
|
||
|
return chart;
|
||
|
};
|
||
|
|
||
|
d3.rebind(chart, graph, 'x', 'y');
|
||
|
|
||
|
chart.graph = graph; // Give direct access for getter/setters, and dispatchers
|
||
|
|
||
|
return chart;
|
||
|
};
|
||
|
|