I would like to seek help how to set the starting point of a hexagon shape in progress animation. Based on my screenshot my issue is that my code is always start at first half of the hexagon shape.
I tried to changed my hexagon data but the issue still not in the correct starting point of the animation.
You can check my code below what's wrong. And thanks in advance.
<html>
<head>
<title>Demo</title>
</head>
<body>
<div id="animation"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.10/d3.min.js"></script>
<script>
/*https://codepen.io/MarcBT/pen/wcLCe/*/
var h = (Math.sqrt(3)/2.2),
radius = 100,
xp = 200,
yp = 200,
hexagonData = [
{ "x": (radius/2+xp) , "y": (-radius*h+yp)},
{ "x": -radius/2+xp, "y": -radius*h+yp},
{ "x": -radius+xp, "y": yp},
{ "x": -radius/2+xp, "y": radius*h+yp},
{ "x": radius/2+xp, "y": radius*h+yp},
{ "x": radius+xp, "y": yp},
];
drawHexagon =
d3.svg.line()
.x(function(d) { return d.x; })
.y(function(d) { return d.y; })
.interpolate("cardinal-closed")
.tension(".1")
var svgContainer =
d3.select("body")
.append("svg")
.attr("width", 600)
.attr("height", 600);
var svgContainer = d3.select("#animation") //create container
.append("svg")
.attr("width", 1000)
.attr("height", 1000);
var path = svgContainer.append('path')
.attr('d', drawHexagon(hexagonData))
//.attr('d',line(pointData))
.attr('stroke', "#E2E2E1")
.attr('stroke-width', '4')
.attr('fill', 'none');
var totalLength = path.node().getTotalLength();
var percent = 100;
console.log(totalLength);
path
.attr("stroke-dasharray", totalLength + " " + totalLength)
.attr("stroke-dashoffset", totalLength)
//.transition()
//.duration(2000)
//.ease("linear")
.attr("stroke-dashoffset",0);
var path1 = svgContainer.append('path')
.attr('d', drawHexagon(hexagonData))
.attr('stroke', "green")
.attr('stroke-width', '4')
.attr('fill', 'none');
var totalLength = path1.node().getTotalLength();
var percent = -30;
//console.log(totalLength);
path1
.attr("stroke-dasharray", totalLength + " " + totalLength)
.attr("stroke-dashoffset",totalLength )
// .attr("fill", "rgba(255,0,0,0.4)")
.transition()
.duration(2000)
.attr("stroke-dashoffset", ((100 - percent)/100) *totalLength)
</script>
</body>
</html>
Here's a fiddle of what you are trying to do : https://jsfiddle.net/udsnbb5m/2/
The animation is starting at the first point of your hexagon. However your points aren't the vertices of your hexagon. You can change that like that:
d3.svg.line()
.x(function(d) { return d.x; })
.y(function(d) { return d.y; })
.interpolate("cardinal-closed")
.tension("0.90") // Previously 0.1
Okay, the animation starts properly.
Now we have to change the hexagon orientation. You can modify directly the points coordinates. (That's what I did)
hexagonData = [
{ "x": xp, "y": -radius+yp}, //5
{ "x": -radius*h+xp , "y": -radius/2+yp}, //4
{ "x": (-radius*h+xp) , "y": (radius/2+yp)}, //3
{ "x": xp , "y": radius+yp}, //2
{ "x": radius*h+xp , "y": radius/2+yp}, //1
{ "x": radius*h+xp , "y": -radius/2+yp}, //6
];
Note that you probably can do it with this attribute:
.attr('transform','rotate(-45)');
Related
I have a polygon and rectangle svg created and I also created a toggle button for a polygon and a rectangle as shown below and jfiddle as well.
What I am trying to achieve is initially both the rectangle and polygon should be displayed on the webpage, then if I click on "toggle polygon" the polygon should be shown and the rectangle should be hidden, and if I click on "toggle rect" the rectangle should be shown and polygon should be hidden.
I wrote the code below to achieve that but for some reason,both rectangle and polygon arent displayed first together and also the toggle buttons aren't even displaying proper shape even though I provided different function names to both.
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="http://d3js.org/d3.v3.js"></script>
<button onclick="myfunc" >Toggle polygon</button>
<button onclick="func">toggle rect</button>
</body>
...
...
var vis = d3.select("body").append("svg")
.attr("width", 1000)
.attr("height", 667),
scaleX = d3.scale.linear()
.domain([-30,30])
.range([0,600]),
scaleY = d3.scale.linear()
.domain([0,50])
.range([500,0]),
poly = [{"x":0.0, "y":25.0},
{"x":8.5,"y":23.4},
{"x":13.0,"y":21.0},
{"x":19.0,"y":15.5}];
var path;
d3.select('button').on('click', function myfunc() {
if ( path ) {
path.remove();
// Remove dots
path = null;
} else {
path=vis.select("polygon")
.data([poly])
.enter().append("polygon")
.attr("points",function(d) {
return d.map(function(d) { return [scaleX(d.x),scaleY(d.y)].join(","); }).join(" ");})
.attr("stroke","black")
.attr("stroke-width",2);
}
});
var rect;
d3.select('button').on('click', function func() {
if ( rect ) {
rect.remove();
// Remove dots
rect= null;
} else {
rect = vis
.append("rect")
.attr("x", 165)
.attr("y", 25)
.attr("height", 100)
.attr("width", 100)
.attr("fill", "#420a91")
.attr("stroke", "#FF00FF")
.attr("stroke-width", "4")
.attr("stroke-dasharray", "10,10");
}
});
...
http://jsfiddle.net/e2juf7op/1/
When you do...
d3.select('button').on('click',
... you are selecting the first button and setting a different listener to that same button (the last one overrides the first one).
The solution is either dropping the selection.on and relying on the inline onclick event or, alternatively, give those buttons different IDs. Also, remember that selection.data() follows selectAll.
Here is your code with those changes:
var vis = d3.select("body").append("svg")
.attr("width", 1000)
.attr("height", 667),
scaleX = d3.scale.linear()
.domain([-30, 30])
.range([0, 600]),
scaleY = d3.scale.linear()
.domain([0, 50])
.range([500, 0]),
poly = [{
"x": 0.0,
"y": 25.0
},
{
"x": 8.5,
"y": 23.4
},
{
"x": 13.0,
"y": 21.0
},
{
"x": 19.0,
"y": 15.5
}
];
var path;
d3.select('#btn1').on('click', function myfunc() {
if (path) {
path.remove();
// Remove dots
path = null;
} else {
path = vis.selectAll("polygon")
.data([poly])
.enter().append("polygon")
.attr("points", function(d) {
return d.map(function(d) {
return [scaleX(d.x), scaleY(d.y)].join(",");
}).join(" ");
})
.attr("stroke", "black")
.attr("stroke-width", 2);
}
});
var rect;
d3.select('#btn2').on('click', function func() {
if (rect) {
rect.remove();
// Remove dots
rect = null;
} else {
rect = vis
.append("rect")
.attr("x", 165)
.attr("y", 25)
.attr("height", 100)
.attr("width", 100)
.attr("fill", "#420a91")
.attr("stroke", "#FF00FF")
.attr("stroke-width", "4")
.attr("stroke-dasharray", "10,10");
}
});
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="http://d3js.org/d3.v3.js"></script>
<button id="btn1">Toggle polygon</button>
<button id="btn2">toggle rect</button>
</body>
I'm trying to create points between any 2 points of my triangle. How do i create mid-points between 2 points? For example, how would i create a point
between the coordinates (150, 0) and (0, 200)?
var points = [
{"x": 150, "y": 0},
{"x": 0, "y": 200},
{"x": 300, "y": 200},
{"x": 150, "y": 0}
];
//CREATE THE SVG CONTAINER
var svg = d3.select("body").append("svg")
.attr("width", 500)
.attr("height", 500)
.style('fill', '#113F8C')
.style('padding-left', '20px')
.style('padding-top', '5px');
// DRAW THE PATH
var path = svg.append("path")
.data([lineData])
.attr("stroke", "black")
.attr("stroke-width", 3)
.attr("d", d3.line());
//SET THE POINTS
svg.selectAll("circle")
.data(points)
.enter().append("circle")
.attr("cx", function(d) {
console.log(d.x+ " hello");
for (var i = 0; i < points.length; i++) {
//console.log(points[i]);
x[i] = d.x;
console.log(d.x);
};
return d.x;
})
.attr("cy", function(d) {console.log(d.y+ " hello"); return d.y; })
.attr("r", 5);
// THE X TEST
x[0];
Since you have a points data with a redundant fourth point in the triangle (which is the same of the first), we can simply remove this fourth object of the data:
.data(points.slice(0, points.length-1))
And don't even mind about the range error of the last data:
.attr("cx", (d,i)=>(d.x + points[i+1].x)/2)
.attr("cy", (d,i)=>(d.y + points[i+1].y)/2);
Here is a demo. The blue points are the points of your data array, the red points are the mid points.
var svg = d3.select("body")
.append("svg")
.attr("width", 400)
.attr("height", 300);
var points = [
{"x": 150, "y": 10},
{"x": 10, "y": 200},
{"x": 300, "y": 200},
{"x": 150, "y": 10}
];
var circles = svg.selectAll(".circles")
.data(points)
.enter()
.append("circle")
.attr("r", 5)
.attr("fill", "blue")
.attr("cx", d=>d.x)
.attr("cy", d=>d.y);
var midPoints = svg.selectAll(".midPoints")
.data(points.slice(0, points.length-1))
.enter()
.append("circle")
.attr("r", 5)
.attr("fill", "brown")
.attr("cx", (d,i)=>(d.x + points[i+1].x)/2)
.attr("cy", (d,i)=>(d.y + points[i+1].y)/2);
<script src="https://d3js.org/d3.v4.min.js"></script>
The same snippet, with lines for each triangle:
var svg = d3.select("body")
.append("svg")
.attr("width", 400)
.attr("height", 300);
var points = [
{"x": 150, "y": 10},
{"x": 10, "y": 200},
{"x": 300, "y": 200},
{"x": 150, "y": 10}
];
var line = d3.line()
.x(d=>d.x)
.y(d=>d.y);
var lineMid = d3.line()
.x((d,i)=>(d.x + points[i+1].x)/2)
.y((d,i)=>(d.y + points[i+1].y)/2)
.curve(d3.curveLinearClosed);
var lineCircles = svg.append("path")
.attr("d", line(points))
.attr("fill", "none")
.attr("stroke", "blue")
.attr("opacity", 0.4);
var lineMidPoints = svg.append("path")
.attr("d", lineMid(points.slice(0, points.length-1)))
.attr("fill", "none")
.attr("stroke", "brown")
.attr("opacity", 0.4);
var circles = svg.selectAll(".circles")
.data(points)
.enter()
.append("circle")
.attr("r", 5)
.attr("fill", "blue")
.attr("cx", d=>d.x)
.attr("cy", d=>d.y);
var midPoints = svg.selectAll(".midPoints")
.data(points.slice(0, points.length-1))
.enter()
.append("circle")
.attr("r", 5)
.attr("fill", "brown")
.attr("cx", (d,i)=>(d.x + points[i+1].x)/2)
.attr("cy", (d,i)=>(d.y + points[i+1].y)/2);
<script src="https://d3js.org/d3.v4.min.js"></script>
A simple program for multiple ellipse I have written. The program shows no error but also no ellipse is being seen. Though i tried add multiple random colors for it. I think there is some slight mistake somewhere. Can someone help out?
SNIPPET:
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.3.0/d3.min.js"></script>
<script>
$(document).ready(function(){
//our basic data
var customData = [
{ "x": 30, "y": 30, "width": 20, "height" : 10 },
{ "x": 70, "y": 70, "width": 20, "height" : 20},
{ "x": 110, "y": 100, "width": 20, "height" : 30}
];
//Make an SVG Container
var mySVG = d3.select("svg");
//create ellipses skeleton by data
var ellipses = mySVG.selectAll("ellipse")
.data(customData)
.enter()
.append("ellipse");
//Draw the Rectangle
ellipses.append("ellipse")
.attr("cx", function (d) { return d.x; })
.attr("cy", function (d) { return d.y; })
.attr("rx", function (d) { return d.width; })
.attr("ry", function(d) { return d.height; })
.attr("fill",function() { return "hsl(" + Math.random() * 360 + ",100%,50%)"; });
});
</script>
</head>
<body>
<svg width="500px" height="500px"></svg>
</body>
</html>
You are appending ellipse elements twice. Here is the working snippet.
var customData = [{
"x": 30,
"y": 30,
"width": 20,
"height": 10
}, {
"x": 70,
"y": 70,
"width": 20,
"height": 20
}, {
"x": 110,
"y": 100,
"width": 20,
"height": 30
}];
//Make an SVG Container
var mySVG = d3.select("svg");
//create ellipses skeleton by data
var ellipses = mySVG.selectAll("ellipse")
.data(customData)
.enter()
.append("ellipse");
// Removed second append from here
//Draw the Rectangle
ellipses.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
})
.attr("rx", function(d) {
return d.width;
})
.attr("ry", function(d) {
return d.height;
})
.attr("fill", function() {
return "hsl(" + Math.random() * 360 + ",100%,50%)";
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<svg width="500px" height="500px"></svg>
I have drawn four svg rect diagram...with different colors....
I'm trying to add node inside of those svg rect...but I'm getting only the svg rect without node inside them...I know that I have done something wrong with data...
But I'm not able to figure them out..I'm just one month old to D3..please advice me on this....
If you run the code below you can see my mistake....
<!DOCTYPE html>
<html>
<head>
<script src="../D3/d3.min.js"></script>
</head>
<body>
<style>
</style>
<script type="text/javascript">
var width = 500,
height = 500;
var nodes = [
{ x: width / 3, y: height / 2 }
//{ x: 2 * width / 3, y: height / 1 },
//{ x: 3 * width / 3, y: height / 2 },
//{ x: 4 * width / 3, y: height / 2 }
];
var force = d3.layout.force()
.size([width, height])
.nodes(nodes)
var svgcontainer = d3.select("body")
.append("svg")
.attr("width", 1000)
.attr("height", 900);
var rectdata = [{ "x": 50, "y": 70, "width": 600, "height": 150,"rx":80,"ry":80,"fill":"skyblue"},
{ "x": 50, "y": 260, "width": 200, "height": 400, "rx": 80, "ry": 90, "fill": "palegreen" },
{ "x": 440, "y": 260, "width": 200, "height": 400, "rx": 80, "ry": 90, "fill": "orange" },
{ "x": 50, "y": 700, "width": 600, "height": 150, "rx": 80, "ry": 80, "fill": "brown" }];
var svgrect = svgcontainer.selectAll("rect").data(rectdata).enter().append("rect");
var node = svgcontainer.selectAll('.node')
.data(nodes)
.enter().append('rect')
.attr('class', 'node');
force.on('end', function () {
svgrect.attr("x", function (d, i) { return d.x; })
.attr("y", function (d, i) { return d.y; })
.attr("rx", function (d, i) { return d.rx; })
.attr("ry", function (d, i) { return d.ry; })
.attr("width", function (d, i) { return d.width; })
.attr("height", function (d, i) { return d.height; })
.attr("fill", function (d, i) { return d.fill; });
});
force.start();
</script>
</body>
</html>
You aren't giving the node any attributes. I take it you want a circle and not a rect :
var node = svgcontainer.selectAll('.node')
.data(nodes)
.enter().append('circle')
.attr('class', 'node')
.attr('x', function(d){ console.log(d); return d.x})
.attr('y', function(d){ return d.y})
.attr('r', 10)
.attr('transform', function(d){
return 'translate(' + d.x + ', ' + d.y + ')'
})
Notice the translate at the bottom. If you are using the force layout in D3, the tick function should take care of this, but it looks like you don't have one, so you have to insert it after you create the nodes.
If you didn't want circles and wanted rectangles then this should do :
var nodeRect = svgcontainer.selectAll('.nodeRect')
.data(nodes)
.enter().append('rect')
.attr('class', 'nodeRect')
.attr('x', function(d){ console.log(d); return d.x})
.attr('y', function(d){ return d.y})
.attr('width', 100)
.attr('height', 50)
.attr('transform', function(d){
return 'translate(' + d.x + ', ' + d.y + ')'
})
Working fiddle with both : https://jsfiddle.net/reko91/n13kqvw9/
var width = 500,
height = 500;
var nodes = [
{ x: width / 3, y: height / 2 }
//{ x: 2 * width / 3, y: height / 1 },
//{ x: 3 * width / 3, y: height / 2 },
//{ x: 4 * width / 3, y: height / 2 }
];
var force = d3.layout.force()
.size([width, height])
.nodes(nodes)
var svgcontainer = d3.select("body")
.append("svg")
.attr("width", 1000)
.attr("height", 900);
var rectdata = [{ "x": 50, "y": 70, "width": 600, "height": 150,"rx":80,"ry":80,"fill":"skyblue"},
{ "x": 50, "y": 260, "width": 200, "height": 400, "rx": 80, "ry": 90, "fill": "palegreen" },
{ "x": 440, "y": 260, "width": 200, "height": 400, "rx": 80, "ry": 90, "fill": "orange" },
{ "x": 50, "y": 700, "width": 600, "height": 150, "rx": 80, "ry": 80, "fill": "brown" }];
var svgrect = svgcontainer.selectAll("rect").data(rectdata).enter().append("rect");
var node = svgcontainer.selectAll('.node')
.data(nodes)
.enter().append('circle')
.attr('class', 'node')
.attr('x', function(d){ console.log(d); return d.x})
.attr('y', function(d){ return d.y})
.attr('r', 10)
.attr('transform', function(d){
return 'translate(' + d.x + ', ' + d.y + ')'
})
var nodeRect = svgcontainer.selectAll('.nodeRect')
.data(nodes)
.enter().append('rect')
.attr('class', 'nodeRect')
.attr('x', function(d){ console.log(d); return d.x})
.attr('y', function(d){ return d.y})
.attr('width', 100)
.attr('height', 50)
.attr('transform', function(d){
return 'translate(' + d.x + ', ' + d.y + ')'
})
force.on('end', function () {
svgrect.attr("x", function (d, i) { return d.x; })
.attr("y", function (d, i) { return d.y; })
.attr("rx", function (d, i) { return d.rx; })
.attr("ry", function (d, i) { return d.ry; })
.attr("width", function (d, i) { return d.width; })
.attr("height", function (d, i) { return d.height; })
.attr("fill", function (d, i) { return d.fill; });
});
force.start();
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
I have a graph for which I need a reference line everywhere the mouse-cursor is inside this graph. And this reference line will follow the mouse movements inside the graph.
But this doesn't seems to work fine. It works only on the axis and the ticks (.axis lines) of the axis. On debugging, I found that mouse event works fine when applied over SVG but not on the group, why so ?
Here is my code :
test.html
<html>
<head>
<script src="jquery.js">
</script>
<script src="d3.v2.js">
</script>
<script src="retest.js">
</script>
<style type="text/css">
.g_main {
cursor:pointer;
}
.axis path, .axis line {
stroke: #DBDBDB;
/*shape-rendering: crispEdges;
*/
}
.y g:first-child text {
display:none;
}
.y g:first-child line {
stroke: #989898 ;
stroke-width: 2.5px;
}
/*.x g:first-child line {
stroke: black ;
stroke-width: 2.5px;
}
*/
.y path {
stroke: #989898 ;
stroke-width: 2.5px;
}
</style>
</head>
<body>
<center>
<button id="reload" onclick="loadViz();">
load Graph
</button>
<div id="viz" class="viz">
</div>
</center>
<script>
loadViz();
</script>
</body>
</html>
retest.js
var series,
classifications,
minVal,
maxVal,
svgW = 600,
svgH = 600,
//w = 1200,
//h = 1200,
vizPadding = {
top: 120,
right: 30,
bottom: 120,
left: 50
},
yAxMin_PA = 0,
yAxMax_PA = 50,
xAxMin_PA = 2002,
xAxMax_PA = 2008,
areaStrokeColors = ['#FF6600', '#3366FF', '#B8860B', '#458B00', 'white'];
var loadViz = function () {
color = d3.scale.category10();
data = {
"lines": [{
"line": [{
"X": 2002,
"Y": 42
}, {
"X": 2003,
"Y": 45
},
{
"X": 2005,
"Y": 47
},
{
"X": 2007,
"Y": 41
}
]
}, {
"line": [{
"X": 2003,
"Y": 33
}, {
"X": 2005,
"Y": 38
}, {
"Y": 36,
"X": 2008
}
]
}, {
"line": [{
"X": 2004,
"Y": 13
}, {
"X": 2005,
"Y": 19
}, {
"X": 2008,
"Y": 21
}
]
}, {
"line": [{
"X": 2003,
"Y": 20
}, {
"X": 2005,
"Y": 27
}, {
"X": 2008,
"Y": 29
}
]
}
]
};
$("#viz").html("");
buildBase();
//setScales();
};
var buildBase = function () {
margin = {
top: 80,
right: 120,
bottom: 40,
left: 40
},
width = 960 - margin.left - margin.right,
height = 550 - margin.top - margin.bottom;
t2 = height + margin.top + margin.bottom;
x = d3.scale.linear()
.domain([xAxMin_PA, xAxMax_PA])
.range([0, width]);
y = d3.scale.linear()
.domain([yAxMin_PA, yAxMax_PA])
.range([height, 0]);
tickSizeToApplyX = 5;
tickSizeToApplyY = 10;
// Function to draw X-axis
xAxis = d3.svg.axis()
.scale(x)
.ticks(tickSizeToApplyX)
.tickSize(-height, 0, 0)
//.tickSize(10)
.orient("bottom")
.tickPadding(5);
// Function to draw Y-axis
yAxis = d3.svg.axis()
.scale(y)
.ticks(tickSizeToApplyY)
.tickSize(-width, 0, 0)
//.tickSize(0)
.orient("left")
.tickPadding(5);
// Define the line
var valueline = d3.svg.line()
.x(function (d) { /*console.log(d.X);*/
return x(d.X);
})
.y(function (d) { /*console.log(d.Y);*/
return y(d.Y);
});
// Define the line
var referline = d3.svg.line()
.x(function (dx) { /*console.log(d.X);*/
return dx;
})
.y(function (dy) { /*console.log(d.Y);*/
return dy;
});
// Append SVG into the html
var viz = d3.select("#viz")
.append("svg")
.attr("width", width + margin.left + margin.right + 10)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("class", "g_main")
.attr("transform", "translate(" + margin.left + "," + ((margin.top) - 30) + ")");
viz.on("mousemove", function () {
cx = d3.mouse(this)[0];
cy = d3.mouse(this)[1];
console.log("xx=>" + cx + "yy=>" + cy);
redrawline(cx, cy);
})
.on("mouseover", function () {
d3.selectAll('.line_over').style("display", "block");
})
.on("mouseout", function () {
d3.selectAll('.line_over').style("display", "none");
});
//console.log(this);
viz.append("line")
//d3.select("svg").append("line")
.attr("class", 'line_over')
.attr("x1", 0)
.attr("y1", 0)
.attr("x2", x(xAxMax_PA))
.attr("y2", 0)
.style("stroke", "gray")
.attr("stroke-dasharray", ("5,5"))
.style("stroke-width", "1.5")
.style("display", "none");
// Draw X-axis
viz.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Draw Y-axis
viz.append("g")
.attr("class", function (d, i) {
return "y axis"
})
.call(yAxis);
function redrawline(cx, cy) {
d3.selectAll('.line_over')
.attr("x1", 0)
.attr("y1", cy)
.attr("x2", x(xAxMax_PA))
.attr("y2", cy)
.style("display", "block");
}
};
The g element is just an empty container which cannot capture click events (see documentation for pointer-events property for details).
However, mouse events do bubble up to it. Hence, the effect you desire can be achieved by first making sure that the g receives all pointer events:
.g_main {
// ..
pointer-events: all;
}
And then appending an invisible rectangle to it as a place to hover over:
viz.on("mousemove", function () {
cx = d3.mouse(this)[0];
cy = d3.mouse(this)[1];
redrawline(cx, cy);
})
.on("mouseover", function () {
d3.selectAll('.line_over').style("display", "block");
})
.on("mouseout", function () {
d3.selectAll('.line_over').style("display", "none");
})
.append('rect')
.attr('class', 'click-capture')
.style('visibility', 'hidden')
.attr('x', 0)
.attr('y', 0)
.attr('width', width)
.attr('height', height);
Working example: http://jsfiddle.net/H3W3k/
As for why they work when applied to the svg element (from the docs):
Note that the ‘svg’ element is not a graphics element, and in a Conforming SVG Stand-Alone File a rootmost ‘svg’ element will never be the target of pointer events, though events can bubble to this element. If a pointer event does not result in a positive hit-test on a graphics element, then it should evoke any user-agent-specific window behavior, such as a presenting a context menu or controls to allow zooming and panning of an SVG document fragment.