xxxxxxxxxx
<meta charset="utf-8">
<style>
.segment {
fill: none;
stroke: #000;
stroke-width: 1.5px;
stroke-linecap: round;
}
.segment--hover {
stroke: red;
stroke-width: 5px;
}
.overlay {
fill: none;
pointer-events: all;
}
.extent {
fill: none;
stroke: #aaa;
shape-rendering: crispEdges;
}
</style>
<svg width="960" height="500"></svg>
<script src="//d3js.org/d3.v3.min.js"></script>
<script src="//d3js.org/topojson.v1.min.js"></script>
<script src="tree.js"></script>
<script>
var topology = {
arcs: [
d3.range(40, 921, 30).map(function(x) {
return [x, (Math.sin(x / 200)) * 200 + 250];
})
]
};
var svg = d3.select("svg")
.on("mousemove", mousemoved);
svg.append("rect")
.attr("class", "overlay")
.attr("width", "100%")
.attr("height", "100%");
var path = d3.geo.path()
.projection(null);
var segment = svg.append("g").selectAll(".segment")
.data(d3.merge(topology.arcs.map(function(arc) { return d3.pairs(arc); })))
.enter().append("path")
.each(function(d) { d[0].node = this; }) // TODO better two-way binding
.attr("class", "segment")
.attr("d", function(d) { return path({type: "LineString", coordinates: d}); });
var root = tree(topology);
function mousemoved() {
var leaf = root.nearest(d3.mouse(this));
d3.select(".segment--hover")
.classed("segment--hover", false);
d3.select(leaf.coordinates[0].node)
.classed("segment--hover", true)
.each(function() { this.parentNode.appendChild(this); });
}
(function visit(node) {
svg.insert("path", "*")
.attr("class", "extent")
.attr("d", path({type: "Polygon", coordinates: [[
[Math.round(node.extent[0][0]), Math.round(node.extent[0][1])],
[Math.round(node.extent[1][0]), Math.round(node.extent[0][1])],
[Math.round(node.extent[1][0]), Math.round(node.extent[1][1])],
[Math.round(node.extent[0][0]), Math.round(node.extent[1][1])],
[Math.round(node.extent[0][0]), Math.round(node.extent[0][1])]
]]})).node();
if (node.children) node.children.forEach(visit);
})(root);
</script>
https://d3js.org/d3.v3.min.js
https://d3js.org/topojson.v1.min.js