D3+Leaflet
前言:虽然Leaflet提供了强大的画图工具,不过它的速度不是很尽人意,当数据量较大的时候,需要较长的渲染时间,交互好感度会降低。
因此我们可以考虑使用D3,在leaflet的地图上蒙上一个svg,在svg上画图会加快一些速度,获得更好的交互体验。
D3官网上有Leaflet+D3的相关介绍https://bost.ocks.org/mike/leaflet/,有一篇CSDN的博客翻译了这篇文章http://blog.csdn.net/zhang1244j/article/details/41440289
文章中已经讲述的内容不再赘述,我具体讲一讲我在实现这部分代码与之不同之处,以及可能需要注意的地方。
d3.json("us-states.json", function(error, collection) {
if (error) throw error;
// code here
});
认真阅读官网中的代码,能了解到它的数据源来自于json文件(如上),它将整个处理管程都包在了这个函数里,在本文中用到的数据来自数据库,虽然有尝试过将其转换成json格式的变量,但依旧throw error
我的解决办法是:
假如我要画圆,我需要点的x,y坐标,半径和颜色(d3画圆的方式详见博客“如何使用d3画基础图形”)
用一个数组去保存圆的这些属性数据,注意保存的是经纬度的坐标数值,当在画图的时候再将数据转换成svg的坐标。之所以这样做,是因为,这个圆的地理位置(也就是latLng)是永远不变的,而它的svg坐标会随着“缩放”而改变,因此需要在‘zoomend’的事件回调函数中,使用该圆的经纬度坐标去更新它的svg坐标。具体函数的写法是
//调整圆的大小,在onMapZoom中调用
function adjustCircle(){ d3.selectAll("circle") .attr('cx', o => mymap.latLngToLayerPoint([o.x_axis, o.y_axis]).x) .attr('cy', o => mymap.latLngToLayerPoint([o.x_axis, o.y_axis]).y); }
注意,和上文提到的两篇博客不同,这种方法并不需要调整画布,只要初始化的时候定义一下画布大小即可
//鼠标缩放操作 function onMapZoom(){ adjustSVG(); adjustCircle(); }
整体的代码如下:
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" ">
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.1.0/dist/leaflet.css" integrity="sha512-wcw6ts8Anuw10Mzh9Ytw4pylW8+NAD4ch3lqm9lzAsTxg0GFeJgoAtxuCLREZSC5lUXdVyo/7yfsqFjQ4S+aKw==" crossorigin=""/>
<script src="https://unpkg.com/leaflet@1.1.0/dist/leaflet.js" integrity="sha512-mNqn2Wg7tSToJhvHcqfzLMU6J4mkOImSPTxVZAdo+lcPlk+GhZmYgACEe0x35K7YzW1zJ7XyJV/TT1MrdXvMcA==" crossorigin=""></script>
<style>body { padding: 0; margin: 0; } html, body, #mapid { height: 500px; width: 960px; }</style>
</head>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<div id="mapid" ></div>
<script>
var mymap = L.map('mapid').setView([51.505, -0.09], 13);
L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw', {
maxZoom: 18,
attribution: 'Map data © <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, ' +
'<a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, ' +
'Imagery © <a href="http://mapbox.com">Mapbox</a>',
id: 'mapbox.streets'
}).addTo(mymap);
//加载SVG
//The data for our line
var lines = new Array();
var circleData = [{"lat": "51.513336399623476", "lng": "-0.0885772705078125"},
{"lat": "51.511092905004745", "lng": "-0.09733200073242189"},
{"lat": "51.50543026060531", "lng": "-0.10145187377929689"},
{"lat": "51.499980636437265", "lng": "-0.09853363037109376"},
{"lat": "51.497202145853784", "lng": " -0.08806228637695314"},
{"lat": "51.4978433510224", "lng": "-0.08222579956054689"},
{"lat": "51.50051494213075", "lng": "-0.07570266723632814"},
{"lat": "51.50564395807757", "lng": "-0.07209777832031251"},
{"lat": "51.51312273822952", "lng": "-0.08050918579101564"},
{"lat": "51.51002453540032", "lng": "-0.07535934448242189"}];
//加载SVG
var svg = d3.select(mymap.getPanes().overlayPane).append("svg").attr("class", "leaflet-zoom-hide"),
g = svg.append("g");
var jsonCircles = new Array();
function drawCircle(){
circleData.forEach(function(d){
console.log(d);
jsonCircles.push({"x_axis":d.lat,"y_axis":d.lng,"radius":12,"color":"green"});
});
console.log("drawCircle");
console.log(jsonCircles);
var t = svg.selectAll("circle")
.data(jsonCircles);
var circleAttributes =
t
.enter()
.append("circle")
.attr("cx",function(d){console.log(mymap.latLngToLayerPoint(L.latLng(d.x_axis,d.y_axis)));return mymap.latLngToLayerPoint(L.latLng(d.x_axis,d.y_axis)).x;})
.attr("cy",function(d){return mymap.latLngToLayerPoint(L.latLng(d.x_axis,d.y_axis)).y;})
.attr("r",function(d){return d.radius;})
.style("fill",function(d){return d.color;});
}
//调整圆的大小,在onMapZoom中调用
function adjustCircle(){
console.log("draw");
d3.selectAll("circle")
.attr('cx', o => mymap.latLngToLayerPoint([o.x_axis, o.y_axis]).x)
.attr('cy', o => mymap.latLngToLayerPoint([o.x_axis, o.y_axis]).y);
}
//鼠标缩放操作
function onMapZoom(){
//adjustSVG();
adjustCircle();
}
function initial(){
svg.attr("width", 1500)
.attr("height", 800);
drawCircle();
}
//初始化画图的函数
initial();
//事件响应
mymap.on('zoom',onMapZoom);
</script>
</body>
</html>

浙公网安备 33010602011771号