Javascript 向自定义贴图点添加缩放行为
作为学习D3的练习,我使用了以前一个关于世界各地机场位置和名称的项目中的数据集。我正在使用D3.csv将其加载到我的网页中,并使用topojson在地图上绘制点 在我的练习中,我正在尝试添加一个功能,使用户可以放大和缩小世界地图。正如你可以想象的,有很多机场,地图变得拥挤,因为我还没有添加任何过滤逻辑 最糟糕的是,我可以让缩放行为在国家工作,但我不确定如何让它在我画的圆圈上工作。如果我使用滚轮放大地图,地图会放大,但圆圈保持不变Javascript 向自定义贴图点添加缩放行为,javascript,d3.js,Javascript,D3.js,作为学习D3的练习,我使用了以前一个关于世界各地机场位置和名称的项目中的数据集。我正在使用D3.csv将其加载到我的网页中,并使用topojson在地图上绘制点 在我的练习中,我正在尝试添加一个功能,使用户可以放大和缩小世界地图。正如你可以想象的,有很多机场,地图变得拥挤,因为我还没有添加任何过滤逻辑 最糟糕的是,我可以让缩放行为在国家工作,但我不确定如何让它在我画的圆圈上工作。如果我使用滚轮放大地图,地图会放大,但圆圈保持不变 <script src="http://d3js.org/d
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="http://d3js.org/topojson.v1.min.js"></script>
<script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script>
<style type="text/css">
.feature {
fill: none;
stroke: grey;
stroke-width: 1px;
stroke-linejoin: round;
}
.mesh {
fill: none;
stroke: lightgrey;
stroke-width: 2px;
stroke-linejoin: round;
}
h1 {
font-family: sans-serif;
}
svg {
background: #eee;
}
.sphere {
fill: #fff;
}
.land {
fill: #000;
}
.boundary {
fill: none;
stroke: #fff;
stroke-linejoin: round;
stroke-linecap: round;
vector-effect: non-scaling-stroke;
}
.overlay {
fill: none;
pointer-events: all;
}
circle{
fill: steelblue;
stroke-width: 1.5px;
}
.d3-tip {
line-height: 1;
font-weight: bold;
padding: 12px;
background: rgba(0, 0, 0, 0.8);
color: #fff;
border-radius: 2px;
}
/* Creates a small triangle extender for the tooltip */
.d3-tip:after {
box-sizing: border-box;
display: inline;
font-size: 10px;
width: 100%;
line-height: 1;
color: rgba(0, 0, 0, 0.8);
content: "\25BC";
position: absolute;
text-align: center;
}
/* Style northward tooltips differently */
.d3-tip.n:after {
margin: -1px 0 0 0;
top: 100%;
left: 0;
}
</style>
</head>
<body>
<h1>Lots of airports across the world</h1>
<script type="text/javascript">
var width = 950,
height = 550;
scale0 = (width - 1) / 2 / Math.PI;
var projection = d3.geo.mercator();
var zoom = d3.behavior.zoom()
.translate([width / 2, height / 2])
.scale(scale0)
.scaleExtent([scale0, 8 * scale0])
.on("zoom", zoomed);
var path = d3.geo.path()
.projection(projection);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g");
var g = svg.append("g");
var circle = svg.append("circle");
svg.append("rect")
.attr("class", "overlay")
.attr("width", width)
.attr("height", height);
svg
.call(zoom)
.call(zoom.event);
var tip = d3.tip()
.attr("class", "d3-tip")
.offset([-10, 0])
.html(function(d) {
return "Name" + ": " + d[2] + "<br>" + "Location" + ": " + d[3];
});
svg.call(tip);
d3.json("world-110m.v1.json", function(error, world) {
if (error) throw error;
g.append("g")
.attr("d", path)
.on("click", clicked)
.on("zoom", zoomed);
g.append("path")
.datum({type: "Sphere"})
.attr("class", "sphere")
.attr("d", path);
g.append("path")
.datum(topojson.merge(world, world.objects.countries.geometries))
.attr("class", "land")
.attr("d", path);
g.append("path")
.datum(topojson.mesh(world, world.objects.countries, function(a, b) { return a !== b; }))
.attr("class", "boundary")
.attr("d", path)
.on("click", clicked);
d3.csv("output.csv",
function(data) {return {name: data.Airport_name, location: data.Location_served,
long : +data.Longitude, lat : +data.Latitude}},
function(data) {
var new_array = data.map(function (d) {return [d.long, d.lat, d.name, d.location]});
console.log("new", new_array)
svg.selectAll("circle")
.data(new_array)
.enter()
.append("circle")
.attr("cx", function (d) { return projection(d)[0]; })
.attr("cy", function (d) { return projection(d)[1]; })
.attr("r", "2px")
.on("mouseover", tip.show)
.on("mouseout", tip.hide);
});
}) //closes the json, do not move.
// begin click-zoom listeners
function clicked(d) {
console.log("d:",d)
var centroid = path.centroid(d),
translate = projection.translate();
projection.translate([
translate[0] - centroid[0] + width / 2,
translate[1] - centroid[1] + height / 2
]);
zoom.translate(projection.translate());
g.selectAll("path").transition()
.duration(700)
.attr("d", path);
}
function zoomed() {
projection.translate(d3.event.translate).scale(d3.event.scale);
g.selectAll("path").attr("d", path);
}
</script>
</body>
缩放功能执行两项操作,即修改投影并使用修改后的投影更新路径:
function zoomed() {
projection.translate(d3.event.translate).scale(d3.event.scale); // modify the projection
g.selectAll("path").attr("d", path); // update the paths
}
好的,除了使用绑定基准修改每次缩放的路径外,我们还需要修改圆:
function zoomed() {
projection.translate(d3.event.translate).scale(d3.event.scale); // modify the projection
g.selectAll("path").attr("d", path); // update the paths
// update the circles/points:
svg.selectAll("circle")
.attr("cx", function (d) { return projection(d)[0]; })
.attr("cy", function (d) { return projection(d)[1]; })
});
}
svg.selectAll("circle")
.data(new_array)
.enter()
.append("circle")
.attr("cx", function (d) { return projection(d)[0]; })
.attr("cy", function (d) { return projection(d)[1]; })
但是,这并不完全有效,我们需要了解如何附加圆:
function zoomed() {
projection.translate(d3.event.translate).scale(d3.event.scale); // modify the projection
g.selectAll("path").attr("d", path); // update the paths
// update the circles/points:
svg.selectAll("circle")
.attr("cx", function (d) { return projection(d)[0]; })
.attr("cy", function (d) { return projection(d)[1]; })
});
}
svg.selectAll("circle")
.data(new_array)
.enter()
.append("circle")
.attr("cx", function (d) { return projection(d)[0]; })
.attr("cy", function (d) { return projection(d)[1]; })
如果svg上没有圆圈,这很好-但是有,您在这里添加了一个圆圈:
var circle = svg.append("circle");
这意味着不会添加数组中的第一个机场,因为svg中已经有一个圆圈用于数据数组中的该项。空选择(d3.selectAll(null))将确保为数据数组中的每个项目输入一个项目
这里最重要的是,在加载数据之前,第一个圆没有绑定基准。这将导致调用缩放时出现一些问题,没有用于重新缩放圆的绑定数据,您将得到一个错误。相反,您可以使用类附加机场,并在缩放事件期间选择这些机场
在我的示例中,我使用了空选择来输入机场,并给了它们一个类,这样我就可以根据更新的投影轻松地选择要重新定位的圆。(为了演示,我还简化了世界地图并增加了点半径)
这看起来像:
function zoomed() {
projection.translate(d3.event.translate).scale(d3.event.scale);
g.selectAll("path").attr("d", path);
svg.selectAll(".airport")
.attr("cx", function (d) { return projection(d)[0]; })
.attr("cy", function (d) { return projection(d)[1]; })
}
输入为:
svg.selectAll() // selectAll() is equivilant to selectAll(null)
.data(new_array)
.enter()
.append("circle")
.attr("class","airport")
.attr("cx", function (d) { return projection(d)[0]; })
.attr("cy", function (d) { return projection(d)[1]; })
.attr("r", "6px")
.on("mouseover", tip.show)
.on("mouseout", tip.hide);
});
“TypeError:无法读取undefined”的属性“0”用于生成我的点的数据是如何在d3.csv函数之外读取的?啊,我没有看到您附加了一个额外的圆:
svg.append(“圆”)代码>这没有绑定的基准。缩放使用绑定到点的数据(与重绘路径时的路径相同),我将进行编辑。虽然如果你能提供你的数据样本,我可以做一个适当的演示。样本添加到主要问题中谢谢,我希望我在更新的答案中说得很清楚-这还为时过早,或者对我来说说得不清楚。这是一个相当好的演示!谢谢,我将进一步阅读附加元素以及添加和操作类属性。