我的要求是在谷歌地图上显示d3图表,其中包含多个节点和链接。我试过以下片段。但它根本不起作用。
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp"></script>
<script src="http://d3js.org/topojson.v1.min.js"></script>
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"> </script>
<style type="text/css">
html,
body,
#map {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
.stations,
.stations svg {
position: absolute;
margin: 0 auto;
}
.links {
position: absolute;
}
.stations svg {
width: 20px;
height: 20px;
margin: 0 auto;
z-index: 4;
}
.stations circle {
fill: blue;
stroke: none;
stroke-width: 1px;
}
</style>
</head>
<body>
<div id="map"></div>
<script type="text/javascript">
var map = new google.maps.Map(d3.select("#map").node(), {
zoom: 7,
center: new google.maps.LatLng(-22.1629209, -47.9922608),
mapTypeId: google.maps.MapTypeId.MAP
});
var dataset = JSON.parse('{"directed": true, "graph": [], "nodes": [{"lat": 44.391643516091975, "lng": 23.159677682342053}, {"lat": 44.315988, "lng": 23.818359, "id": "a:a::"}, {"lat": 44.29844994776969, "lng": 24.402314492323608, "id": "b:b"}, {"lat": 44.351118152120485, "lng": 23.341791630955303, "id": "a:c"}, {"lat": 44.889424527442685, "lng": 23.960970697645276, "id": "e:d"}, {"lat": 43.46084400349923, "lng": 23.975774627524885, "id": "d:6104:1"}, {"lat": 44.64680010013528, "lng": 23.20292820976948, "id": "c:6104:2"}, {"lat": 44.40446080879215, "lng": 23.953536570796015, "id": "b:6104:3"}, {"lat": 44.18593375168617, "lng": 23.769879901486856, "id": "af:6104:4"}, {"lat": 44.09051846584001, "lng": 24.14130778735744}, {"lat": 44.66376251969314, "lng": 23.77379490100736}, {"lat": 44.6240449587762, "lng": 24.08347249542858, "id": "aaaa3bab:3d:6f06"}, {"lat": 45.00138334367271, "lng": 24.092331272179138, "id": "aaaa3bab:3d:1306"}, {"lat": 44.55033831045195, "lng": 24.312914121854526, "id": "aaaa3bab:3c:ef05"}, {"lat": 44.74421652327631, "lng": 24.728457702115804, "id": "aaaa3bab:3c:ea03"}, {"lat": 43.79401723931746, "lng": 23.77846416630604, "id": "aaaa3bab:3d:7200"}, {"lat": 43.67351687345779, "lng": 23.00140978137842, "id": "aaaa3bab:3d:5d07"}, {"lat": 43.87692500855015, "lng": 24.28543591328852, "id": "aaaa3bab:3d:550b"}, {"lat": 44.28189405244278, "lng": 23.972410391551893, "id": "aaaa3bab:3d:2706"}, {"lat": 43.94916218711252, "lng": 23.9733463072956}, {"lat": 44.61479884874806, "lng": 24.27581898293906}, {"lat": 44.92223011339065, "lng": 23.505887513934034}, {"lat": 44.20117807597118, "lng": 23.70555450810448, "id": "aaaa3bab:3d:2603"}, {"lat": 43.547714841247966, "lng": 24.56985383484244, "id": "aaaa3bab:3d:2601"}, {"lat": 43.92116991202797, "lng": 22.82805535024416, "id": "aaaa3bab:3d:5803"}, {"lat": 44.56587414638437, "lng": 22.970799697228976, "id": "aaaa3bab:3d:7406"}, {"lat": 44.10230727065641, "lng": 23.701204095342597, "id": "aaaa3bab:3d:7407"}, {"lat": 45.25416535851712, "lng": 24.434312172789625, "id": "aaaa3bab:3d:7404"}, {"lat": 44.91647619491961, "lng": 23.678252259828515, "id": "aaaa3bab:3d:7405"}, {"lat": 45.03473433359779, "lng": 24.07596179597473}, {"lat": 45.16855171992733, "lng": 23.435986773864467}, {"lat": 44.553669079256146, "lng": 23.05123326220677}, {"lat": 43.32871087231798, "lng": 23.325707869122013, "id": "aaaa3bab:3d:5308"}, {"lat": 43.40444516345915, "lng": 23.485798521785892, "id": "aaaa3bab:3c:f107"}, {"lat": 43.9435337313432, "lng": 22.968285824722354}, {"lat": 44.74549949495889, "lng": 22.832034225254052}, {"lat": 44.34901730307382, "lng": 24.33506529636527}, {"lat": 43.53125851464172, "lng": 24.763229039168245, "id": "aaaa3bab:3d:6602"}, {"lat": 44.155575603194634, "lng": 23.250881840942217, "id": "aaaa3bab:3c:e300"}], "links": [ {"source": 1, "target": 25}, {"source": 1, "target": 26}, {"source": 1, "target": 27}, {"source": 1, "target": 28}, {"source": 1, "target": 29}, {"source": 1, "target": 30}, {"source": 1, "target": 31}, {"source": 1, "target": 34}, {"source": 1, "target": 35}, {"source": 1, "target": 36}, {"source": 3, "target": 5}, {"source": 3, "target": 6}, {"source": 4, "target": 15}, {"source": 4, "target": 9}, {"source": 5, "target": 19}, {"source": 5, "target": 23}, {"source": 6, "target": 18}, {"source": 6, "target": 20}, {"source": 7, "target": 22}, {"source": 8, "target": 37}, {"source": 8, "target": 3}, {"source": 10, "target": 11}, {"source": 17, "target": 21}, {"source": 18, "target": 13}, {"source": 18, "target": 14}, {"source": 19, "target": 33}, {"source": 19, "target": 38}, {"source": 23, "target": 2}, {"source": 25, "target": 10}, {"source": 28, "target": 4}, {"source": 28, "target": 17}, {"source": 29, "target": 32}, {"source": 32, "target": 25}, {"source": 34, "target": 24}, {"source": 35, "target": 8}, {"source": 35, "target": 16}, {"source": 37, "target": 7}, {"source": 37, "target": 12}], "multigraph": false}');
d3.json(dataset, function (json) {
var overlay = new google.maps.OverlayView();
// Add the container when the overlay is added to the map.
overlay.onAdd = function () {
var layer = d3.select(this.getPanes().overlayLayer)
.append("div")
.attr("height", "100%")
.attr("width", "100%")
.attr("class", "stations");
overlay.draw = function () {
var radius = 5;
var projection = this.getProjection(),
padding = 10;
var node_coord = {};
var marker = layer.selectAll("svg")
.data(d3.entries(dataset))
.each(transform) // update existing markers
.enter().append("svg:svg")
.each(transform)
.attr("class", "marker");
marker.append("svg:circle")
.attr("r", radius)
.attr("cx", padding)
.attr("cy", padding);
var markerLink = layer.selectAll(".links")
.data(d3.entries(dataset))
.each(pathTransform) // update existing markers
.enter().append("svg:svg")
.attr("class", "links")
.each(pathTransform);
function pathTransform(d) {
var t, b, l, r, w, h, currentSvg;
var d1 = new Object();
var d2 = new Object();
$(this).empty();
d1.x = node_coord[d.source + "," + 0]
d1.y = node_coord[d.source + "," + 1]
d2.x = node_coord[d.target + "," + 0]
d2.y = node_coord[d.target + "," + 1]
if (d1.y < d2.y) {
t = d1.y;
b = d2.y;
} else {
t = d2.y;
b = d1.y;
}
if (d1.x < d2.x) {
l = d1.x;
r = d2.x;
} else {
l = d2.x;
r = d1.x;
}
currentSvg = d3.select(this)
.style("z-index", "1")
.style("left", (l + 2 * radius) + "px")
.style("top", (t + 2 * radius) + "px")
.style("width", (r - l + 2 * radius) + "px")
.style("height", (b - t + 2 * radius) + "px");
var x1 = 0, y1 = 0, x2 = 0, y2 = 0;
if ((d1.y < d2.y) && (d1.x < d2.x)) {
x2 = r - l;
y2 = b - t;
} else if ((d1.x > d2.x) && (d1.y > d2.y)) {
x2 = r - l;
y2 = b - t;
} else if ((d1.y < d2.y) && (d1.x > d2.x)) {
x1 = r - l;
y2 = b - t;
} else if ((d1.x < d2.x) && (d1.y > d2.y)) {
x1 = r - l;
y2 = b - t;
}
currentSvg.append("svg:line")
.style("stroke-width", 2)
.style("stroke", "black")
.attr("x1", x1)
.attr("y1", y1)
.attr("x2", x2)
.attr("y2", y2);
return currentSvg;
}
function transform(d, i) {
d = new google.maps.LatLng(d.lat, d.lng);
d = projection.fromLatLngToDivPixel(d);
node_coord[i + "," + 0] = d.x;
node_coord[i + "," + 1] = d.y;
return d3.select(this)
.style("left", (d.x) + "px")
.style("top", (d.y) + "px");
}
layer.append("div")
.attr("class", "stations.line");
};
};
// Bind our overlay to the map…
overlay.setMap(map);
});
当我尝试实现仅绘制节点的example时,它运行良好。但我需要使用链接对象中的源和目标详细信息在这些节点之间创建链接。
答案 0 :(得分:2)
您的代码中存在错误。绑定到链接和节点的数据集不正确。您必须将节点数组设置为节点元素和链接元素的链接数组。
而不是代码,
var marker = layer.selectAll("svg")
.data(d3.entries(dataset)) //Replace this line
.each(transform)
.enter().append("svg:svg")
.each(transform)
.attr("class", "marker");
marker.append("svg:circle")
.attr("r", radius)
.attr("cx", padding)
.attr("cy", padding);
var markerLink = layer.selectAll(".links")
.data(d3.entries(dataset)) //Replace this line
.each(pathTransform)
.enter().append("svg:svg")
.attr("class", "links")
.each(pathTransform);
使用以下代码。
var marker = layer.selectAll("svg")
.data(dataset.nodes)
.each(transform) // update existing markers
.enter().append("svg:svg")
.each(transform)
.attr("class", "marker");
marker.append("svg:circle")
.attr("r", radius)
.attr("cx", padding)
.attr("cy", padding);
var markerLink = layer.selectAll(".links")
.data(dataset.links)
.each(pathTransform) // update existing markers
.enter().append("svg:svg")
.attr("class", "links")
.each(pathTransform);
工作代码段
var map = new google.maps.Map(d3.select("#map").node(), {
zoom: 7,
center: new google.maps.LatLng(-22.1629209, -47.9922608),
mapTypeId: google.maps.MapTypeId.MAP
});
var dataset = JSON.parse('{"directed": true, "graph": [], "nodes": [{"lat": 44.391643516091975, "lng": 23.159677682342053}, {"lat": 44.315988, "lng": 23.818359, "id": "a:a::"}, {"lat": 44.29844994776969, "lng": 24.402314492323608, "id": "b:b"}, {"lat": 44.351118152120485, "lng": 23.341791630955303, "id": "a:c"}, {"lat": 44.889424527442685, "lng": 23.960970697645276, "id": "e:d"}, {"lat": 43.46084400349923, "lng": 23.975774627524885, "id": "d:6104:1"}, {"lat": 44.64680010013528, "lng": 23.20292820976948, "id": "c:6104:2"}, {"lat": 44.40446080879215, "lng": 23.953536570796015, "id": "b:6104:3"}, {"lat": 44.18593375168617, "lng": 23.769879901486856, "id": "af:6104:4"}, {"lat": 44.09051846584001, "lng": 24.14130778735744}, {"lat": 44.66376251969314, "lng": 23.77379490100736}, {"lat": 44.6240449587762, "lng": 24.08347249542858, "id": "aaaa3bab:3d:6f06"}, {"lat": 45.00138334367271, "lng": 24.092331272179138, "id": "aaaa3bab:3d:1306"}, {"lat": 44.55033831045195, "lng": 24.312914121854526, "id": "aaaa3bab:3c:ef05"}, {"lat": 44.74421652327631, "lng": 24.728457702115804, "id": "aaaa3bab:3c:ea03"}, {"lat": 43.79401723931746, "lng": 23.77846416630604, "id": "aaaa3bab:3d:7200"}, {"lat": 43.67351687345779, "lng": 23.00140978137842, "id": "aaaa3bab:3d:5d07"}, {"lat": 43.87692500855015, "lng": 24.28543591328852, "id": "aaaa3bab:3d:550b"}, {"lat": 44.28189405244278, "lng": 23.972410391551893, "id": "aaaa3bab:3d:2706"}, {"lat": 43.94916218711252, "lng": 23.9733463072956}, {"lat": 44.61479884874806, "lng": 24.27581898293906}, {"lat": 44.92223011339065, "lng": 23.505887513934034}, {"lat": 44.20117807597118, "lng": 23.70555450810448, "id": "aaaa3bab:3d:2603"}, {"lat": 43.547714841247966, "lng": 24.56985383484244, "id": "aaaa3bab:3d:2601"}, {"lat": 43.92116991202797, "lng": 22.82805535024416, "id": "aaaa3bab:3d:5803"}, {"lat": 44.56587414638437, "lng": 22.970799697228976, "id": "aaaa3bab:3d:7406"}, {"lat": 44.10230727065641, "lng": 23.701204095342597, "id": "aaaa3bab:3d:7407"}, {"lat": 45.25416535851712, "lng": 24.434312172789625, "id": "aaaa3bab:3d:7404"}, {"lat": 44.91647619491961, "lng": 23.678252259828515, "id": "aaaa3bab:3d:7405"}, {"lat": 45.03473433359779, "lng": 24.07596179597473}, {"lat": 45.16855171992733, "lng": 23.435986773864467}, {"lat": 44.553669079256146, "lng": 23.05123326220677}, {"lat": 43.32871087231798, "lng": 23.325707869122013, "id": "aaaa3bab:3d:5308"}, {"lat": 43.40444516345915, "lng": 23.485798521785892, "id": "aaaa3bab:3c:f107"}, {"lat": 43.9435337313432, "lng": 22.968285824722354}, {"lat": 44.74549949495889, "lng": 22.832034225254052}, {"lat": 44.34901730307382, "lng": 24.33506529636527}, {"lat": 43.53125851464172, "lng": 24.763229039168245, "id": "aaaa3bab:3d:6602"}, {"lat": 44.155575603194634, "lng": 23.250881840942217, "id": "aaaa3bab:3c:e300"}], "links": [ {"source": 1, "target": 25}, {"source": 1, "target": 26}, {"source": 1, "target": 27}, {"source": 1, "target": 28}, {"source": 1, "target": 29}, {"source": 1, "target": 30}, {"source": 1, "target": 31}, {"source": 1, "target": 34}, {"source": 1, "target": 35}, {"source": 1, "target": 36}, {"source": 3, "target": 5}, {"source": 3, "target": 6}, {"source": 4, "target": 15}, {"source": 4, "target": 9}, {"source": 5, "target": 19}, {"source": 5, "target": 23}, {"source": 6, "target": 18}, {"source": 6, "target": 20}, {"source": 7, "target": 22}, {"source": 8, "target": 37}, {"source": 8, "target": 3}, {"source": 10, "target": 11}, {"source": 17, "target": 21}, {"source": 18, "target": 13}, {"source": 18, "target": 14}, {"source": 19, "target": 33}, {"source": 19, "target": 38}, {"source": 23, "target": 2}, {"source": 25, "target": 10}, {"source": 28, "target": 4}, {"source": 28, "target": 17}, {"source": 29, "target": 32}, {"source": 32, "target": 25}, {"source": 34, "target": 24}, {"source": 35, "target": 8}, {"source": 35, "target": 16}, {"source": 37, "target": 7}, {"source": 37, "target": 12}], "multigraph": false}');
d3.json(dataset, function(json) {
var overlay = new google.maps.OverlayView();
// Add the container when the overlay is added to the map.
overlay.onAdd = function() {
var layer = d3.select(this.getPanes().overlayLayer)
.append("div")
.attr("height", "100%")
.attr("width", "100%")
.attr("class", "stations");
overlay.draw = function() {
var radius = 5;
var projection = this.getProjection(),
padding = 10;
var node_coord = {};
var marker = layer.selectAll("svg")
.data(dataset.nodes)
.each(transform) // update existing markers
.enter().append("svg:svg")
.each(transform)
.attr("class", "marker");
marker.append("svg:circle")
.attr("r", radius)
.attr("cx", padding)
.attr("cy", padding);
var markerLink = layer.selectAll(".links")
.data(dataset.links)
.each(pathTransform) // update existing markers
.enter().append("svg:svg")
.attr("class", "links")
.each(pathTransform);
function pathTransform(d) {
var t, b, l, r, w, h, currentSvg;
var d1 = new Object();
var d2 = new Object();
$(this).empty();
d1.x = node_coord[d.source + "," + 0]
d1.y = node_coord[d.source + "," + 1]
d2.x = node_coord[d.target + "," + 0]
d2.y = node_coord[d.target + "," + 1]
if (d1.y < d2.y) {
t = d1.y;
b = d2.y;
} else {
t = d2.y;
b = d1.y;
}
if (d1.x < d2.x) {
l = d1.x;
r = d2.x;
} else {
l = d2.x;
r = d1.x;
}
currentSvg = d3.select(this)
.style("z-index", "1")
.style("left", (l + 2 * radius) + "px")
.style("top", (t + 2 * radius) + "px")
.style("width", (r - l + 2 * radius) + "px")
.style("height", (b - t + 2 * radius) + "px");
var x1 = 0,
y1 = 0,
x2 = 0,
y2 = 0;
if ((d1.y < d2.y) && (d1.x < d2.x)) {
x2 = r - l;
y2 = b - t;
} else if ((d1.x > d2.x) && (d1.y > d2.y)) {
x2 = r - l;
y2 = b - t;
} else if ((d1.y < d2.y) && (d1.x > d2.x)) {
x1 = r - l;
y2 = b - t;
} else if ((d1.x < d2.x) && (d1.y > d2.y)) {
x1 = r - l;
y2 = b - t;
}
currentSvg.append("svg:line")
.style("stroke-width", 2)
.style("stroke", "black")
.attr("x1", x1)
.attr("y1", y1)
.attr("x2", x2)
.attr("y2", y2);
return currentSvg;
}
function transform(d, i) {
console.log("here");
d = new google.maps.LatLng(d.lat, d.lng);
d = projection.fromLatLngToDivPixel(d);
node_coord[i + "," + 0] = d.x;
node_coord[i + "," + 1] = d.y;
return d3.select(this)
.style("left", (d.x) + "px")
.style("top", (d.y) + "px");
}
layer.append("div")
.attr("class", "stations.line");
};
};
// Bind our overlay to the map…
overlay.setMap(map);
});
html,
body,
#map {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
.stations,
.stations svg {
position: absolute;
margin: 0 auto;
}
.links {
position: absolute;
}
.stations svg {
width: 20px;
height: 20px;
margin: 0 auto;
z-index: 4;
}
.stations circle {
fill: blue;
stroke: none;
stroke-width: 1px;
}
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp"></script>
<script src="http://d3js.org/topojson.v1.min.js"></script>
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js">
</script>
</head>
<body>
<div id="map"></div>
答案 1 :(得分:0)
不确定是否可以单独使用d3绘制svg行。
我正在使用google google.maps.Polyline 生成行
这样的事情:
var flightPlanCoordinates = [
{lat: 36.98, lng: -120.12},//start point of line
{lat: 37.37, lng: -121.92},//end point of line1
{lat: 37.28, lng: -120.50},//end point of line2
{lat:37.70, lng:-121.82}//end point of line3
];
var flightPath = new google.maps.Polyline({
path: flightPlanCoordinates,
geodesic: true,
strokeColor: '#FF0000',
strokeOpacity: 1.0,
strokeWeight: 2
});
flightPath.setMap(map);
工作代码here
希望这有帮助!