我正在玩mbostock's example of using d3.js with google maps,尝试使用我自己数据的二维数组进行调整。
我的数据是一个对象数组,每个对象都有一个时间戳和一个GeoCoordinates数组Coordinates
。
[{"TimeStamp":"2014-06-18T22:18:07+04:30","Coordinates":[{"Latitude":40.416775,"Longitude":-3.70379},{"Latitude":40.415793,"Longitude":-3.707424},{"Latitude":40.414142,"Longitude":-3.707982}]}
,{"TimeStamp":"2014-06-18T22:23:07+04:30","Coordinates":[{"Latitude":40.411365,"Longitude":-3.708712},{"Latitude":40.411986,"Longitude":-3.705021},{"Latitude":40.406774,"Longitude":-3.711716}]}
,{"TimeStamp":"2014-06-18T22:28:07+04:30","Coordinates":[{"Latitude":40.401365,"Longitude":-3.720449},{"Latitude":40.388455,"Longitude":-3.731843},{"Latitude":40.383568,"Longitude":-3.738881}]}]
我无法找到迭代所有Coordinate对象的方法,因此为第一级数组的每个元素添加了for循环:
// Add the container when the overlay is added to the map.
overlay.onAdd = function() {
var layer = d3.select(this.getPanes().overlayLayer).append("div")
.attr("class", "stations");
// Draw each marker as a separate SVG element.
// We could use a single SVG, but what size would it have?
overlay.draw = function() {
var projection = this.getProjection(),
padding = 10;
for( var i = 0; i < data.length; i++)
{
var marker = layer.selectAll("svg")
.data(data[i].Coordinates)
.each(transform) // update existing markers
.enter()
.append("svg:svg")
.each(transform)
.attr("class", "marker");
// Add a circle.
marker.append("svg:circle")
.attr("r", 4.5)
.attr("cx", padding)
.attr("cy", padding);
// Add a label.
marker.append("svg:text")
.attr("x", padding + 7)
.attr("y", padding)
.attr("dy", ".31em")
.text(function(d, i){
return i;
});
}
function transform(d) {
d = new google.maps.LatLng(d.Latitude, d.Longitude);
d = projection.fromLatLngToDivPixel(d);
return d3.select(this)
.style("left", (d.x - padding) + "px")
.style("top", (d.y - padding) + "px");
}
};
};
但是,d3会在每次迭代中覆盖标记svg元素,在这种情况下只显示3个标记而不是9个。
为什么?
答案 0 :(得分:1)
要直接回答这个问题,d3会覆盖每个循环上的SVG元素,因为它们是按照它们在数组中的位置编制索引的。您必须提供id函数,这是data()
函数的第二个参数。代码要遵循。
嵌套选择不适合这种情况,因为您不想要嵌套的html,原因在于链接代码中指出的原因:&#34;我们可以使用单个SVG,但是大小会是多少它有?&#34;。所以我们确实想在某个时候使用for循环。
另请注意,只有“进入阶段”才会进入&#39;这需要进入for循环,但如果你把渲染放在那里也不应该有很大的不同。
var map = new google.maps.Map(d3.select("#map").node(), {
zoom: 8,
center: new google.maps.LatLng(40.411365, -3.708712),
mapTypeId: google.maps.MapTypeId.ROADMAP
});
// Load the station data. When the data comes back, create an overlay.
d3.json("soQuest.json", function(data) {
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("class", "stations");
// Draw each marker as a separate SVG element.
// We could use a single SVG, but what size would it have?
overlay.draw = function() {
var projection = this.getProjection(),
padding = 10,
marker;
for (i = 0; i < data.length; i++) {
marker = layer.selectAll("svg")
.data(data[i].Coordinates, function(d, index){
return data[i].TimeStamp + index + d.Latitude + d.Longitude;
})
.enter().append("svg");
}
marker = layer.selectAll("svg")
.each(transform) // update existing markers
.attr("class", "marker");
// Add a circle.
marker.append("svg:circle")
.attr("r", 4.5)
.attr("cx", padding)
.attr("cy", padding);
// Add a label.
marker.append("svg:text")
.attr("x", padding + 7)
.attr("y", padding)
.attr("dy", ".31em")
.text(function(d) {
return "MARKER"; //d.key;
});
function transform(d) {
d = new google.maps.LatLng(d.Latitude, d.Longitude);
d = projection.fromLatLngToDivPixel(d);
return d3.select(this)
.style("left", (d.x - padding) + "px")
.style("top", (d.y - padding) + "px");
}
};
};
// Bind our overlay to the map…
overlay.setMap(map);
});
答案 1 :(得分:0)
我建议你尝试在for循环之外定义变量marker
。如果能解决问题,请告诉我。 :)
答案 2 :(得分:0)
可能最简单的方法就是将阵列弄平,
var flat_data = [];
for (var i=0; i<data.length; i++){
for (var j=0; j<data[i].length; j++){
flat_data.push(data[i][j])
}
}
然后跳过你的for循环,然后执行
var layer = d3.select(this.getPanes().overlayLayer).append("div")
.attr("class", "stations");
// Draw each marker as a separate SVG element.
// We could use a single SVG, but what size would it have?
overlay.draw = function() {
var projection = this.getProjection(),
padding = 10;
var marker = layer.selectAll("svg")
.data(flat_data)
.each(transform) // update existing markers
.enter()
.append("svg:svg")
.each(transform)
.attr("class", "marker");
// Add a circle.
marker.append("svg:circle")
.attr("r", 4.5)
.attr("cx", padding)
.attr("cy", padding);
// Add a label.
marker.append("svg:text")
.attr("x", padding + 7)
.attr("y", padding)
.attr("dy", ".31em")
.text(function(d, i){
return i;
});
}
function transform(d) {
d = new google.maps.LatLng(d.Latitude, d.Longitude);
d = projection.fromLatLngToDivPixel(d);
return d3.select(this)
.style("left", (d.x - padding) + "px")
.style("top", (d.y - padding) + "px");
}
};
};