Added interactiveLayer.js and integrated this utility into lineChart.js.

master
Robin Hu 11 years ago
parent c079f3e122
commit dbe826943f

@ -31,6 +31,7 @@ svg {
}
#chart1 {
margin-top: 200px;
margin-left: 100px;
}
</style>
<body>
@ -43,6 +44,7 @@ svg {
<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>

@ -0,0 +1,112 @@
/* Utility class to handle creation of an interactive layer.
This places a rectangle on top of the chart. When you mouse move over it, it sends a dispatch
containing the X-coordinate. It can also render a vertical line where the mouse is located.
*/
nv.interactiveLineLayer = function() {
//Public settings
var width = null
, height = null
, xScale = d3.scale.linear()
, dispatch = d3.dispatch('elementMousemove', 'elementMouseout')
;
//Private variables
var previousXCoordinate = null
;
function layer(selection) {
selection.each(function(data) {
var container = d3.select(this);
var availableWidth = (width || 960), availableHeight = (height || 400);
var wrap = container.selectAll("g.nv-wrap.nv-interactiveLineLayer").data([data]);
var gEnter = wrap.enter()
.append("g").attr("class", " nv-wrap nv-interactiveLineLayer")
.append("g");
var guideLine = gEnter.append("g").attr("class","nv-interactiveGuideLine");
var mouseMoveLayer = gEnter.append("rect").attr("class", "nv-mouseMoveLayer");
mouseMoveLayer
.attr("width",availableWidth)
.attr("height",availableHeight)
.attr("opacity", 0)
.on("mousemove",function() {
var padding = Math.floor(xScale(1)) /2;
var mouseX = d3.mouse(this)[0];
var mouseY = d3.mouse(this)[1];
var pointIndex = Math.floor(xScale.invert(mouseX + padding));
if (pointIndex !== previousXCoordinate) {
previousXCoordinate = pointIndex;
dispatch.elementMousemove({
mouseX: mouseX,
mouseY: mouseY,
pointIndex: pointIndex
});
showGuideLine(xScale(pointIndex));
}
})
.on("mouseout",function() {
var padding = Math.floor(xScale(1)) /2;
var mouseX = d3.mouse(this)[0];
var mouseY = d3.mouse(this)[1];
var pointIndex = Math.floor(xScale.invert(mouseX + padding));
dispatch.elementMouseout({
mouseX: mouseX,
mouseY: mouseY,
pointIndex: pointIndex
});
showGuideLine(null);
})
;
function showGuideLine(x) {
var line = wrap.select(".nv-interactiveGuideLine")
.selectAll("line")
.data((x != null) ? [x] : [], String);
line.enter()
.append("line")
.attr("stroke", "#00f")
.attr("x1", function(d) { return d;})
.attr("x2", function(d) { return d;})
.attr("y1", availableHeight)
.attr("y2",0)
;
line.exit().remove();
}
});
}
layer.dispatch = dispatch;
layer.width = function(_) {
if (!arguments.length) return width;
width = _;
return layer;
};
layer.height = function(_) {
if (!arguments.length) return height;
height = _;
return layer;
};
layer.xScale = function(_) {
if (!arguments.length) return xScale;
xScale = _;
return layer;
};
return layer;
};

@ -209,7 +209,7 @@ nv.models.line = function() {
chart.dispatch = scatter.dispatch;
chart.scatter = scatter;
d3.rebind(chart, scatter, 'id', 'interactive', 'size', 'xScale', 'yScale', 'zScale', 'xDomain', 'yDomain', 'sizeDomain', 'forceX', 'forceY', 'forceSize', 'clipVoronoi', 'clipRadius', 'padData');
d3.rebind(chart, scatter, 'id', 'interactive', 'size', 'xScale', 'yScale', 'zScale', 'xDomain', 'yDomain', 'sizeDomain', 'forceX', 'forceY', 'forceSize', 'clipVoronoi', 'useVoronoi', 'clipRadius', 'padData');
chart.margin = function(_) {
if (!arguments.length) return margin;

@ -9,6 +9,7 @@ nv.models.lineChart = function() {
, xAxis = nv.models.axis()
, yAxis = nv.models.axis()
, legend = nv.models.legend()
, interactiveLayer = nv.interactiveLineLayer()
;
//set margin.right to 23 to fit dates on the x-axis within the chart
@ -52,7 +53,7 @@ nv.models.lineChart = function() {
var x = xAxis.tickFormat()(lines.x()(e.point, e.pointIndex));
var tip = nv.models.tooltip()
.position({left: e.pos[0], top: e.pos[1]})
.position(e.position)
.chartContainer(offsetElement)
.fixedTop(30)
.enabled(tooltips)
@ -63,7 +64,7 @@ nv.models.lineChart = function() {
{
key: "",
value: x,
seriesSelectedKey: e.series.key,
// seriesSelectedKey: e.series.key,
series: e.allSeriesData
}
)
@ -147,22 +148,13 @@ nv.models.lineChart = function() {
gEnter.append('g').attr('class', 'nv-y nv-axis');
gEnter.append('g').attr('class', 'nv-linesWrap');
gEnter.append('g').attr('class', 'nv-legendWrap');
gEnter.append('rect').attr('class', 'nv-mouseMoveLayer');
gEnter.append('g').attr('class', 'nv-interactive');
//------------------------------------------------------------
//Set up interactive layer
interactiveLayer.width(availableWidth).height(availableHeight).xScale(x);
wrap.select(".nv-mouseMoveLayer")
.attr("width",availableWidth)
.attr("height",availableHeight)
.attr("opacity", 0)
.on("mousemove",function() {
var padding = Math.floor(availableWidth / data[0].values.length);
var pointIndex = Math.floor(x.invert(d3.mouse(this)[0] + padding));
lines.dispatch.clearHighlights();
data.forEach(function(item, i) {
lines.dispatch.highlightPoint(i, pointIndex, true);
});
});
wrap.select(".nv-interactive").call(interactiveLayer);
//------------------------------------------------------------
// Legend
@ -273,18 +265,31 @@ nv.models.lineChart = function() {
chart.update();
});
interactiveLayer.dispatch.on('elementMousemove', function(e) {
lines.dispatch.clearHighlights();
var xValue, allData = [];
data.forEach(function(series,i) {
lines.dispatch.highlightPoint(i, e.pointIndex, true);
allData.push({
key: series.key,
value: lines.y()(series.values[e.pointIndex], e.pointIndex),
color: color(series)
});
});
showTooltip({
position: {left: e.mouseX + margin.left, top: e.mouseY + margin.top},
pointIndex: e.pointIndex,
allSeriesData: allData
/*
legend.dispatch.on('legendMouseover', function(d, i) {
d.hover = true;
selection.transition().call(chart)
}, that.parentNode);
});
legend.dispatch.on('legendMouseout', function(d, i) {
d.hover = false;
selection.transition().call(chart)
interactiveLayer.dispatch.on("elementMouseout",function(e) {
dispatch.tooltipHide();
lines.dispatch.clearHighlights();
});
*/
dispatch.on('tooltipShow', function(e) {
showTooltip(e, that.parentNode);
@ -318,17 +323,11 @@ nv.models.lineChart = function() {
lines.dispatch.on('elementMouseover.tooltip', function(e) {
e.pos = [e.pos[0] + margin.left, e.pos[1] + margin.top];
e.allSeriesData.forEach(function(item, i) {
lines.dispatch.highlightPoint(i, e.pointIndex, true);
});
dispatch.tooltipShow(e);
// dispatch.tooltipShow(e);
});
lines.dispatch.on('elementMouseout.tooltip', function(e) {
e.allSeriesData.forEach(function(item, i) {
lines.dispatch.highlightPoint(i, e.pointIndex, false);
});
dispatch.tooltipHide(e);
// dispatch.tooltipHide(e);
});
dispatch.on('tooltipHide', function() {
@ -349,7 +348,7 @@ nv.models.lineChart = function() {
chart.xAxis = xAxis;
chart.yAxis = yAxis;
d3.rebind(chart, lines, 'defined', 'isArea', 'x', 'y', 'size', 'xScale', 'yScale', 'xDomain', 'yDomain', 'forceX', 'forceY', 'interactive', 'clipEdge', 'clipVoronoi', 'id', 'interpolate');
d3.rebind(chart, lines, 'defined', 'isArea', 'x', 'y', 'size', 'xScale', 'yScale', 'xDomain', 'yDomain', 'forceX', 'forceY', 'interactive', 'clipEdge', 'clipVoronoi', 'useVoronoi','id', 'interpolate');
chart.margin = function(_) {
if (!arguments.length) return margin;

@ -181,28 +181,38 @@
return nvtooltip;
};
//Global utility function to render a tooltip on the DOM.
nv.tooltip.show = function(pos, content, gravity, dist, parentContainer, classes) {
var container = document.createElement('div');
var container = document.getElementsByClassName("nvtooltip");
if (container.length === 0) {
//Create new tooltip div if it doesn't exist on DOM.
container = document.createElement('div');
container.className = 'nvtooltip ' + (classes ? classes : 'xy-tooltip');
gravity = gravity || 's';
dist = dist || 20;
var body = parentContainer;
if ( !parentContainer || parentContainer.tagName.match(/g|svg/i)) {
//If the parent element is an SVG element, place tooltip in the <body> element.
body = document.getElementsByTagName('body')[0];
}
container.innerHTML = content;
container.style.left = 0;
container.style.top = 0;
container.style.opacity = 0;
body.appendChild(container);
}
else {
container = container[0];
}
container.innerHTML = content;
nv.tooltip.calcTooltipPosition(pos, gravity, dist, container);
};
//Global utility function to render a tooltip on the DOM.
nv.tooltip.calcTooltipPosition = function(pos, gravity, dist, container) {
var height = parseInt(container.offsetHeight),
width = parseInt(container.offsetWidth),
windowWidth = nv.utils.windowSize().width,
@ -214,8 +224,13 @@
windowHeight = window.innerWidth >= document.body.scrollWidth ? windowHeight : windowHeight - 16;
windowWidth = window.innerHeight >= document.body.scrollHeight ? windowWidth : windowWidth - 16;
gravity = gravity || 's';
dist = dist || 20;
var tooltipTop = function ( Elem ) {
var offsetTop = top;
if (Elem.offsetParent.tagName === 'BODY') return offsetTop;
do {
if( !isNaN( Elem.offsetTop ) ) {
offsetTop += (Elem.offsetTop);
@ -226,6 +241,8 @@
var tooltipLeft = function ( Elem ) {
var offsetLeft = left;
if (Elem.offsetParent.tagName === 'BODY') return offsetLeft;
do {
if( !isNaN( Elem.offsetLeft ) ) {
offsetLeft += (Elem.offsetLeft);

Loading…
Cancel
Save