New linePlusBarWithFocusChart model and example
parent
9661ffb4d3
commit
f53e2db9b7
@ -0,0 +1,128 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
|
||||
<link href="../src/nv.d3.css" rel="stylesheet" type="text/css">
|
||||
|
||||
<style>
|
||||
|
||||
body {
|
||||
overflow-y:scroll;
|
||||
}
|
||||
|
||||
text {
|
||||
font: 12px sans-serif;
|
||||
}
|
||||
|
||||
#chart1 svg {
|
||||
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">
|
||||
<svg> </svg>
|
||||
</div>
|
||||
|
||||
<script src="../lib/d3.v2.js"></script>
|
||||
<script src="../nv.d3.js"></script>
|
||||
<script src="../src/utils.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/linePlusBarWithFocusChart.dev.js"></script>
|
||||
<script>
|
||||
|
||||
|
||||
var testdata = [
|
||||
{
|
||||
"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;
|
||||
});
|
||||
|
||||
|
||||
/*
|
||||
//For testing single data point
|
||||
var testdata = [
|
||||
{
|
||||
"key" : "Quantity" ,
|
||||
"bar": true,
|
||||
"values" : [ [ 1136005200000 , 1271000.0] ]
|
||||
} ,
|
||||
{
|
||||
"key" : "Price" ,
|
||||
"values" : [ [ 1136005200000 , 71.89] ]
|
||||
}
|
||||
].map(function(series) {
|
||||
series.values = series.values.map(function(d) { return {x: d[0], y: d[1] } });
|
||||
return series;
|
||||
});
|
||||
*/
|
||||
|
||||
|
||||
|
||||
nv.addGraph(function() {
|
||||
var chart = nv.models.linePlusBarWithFocusChart()
|
||||
.margin({top: 30, right: 60, bottom: 50, left: 70})
|
||||
.x(function(d,i) { return i })
|
||||
.color(d3.scale.category10().range());
|
||||
|
||||
chart.xAxis.tickFormat(function(d) {
|
||||
var dx = testdata[0].values[d] && testdata[0].values[d].x || 0;
|
||||
if (dx > 0) {
|
||||
return d3.time.format('%x')(new Date(dx))
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
chart.x2Axis.tickFormat(function(d) {
|
||||
var dx = testdata[0].values[d] && testdata[0].values[d].x || 0;
|
||||
return d3.time.format('%x')(new Date(dx))
|
||||
});
|
||||
|
||||
chart.y1Axis
|
||||
.tickFormat(d3.format(',f'));
|
||||
|
||||
chart.y3Axis
|
||||
.tickFormat(d3.format(',f'));
|
||||
|
||||
chart.y2Axis
|
||||
.tickFormat(function(d) { return '$' + d3.format(',.2f')(d) });
|
||||
|
||||
chart.y4Axis
|
||||
.tickFormat(function(d) { return '$' + d3.format(',.2f')(d) });
|
||||
|
||||
chart.bars.forceY([0]);
|
||||
chart.bars2.forceY([0]);
|
||||
//chart.lines.forceY([0]);
|
||||
|
||||
d3.select('#chart1 svg')
|
||||
.datum(testdata)
|
||||
.transition().duration(500).call(chart);
|
||||
|
||||
// nv.utils.windowResize(chart.update);
|
||||
|
||||
return chart;
|
||||
});
|
||||
|
||||
</script>
|
@ -0,0 +1,657 @@
|
||||
|
||||
nv.models.linePlusBarWithFocusChart = function() {
|
||||
|
||||
//============================================================
|
||||
// Public Variables with Default Settings
|
||||
//------------------------------------------------------------
|
||||
|
||||
var lines = nv.models.line()
|
||||
, lines2 = nv.models.line()
|
||||
, bars = nv.models.historicalBar()
|
||||
, bars2 = nv.models.historicalBar()
|
||||
, xAxis = nv.models.axis()
|
||||
, x2Axis = nv.models.axis()
|
||||
, y1Axis = nv.models.axis()
|
||||
, y2Axis = nv.models.axis()
|
||||
, y3Axis = nv.models.axis()
|
||||
, y4Axis = nv.models.axis()
|
||||
, legend = nv.models.legend()
|
||||
, brush = d3.svg.brush()
|
||||
;
|
||||
|
||||
var margin = {top: 30, right: 30, bottom: 30, left: 60}
|
||||
, margin2 = {top: 0, right: 30, bottom: 20, left: 60}
|
||||
, width = null
|
||||
, height = null
|
||||
, height2 = 100
|
||||
, getX = function(d) { return d.x }
|
||||
, getY = function(d) { return d.y }
|
||||
, color = nv.utils.defaultColor()
|
||||
, showLegend = true
|
||||
, extent
|
||||
, brushExtent = null
|
||||
, tooltips = true
|
||||
, tooltip = function(key, x, y, e, graph) {
|
||||
return '<h3>' + key + '</h3>' +
|
||||
'<p>' + y + ' at ' + x + '</p>';
|
||||
}
|
||||
, x
|
||||
, x2
|
||||
, y1
|
||||
, y2
|
||||
, y3
|
||||
, y4
|
||||
, noData = "No Data Available."
|
||||
, dispatch = d3.dispatch('tooltipShow', 'tooltipHide', 'brush')
|
||||
;
|
||||
|
||||
lines
|
||||
.clipEdge(true)
|
||||
;
|
||||
lines2
|
||||
.interactive(false)
|
||||
;
|
||||
xAxis
|
||||
.orient('bottom')
|
||||
.tickPadding(5)
|
||||
;
|
||||
y1Axis
|
||||
.orient('left')
|
||||
;
|
||||
y2Axis
|
||||
.orient('right')
|
||||
;
|
||||
x2Axis
|
||||
.orient('bottom')
|
||||
.tickPadding(5)
|
||||
;
|
||||
y3Axis
|
||||
.orient('left')
|
||||
;
|
||||
y4Axis
|
||||
.orient('right')
|
||||
;
|
||||
|
||||
//============================================================
|
||||
|
||||
|
||||
//============================================================
|
||||
// Private Variables
|
||||
//------------------------------------------------------------
|
||||
|
||||
var showTooltip = function(e, offsetElement) {
|
||||
if (extent) {
|
||||
e.pointIndex += Math.ceil(extent[0]);
|
||||
}
|
||||
var left = e.pos[0] + ( offsetElement.offsetLeft || 0 ),
|
||||
top = e.pos[1] + ( offsetElement.offsetTop || 0),
|
||||
x = xAxis.tickFormat()(lines.x()(e.point, e.pointIndex)),
|
||||
y = (e.series.bar ? y1Axis : y2Axis).tickFormat()(lines.y()(e.point, e.pointIndex)),
|
||||
content = tooltip(e.series.key, x, y, e, chart);
|
||||
|
||||
nv.tooltip.show([left, top], content, e.value < 0 ? 'n' : 's', null, offsetElement);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
function chart(selection) {
|
||||
selection.each(function(data) {
|
||||
var container = d3.select(this),
|
||||
that = this;
|
||||
|
||||
var availableWidth = (width || parseInt(container.style('width')) || 960)
|
||||
- margin.left - margin.right,
|
||||
availableHeight1 = (height || parseInt(container.style('height')) || 400)
|
||||
- margin.top - margin.bottom - height2,
|
||||
availableHeight2 = height2 - margin2.top - margin2.bottom;
|
||||
|
||||
chart.update = function() { chart(selection) };
|
||||
chart.container = this;
|
||||
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Display No Data message if there's nothing to show.
|
||||
|
||||
if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) {
|
||||
var noDataText = container.selectAll('.nv-noData').data([noData]);
|
||||
|
||||
noDataText.enter().append('text')
|
||||
.attr('class', 'nvd3 nv-noData')
|
||||
.attr('dy', '-.7em')
|
||||
.style('text-anchor', 'middle');
|
||||
|
||||
noDataText
|
||||
.attr('x', margin.left + availableWidth / 2)
|
||||
.attr('y', margin.top + availableHeight1 / 2)
|
||||
.text(function(d) { return d });
|
||||
|
||||
return chart;
|
||||
} else {
|
||||
container.selectAll('.nv-noData').remove();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Setup Scales
|
||||
|
||||
var dataBars = data.filter(function(d) { return !d.disabled && d.bar });
|
||||
var dataLines = data.filter(function(d) { return !d.bar }); // removed the !d.disabled clause here to fix Issue #240
|
||||
|
||||
x = bars.xScale();
|
||||
x2 = x2Axis.scale();
|
||||
y1 = bars.yScale();
|
||||
y2 = lines.yScale();
|
||||
y3 = bars2.yScale();
|
||||
y4 = lines2.yScale();
|
||||
|
||||
var series1 = 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 series2 = 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 .range([0, availableWidth]);
|
||||
|
||||
x2 .domain(d3.extent(d3.merge(series1.concat(series2)), function(d) { return d.x } ))
|
||||
.range([0, availableWidth]);
|
||||
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Setup containers and skeleton of chart
|
||||
|
||||
var wrap = container.selectAll('g.nv-wrap.nv-linePlusBar').data([data]);
|
||||
var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-linePlusBar').append('g');
|
||||
var g = wrap.select('g');
|
||||
|
||||
gEnter.append('g').attr('class', 'nv-legendWrap');
|
||||
|
||||
var focusEnter = gEnter.append('g').attr('class', 'nv-focus');
|
||||
focusEnter.append('g').attr('class', 'nv-x nv-axis');
|
||||
focusEnter.append('g').attr('class', 'nv-y1 nv-axis');
|
||||
focusEnter.append('g').attr('class', 'nv-y2 nv-axis');
|
||||
focusEnter.append('g').attr('class', 'nv-barsWrap');
|
||||
focusEnter.append('g').attr('class', 'nv-linesWrap');
|
||||
|
||||
var contextEnter = gEnter.append('g').attr('class', 'nv-context');
|
||||
contextEnter.append('g').attr('class', 'nv-x nv-axis');
|
||||
contextEnter.append('g').attr('class', 'nv-y1 nv-axis');
|
||||
contextEnter.append('g').attr('class', 'nv-y2 nv-axis');
|
||||
contextEnter.append('g').attr('class', 'nv-barsWrap');
|
||||
contextEnter.append('g').attr('class', 'nv-linesWrap');
|
||||
contextEnter.append('g').attr('class', 'nv-brushBackground');
|
||||
contextEnter.append('g').attr('class', 'nv-x nv-brush');
|
||||
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Legend
|
||||
|
||||
if (showLegend) {
|
||||
legend.width( availableWidth / 2 );
|
||||
|
||||
g.select('.nv-legendWrap')
|
||||
.datum(data.map(function(series) {
|
||||
series.originalKey = series.originalKey === undefined ? series.key : series.originalKey;
|
||||
series.key = series.originalKey + (series.bar ? ' (left axis)' : ' (right axis)');
|
||||
return series;
|
||||
}))
|
||||
.call(legend);
|
||||
|
||||
if ( margin.top != legend.height()) {
|
||||
margin.top = legend.height();
|
||||
availableHeight1 = (height || parseInt(container.style('height')) || 400)
|
||||
- margin.top - margin.bottom - height2;
|
||||
}
|
||||
|
||||
g.select('.nv-legendWrap')
|
||||
.attr('transform', 'translate(' + ( availableWidth / 2 ) + ',' + (-margin.top) +')');
|
||||
}
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
||||
|
||||
wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
|
||||
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Context Components
|
||||
|
||||
bars2
|
||||
.width(availableWidth)
|
||||
.height(availableHeight2)
|
||||
.color(data.map(function(d,i) {
|
||||
return d.color || color(d, i);
|
||||
}).filter(function(d,i) { return !data[i].disabled && data[i].bar }));
|
||||
|
||||
lines2
|
||||
.width(availableWidth)
|
||||
.height(availableHeight2)
|
||||
.color(data.map(function(d,i) {
|
||||
return d.color || color(d, i);
|
||||
}).filter(function(d,i) { return !data[i].disabled && !data[i].bar }));
|
||||
|
||||
var bars2Wrap = g.select('.nv-context .nv-barsWrap')
|
||||
.datum(dataBars.length ? dataBars : [{values:[]}]);
|
||||
|
||||
var lines2Wrap = g.select('.nv-context .nv-linesWrap')
|
||||
.datum(!dataLines[0].disabled ? dataLines : [{values:[]}]);
|
||||
|
||||
g.select('.nv-context')
|
||||
.attr('transform', 'translate(0,' + ( availableHeight1 + margin.bottom + margin2.top) + ')')
|
||||
|
||||
d3.transition(bars2Wrap).call(bars2);
|
||||
d3.transition(lines2Wrap).call(lines2);
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Setup Brush
|
||||
|
||||
brush
|
||||
.x(x2)
|
||||
.on('brush', onBrush);
|
||||
|
||||
if (brushExtent) brush.extent(brushExtent);
|
||||
|
||||
var brushBG = g.select('.nv-brushBackground').selectAll('g')
|
||||
.data([brushExtent || brush.extent()])
|
||||
|
||||
var brushBGenter = brushBG.enter()
|
||||
.append('g');
|
||||
|
||||
brushBGenter.append('rect')
|
||||
.attr('class', 'left')
|
||||
.attr('x', 0)
|
||||
.attr('y', 0)
|
||||
.attr('height', availableHeight2);
|
||||
|
||||
brushBGenter.append('rect')
|
||||
.attr('class', 'right')
|
||||
.attr('x', 0)
|
||||
.attr('y', 0)
|
||||
.attr('height', availableHeight2);
|
||||
|
||||
var gBrush = g.select('.nv-x.nv-brush')
|
||||
.call(brush);
|
||||
gBrush.selectAll('rect')
|
||||
//.attr('y', -5)
|
||||
.attr('height', availableHeight2);
|
||||
gBrush.selectAll('.resize').append('path').attr('d', resizePath);
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Setup Secondary (Context) Axes
|
||||
|
||||
x2Axis
|
||||
.ticks( availableWidth / 100 )
|
||||
.tickSize(-availableHeight2, 0);
|
||||
|
||||
g.select('.nv-context .nv-x.nv-axis')
|
||||
.attr('transform', 'translate(0,' + y3.range()[0] + ')');
|
||||
d3.transition(g.select('.nv-context .nv-x.nv-axis'))
|
||||
.call(x2Axis);
|
||||
|
||||
|
||||
y3Axis
|
||||
.scale(y3)
|
||||
.ticks( availableHeight2 / 36 )
|
||||
.tickSize( -availableWidth, 0);
|
||||
|
||||
g.select('.nv-context .nv-y1.nv-axis')
|
||||
.style('opacity', dataBars.length ? 1 : 0)
|
||||
.attr('transform', 'translate(0,' + x2.range()[0] + ')');
|
||||
|
||||
d3.transition(g.select('.nv-context .nv-y1.nv-axis'))
|
||||
.call(y3Axis);
|
||||
|
||||
|
||||
y4Axis
|
||||
.scale(y4)
|
||||
.ticks( availableHeight2 / 36 )
|
||||
.tickSize(dataBars.length ? 0 : -availableWidth, 0); // Show the y2 rules only if y1 has none
|
||||
|
||||
g.select('.nv-context .nv-y2.nv-axis')
|
||||
.style('opacity', dataLines.length ? 1 : 0)
|
||||
.attr('transform', 'translate(' + x2.range()[1] + ',0)');
|
||||
|
||||
d3.transition(g.select('.nv-context .nv-y2.nv-axis'))
|
||||
.call(y4Axis);
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
||||
//============================================================
|
||||
// Event Handling/Dispatching (in chart's scope)
|
||||
//------------------------------------------------------------
|
||||
|
||||
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('.nv-series').classed('disabled', false);
|
||||
return d;
|
||||
});
|
||||
}
|
||||
|
||||
selection.call(chart);
|
||||
});
|
||||
|
||||
dispatch.on('tooltipShow', function(e) {
|
||||
if (tooltips) showTooltip(e, that.parentNode);
|
||||
});
|
||||
|
||||
//============================================================
|
||||
|
||||
|
||||
//============================================================
|
||||
// Functions
|
||||
//------------------------------------------------------------
|
||||
|
||||
// Taken from crossfilter (http://square.github.com/crossfilter/)
|
||||
function resizePath(d) {
|
||||
var e = +(d == 'e'),
|
||||
x = e ? 1 : -1,
|
||||
y = availableHeight2 / 3;
|
||||
return 'M' + (.5 * x) + ',' + y
|
||||
+ 'A6,6 0 0 ' + e + ' ' + (6.5 * x) + ',' + (y + 6)
|
||||
+ 'V' + (2 * y - 6)
|
||||
+ 'A6,6 0 0 ' + e + ' ' + (.5 * x) + ',' + (2 * y)
|
||||
+ 'Z'
|
||||
+ 'M' + (2.5 * x) + ',' + (y + 8)
|
||||
+ 'V' + (2 * y - 8)
|
||||
+ 'M' + (4.5 * x) + ',' + (y + 8)
|
||||
+ 'V' + (2 * y - 8);
|
||||
}
|
||||
|
||||
|
||||
function updateBrushBG() {
|
||||
if (!brush.empty()) brush.extent(brushExtent);
|
||||
brushBG
|
||||
.data([brush.empty() ? x2.domain() : brushExtent])
|
||||
.each(function(d,i) {
|
||||
var leftWidth = x2(d[0]) - x2.range()[0],
|
||||
rightWidth = x2.range()[1] - x2(d[1]);
|
||||
d3.select(this).select('.left')
|
||||
.attr('width', leftWidth < 0 ? 0 : leftWidth);
|
||||
|
||||
d3.select(this).select('.right')
|
||||
.attr('x', x2(d[1]))
|
||||
.attr('width', rightWidth < 0 ? 0 : rightWidth);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function onBrush() {
|
||||
brushExtent = brush.empty() ? null : brush.extent();
|
||||
extent = brush.empty() ? x2.domain() : brush.extent();
|
||||
|
||||
|
||||
dispatch.brush({extent: extent, brush: brush});
|
||||
|
||||
updateBrushBG();
|
||||
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Prepare Main (Focus) Bars and Lines
|
||||
|
||||
bars
|
||||
.width(availableWidth)
|
||||
.height(availableHeight1)
|
||||
.color(data.map(function(d,i) {
|
||||
return d.color || color(d, i);
|
||||
}).filter(function(d,i) { return !data[i].disabled && data[i].bar }));
|
||||
|
||||
lines
|
||||
.width(availableWidth)
|
||||
.height(availableHeight1)
|
||||
.color(data.map(function(d,i) {
|
||||
return d.color || color(d, i);
|
||||
}).filter(function(d,i) { return !data[i].disabled && !data[i].bar }));
|
||||
|
||||
var focusBarsWrap = g.select('.nv-focus .nv-barsWrap')
|
||||
.datum(!dataBars.length ? [{values:[]}] :
|
||||
dataBars
|
||||
.map(function(d,i) {
|
||||
return {
|
||||
key: d.key,
|
||||
values: d.values.filter(function(d,i) {
|
||||
return bars.x()(d,i) >= extent[0] && bars.x()(d,i) <= extent[1];
|
||||
})
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
var focusLinesWrap = g.select('.nv-focus .nv-linesWrap')
|
||||
.datum(dataLines[0].disabled ? [{values:[]}] :
|
||||
dataLines
|
||||
.map(function(d,i) {
|
||||
return {
|
||||
key: d.key,
|
||||
values: d.values.filter(function(d,i) {
|
||||
return lines.x()(d,i) >= extent[0] && lines.x()(d,i) <= extent[1];
|
||||
})
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Update Main (Focus) X Axis
|
||||
|
||||
if (dataBars.length) {
|
||||
x = bars.xScale();
|
||||
} else {
|
||||
x = lines.xScale();
|
||||
}
|
||||
|
||||
xAxis
|
||||
.scale(x)
|
||||
.ticks( availableWidth / 100 )
|
||||
.tickSize(-availableHeight1, 0);
|
||||
|
||||
xAxis.domain([Math.ceil(extent[0]), Math.floor(extent[1])]);
|
||||
|
||||
d3.transition(g.select('.nv-x.nv-axis'))
|
||||
.call(xAxis);
|
||||
//------------------------------------------------------------
|
||||
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Update Main (Focus) Bars and Lines
|
||||
|
||||
d3.transition(focusBarsWrap).call(bars);
|
||||
d3.transition(focusLinesWrap).call(lines);
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Setup and Update Main (Focus) Y Axes
|
||||
|
||||
g.select('.nv-focus .nv-x.nv-axis')
|
||||
.attr('transform', 'translate(0,' + y1.range()[0] + ')');
|
||||
|
||||
|
||||
y1Axis
|
||||
.scale(y1)
|
||||
.ticks( availableHeight1 / 36 )
|
||||
.tickSize(-availableWidth, 0);
|
||||
|
||||
g.select('.nv-focus .nv-y1.nv-axis')
|
||||
.style('opacity', dataBars.length ? 1 : 0);
|
||||
|
||||
|
||||
y2Axis
|
||||
.scale(y2)
|
||||
.ticks( availableHeight1 / 36 )
|
||||
.tickSize(dataBars.length ? 0 : -availableWidth, 0); // Show the y2 rules only if y1 has none
|
||||
|
||||
g.select('.nv-focus .nv-y2.nv-axis')
|
||||
.style('opacity', dataLines.length ? 1 : 0)
|
||||
.attr('transform', 'translate(' + x.range()[1] + ',0)');
|
||||
|
||||
d3.transition(g.select('.nv-focus .nv-y1.nv-axis'))
|
||||
.call(y1Axis);
|
||||
d3.transition(g.select('.nv-focus .nv-y2.nv-axis'))
|
||||
.call(y2Axis);
|
||||
}
|
||||
|
||||
//============================================================
|
||||
|
||||
onBrush();
|
||||
|
||||
});
|
||||
|
||||
return chart;
|
||||
}
|
||||
|
||||
|
||||
//============================================================
|
||||
// Event Handling/Dispatching (out of chart's scope)
|
||||
//------------------------------------------------------------
|
||||
|
||||
lines.dispatch.on('elementMouseover.tooltip', function(e) {
|
||||
e.pos = [e.pos[0] + margin.left, e.pos[1] + margin.top];
|
||||
dispatch.tooltipShow(e);
|
||||
});
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
dispatch.on('tooltipHide', function() {
|
||||
if (tooltips) nv.tooltip.cleanup();
|
||||
});
|
||||
|
||||
//============================================================
|
||||
|
||||
|
||||
//============================================================
|
||||
// Expose Public Variables
|
||||
//------------------------------------------------------------
|
||||
|
||||
// expose chart's sub-components
|
||||
chart.dispatch = dispatch;
|
||||
chart.legend = legend;
|
||||
chart.lines = lines;
|
||||
chart.lines2 = lines2;
|
||||
chart.bars = bars;
|
||||
chart.bars2 = bars2;
|
||||
chart.xAxis = xAxis;
|
||||
chart.x2Axis = x2Axis;
|
||||
chart.y1Axis = y1Axis;
|
||||
chart.y2Axis = y2Axis;
|
||||
chart.y3Axis = y3Axis;
|
||||
chart.y4Axis = y4Axis;
|
||||
|
||||
d3.rebind(chart, lines, 'defined', 'size', 'clipVoronoi', 'interpolate');
|
||||
//TODO: consider rebinding x, y and some other stuff, and simply do soemthign lile bars.x(lines.x()), etc.
|
||||
//d3.rebind(chart, lines, 'x', 'y', 'size', 'xDomain', 'yDomain', 'forceX', 'forceY', 'interactive', 'clipEdge', 'clipVoronoi', 'id');
|
||||
|
||||
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.top = typeof _.top != 'undefined' ? _.top : margin.top;
|
||||
margin.right = typeof _.right != 'undefined' ? _.right : margin.right;
|
||||
margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom;
|
||||
margin.left = typeof _.left != 'undefined' ? _.left : margin.left;
|
||||
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 = nv.utils.getColor(_);
|
||||
legend.color(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;
|
||||
};
|
||||
|
||||
chart.noData = function(_) {
|
||||
if (!arguments.length) return noData;
|
||||
noData = _;
|
||||
return chart;
|
||||
};
|
||||
|
||||
//============================================================
|
||||
|
||||
|
||||
return chart;
|
||||
}
|
Loading…
Reference in New Issue