D3地理地图缩放无法正常工作(画布)

时间:2018-08-10 07:18:32

标签: javascript d3.js zoom

我正在尝试在画布中缩放地图。

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()));

1 个答案:

答案 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),并且fitSizefitExtent不会通过修改旋转和居中来定位要素,而是通过平移来定位。因此,在修改投影时(与缩放一样),您需要考虑初始平移:

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>