我正在尝试在画布中缩放地图。
var projection = d3.geoMercator()
projection.fitExtent([[margin.left, margin.top], [width, height]], land);
var path = d3.geoPath().projection(projection).context(context);
当我将平移和缩放应用于画布上下文时,它可以完美工作。但是当我致电var latlong = projection.invert(d3.mouse(this));
时,它不会返回正确的纬度和经度,因为投影没有相应地转换。
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()));
答案 0 :(得分:2)
对于第一种方法,您需要先将缩放比例反转,然后再将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]
(假设画布为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>