D3 + Leaflet入门

很久前于 D3官网 初识此文,不明所以,后遇相似疑惑,熟读深悉,方觉大有所用,遂翻译之,仅供参考。
原文载于:http://bost.ocks.org/mike/leaflet/

这是一篇快速示范,使用D3结合Leaflet来生成GeoJSON图形。实现简单明确,但是遗憾的是,Leaflet缺少自定义覆盖图层的文档和示例,所以希望能帮助入门。(注:Leaflet文档已经更新,在ILayer章节中有《Implementing Custom Layers》(实现自定义图层))。

#初始化Map和SVG覆盖层

创建基于MapBox瓦片的基本地图

var map = new L.Map("map", {center: [37.8, -96.9], zoom: 4})
    .addLayer(new L.TileLayer("http://{s}.tiles.mapbox.com/v3/examples.map-vyofok3q/{z}/{x}/{y}.png"));

地图放置于id为“map”的页面元素中,指定的样式尺寸为:

#map {
  width: 960px;
  height: 500px;
}

接下来,向Leaflet的overlay图层添加SVG元素。当地图漫游时,Leaflet会自动重新定位overlay框。需要注意的时,SVG元素初始化时没有宽度width和高度height,尺寸必须动态设置,因为随着地图的缩放会改变。

var svg = d3.select(map.getPanes().overlayPane).append("svg"),
    g = svg.append("g").attr("class", "leaflet-zoom-hide");

在SVG中,还需要一个G(group)元素,用来转换SVG元素,确保SVG左上角坐标(0,0),与Leaflet的图层原点相一致。“leaflet-zoom-hide”类用来在leaflet缩放时隐藏覆盖图层overlay。另外,在构造map时可以使用zoomAnimation选项来禁止过渡效果。

#加载和投影GeoJSON

使用d3.json来加载GeoJSON文件:

d3.json("us-states.json", function(collection) {
  // code here
});

加载是异步进行,所以本实例剩余代码均位于回调函数中。传递来的collection是json文件的内容,单个的FeatureCollection,包含50个州以及波多黎各的坐标特征。

D3和Leaflet使用不同的API来生成图形,投影点。幸运的是,很容易应用自定义几何转换来让Leaflet的API适应D3。transform将一个输入的几何形状(例如用球形几何坐标表示的多边形),转换输出为不同的几何形状(例如用投影屏幕坐标表示的多边形)。利用d3.geo.transform可以作为一个简单方法来投影单个点。

function projectPoint(x, y) {
  var point = map.latLngToLayerPoint(new L.LatLng(y, x));
  this.stream.point(point.x, point.y);
}

创建d3.geo.path来投影GeoJSON

var transform = d3.geo.transform({point: projectPoint}),
    path = d3.geo.path().projection(transform);

利用D3的data方法为每个特征创建path元素

var feature = g.selectAll("path")
    .data(collection.features)
  .enter().append("path");

path元素初始化时为空,稍后设置其d属性来赋予path数据。

feature.attr("d", path);

selection.attr方法为每个特征赋予path数据。path元素绑定到相关的GeoJSON特征,这些特征被送至path生成器(d3.geo.path),调用自定义投影方法,依次调用Leaflet的投影方法。

# SVG适应图层

SVG元素需要多大?不能简单地设定为960*500,因为用户可以缩放和漫游地图,所以SVG大小应当取决于显示的几何特征和当前缩放级别。

根据任意的投影是很难计算SVG的盒大小。D3提供了便利机制(path.bounds方法)来计算投影后的盒大小,利用自定义transform方法将经纬度坐标转换为像素。

var bounds = path.bounds(collection),
    topLeft = bounds[0],
    bottomRight = bounds[1];

为了在图层原点上方或左侧显示几何特征,需要给SVG尺寸设置足够的填充空间。图层原点是任意的,有时需要在其上方或左侧绘制,不需要额外的填充空间。左上角会被遮挡住,一些特征将会隐藏。需要注意的是,设置left和top样式,需要依赖SVG元素的位置属性为relative。

svg .attr("width", bottomRight[0] - topLeft[0])
    .attr("height", bottomRight[1] - topLeft[1])
    .style("left", topLeft[0] + "px")
    .style("top", topLeft[1] + "px");

g   .attr("transform", "translate(" + -topLeft[0] + "," + -topLeft[1] + ")");

最后,上述代码需要被Leaflet的viewreset事件所响应,确保当地图缩放时,SVG可以重新定位和重绘。查看完整的源代码。

小结,D3+Leaflet绘制SVG过程:

1.Geo投影,D3自带,也可自定义。
2.SVG绘制,可以用D3的data和attr方法,也可用d3.svg方法,还可用SVG原生方法。
3.SVG适应,依据投影转换,设置宽度、高度、位置等属性。

你可能感兴趣的:(svg,图形,d3,leaflet)