私は(このFiddleに基づいて)別のdiv内の1つのdiv要素とD3-折りたたみ可能なツリーの基本的なリーフレット地図を持っています。 D3ツリーやリーフレット地図意図しないIntereference
地図(右divが)にGeoJSONをロードD3ツリー(左のdiv)は、対応する階層JSonデータをロードします。ツリー内のノードを展開すると、マップ要素も移動します(赤い矢印を参照)。
すべてのクラス名、変数、IDの名前を変更しようとしましたが、問題は解決しません。 Hereは、データが&コードのcodepenです。ノード/機能のグループ化されたSVG要素(1つには<g>
?)を使用してリーフレットとD3の両方と関係があると思います。 を使用してツリーを調整しました。
私の問題に特定の解決策を提示できない場合は、お互いに隣り合わせにD3とリーフレットを使用する方法を示すリファレンスまたは例もあります。
[編集]問題解決:
私はすべての<g>
を保持しているロブSchmueckerのブロック7880033必要な木SVG(svgTree
)の両方とコンテナSVG(svgGroup
)から組み込むことを試みたパン機能要素。最後に、centerNode機能がsvgTree.select("g").transition()
(とないd3.select("g")
またはsvgGroup.select("g")
)ここで
が更新されたコードで呼び出す必要があります。リーフレットマップのコードは本体にあります
<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-ツリーのコードをヘッダーにロードされます。
//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]);
}
}
うわー、素晴らしい - 私はこれを見つけませんでした。ちょうど理解しようとしています:d3.select( 'g')は、リーフレットSVGを含む「すべてのSVG要素を選択」を意味しますか? –
Alex
主な違いはこれです: 'svgTree.select'は' svgTree'選択内の要素だけを選択します。一方、 'd3.select'は* anywhere *の要素を選択します。 –
Gerardoさん、ありがとうございました。上のコードにはまだいくつかのバグがありますが、それはまったく異なるものです。あなたの答えは大きな助けになった! – Alex