D3 地理地图缩放无法正常工作 (Canvas)
D3 Geo map zoom is not working correctly (Canvas)
我正在尝试在 canvas 中缩放地图。
var projection = d3.geoMercator()
projection.fitExtent([[margin.left, margin.top], [width, height]], land);
var path = d3.geoPath().projection(projection).context(context);
当我将平移和缩放应用到 canvas 上下文时,它工作得很好。但是当我调用 var latlong = projection.invert(d3.mouse(this));
时,return 没有正确的 纬度和经度 ,因为投影没有相应地转换。
var zoom = d3.zoom()
.scaleExtent([1, Infinity])
.on("zoom", zoomByContext);
function zoomByContext() {
var transform = d3.event.transform;
context.clearRect(0, 0, width, height);
context.save();
context.translate(transform.x, transform.y);
context.lineWidth = 0.5 / transform.k;
context.scale(transform.k, transform.k);
renderFeature();
context.restore();
}
所以我尝试像打击一样重新投影投影。但是当我用下面的代码缩放时它会转到左上角。
var zoom = d3.zoom()
.scaleExtent([1, Infinity])
.on("zoom", zoomByProjection);
function zoomByProjection() {
var transform = d3.event.transform;
projection.translate([transform.x, transform.y]);
projection.scale(scale * transform.k);
renderFeature();
}
而且我这样称呼缩放
canvas.call(zoom, d3.zoomIdentity
.translate(projection.translate())
.scale(projection.scale()));
对于第一种方法,您需要先反转缩放,然后再将 xy 坐标转换为长纬度坐标:
var transform = d3.zoomTransform(this);
var xy = transform.invert(d3.mouse(this));
var longlat = projection.invert(xy);
我们在像素坐标中获取鼠标位置,将其转换为缩放坐标,然后将其转换为地理坐标。
这应该证明以上内容:
var width = 960;
var height = 500;
var canvas = d3.select("canvas");
var context = canvas.node().getContext("2d")
var projection = d3.geoMercator();
var path = d3.geoPath(projection,context);
d3.json("https://unpkg.com/world-atlas@1/world/110m.json", function(error, world) {
if (error) throw error;
renderFeature();
var zoom = d3.zoom()
.scaleExtent([1, Infinity])
.on("zoom", zoomByContext);
canvas.call(zoom);
function zoomByContext() {
var transform = d3.event.transform;
context.clearRect(0, 0, width, height);
context.save();
context.translate(transform.x, transform.y);
context.lineWidth = 0.5 / transform.k;
context.scale(transform.k, transform.k);
renderFeature();
context.restore();
}
function renderFeature() {
context.beginPath();
path(topojson.mesh(world));
context.stroke();
}
canvas.on("click", function() {
var transform = d3.zoomTransform(this);
var xy = transform.invert(d3.mouse(this));
var longlat = projection.invert(xy);
console.log(longlat);
})
});
<canvas width="960" height="500"></canvas>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://unpkg.com/topojson-client@3"></script>
第二种方法有点棘手,如果投影的平移是 [0,0]
,则您所采用的方法会奏效,但这种情况很少见。默认值为 [480,250]
(假设 canvas 为 960x500),并且 fitSize
和 fitExtent
不通过修改旋转和居中来定位特征,而是平移。所以你需要在修改投影时考虑初始翻译(就像你对比例所做的那样):
var transform = d3.event.transform;
projection.translate([transform.x+translate[0]*transform.k, transform.y+translate[1]*transform.k]);
projection.scale(scale * transform.k);
这里translate
是一个保存初始翻译值的数组
这里有一个演示可以证明以上内容:
var width = 960;
var height = 500;
var canvas = d3.select("canvas");
var context = canvas.node().getContext("2d")
var projection = d3.geoMercator().center([105,3]).scale(1200).translate([2000,0]);
var path = d3.geoPath(projection,context);
var scale = projection.scale();
var translate = projection.translate();
d3.json("https://unpkg.com/world-atlas@1/world/110m.json", function(error, world) {
if (error) throw error;
renderFeature();
var zoom = d3.zoom()
.scaleExtent([0.1, Infinity])
.on("zoom", zoomByProjection);
canvas.call(zoom);
function zoomByProjection() {
context.clearRect(0, 0, width, height);
var transform = d3.event.transform;
projection.translate([transform.x+translate[0]*transform.k, transform.y+translate[1]*transform.k]);
projection.scale(scale * transform.k);
renderFeature();
}
function renderFeature() {
context.beginPath();
path(topojson.mesh(world));
context.stroke();
}
});
<canvas width="960" height="500"></canvas>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://unpkg.com/topojson-client@3"></script>
我正在尝试在 canvas 中缩放地图。
var projection = d3.geoMercator()
projection.fitExtent([[margin.left, margin.top], [width, height]], land);
var path = d3.geoPath().projection(projection).context(context);
当我将平移和缩放应用到 canvas 上下文时,它工作得很好。但是当我调用 var latlong = projection.invert(d3.mouse(this));
时,return 没有正确的 纬度和经度 ,因为投影没有相应地转换。
var zoom = d3.zoom()
.scaleExtent([1, Infinity])
.on("zoom", zoomByContext);
function zoomByContext() {
var transform = d3.event.transform;
context.clearRect(0, 0, width, height);
context.save();
context.translate(transform.x, transform.y);
context.lineWidth = 0.5 / transform.k;
context.scale(transform.k, transform.k);
renderFeature();
context.restore();
}
所以我尝试像打击一样重新投影投影。但是当我用下面的代码缩放时它会转到左上角。
var zoom = d3.zoom()
.scaleExtent([1, Infinity])
.on("zoom", zoomByProjection);
function zoomByProjection() {
var transform = d3.event.transform;
projection.translate([transform.x, transform.y]);
projection.scale(scale * transform.k);
renderFeature();
}
而且我这样称呼缩放
canvas.call(zoom, d3.zoomIdentity
.translate(projection.translate())
.scale(projection.scale()));
对于第一种方法,您需要先反转缩放,然后再将 xy 坐标转换为长纬度坐标:
var transform = d3.zoomTransform(this);
var xy = transform.invert(d3.mouse(this));
var longlat = projection.invert(xy);
我们在像素坐标中获取鼠标位置,将其转换为缩放坐标,然后将其转换为地理坐标。
这应该证明以上内容:
var width = 960;
var height = 500;
var canvas = d3.select("canvas");
var context = canvas.node().getContext("2d")
var projection = d3.geoMercator();
var path = d3.geoPath(projection,context);
d3.json("https://unpkg.com/world-atlas@1/world/110m.json", function(error, world) {
if (error) throw error;
renderFeature();
var zoom = d3.zoom()
.scaleExtent([1, Infinity])
.on("zoom", zoomByContext);
canvas.call(zoom);
function zoomByContext() {
var transform = d3.event.transform;
context.clearRect(0, 0, width, height);
context.save();
context.translate(transform.x, transform.y);
context.lineWidth = 0.5 / transform.k;
context.scale(transform.k, transform.k);
renderFeature();
context.restore();
}
function renderFeature() {
context.beginPath();
path(topojson.mesh(world));
context.stroke();
}
canvas.on("click", function() {
var transform = d3.zoomTransform(this);
var xy = transform.invert(d3.mouse(this));
var longlat = projection.invert(xy);
console.log(longlat);
})
});
<canvas width="960" height="500"></canvas>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://unpkg.com/topojson-client@3"></script>
第二种方法有点棘手,如果投影的平移是 [0,0]
,则您所采用的方法会奏效,但这种情况很少见。默认值为 [480,250]
(假设 canvas 为 960x500),并且 fitSize
和 fitExtent
不通过修改旋转和居中来定位特征,而是平移。所以你需要在修改投影时考虑初始翻译(就像你对比例所做的那样):
var transform = d3.event.transform;
projection.translate([transform.x+translate[0]*transform.k, transform.y+translate[1]*transform.k]);
projection.scale(scale * transform.k);
这里translate
是一个保存初始翻译值的数组
这里有一个演示可以证明以上内容:
var width = 960;
var height = 500;
var canvas = d3.select("canvas");
var context = canvas.node().getContext("2d")
var projection = d3.geoMercator().center([105,3]).scale(1200).translate([2000,0]);
var path = d3.geoPath(projection,context);
var scale = projection.scale();
var translate = projection.translate();
d3.json("https://unpkg.com/world-atlas@1/world/110m.json", function(error, world) {
if (error) throw error;
renderFeature();
var zoom = d3.zoom()
.scaleExtent([0.1, Infinity])
.on("zoom", zoomByProjection);
canvas.call(zoom);
function zoomByProjection() {
context.clearRect(0, 0, width, height);
var transform = d3.event.transform;
projection.translate([transform.x+translate[0]*transform.k, transform.y+translate[1]*transform.k]);
projection.scale(scale * transform.k);
renderFeature();
}
function renderFeature() {
context.beginPath();
path(topojson.mesh(world));
context.stroke();
}
});
<canvas width="960" height="500"></canvas>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://unpkg.com/topojson-client@3"></script>