Added another layer of abstraction to take care of all the glue and make the chart api extremely simple. First try, so not entirely complete, but does function.
This commit is contained in:
parent
1880f11775
commit
4e7475da73
81
examples/lineChart.html
Normal file
81
examples/lineChart.html
Normal file
@ -0,0 +1,81 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
|
||||
<link href="../src/d3.css" rel="stylesheet" type="text/css">
|
||||
|
||||
<style>
|
||||
|
||||
body {
|
||||
overflow-y:scroll;
|
||||
}
|
||||
|
||||
text {
|
||||
font: 12px sans-serif;
|
||||
}
|
||||
|
||||
#chart1 {
|
||||
height: 500px;
|
||||
margin: 10px;
|
||||
min-width: 100px;
|
||||
min-height: 100px;
|
||||
/*
|
||||
Minimum height and width is a good idea to prevent negative SVG dimensions...
|
||||
For example width should be =< margin.left + margin.right + 1,
|
||||
of course 1 pixel for the entire chart would not be very useful, BUT should not have errors
|
||||
*/
|
||||
}
|
||||
|
||||
</style>
|
||||
<body>
|
||||
|
||||
<div id="chart1">
|
||||
</div>
|
||||
|
||||
<script src="../lib/d3.v2.js"></script>
|
||||
<script src="../lib/jquery.min.js"></script>
|
||||
<script src="../nv.d3.js"></script>
|
||||
<script src="../src/nvtooltip.js"></script>
|
||||
<script src="../src/models/legend.js"></script>
|
||||
<script src="../src/models/xaxis.js"></script>
|
||||
<script src="../src/models/yaxis.js"></script>
|
||||
<script src="../src/models/line.js"></script>
|
||||
<script src="../src/models/lineWithLegend.js"></script>
|
||||
<script src="../src/charts/lineChart.js"></script>
|
||||
<script>
|
||||
|
||||
|
||||
|
||||
nv.charts.line()
|
||||
.data(sinAndCos())
|
||||
.selector('#chart1')
|
||||
.yAxisLabel('Voltage (v)')
|
||||
.build();
|
||||
|
||||
|
||||
|
||||
|
||||
function sinAndCos() {
|
||||
var sin = [],
|
||||
cos = [];
|
||||
|
||||
for (var i = 0; i < 100; i++) {
|
||||
sin.push({x: i, y: Math.sin(i/10)});
|
||||
cos.push({x: i, y: .5 * Math.cos(i/10)});
|
||||
}
|
||||
|
||||
return [
|
||||
{
|
||||
values: sin,
|
||||
key: "Sine Wave",
|
||||
color: "#ff7f0e"
|
||||
},
|
||||
{
|
||||
values: cos,
|
||||
key: "Cosine Wave",
|
||||
color: "#2ca02c"
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
</script>
|
@ -13,11 +13,22 @@ text {
|
||||
font: 12px sans-serif;
|
||||
}
|
||||
|
||||
#chart1 {
|
||||
height: 500px;
|
||||
margin: 10px;
|
||||
min-width: 100px;
|
||||
min-height: 100px;
|
||||
/*
|
||||
Minimum height and width is a good idea to prevent negative SVG dimensions...
|
||||
For example width should be =< margin.left + margin.right + 1,
|
||||
of course 1 pixel for the entire chart would not be very useful, BUT should not have errors
|
||||
*/
|
||||
}
|
||||
|
||||
</style>
|
||||
<body>
|
||||
|
||||
<div id="test1">
|
||||
<svg></svg>
|
||||
<div id="chart1">
|
||||
</div>
|
||||
|
||||
<script src="../lib/d3.v2.js"></script>
|
||||
@ -31,86 +42,76 @@ text {
|
||||
<script src="../src/models/lineWithLegend.js"></script>
|
||||
<script>
|
||||
|
||||
/************
|
||||
* Considering making an nv.charts object which will contain abstractions similar to the one below,
|
||||
* but with the usual d3 reusable style.
|
||||
* I could make this abstraction inside the layer above, but this layer incorporates some jQuery, so
|
||||
* thinking nv.charts can be the glue that's not 100% d3
|
||||
************/
|
||||
|
||||
var selector = '#chart1',
|
||||
chart = nv.models.lineWithLegend(),
|
||||
data = sinAndCos(),
|
||||
xTickFormat = d3.format(',r'),
|
||||
yTickFormat = d3.format(',.2f'),
|
||||
xAxisLabel = null,
|
||||
yAxisLabel = 'Voltage (v)',
|
||||
duration = 500;
|
||||
|
||||
//Format A
|
||||
nv.addGraph({
|
||||
generate: function() {
|
||||
var width = $(window).width() - 40,
|
||||
height = $(window).height() - 40;
|
||||
var container = d3.select(selector),
|
||||
width = function() { return parseInt(container.style('width')) },
|
||||
height = function() { return parseInt(container.style('height')) },
|
||||
svg = container.append('svg');
|
||||
|
||||
var chart = nv.models.lineWithLegend()
|
||||
.width(width)
|
||||
.height(height)
|
||||
//.margin({top: 20, right: 10, bottom: 50, left: 80})
|
||||
chart
|
||||
.width(width)
|
||||
.height(height)
|
||||
|
||||
//chart.yAxis.axisLabel('Cumulative');
|
||||
//chart.xAxis.axisLabel('Date');
|
||||
chart.xAxis
|
||||
.tickFormat(xTickFormat);
|
||||
|
||||
chart.yAxis
|
||||
.tickFormat(yTickFormat)
|
||||
.axisLabel(yAxisLabel);
|
||||
|
||||
chart.yAxis.tickFormat(d3.format(',%'))
|
||||
chart.xAxis.tickFormat(function(d) {
|
||||
return d3.time.format('%x')(new Date(d))
|
||||
})
|
||||
|
||||
//chart.xaxis.tickFormat(d3.format(".02f"))
|
||||
|
||||
var svg = d3.select('#test1 svg')
|
||||
.attr('width', width)
|
||||
.attr('height', height)
|
||||
.datum(sinAndCos())
|
||||
|
||||
svg.transition().duration(500).call(chart);
|
||||
svg
|
||||
.attr('width', width())
|
||||
.attr('height', height())
|
||||
.datum(data)
|
||||
.transition().duration(duration).call(chart);
|
||||
|
||||
return chart;
|
||||
},
|
||||
callback: function(graph) {
|
||||
callback: function(chart) {
|
||||
var showTooltip = function(e) {
|
||||
var offset = $(selector).offset(),
|
||||
left = e.pos[0] + offset.left,
|
||||
top = e.pos[1] + offset.top,
|
||||
formatY = chart.yAxis.tickFormat(), //Assumes using same format as axis, can customize to show higher precision, etc.
|
||||
formatX = chart.xAxis.tickFormat();
|
||||
|
||||
graph.dispatch.on('tooltipShow', function(e) {
|
||||
var offset = $('#test1').offset(),
|
||||
left = e.pos[0] + offset.left,
|
||||
top = e.pos[1] + offset.top,
|
||||
formatterY = d3.format(",.2%"),
|
||||
formatterX = function(d) {
|
||||
return d3.time.format('%x')(new Date(d))
|
||||
};
|
||||
// uses the chart's getX and getY, you may customize if x position is not the same as the value you want
|
||||
// ex. daily data without weekends, x is the index, while you want the date
|
||||
var content = '<h3>' + e.series.key + '</h3>' +
|
||||
'<p>' +
|
||||
formatY(chart.y()(e.point)) + ' at ' + formatX(chart.x()(e.point)) +
|
||||
'</p>';
|
||||
|
||||
var content = '<h3>' + e.series.key + '</h3>' +
|
||||
'<p>' +
|
||||
formatterY(graph.y()(e.point)) + ' on ' + formatterX(graph.x()(e.point)) +
|
||||
'</p>';
|
||||
|
||||
//$('#positionTest').css({'left': left, 'top': top});
|
||||
nvtooltip.show([left, top], content);
|
||||
});
|
||||
|
||||
graph.dispatch.on('tooltipHide', function(e) {
|
||||
nvtooltip.cleanup();
|
||||
});
|
||||
nvtooltip.show([left, top], content);
|
||||
};
|
||||
|
||||
chart.dispatch.on('tooltipShow', showTooltip);
|
||||
chart.dispatch.on('tooltipHide', nvtooltip.cleanup);
|
||||
|
||||
|
||||
$(window).resize(function() {
|
||||
var width = $(window).width() - 40,
|
||||
height = $(window).height() - 40,
|
||||
margin = graph.margin();
|
||||
|
||||
|
||||
if (width < margin.left + margin.right + 20)
|
||||
width = margin.left + margin.right + 20;
|
||||
|
||||
if (height < margin.top + margin.bottom + 20)
|
||||
height = margin.top + margin.bottom + 20;
|
||||
|
||||
|
||||
graph
|
||||
.width(width)
|
||||
.height(height);
|
||||
|
||||
d3.select('#test1 svg')
|
||||
.attr('width', width)
|
||||
.attr('height', height)
|
||||
.call(graph);
|
||||
|
||||
// now that width and height are functions, should be automatic..of course you can always override them
|
||||
d3.select('#chart1 svg')
|
||||
.attr('width', chart.width()()) //need to set SVG dimensions, chart is not aware of the SVG component
|
||||
.attr('height', chart.height()())
|
||||
.call(chart);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -67,15 +67,18 @@ nv.addGraph({
|
||||
},
|
||||
callback: function(graph) {
|
||||
|
||||
/*
|
||||
graph.dispatch.on('tooltipShow', function(e) {
|
||||
var offset = $('#chart').offset(),
|
||||
left = e.pos[0] + offset.left,
|
||||
top = e.pos[1] + offset.top,
|
||||
formatterY = graph.stacked.offset() == 'expand' ? d3.format(',.2%') : d3.format(',.2f'), //TODO: stacked format should be set by caller
|
||||
formatterX = function(d) { return d };
|
||||
/*
|
||||
formatterY = d3.format(",.2%"),
|
||||
formatterX = function(d) {
|
||||
return d3.time.format('%x')(new Date(d))
|
||||
};
|
||||
*/
|
||||
|
||||
var content = '<h3>' + e.series.key + '</h3>' +
|
||||
'<p>' +
|
||||
@ -89,7 +92,6 @@ nv.addGraph({
|
||||
graph.dispatch.on('tooltipHide', function(e) {
|
||||
nvtooltip.cleanup();
|
||||
});
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
77
nv.d3.js
77
nv.d3.js
@ -91,9 +91,10 @@ var nv = {version: "0.0.1"};
|
||||
|
||||
window.nv = nv;
|
||||
|
||||
nv.models = {};
|
||||
nv.graphs = [];
|
||||
nv.log = {};
|
||||
nv.models = {}; //stores all the possible models/components
|
||||
nv.charts = {}; //stores all the ready to use charts
|
||||
nv.graphs = []; //stores all the graphs currently on the page
|
||||
nv.log = {}; //stores some statistics and potential error messages
|
||||
|
||||
nv.dispatch = d3.dispatch("render_start", "render_end");
|
||||
|
||||
@ -124,7 +125,7 @@ nv.dispatch.on("render_end", function(e) {
|
||||
nv.log.endTime = +new Date;
|
||||
nv.log.totalTime = nv.log.endTime - nv.log.startTime;
|
||||
//log('end', nv.log.endTime);
|
||||
log('total', nv.log.totalTime);
|
||||
log('total', nv.log.totalTime); //used for development, to keep track of graph generation times
|
||||
});
|
||||
|
||||
|
||||
@ -1242,8 +1243,8 @@ nv.models.lineWithFocus = function() {
|
||||
|
||||
nv.models.lineWithLegend = function() {
|
||||
var margin = {top: 30, right: 20, bottom: 50, left: 60},
|
||||
width = 960,
|
||||
height = 500,
|
||||
getWidth = function() { return 960 },
|
||||
getHeight = function() { return 500 },
|
||||
dotRadius = function() { return 2.5 },
|
||||
color = d3.scale.category10().range(),
|
||||
dispatch = d3.dispatch('tooltipShow', 'tooltipHide');
|
||||
@ -1260,6 +1261,9 @@ nv.models.lineWithLegend = function() {
|
||||
|
||||
function chart(selection) {
|
||||
selection.each(function(data) {
|
||||
var width = getWidth(),
|
||||
height = getHeight();
|
||||
|
||||
var series = data.filter(function(d) { return !d.disabled })
|
||||
.map(function(d) { return d.values });
|
||||
|
||||
@ -1395,14 +1399,14 @@ nv.models.lineWithLegend = function() {
|
||||
};
|
||||
|
||||
chart.width = function(_) {
|
||||
if (!arguments.length) return width;
|
||||
width = _;
|
||||
if (!arguments.length) return getWidth;
|
||||
getWidth = d3.functor(_);
|
||||
return chart;
|
||||
};
|
||||
|
||||
chart.height = function(_) {
|
||||
if (!arguments.length) return height;
|
||||
height = _;
|
||||
if (!arguments.length) return getHeight;
|
||||
getHeight = d3.functor(_);
|
||||
return chart;
|
||||
};
|
||||
|
||||
@ -2042,6 +2046,7 @@ nv.models.stackedArea = function() {
|
||||
* 'default' (input order)
|
||||
************************************/
|
||||
|
||||
var lines = nv.models.line();
|
||||
|
||||
function chart(selection) {
|
||||
selection.each(function(data) {
|
||||
@ -2049,30 +2054,44 @@ nv.models.stackedArea = function() {
|
||||
// Need to leave data alone to switch between stacked, stream, and expanded
|
||||
var dataCopy = JSON.parse(JSON.stringify(data));
|
||||
|
||||
//log(dataCopy);
|
||||
dataCopy = dataCopy.map(function(series) { return series.values })
|
||||
|
||||
//compute the data based on offset and order (calc's y0 for every point)
|
||||
//dataCopy = d3.layout.stack().offset(offset).order(order).values(function(d){ return d.values })(dataCopy);
|
||||
dataCopy = d3.layout.stack().offset(offset).order(order)(dataCopy);
|
||||
dataCopy = d3.layout.stack().offset(offset).order(order).values(function(d){ return d.values })(dataCopy);
|
||||
|
||||
var mx = dataCopy[0].length - 1, // assumes that all layers have same # of samples & that there is at least one layer
|
||||
var mx = dataCopy[0].values.length - 1, // assumes that all layers have same # of samples & that there is at least one layer
|
||||
my = d3.max(dataCopy, function(d) {
|
||||
return d3.max(d, function(d) {
|
||||
return d3.max(d.values, function(d) {
|
||||
return d.y0 + d.y;
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
lines
|
||||
.width(width - margin.left - margin.right)
|
||||
.height(height - margin.top - margin.bottom)
|
||||
.y(function(d) { return d.y + d.y0 })
|
||||
.color(data.map(function(d,i) {
|
||||
return d.color || color[i % 10];
|
||||
}).filter(function(d,i) { return !data[i].disabled }));
|
||||
|
||||
// Select the wrapper g, if it exists.
|
||||
var wrap = d3.select(this).selectAll('g.d3stream').data([dataCopy]);
|
||||
var wrap = d3.select(this).selectAll('g.d3stackedarea').data([dataCopy]);
|
||||
|
||||
// Create the skeletal chart on first load.
|
||||
var gEnter = wrap.enter().append('g').attr('class', 'd3stream').append('g');
|
||||
var gEnter = wrap.enter().append('g').attr('class', 'd3stackedarea').append('g');
|
||||
|
||||
gEnter.append('g').attr('class', 'areaWrap');
|
||||
gEnter.append('g').attr('class', 'linesWrap');
|
||||
|
||||
|
||||
var g = wrap.select('g')
|
||||
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
|
||||
|
||||
var linesWrap = g.select('.linesWrap')
|
||||
.datum(dataCopy.filter(function(d) { return !d.disabled }))
|
||||
|
||||
d3.transition(linesWrap).call(lines);
|
||||
|
||||
|
||||
// Update the stacked graph
|
||||
var availableWidth = width - margin.left - margin.right,
|
||||
@ -2088,20 +2107,17 @@ nv.models.stackedArea = function() {
|
||||
.y0(function(d) { return availableHeight - d.y0 * availableHeight / my; })
|
||||
.y1(function(d) { return availableHeight - d.y0 * availableHeight / my; })
|
||||
|
||||
var path = g.selectAll('path')
|
||||
var path = g.select('.areaWrap').selectAll('path.area')
|
||||
.data(function(d) { return d });
|
||||
//.data(dataCopy);
|
||||
path.enter().append('path');
|
||||
path.enter().append('path').attr('class', 'area');
|
||||
d3.transition(path.exit())
|
||||
.attr('d', zeroArea)
|
||||
.attr('d', function(d,i) { return zeroArea(d.values,i) })
|
||||
.remove();
|
||||
path
|
||||
.style('fill-opacity', .75)
|
||||
.style('stroke-opacity', .75)
|
||||
.style('fill', function(d,i){ return color[i % 10] })
|
||||
.style('stroke', function(d,i){ return color[i % 10] });
|
||||
d3.transition(path)
|
||||
.attr('d', area);
|
||||
.attr('d', function(d,i) { return area(d.values,i) })
|
||||
|
||||
});
|
||||
|
||||
@ -2168,6 +2184,7 @@ nv.models.stackedArea = function() {
|
||||
return chart;
|
||||
};
|
||||
|
||||
chart.dispatch = lines.dispatch;
|
||||
|
||||
return chart;
|
||||
}
|
||||
@ -2214,9 +2231,8 @@ nv.models.stackedAreaWithLegend = function() {
|
||||
x .domain(d3.extent(d3.merge(series), getX ))
|
||||
.range([0, width - margin.left - margin.right]);
|
||||
|
||||
//TODO: remove if stream
|
||||
y .domain(stacked.offset() == 'zero' ?
|
||||
d3.extent(d3.merge(series), getY ) :
|
||||
y .domain(stacked.offset() == 'zero' ?
|
||||
[0, d3.max(d3.merge(series), getY )] :
|
||||
[0, 1] // 0 - 100%
|
||||
)
|
||||
.range([height - margin.top - margin.bottom, 0]);
|
||||
@ -2291,6 +2307,7 @@ nv.models.stackedAreaWithLegend = function() {
|
||||
d.hover = false;
|
||||
selection.transition().call(chart)
|
||||
});
|
||||
*/
|
||||
|
||||
stacked.dispatch.on('pointMouseover.tooltip', function(e) {
|
||||
dispatch.tooltipShow({
|
||||
@ -2306,7 +2323,6 @@ nv.models.stackedAreaWithLegend = function() {
|
||||
dispatch.tooltipHide(e);
|
||||
});
|
||||
|
||||
*/
|
||||
|
||||
|
||||
//TODO: margins should be adjusted based on what components are used: axes, axis labels, legend
|
||||
@ -2358,7 +2374,7 @@ nv.models.stackedAreaWithLegend = function() {
|
||||
.range(y.range())
|
||||
.ticks( stacked.offset() == 'wiggle' ? 0 : height / 36 )
|
||||
.tickSize(-(width - margin.right - margin.left), 0)
|
||||
.tickFormat(stacked.offset() == 'zero' ? d3.format(',2f') : d3.format('%')); //TODO: stacked format should be set by caller
|
||||
.tickFormat(stacked.offset() == 'zero' ? d3.format(',.2f') : d3.format('%')); //TODO: stacked format should be set by caller
|
||||
|
||||
d3.transition(g.select('.y.axis'))
|
||||
.call(yAxis);
|
||||
@ -2409,6 +2425,7 @@ nv.models.stackedAreaWithLegend = function() {
|
||||
return chart;
|
||||
};
|
||||
|
||||
chart.stacked = stacked;
|
||||
|
||||
// Expose the x-axis' tickFormat method.
|
||||
//chart.xAxis = {};
|
||||
|
4
nv.d3.min.js
vendored
4
nv.d3.min.js
vendored
File diff suppressed because one or more lines are too long
137
src/charts/lineChart.js
Normal file
137
src/charts/lineChart.js
Normal file
@ -0,0 +1,137 @@
|
||||
|
||||
//may make these more specific, like 'time series line with month end data points', etc.
|
||||
// or may make that yet another layer of abstraction.... trying to not get too crazy
|
||||
nv.charts.line = function() {
|
||||
|
||||
var selector = null,
|
||||
data = [],
|
||||
xTickFormat = d3.format(',r'),
|
||||
yTickFormat = d3.format(',.2f'),
|
||||
xAxisLabel = null,
|
||||
yAxisLabel = null,
|
||||
duration = 500;
|
||||
|
||||
var graph = nv.models.lineWithLegend(),
|
||||
showTooltip = function(e) { //TODO: simplify so all the calcualtions don't need to be done by the user.
|
||||
var offset = $(selector).offset(),
|
||||
left = e.pos[0] + offset.left,
|
||||
top = e.pos[1] + offset.top,
|
||||
formatY = graph.yAxis.tickFormat(), //Assumes using same format as axis, can customize to show higher precision, etc.
|
||||
formatX = graph.xAxis.tickFormat();
|
||||
|
||||
// uses the chart's getX and getY, you may customize if x position is not the same as the value you want
|
||||
// ex. daily data without weekends, x is the index, while you want the date
|
||||
var content = '<h3>' + e.series.key + '</h3>' +
|
||||
'<p>' +
|
||||
formatY(graph.y()(e.point)) + ' at ' + formatX(graph.x()(e.point)) +
|
||||
'</p>';
|
||||
|
||||
nvtooltip.show([left, top], content);
|
||||
};
|
||||
|
||||
|
||||
function chart() {
|
||||
return chart;
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
|
||||
graph.xAxis
|
||||
.tickFormat(xTickFormat);
|
||||
|
||||
graph.yAxis
|
||||
.tickFormat(yTickFormat)
|
||||
.axisLabel(yAxisLabel);
|
||||
|
||||
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', nvtooltip.cleanup);
|
||||
|
||||
$(window).resize(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;
|
||||
};
|
||||
|
||||
|
||||
chart.update = function() {
|
||||
//TODO: create update code
|
||||
|
||||
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.xTickFormat = function(_) {
|
||||
if (!arguments.length) return xTickFormat;
|
||||
xTickFormat = _;
|
||||
return chart;
|
||||
};
|
||||
|
||||
chart.yTickFormat = function(_) {
|
||||
if (!arguments.length) return yTickFormat;
|
||||
yTickFormat = _;
|
||||
return chart;
|
||||
};
|
||||
|
||||
chart.xAxisLabel = function(_) {
|
||||
if (!arguments.length) return xAxisLabel;
|
||||
xAxisLabel = _;
|
||||
return chart;
|
||||
};
|
||||
|
||||
chart.yAxisLabel = function(_) {
|
||||
if (!arguments.length) return yAxisLabel;
|
||||
yAxisLabel = _;
|
||||
return chart;
|
||||
};
|
||||
|
||||
|
||||
return chart;
|
||||
}
|
||||
|
@ -2,9 +2,10 @@ var nv = {version: "0.0.1"};
|
||||
|
||||
window.nv = nv;
|
||||
|
||||
nv.models = {};
|
||||
nv.graphs = [];
|
||||
nv.log = {};
|
||||
nv.models = {}; //stores all the possible models/components
|
||||
nv.charts = {}; //stores all the ready to use charts
|
||||
nv.graphs = []; //stores all the graphs currently on the page
|
||||
nv.log = {}; //stores some statistics and potential error messages
|
||||
|
||||
nv.dispatch = d3.dispatch("render_start", "render_end");
|
||||
|
||||
@ -35,7 +36,7 @@ nv.dispatch.on("render_end", function(e) {
|
||||
nv.log.endTime = +new Date;
|
||||
nv.log.totalTime = nv.log.endTime - nv.log.startTime;
|
||||
//log('end', nv.log.endTime);
|
||||
log('total', nv.log.totalTime);
|
||||
log('total', nv.log.totalTime); //used for development, to keep track of graph generation times
|
||||
});
|
||||
|
||||
|
||||
|
19
src/d3.css
19
src/d3.css
@ -49,6 +49,7 @@
|
||||
.nvtooltip p {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.nvtooltip span {
|
||||
@ -235,10 +236,26 @@ text {
|
||||
* Stacked Area
|
||||
*/
|
||||
|
||||
.d3stackedarea path {
|
||||
.d3stackedarea path.area {
|
||||
fill-opacity: .75;
|
||||
stroke-opacity: .75;
|
||||
}
|
||||
|
||||
.d3stackedarea .lines path {
|
||||
stroke-opacity: 0;
|
||||
}
|
||||
|
||||
|
||||
.d3stackedarea .lines .point {
|
||||
stroke-opacity: 0;
|
||||
fill-opacity: 0;
|
||||
transition: all 250ms linear;
|
||||
-moz-transition: all 250ms linear;
|
||||
-webkit-transition: all 250ms linear;
|
||||
}
|
||||
|
||||
.d3stackedarea .lines .point.hover {
|
||||
stroke-width: 20px;
|
||||
stroke-opacity: .75;
|
||||
fill-opacity: 1;
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
|
||||
nv.models.lineWithLegend = function() {
|
||||
var margin = {top: 30, right: 20, bottom: 50, left: 60},
|
||||
width = 960,
|
||||
height = 500,
|
||||
getWidth = function() { return 960 },
|
||||
getHeight = function() { return 500 },
|
||||
dotRadius = function() { return 2.5 },
|
||||
color = d3.scale.category10().range(),
|
||||
dispatch = d3.dispatch('tooltipShow', 'tooltipHide');
|
||||
@ -19,6 +19,9 @@ nv.models.lineWithLegend = function() {
|
||||
|
||||
function chart(selection) {
|
||||
selection.each(function(data) {
|
||||
var width = getWidth(),
|
||||
height = getHeight();
|
||||
|
||||
var series = data.filter(function(d) { return !d.disabled })
|
||||
.map(function(d) { return d.values });
|
||||
|
||||
@ -154,14 +157,14 @@ nv.models.lineWithLegend = function() {
|
||||
};
|
||||
|
||||
chart.width = function(_) {
|
||||
if (!arguments.length) return width;
|
||||
width = _;
|
||||
if (!arguments.length) return getWidth;
|
||||
getWidth = d3.functor(_);
|
||||
return chart;
|
||||
};
|
||||
|
||||
chart.height = function(_) {
|
||||
if (!arguments.length) return height;
|
||||
height = _;
|
||||
if (!arguments.length) return getHeight;
|
||||
getHeight = d3.functor(_);
|
||||
return chart;
|
||||
};
|
||||
|
||||
|
@ -20,6 +20,7 @@ nv.models.stackedArea = function() {
|
||||
* 'default' (input order)
|
||||
************************************/
|
||||
|
||||
var lines = nv.models.line();
|
||||
|
||||
function chart(selection) {
|
||||
selection.each(function(data) {
|
||||
@ -38,16 +39,33 @@ nv.models.stackedArea = function() {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
lines
|
||||
.width(width - margin.left - margin.right)
|
||||
.height(height - margin.top - margin.bottom)
|
||||
.y(function(d) { return d.y + d.y0 })
|
||||
.color(data.map(function(d,i) {
|
||||
return d.color || color[i % 10];
|
||||
}).filter(function(d,i) { return !data[i].disabled }));
|
||||
|
||||
// Select the wrapper g, if it exists.
|
||||
var wrap = d3.select(this).selectAll('g.d3stackedarea').data([dataCopy]);
|
||||
|
||||
// Create the skeletal chart on first load.
|
||||
var gEnter = wrap.enter().append('g').attr('class', 'd3stackedarea').append('g');
|
||||
|
||||
gEnter.append('g').attr('class', 'areaWrap');
|
||||
gEnter.append('g').attr('class', 'linesWrap');
|
||||
|
||||
|
||||
var g = wrap.select('g')
|
||||
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
|
||||
|
||||
var linesWrap = g.select('.linesWrap')
|
||||
.datum(dataCopy.filter(function(d) { return !d.disabled }))
|
||||
|
||||
d3.transition(linesWrap).call(lines);
|
||||
|
||||
|
||||
// Update the stacked graph
|
||||
var availableWidth = width - margin.left - margin.right,
|
||||
@ -63,9 +81,9 @@ nv.models.stackedArea = function() {
|
||||
.y0(function(d) { return availableHeight - d.y0 * availableHeight / my; })
|
||||
.y1(function(d) { return availableHeight - d.y0 * availableHeight / my; })
|
||||
|
||||
var path = g.selectAll('path')
|
||||
var path = g.select('.areaWrap').selectAll('path.area')
|
||||
.data(function(d) { return d });
|
||||
path.enter().append('path');
|
||||
path.enter().append('path').attr('class', 'area');
|
||||
d3.transition(path.exit())
|
||||
.attr('d', function(d,i) { return zeroArea(d.values,i) })
|
||||
.remove();
|
||||
@ -140,6 +158,7 @@ nv.models.stackedArea = function() {
|
||||
return chart;
|
||||
};
|
||||
|
||||
chart.dispatch = lines.dispatch;
|
||||
|
||||
return chart;
|
||||
}
|
||||
|
@ -117,6 +117,7 @@ nv.models.stackedAreaWithLegend = function() {
|
||||
d.hover = false;
|
||||
selection.transition().call(chart)
|
||||
});
|
||||
*/
|
||||
|
||||
stacked.dispatch.on('pointMouseover.tooltip', function(e) {
|
||||
dispatch.tooltipShow({
|
||||
@ -132,7 +133,6 @@ nv.models.stackedAreaWithLegend = function() {
|
||||
dispatch.tooltipHide(e);
|
||||
});
|
||||
|
||||
*/
|
||||
|
||||
|
||||
//TODO: margins should be adjusted based on what components are used: axes, axis labels, legend
|
||||
@ -184,7 +184,7 @@ nv.models.stackedAreaWithLegend = function() {
|
||||
.range(y.range())
|
||||
.ticks( stacked.offset() == 'wiggle' ? 0 : height / 36 )
|
||||
.tickSize(-(width - margin.right - margin.left), 0)
|
||||
.tickFormat(stacked.offset() == 'zero' ? d3.format(',2f') : d3.format('%')); //TODO: stacked format should be set by caller
|
||||
.tickFormat(stacked.offset() == 'zero' ? d3.format(',.2f') : d3.format('%')); //TODO: stacked format should be set by caller
|
||||
|
||||
d3.transition(g.select('.y.axis'))
|
||||
.call(yAxis);
|
||||
@ -235,6 +235,7 @@ nv.models.stackedAreaWithLegend = function() {
|
||||
return chart;
|
||||
};
|
||||
|
||||
chart.stacked = stacked;
|
||||
|
||||
// Expose the x-axis' tickFormat method.
|
||||
//chart.xAxis = {};
|
||||
|
Loading…
Reference in New Issue
Block a user