Added test page for lineChart. Continued work on making the interactive line layer.

master
Robin Hu 11 years ago
parent dbe826943f
commit 0b3ef24e0b

@ -1,6 +1,7 @@
JS_FILES = \ JS_FILES = \
src/intro.js \ src/intro.js \
src/core.js \ src/core.js \
src/interactiveLayer.js \
src/tooltip.js \ src/tooltip.js \
src/utils.js \ src/utils.js \
src/models/axis.js \ src/models/axis.js \

@ -93,14 +93,16 @@ nv.addGraph(function() {
function sinAndCos() { function sinAndCos() {
var sin = [], var sin = [],
cos = [] cos = [],
rand = [] rand = [],
rand2 = []
; ;
for (var i = 0; i < 100; i++) { for (var i = 0; i < 100; i++) {
sin.push({x: i, y: i % 10 == 5 ? null : Math.sin(i/10) }); //the nulls are to show how defined works sin.push({x: i, y: i % 10 == 5 ? null : Math.sin(i/10) }); //the nulls are to show how defined works
cos.push({x: i, y: .5 * Math.cos(i/10)}); cos.push({x: i, y: .5 * Math.cos(i/10)});
rand.push({x:i, y: Math.random() / 10}); rand.push({x:i, y: Math.random() / 10});
rand2.push({x: i, y: Math.cos(i/10) + Math.random() / 10 })
} }
return [ return [
@ -120,6 +122,12 @@ function sinAndCos() {
key: "Random Points", key: "Random Points",
color: "#2222ff" color: "#2222ff"
} }
,
{
values: rand2,
key: "Random Cosine",
color: "#667711"
}
]; ];
} }

@ -23,15 +23,15 @@ nv.interactiveLineLayer = function() {
var availableWidth = (width || 960), availableHeight = (height || 400); var availableWidth = (width || 960), availableHeight = (height || 400);
var wrap = container.selectAll("g.nv-wrap.nv-interactiveLineLayer").data([data]); var wrap = container.selectAll("g.nv-wrap.nv-interactiveLineLayer").data([data]);
var gEnter = wrap.enter() var wrapEnter = wrap.enter()
.append("g").attr("class", " nv-wrap nv-interactiveLineLayer") .append("g").attr("class", " nv-wrap nv-interactiveLineLayer");
.append("g");
var guideLine = gEnter.append("g").attr("class","nv-interactiveGuideLine"); wrapEnter.append("g").attr("class","nv-interactiveGuideLine");
var mouseMoveLayer = gEnter.append("rect").attr("class", "nv-mouseMoveLayer"); wrapEnter.append("rect").attr("class", "nv-mouseMoveLayer");
mouseMoveLayer wrap.select(".nv-mouseMoveLayer")
.attr("width",availableWidth) .attr("width",availableWidth)
.attr("height",availableHeight) .attr("height",availableHeight)
.attr("opacity", 0) .attr("opacity", 0)
@ -40,16 +40,17 @@ nv.interactiveLineLayer = function() {
var mouseX = d3.mouse(this)[0]; var mouseX = d3.mouse(this)[0];
var mouseY = d3.mouse(this)[1]; var mouseY = d3.mouse(this)[1];
var pointIndex = Math.floor(xScale.invert(mouseX + padding)); var pointIndex = Math.floor(xScale.invert(mouseX + padding));
if (pointIndex !== previousXCoordinate) { var pointLocation = xScale(pointIndex);
previousXCoordinate = pointIndex; dispatch.elementMousemove({
dispatch.elementMousemove({ mouseX: mouseX,
mouseX: mouseX, mouseY: mouseY,
mouseY: mouseY, pointIndex: pointIndex,
pointIndex: pointIndex pointLocation: pointLocation
}); });
showGuideLine(pointLocation);
showGuideLine(xScale(pointIndex));
}
}) })
.on("mouseout",function() { .on("mouseout",function() {
var padding = Math.floor(xScale(1)) /2; var padding = Math.floor(xScale(1)) /2;
@ -75,7 +76,7 @@ nv.interactiveLineLayer = function() {
line.enter() line.enter()
.append("line") .append("line")
.attr("stroke", "#00f") .attr("stroke", "#ccc")
.attr("x1", function(d) { return d;}) .attr("x1", function(d) { return d;})
.attr("x2", function(d) { return d;}) .attr("x2", function(d) { return d;})
.attr("y1", availableHeight) .attr("y1", availableHeight)

@ -10,6 +10,7 @@ nv.models.lineChart = function() {
, yAxis = nv.models.axis() , yAxis = nv.models.axis()
, legend = nv.models.legend() , legend = nv.models.legend()
, interactiveLayer = nv.interactiveLineLayer() , interactiveLayer = nv.interactiveLineLayer()
, tooltip = nv.models.tooltip()
; ;
//set margin.right to 23 to fit dates on the x-axis within the chart //set margin.right to 23 to fit dates on the x-axis within the chart
@ -55,7 +56,9 @@ nv.models.lineChart = function() {
var tip = nv.models.tooltip() var tip = nv.models.tooltip()
.position(e.position) .position(e.position)
.chartContainer(offsetElement) .chartContainer(offsetElement)
.fixedTop(30) .gravity('w')
.distance(50)
.snapDistance(25)
.enabled(tooltips) .enabled(tooltips)
.valueFormatter(function(d,i) { .valueFormatter(function(d,i) {
return yAxis.tickFormat()(d); return yAxis.tickFormat()(d);
@ -191,6 +194,7 @@ nv.models.lineChart = function() {
lines lines
.width(availableWidth) .width(availableWidth)
.height(availableHeight) .height(availableHeight)
.interactive(false)
.color(data.map(function(d,i) { .color(data.map(function(d,i) {
return d.color || color(d, i); return d.color || color(d, i);
}).filter(function(d,i) { return !data[i].disabled })); }).filter(function(d,i) { return !data[i].disabled }));
@ -268,18 +272,24 @@ nv.models.lineChart = function() {
interactiveLayer.dispatch.on('elementMousemove', function(e) { interactiveLayer.dispatch.on('elementMousemove', function(e) {
lines.dispatch.clearHighlights(); lines.dispatch.clearHighlights();
var xValue, allData = []; var xValue, allData = [];
data.forEach(function(series,i) { data
.filter(function(series, i) {
series.seriesIndex = i;
return !series.disabled;
})
.forEach(function(series,i) {
lines.dispatch.highlightPoint(i, e.pointIndex, true); lines.dispatch.highlightPoint(i, e.pointIndex, true);
var point = series.values[e.pointIndex];
if (typeof point === 'undefined') return;
allData.push({ allData.push({
key: series.key, key: series.key,
value: lines.y()(series.values[e.pointIndex], e.pointIndex), value: lines.y()(series.values[e.pointIndex], e.pointIndex),
color: color(series) color: color(series,series.seriesIndex)
}); });
}); });
showTooltip({ showTooltip({
position: {left: e.mouseX + margin.left, top: e.mouseY + margin.top}, position: {left: e.pointLocation + margin.left, top: e.mouseY + margin.top},
pointIndex: e.pointIndex, pointIndex: e.pointIndex,
allSeriesData: allData allSeriesData: allData
@ -409,11 +419,6 @@ nv.models.lineChart = function() {
return chart; return chart;
}; };
chart.tooltipContent = function(_) {
if (!arguments.length) return tooltip;
tooltip = _;
return chart;
};
chart.state = function(_) { chart.state = function(_) {
if (!arguments.length) return state; if (!arguments.length) return state;

@ -445,17 +445,16 @@ nv.models.scatter = function() {
}); });
dispatch.on('highlightPoint', function(seriesIndex, pointIndex, isHoverOver) { dispatch.on('highlightPoint', function(seriesIndex, pointIndex, isHoverOver) {
if (interactive) { d3.select(".nv-chart-" + id + " .nv-series-" + seriesIndex + " .nv-point-" + pointIndex)
d3.select(".nv-chart-" + id + " .nv-series-" + seriesIndex + " .nv-point-" + pointIndex) .classed("hover",isHoverOver);
.classed("hover",isHoverOver);
}
}); });
dispatch.on('elementMouseover.point', function(d) { dispatch.on('elementMouseover.point', function(d) {
dispatch.highlightPoint(d.seriesIndex,d.pointIndex,true); if (interactive) dispatch.highlightPoint(d.seriesIndex,d.pointIndex,true);
}); });
dispatch.on('elementMouseout.point', function(d) { dispatch.on('elementMouseout.point', function(d) {
dispatch.highlightPoint(d.seriesIndex,d.pointIndex,false); if (interactive) dispatch.highlightPoint(d.seriesIndex,d.pointIndex,false);
}); });
//============================================================ //============================================================

@ -17,7 +17,7 @@
.nvtooltip { .nvtooltip {
position: absolute; position: absolute;
background-color: rgba(255,255,255,0.75); background-color: rgba(255,255,255,1.0);
padding: 1px; padding: 1px;
border: 1px solid rgba(0,0,0,.2); border: 1px solid rgba(0,0,0,.2);
z-index: 10000; z-index: 10000;
@ -392,7 +392,7 @@ svg .title {
.nvd3 .nv-groups .nv-point { .nvd3 .nv-groups .nv-point {
transition: stroke-width 250ms linear, stroke-opacity 250ms linear; transition: stroke-width 250ms linear, stroke-opacity 250ms linear;
-moz-transition: stroke-width 250ms linear, stroke-opacity 250ms linear; -moz-transition: stroke-width 250ms linear, stroke-opacity 250ms linear;
-webkit-transition: stroke-width 250ms linear, stroke-opacity 250ms linear; -webkit-transition: stroke-width 0ms linear, stroke-opacity 0ms linear;
} }

@ -38,6 +38,7 @@
*/ */
, gravity = 's' //Can be 'n','s','e','w'. Determines how tooltip is positioned. , gravity = 's' //Can be 'n','s','e','w'. Determines how tooltip is positioned.
, distance = 20 //Distance to offset tooltip from the mouse location. , distance = 20 //Distance to offset tooltip from the mouse location.
, snapDistance = 30
, fixedTop = null //If not null, this fixes the top position of the tooltip. , fixedTop = null //If not null, this fixes the top position of the tooltip.
, classes = null //Attaches additional CSS classes to the tooltip DIV that is created. , classes = null //Attaches additional CSS classes to the tooltip DIV that is created.
, chartContainer = null //Parent container that holds the chart. , chartContainer = null //Parent container that holds the chart.
@ -68,6 +69,12 @@
return html; return html;
}; };
var dataSeriesExists = function(d) {
if (d && d.series && d.series.length > 0) return true;
return false;
};
//In situations where the chart is in a 'viewBox', re-position the tooltip based on how far chart is zoomed. //In situations where the chart is in a 'viewBox', re-position the tooltip based on how far chart is zoomed.
function convertViewBoxRatio() { function convertViewBoxRatio() {
if (chartContainer) { if (chartContainer) {
@ -87,6 +94,7 @@
//Draw the tooltip onto the DOM. //Draw the tooltip onto the DOM.
nvtooltip.render = function() { nvtooltip.render = function() {
if (!enabled) return; if (!enabled) return;
if (!dataSeriesExists(data)) return;
convertViewBoxRatio(); convertViewBoxRatio();
@ -98,6 +106,11 @@
top += (chartContainer.offsetTop || 0); top += (chartContainer.offsetTop || 0);
} }
if (snapDistance && snapDistance > 0) {
// left = Math.floor(left/snapDistance) * snapDistance;
top = Math.floor(top/snapDistance) * snapDistance;
}
nv.tooltip.show([left, top], nv.tooltip.show([left, top],
contentGenerator(data), contentGenerator(data),
gravity, gravity,
@ -138,6 +151,12 @@
return nvtooltip; return nvtooltip;
}; };
nvtooltip.snapDistance = function(_) {
if (!arguments.length) return snapDistance;
snapDistance = _;
return nvtooltip;
};
nvtooltip.classes = function(_) { nvtooltip.classes = function(_) {
if (!arguments.length) return classes; if (!arguments.length) return classes;
classes = _; classes = _;
@ -264,6 +283,8 @@
case 'w': case 'w':
left = pos[0] + dist; left = pos[0] + dist;
top = pos[1] - (height / 2); top = pos[1] - (height / 2);
var tLeft = tooltipLeft(container);
var tTop = tooltipTop(container);
if (tLeft + width > windowWidth) left = pos[0] - width - dist; if (tLeft + width > windowWidth) left = pos[0] - width - dist;
if (tTop < scrollTop) top = scrollTop + 5; if (tTop < scrollTop) top = scrollTop + 5;
if (tTop + height > scrollTop + windowHeight) top = scrollTop - height - 5; if (tTop + height > scrollTop + windowHeight) top = scrollTop - height - 5;

@ -0,0 +1,231 @@
<!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;
}
.chart {
float: left;
width: 50%;
}
.chart svg {
height: 500px;
width: 100%;
}
</style>
<body>
<div class='chart' id='chart1'>
<svg></svg>
</div>
<div class='chart' id='chart2'>
<svg></svg>
</div>
<div class='chart' id='chart3'>
<svg></svg>
</div>
<div class='chart' id='chart4'>
<svg></svg>
</div>
<div class='chart' id='chart5'>
<svg></svg>
</div>
<div class='chart' id='chart6'>
<svg></svg>
</div>
<script src="../lib/d3.v3.js"></script>
<script src="../nv.d3.js"></script>
<script src="../src/tooltip.js"></script>
<script src="../src/utils.js"></script>
<script src="../src/interactiveLayer.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/lineChart.js"></script>
<script>
//------------ CHART 1
defaultChartConfig("chart1", sinAndCos(), true);
//-------------- CHART 2
nv.addGraph(function() {
var chart;
chart = nv.models.lineChart();
chart
.x(function(d,i) { return i });
chart.xAxis // chart sub-models (ie. xAxis, yAxis, etc) when accessed directly, return themselves, not the parent chart, so need to chain separately
.tickFormat(d3.format(',.1f'));
chart.yAxis
.axisLabel('Voltage (v)')
.tickFormat(d3.format(',.4f'));
chart.showXAxis(true).showYAxis(true).rightAlignYAxis(true).margin({right: 90});
d3.select('#chart2 svg')
//.datum([]) //for testing noData
.datum(hyperbole())
.transition().duration(500)
.call(chart);
nv.utils.windowResize(chart.update);
return chart;
});
defaultChartConfig("chart3", smallDataSet(3));
defaultChartConfig("chart4", badDataSet());
defaultChartConfig("chart5", smallDataSet(1));
defaultChartConfig("chart6", normalDist());
function defaultChartConfig(containerid, data, useDates) {
nv.addGraph(function() {
var chart;
chart = nv.models.lineChart();
chart
.x(function(d,i) { return i });
var formatter;
if (useDates !== undefined) {
formatter = function(d,i) {
var now = (new Date()).getTime() - 86400 * 1000 * 365;
now = new Date(now + d * 86400 * 1000);
return d3.time.format('%b %d %Y')(now );
}
}
else {
formatter = d3.format(",.1f");
}
chart.margin({right: 40});
chart.xAxis // chart sub-models (ie. xAxis, yAxis, etc) when accessed directly, return themselves, not the parent chart, so need to chain separately
.tickFormat(
formatter
);
chart.yAxis
.axisLabel('Voltage (v)')
.tickFormat(d3.format(',.2f'));
d3.select('#' + containerid + ' svg')
.datum(data)
.transition().duration(500)
.call(chart);
nv.utils.windowResize(chart.update);
return chart;
});
}
function sinAndCos() {
var sin = [],
cos = [],
rand = [],
rand2 = []
;
var now = (new Date()).getTime();
for (var i = 0; i < 100; i++) {
sin.push({x: i, y: i % 10 == 5 ? null : Math.sin(i/10) }); //the nulls are to show how defined works
cos.push({x: i, y: .5 * Math.cos(i/10)});
rand.push({x:i, y: Math.random() / 10});
rand2.push({x: i, y: Math.cos(i/10) + Math.random() / 10 })
}
return [
{
area: true,
values: sin,
key: "Sine Wave",
color: "#ff7f0e"
},
{
values: cos,
key: "Cosine Wave",
color: "#2ca02c"
},
{
values: rand,
key: "Random Points",
color: "#2222ff"
}
,
{
values: rand2,
key: "Random Cosine",
color: "#667711"
}
];
}
function hyperbole() {
var series1 = [], series2 = [], series3 = [];
for(var i = 1; i < 100; i++) {
series1.push({x: i, y: 1 / i});
series2.push({x: i, y: 5 / i});
series3.push({x: i, y: -8 / i});
}
return [
{values: series1, key: "Series 1"},
{values: series2, key: "Series 2"},
{values: series3, key: "Series 3"}
];
}
function smallDataSet(n) {
var series = [];
for(var i = 0; i < n; i++) {
series.push({x: i, y: i * 0.3 + 2})
}
return [
{values: series, key: "Line 1"}
];
}
function badDataSet() {
var series1 = [], series2 = [];
for(var i =0; i < 30; i++) {
series1.push({x:i, y: i*0.3 + 12});
}
for(i = 0; i < 30; i += 5) {
series2.push({x:i, y: i*0.7 + 8});
}
return [
{values: series1, key:"Series 1"},
{values: series2, key:"Series 2"}
];
}
function normalDist() {
var series1 = [], series2 = [];
for(var i = -500; i < 500; i += 1) {
var x = i / 100;
var y = 0.3989 * Math.pow(2.71, -0.5*x*x);
series1.push({x:i, y:y});
series2.push({x:i, y:y*2});
}
return [
{values: series1, key:"Normal 1"},
{values: series2, key:"Normal 2"}];
}
</script>
Loading…
Cancel
Save