我在一个 div 中有一个基本的 Leaflet Map,在另一个 div 中有一个 d3-collapsible 树(基于此 Fiddle ):
Map(右div)加载GeoJSON,D3树(左div)加载相应的分层JSon数据。现在,当我伸展树(Splay Tree)中的节点时, map 元素也会移动(参见红色箭头)。
我尝试重命名所有类名、变量和 ID,但问题仍然存在。
<强> Here是一个带有数据和代码的codepen。我认为它可能与使用分组SVG元素(全部在一个<g>
?)作为节点/功能的传单和D3有关。我调整了我的树以使用 var svgTree =
没有成功..
如果您无法为我的问题提供具体的解决方案,我也很乐意提供演示如何相邻使用 D3 和 Leaflet 的引用或示例。
[编辑]问题已解决:
我尝试从 Rob Schmuecker 的 Block 7880033 中合并的平移功能需要一个树 svg ( svgTree
) 和一个容器 svg ( svgGroup
),它包含所有 <g>
-元素。最后centerNode函数需要调用svgTree.select("g").transition()
(而不是 d3.select("g")
或 svgGroup.select("g")
)
这是更新后的代码。 Leaflet map 的代码在Body中:
<body>
<div id="map"></div>
<div id="d3tree"></div>
<!--Leaflet Map JS-->
<script>
var CartoDB_Positron = L.tileLayer('http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png', {
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> © <a href="http://cartodb.com/attributions">CartoDB</a>',
subdomains: 'abcd',
maxZoom: 19
});
var map = new L.Map("map", {
center: [37.8, -96.9],
zoom: 4
})
.addLayer(CartoDB_Positron);
var legend = L.control({position: 'topright'});
legend.onAdd = function (map) {
var div = L.DomUtil.create('div', 'info legend');
div.innerHTML = '<select><option>root</option><option>1</option><option>2</option></select>';
div.firstChild.onmousedown = div.firstChild.ondblclick = L.DomEvent.stopPropagation;
return div;
};
legend.addTo(map);
//set empty geojson feature layer with pre-defined layout & oneachfeature function handlers
var geojsonLayer = L.geoJSON(false, {
style: function(feature) {
return {
stroke: true,
weight: 1,
color: '#4682B4',
weight: 2,
fillOpacity: 0.6
};
},
onEachFeature: onEachFeature
}).addTo(map);
// add GeoJSON layer to the map once the file is loaded
geojsonLayer.addData(data);
map.fitBounds(geojsonLayer.getBounds());
//OnClick function for features
function onEachFeature(feature, layer) {
popupOptions = {
maxWidth: 200
};
layer.bindPopup("<b>Cluster HFID:</b> " + feature.properties.H_FID +
"<br><b>Reference Tag: goldengatebridge</b>" +
"<br><br>This photo cluster consists of " + feature.properties.PCount+ " photos from " + feature.properties.UCount + " Flickr users.", popupOptions);
//Auto zoom to feature
layer.on({
click: zoomToFeature
});
}
//Zoom to feature function
function zoomToFeature(e) {
map.fitBounds(e.target.getBounds());
}
//Change GeoJSON based on click/selection event
function clean_map() {
map.eachLayer(function (layer) {
if (layer instanceof L.GeoJSON)
{
map.removeLayer(layer);
}
//console.log(layer);
});
}
</script>
</body>
D3-Tree 的代码已加载到 header 中:
//Script initialized on load to fit to browser size (root center)
//TODO: add root center update function upon window resize
//D3 Tree JS
//zoom/pan to node http://bl.ocks.org/robschmuecker/7880033
window.onload = function () {
var margin = {
top: 20,
right: 120,
bottom: 20,
left: 120
},
width = document.getElementById("d3tree").offsetWidth,
height = document.getElementById("d3tree").offsetHeight;
// size of the diagram
var viewerWidth = width
var viewerHeight = height
var i = 0,
duration = 750,
nodeRectW = 60,
nodeRectH = 30;
//Set Fixed Node Size
var tree = d3.layout.tree().nodeSize([nodeRectW + 10, nodeRectH + 10]);
var diagonal = d3.svg.diagonal()
.projection(function (d) {
return [d.x + nodeRectW / 2, d.y + nodeRectH / 2];
});
// Define the redraw function for the whole (zoomable) tree
function redraw() {
svgGroup.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
// define the zoomListener which calls the zoom function on the "zoom" event constrained within the scaleExtents
// this updates the center of the tree, needed for auto panning
var zoomListener = d3.behavior.zoom().scaleExtent([0.1, 3]).on("zoom", redraw);
// Append a group which holds all nodes and which the zoomListener can act upon
var svgTree = d3.select("#d3tree").append("svg")
.attr("width", viewerWidth)
.attr("height", viewerHeight)
.call(zoomListener);
// Add tooltip div
var tooltipDiv = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 1e-6);
//Set position of treeRoot
//root = treeData; -->not necessary because of var treeRoot in subfile
treeRoot.x0 = 0;
treeRoot.y0 = height / 2;
//Collapse function
function collapse(d) {
if (d.children) {
d._children = d.children;
d._children.forEach(collapse);
d.children = null;
}
}
// Append a group which holds all nodes and which the zoom Listener can act upon.
var svgGroup = svgTree.append("g");
// Collapse all nodes upon start
treeRoot.children.forEach(collapse);
update_tree(treeRoot);
centerNode(treeRoot);
//Update tree on event
function update_tree(source) {
// Compute the new tree layout.
var nodes = tree.nodes(treeRoot).reverse(),
links = tree.links(nodes);
// Normalize for fixed-depth (depth = vertival distance of nodes)
nodes.forEach(function (d) {
d.y = d.depth * 110;
});
// Update the nodes
var node = svgGroup.selectAll("g.node")
.data(nodes, function (d) {
return d.id || (d.id = ++i);
});
// Enter any new nodes at the parent's previous position.
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.attr("transform", function (d) {
return "translate(" + source.x0 + "," + source.y0 + ")";
})
.on("click", click_tree)
.on("mouseover", function (d) {
var g = d3.select(this) // The node
// The class is used to remove the additional text later
var info = g.append('text')
.classed('info', true)
.attr('x', 20)
.attr('y', -20)
.text(function (d) {
return d.id; //Feature ID
});
})
.on("mouseout", function () {
// Remove the info text on mouse out.
tooltipDiv.transition()
.duration(300)
.style("opacity", 1e-6)
d3.select(this).select('text.info').remove();
});
nodeEnter.append("rect")
.attr("width", nodeRectW)
.attr("height", nodeRectH)
.attr("stroke", "black")
.attr("stroke-width", 0.25)
.style("fill", function (d) {
return d._children ? "lightsteelblue" : "#fff";
});
nodeEnter.append("text")
.attr("x", nodeRectW / 2)
.attr("y", nodeRectH / 2)
.attr("dy", ".35em")
.attr("text-anchor", "middle")
.text(function (d) {
return d.name;
});
// Transition nodes to their new position.
var nodeUpdate = node.transition()
.duration(duration)
.attr("transform", function (d) {
return "translate(" + d.x + "," + d.y + ")";
});
nodeUpdate.select("rect")
.attr("width", nodeRectW)
.attr("height", nodeRectH)
.attr("stroke", "black")
.attr("stroke-width", 0.25)
.style("fill", function (d) {
return d._children ? "lightsteelblue" : "#fff";
});
nodeUpdate.select("text")
.style("fill-opacity", 1);
// Transition exiting nodes to the parent's new position.
var nodeExit = node.exit().transition()
.duration(duration)
.attr("transform", function (d) {
return "translate(" + source.x + "," + source.y + ")";
})
.remove();
nodeExit.select("rect")
.attr("width", nodeRectW)
.attr("height", nodeRectH)
.attr("stroke", "black")
.attr("stroke-width", 1);
nodeExit.select("text");
// Update the links
var link = svgGroup.selectAll("path.link")
.data(links, function (d) {
return d.target.id;
});
// Enter any new links at the parent's previous position.
link.enter().insert("path", "g")
.attr("class", "link")
.attr("x", nodeRectW / 2)
.attr("y", nodeRectH / 2)
.attr("d", function (d) {
var o = {
x: source.x0,
y: source.y0
};
return diagonal({
source: o,
target: o
});
});
// Transition links to their new position.
link.transition()
.duration(duration)
.attr("d", diagonal);
// Transition exiting nodes to the parent's new position.
link.exit().transition()
.duration(duration)
.attr("d", function (d) {
var o = {
x: source.x,
y: source.y
};
return diagonal({
source: o,
target: o
});
})
.remove();
// Stash the old positions for transition.
nodes.forEach(function (d) {
d.x0 = d.x;
d.y0 = d.y;
});
}
// Toggle children on click.
function click_tree(d) {
if (d.children) {
d._children = d.children;
d.children = null;
} else {
d.children = d._children;
d._children = null;
}
update_tree(d);
centerNode(d); //PanToNode
}
// Function to center node when clicked so node doesn't get lost when collapsing/moving with large amount of children.
function centerNode(source) {
//find the current zoom level by calling:
scale = zoomListener.scale();
x = -source.x0;
y = -source.y0;
x = x * scale + width / 2;
y = y * scale + height / 2;
svgTree.select("g").transition()
.duration(duration)
.attr("transform", "translate(" + x + "," + y + ")scale(" + scale + ")");
zoomListener.scale(scale);
zoomListener.translate([x, y]);
}
}
最佳答案
在您的 centerNode
函数中,而不是:
d3.select('g').transition()
应该是:
svgTree.select('g').transition()
这是您更新的 CodePen:http://codepen.io/anon/pen/NjRdGB?editors=0010
关于javascript - D3 树和传单 map 意外干扰,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43586326/