Fixed height and width getter/setters and started working on linePlusBarChart, halfway done

This commit is contained in:
Bob Monteverde 2012-06-15 20:39:16 -04:00
parent 601d598b34
commit 04c11e3bde
6 changed files with 460 additions and 8 deletions

View File

@ -0,0 +1,165 @@
<!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="../nv.d3.js"></script>
<script src="../src/tooltip.js"></script>
<script src="../src/models/legend.js"></script>
<script src="../src/models/axis.js"></script>
<script src="../src/models/scatter.js"></script>
<script src="../src/models/line.js"></script>
<script src="../src/models/historicalBar.js"></script>
<script src="../src/models/linePlusBarChart.js"></script>
<script>
var valueVsQuantity = [
{
"key" : "Quantity" ,
"bar": true,
"values" : [ [ 1136005200000 , 1271000.0] , [ 1138683600000 , 1271000.0] , [ 1141102800000 , 1271000.0] , [ 1143781200000 , 0] , [ 1146369600000 , 0] , [ 1149048000000 , 0] , [ 1151640000000 , 0] , [ 1154318400000 , 0] , [ 1156996800000 , 0] , [ 1159588800000 , 3899486.0] , [ 1162270800000 , 3899486.0] , [ 1164862800000 , 3899486.0] , [ 1167541200000 , 3564700.0] , [ 1170219600000 , 3564700.0] , [ 1172638800000 , 3564700.0] , [ 1175313600000 , 2648493.0] , [ 1177905600000 , 2648493.0] , [ 1180584000000 , 2648493.0] , [ 1183176000000 , 2522993.0] , [ 1185854400000 , 2522993.0] , [ 1188532800000 , 2522993.0] , [ 1191124800000 , 2906501.0] , [ 1193803200000 , 2906501.0] , [ 1196398800000 , 2906501.0] , [ 1199077200000 , 2206761.0] , [ 1201755600000 , 2206761.0] , [ 1204261200000 , 2206761.0] , [ 1206936000000 , 2287726.0] , [ 1209528000000 , 2287726.0] , [ 1212206400000 , 2287726.0] , [ 1214798400000 , 2732646.0] , [ 1217476800000 , 2732646.0] , [ 1220155200000 , 2732646.0] , [ 1222747200000 , 2599196.0] , [ 1225425600000 , 2599196.0] , [ 1228021200000 , 2599196.0] , [ 1230699600000 , 1924387.0] , [ 1233378000000 , 1924387.0] , [ 1235797200000 , 1924387.0] , [ 1238472000000 , 1756311.0] , [ 1241064000000 , 1756311.0] , [ 1243742400000 , 1756311.0] , [ 1246334400000 , 1743470.0] , [ 1249012800000 , 1743470.0] , [ 1251691200000 , 1743470.0] , [ 1254283200000 , 1519010.0] , [ 1256961600000 , 1519010.0] , [ 1259557200000 , 1519010.0] , [ 1262235600000 , 1591444.0] , [ 1264914000000 , 1591444.0] , [ 1267333200000 , 1591444.0] , [ 1270008000000 , 1543784.0] , [ 1272600000000 , 1543784.0] , [ 1275278400000 , 1543784.0] , [ 1277870400000 , 1309915.0] , [ 1280548800000 , 1309915.0] , [ 1283227200000 , 1309915.0] , [ 1285819200000 , 1331875.0] , [ 1288497600000 , 1331875.0] , [ 1291093200000 , 1331875.0] , [ 1293771600000 , 1331875.0] , [ 1296450000000 , 1154695.0] , [ 1298869200000 , 1154695.0] , [ 1301544000000 , 1194025.0] , [ 1304136000000 , 1194025.0] , [ 1306814400000 , 1194025.0] , [ 1309406400000 , 1194025.0] , [ 1312084800000 , 1194025.0] , [ 1314763200000 , 1244525.0] , [ 1317355200000 , 475000.0] , [ 1320033600000 , 475000.0] , [ 1322629200000 , 475000.0] , [ 1325307600000 , 690033.0] , [ 1327986000000 , 690033.0] , [ 1330491600000 , 690033.0] , [ 1333166400000 , 514733.0] , [ 1335758400000 , 514733.0]]
} ,
{
"key" : "Price" ,
"values" : [ [ 1136005200000 , 71.89] , [ 1138683600000 , 75.51] , [ 1141102800000 , 68.49] , [ 1143781200000 , 62.72] , [ 1146369600000 , 70.39] , [ 1149048000000 , 59.77] , [ 1151640000000 , 57.27] , [ 1154318400000 , 67.96] , [ 1156996800000 , 67.85] , [ 1159588800000 , 76.98] , [ 1162270800000 , 81.08] , [ 1164862800000 , 91.66] , [ 1167541200000 , 84.84] , [ 1170219600000 , 85.73] , [ 1172638800000 , 84.61] , [ 1175313600000 , 92.91] , [ 1177905600000 , 99.8] , [ 1180584000000 , 121.191] , [ 1183176000000 , 122.04] , [ 1185854400000 , 131.76] , [ 1188532800000 , 138.48] , [ 1191124800000 , 153.47] , [ 1193803200000 , 189.95] , [ 1196398800000 , 182.22] , [ 1199077200000 , 198.08] , [ 1201755600000 , 135.36] , [ 1204261200000 , 125.02] , [ 1206936000000 , 143.5] , [ 1209528000000 , 173.95] , [ 1212206400000 , 188.75] , [ 1214798400000 , 167.44] , [ 1217476800000 , 158.95] , [ 1220155200000 , 169.53] , [ 1222747200000 , 113.66] , [ 1225425600000 , 107.59] , [ 1228021200000 , 92.67] , [ 1230699600000 , 85.35] , [ 1233378000000 , 90.13] , [ 1235797200000 , 89.31] , [ 1238472000000 , 105.12] , [ 1241064000000 , 125.83] , [ 1243742400000 , 135.81] , [ 1246334400000 , 142.43] , [ 1249012800000 , 163.39] , [ 1251691200000 , 168.21] , [ 1254283200000 , 185.35] , [ 1256961600000 , 188.5] , [ 1259557200000 , 199.91] , [ 1262235600000 , 210.732] , [ 1264914000000 , 192.063] , [ 1267333200000 , 204.62] , [ 1270008000000 , 235.0] , [ 1272600000000 , 261.09] , [ 1275278400000 , 256.88] , [ 1277870400000 , 251.53] , [ 1280548800000 , 257.25] , [ 1283227200000 , 243.1] , [ 1285819200000 , 283.75] , [ 1288497600000 , 300.98] , [ 1291093200000 , 311.15] , [ 1293771600000 , 322.56] , [ 1296450000000 , 339.32] , [ 1298869200000 , 353.21] , [ 1301544000000 , 348.5075] , [ 1304136000000 , 350.13] , [ 1306814400000 , 347.83] , [ 1309406400000 , 335.67] , [ 1312084800000 , 390.48] , [ 1314763200000 , 384.83] , [ 1317355200000 , 381.32] , [ 1320033600000 , 404.78] , [ 1322629200000 , 382.2] , [ 1325307600000 , 405.0] , [ 1327986000000 , 456.48] , [ 1330491600000 , 542.44] , [ 1333166400000 , 599.55] , [ 1335758400000 , 583.98]]
}
].map(function(series) {
series.values = series.values.map(function(d) { return {x: d[0], y: d[1] } });
return series;
});
var selector = '#chart1',
chart = nv.models.linePlusBarChart(),
//data = sinAndCos(),
data = valueVsQuantity,
xTickFormat = d3.format(',r'),
y1TickFormat = d3.format(',f'),
y2TickFormat = function(d) { return '$' + d3.format(',f')(d) },
duration = 500;
nv.addGraph({
generate: function() {
var container = d3.select(selector),
svg = container.append('svg');
chart
.x(function(d,i) { return i })
.color(d3.scale.category10().range());
chart.xAxis.tickFormat(function(d) {
var dx = data[0].values[d] && data[0].values[d].x || 0;
return d3.time.format('%x')(new Date(dx))
//return d3.time.format('%x')(new Date(data[0].values[d].x))
});
chart.yAxis1
.tickFormat(y1TickFormat)
chart.yAxis2
.tickFormat(y2TickFormat)
chart.bars.forceY([0]);
//chart.lines.forceY([0]);
svg
.datum(data)
.transition().duration(duration).call(chart);
return chart;
},
callback: function(chart) {
var showTooltip = function(e) {
var offsetElement = document.getElementById(selector.substr(1)),
left = e.pos[0] + offsetElement.offsetLeft,
top = e.pos[1] + offsetElement.offsetTop,
formatY1 = chart.yAxis1.tickFormat(), //Assumes using same format as axis, can customize to show higher precision, etc.
formatY2 = chart.yAxis2.tickFormat(), //Assumes using same format as axis, can customize to show higher precision, etc.
formatX = chart.xAxis.tickFormat(),
x = formatX(chart.x()(e, e.pointIndex)),
y = e.series.bar ? formatY1(chart.y()(e.point)) : formatY2(chart.y()(e.point));
// 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.replace(/\s*\(.*\)/, '') + '</h3>' + //removing the (left/right axis) note from series label in tooltip
'<p>' +
y + ' at ' + x +
'</p>';
nv.tooltip.show([left, top], content, chart.y()(e.point) < 0 ? 'n' : 's' );
};
chart.dispatch.on('tooltipShow', showTooltip);
chart.dispatch.on('tooltipHide', nv.tooltip.cleanup);
window.onresize= function() {
// now that width and height are functions, should be automatic..of course you can always override them
d3.select('#chart1 svg')
.call(chart);
};
}
});
function sinAndCos() {
var sin = [],
cos = [];
for (var i = 0; i < 100; i++) {
sin.push({x: i, y: Math.sin(i/10) + 1});
cos.push({x: i, y: .5 * Math.cos(i/10) + .5});
}
return [
{
values: sin,
key: "Sine Wave",
bar: true
},
{
values: cos,
key: "Cosine Wave"
}
];
}
</script>

View File

@ -186,13 +186,13 @@ nv.models.discreteBarChart = function() {
chart.width = function(_) {
if (!arguments.length) return width;
width = d3.functor(_);
width = _;
return chart;
};
chart.height = function(_) {
if (!arguments.length) return height;
height = d3.functor(_);
height = _;
return chart;
};

View File

@ -186,14 +186,12 @@ nv.models.lineChart = function() {
chart.width = function(_) {
if (!arguments.length) return width;
width = _;
//width = d3.functor(_);
return chart;
};
chart.height = function(_) {
if (!arguments.length) return height;
height = _;
//height = d3.functor(_);
return chart;
};

View File

@ -0,0 +1,289 @@
nv.models.linePlusBarChart = function() {
var margin = {top: 30, right: 60, bottom: 50, left: 60},
width = null,
height = null,
dotRadius = function() { return 2.5 },
getX = function(d) { return d.x },
getY = function(d) { return d.y },
color = d3.scale.category20().range(),
showLegend = true,
tooltips = true,
tooltip = function(key, x, y, e, graph) {
return '<h3>' + key + '</h3>' +
'<p>' + y + ' at ' + x + '</p>'
};
var lines = nv.models.line(),
bars = nv.models.historicalBar(),
x = d3.scale.linear(),
y1 = d3.scale.linear(),
y2 = d3.scale.linear(),
xAxis = nv.models.axis().scale(x).orient('bottom'),
yAxis1 = nv.models.axis().scale(y1).orient('left'),
yAxis2 = nv.models.axis().scale(y2).orient('right'),
legend = nv.models.legend().height(30),
dispatch = d3.dispatch('tooltipShow', 'tooltipHide');
function chart(selection) {
selection.each(function(data) {
var container = d3.select(this);
var availableWidth = (width || parseInt(container.style('width')) || 960)
- margin.left - margin.right,
availableHeight = (height || parseInt(container.style('height')) || 400)
- margin.top - margin.bottom;
var dataBars = data.filter(function(d) { return !d.disabled && d.bar })
.map(function(d) {
return d.values.map(function(d,i) {
return { x: getX(d,i), y: getY(d,i) }
})
});
var dataLines = data.filter(function(d) { return !d.disabled && !d.bar })
.map(function(d) {
return d.values.map(function(d,i) {
return { x: getX(d,i), y: getY(d,i) }
})
});
x .domain(d3.extent(d3.merge(dataBars.concat(dataLines)), function(d) { return d.x } ))
.range([0, availableWidth]);
y1 .domain(d3.extent(d3.merge(dataBars), function(d) { return d.y } ))
.range([availableHeight, 0]);
y2 .domain(d3.extent(d3.merge(dataLines), function(d) { return d.y } ))
.range([availableHeight, 0]);
lines
.width(availableWidth)
.height(availableHeight)
.color(data.map(function(d,i) {
return d.color || color[i % 10];
}).filter(function(d,i) { return !data[i].disabled && !data[i].bar }))
bars
.width(availableWidth)
.height(availableHeight)
.color(data.map(function(d,i) {
return d.color || color[i % 10];
}).filter(function(d,i) { return !data[i].disabled && data[i].bar }))
var wrap = d3.select(this).selectAll('g.wrap.linePlusBar').data([data]);
var gEnter = wrap.enter().append('g').attr('class', 'wrap nvd3 linePlusBar').append('g');
gEnter.append('g').attr('class', 'x axis');
gEnter.append('g').attr('class', 'y1 axis');
gEnter.append('g').attr('class', 'y2 axis');
gEnter.append('g').attr('class', 'barsWrap');
gEnter.append('g').attr('class', 'linesWrap');
gEnter.append('g').attr('class', 'legendWrap');
//TODO: margins should be adjusted based on what components are used: axes, axis labels, legend
margin.top = legend.height();
var g = wrap.select('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
if (showLegend) {
legend.width(availableWidth);
g.select('.legendWrap')
.datum(data.map(function(series) {
series.key = series.key + (series.bar ? ' (left axis)' : ' (right axis)');
return series;
}))
.call(legend);
if ( margin.top != legend.height()) {
margin.top = legend.height();
availableHeight = (height || parseInt(container.style('height')) || 400)
- margin.top - margin.bottom;
}
g.select('.legendWrap')
.attr('transform', 'translate(0,' + (-margin.top) +')');
}
var barsData = data.filter(function(d) { return !d.disabled && d.bar });
var barsWrap = g.select('.barsWrap')
.datum(barsData.length ? barsData : [{values:[]}])
//.datum(data.filter(function(d) { return !d.disabled && d.bar }))
var linesWrap = g.select('.linesWrap')
.datum(data.filter(function(d) { return !d.disabled && !d.bar }))
d3.transition(barsWrap).call(bars);
d3.transition(linesWrap).call(lines);
xAxis
.domain(x.domain())
.range(x.range())
.ticks( availableWidth / 100 )
.tickSize(-availableHeight, 0);
g.select('.x.axis')
.attr('transform', 'translate(0,' + y1.range()[0] + ')');
d3.transition(g.select('.x.axis'))
.call(xAxis);
yAxis1
.domain(y1.domain())
.range(y1.range())
.ticks( availableHeight / 36 )
.tickSize(-availableWidth, 0);
d3.transition(g.select('.y1.axis'))
.call(yAxis1);
yAxis2
.domain(y2.domain())
.range(y2.range())
.ticks( availableHeight / 36 )
.tickSize(dataBars.length ? 0 : -availableWidth, 0); // Show the y2 rules only if y1 has none
g.select('.y2.axis')
.attr('transform', 'translate(' + x.range()[1] + ',0)');
d3.transition(g.select('.y2.axis'))
.call(yAxis2);
legend.dispatch.on('legendClick', function(d,i) {
d.disabled = !d.disabled;
if (!data.filter(function(d) { return !d.disabled }).length) {
data.map(function(d) {
d.disabled = false;
wrap.selectAll('.series').classed('disabled', false);
return d;
});
}
selection.transition().call(chart);
});
lines.dispatch.on('elementMouseover.tooltip', function(e) {
dispatch.tooltipShow({
point: e.point,
series: e.series,
pos: [e.pos[0] + margin.left, e.pos[1] + margin.top],
seriesIndex: e.seriesIndex,
pointIndex: e.pointIndex
});
});
lines.dispatch.on('elementMouseout.tooltip', function(e) {
dispatch.tooltipHide(e);
});
bars.dispatch.on('elementMouseover.tooltip', function(e) {
e.pos = [e.pos[0] + margin.left, e.pos[1] + margin.top];
dispatch.tooltipShow(e);
});
bars.dispatch.on('elementMouseout.tooltip', function(e) {
dispatch.tooltipHide(e);
});
});
return chart;
}
chart.dispatch = dispatch;
chart.legend = legend;
chart.lines = lines;
chart.bars = bars;
chart.xAxis = xAxis;
chart.yAxis1 = yAxis1;
chart.yAxis2 = yAxis2;
d3.rebind(chart, lines, 'size', 'clipVoronoi');
//d3.rebind(chart, lines, 'x', 'y', 'size', 'xDomain', 'yDomain', 'forceX', 'forceY', 'interactive', 'clipEdge', 'clipVoronoi', 'id');
//d3.rebind(chart, lines, 'interactive');
//consider rebinding x and y as well
chart.x = function(_) {
if (!arguments.length) return getX;
getX = _;
lines.x(_);
bars.x(_);
return chart;
};
chart.y = function(_) {
if (!arguments.length) return getY;
getY = _;
lines.y(_);
bars.y(_);
return chart;
};
chart.margin = function(_) {
if (!arguments.length) return margin;
margin = _;
return chart;
};
chart.width = function(_) {
if (!arguments.length) return width;
width = _;
return chart;
};
chart.height = function(_) {
if (!arguments.length) return height;
height = _;
return chart;
};
chart.color = function(_) {
if (!arguments.length) return color;
color = _;
legend.color(_);
return chart;
};
chart.showLegend = function(_) {
if (!arguments.length) return showLegend;
showLegend = _;
return chart;
};
chart.tooltips = function(_) {
if (!arguments.length) return tooltips;
tooltips = _;
return chart;
};
chart.tooltipContent = function(_) {
if (!arguments.length) return tooltip;
tooltip = _;
return chart;
};
return chart;
}

View File

@ -247,13 +247,13 @@ nv.models.multiBarChart = function() {
chart.width = function(_) {
if (!arguments.length) return width;
width = d3.functor(_);
width = _;
return chart;
};
chart.height = function(_) {
if (!arguments.length) return height;
height = d3.functor(_);
height = _;
return chart;
};

View File

@ -252,13 +252,13 @@ nv.models.scatterChart = function() {
chart.width = function(_) {
if (!arguments.length) return width;
width = d3.functor(_);
width = _;
return chart;
};
chart.height = function(_) {
if (!arguments.length) return height;
height = d3.functor(_);
height = _;
return chart;
};