D3+Leaflet
Posted 肉松松鼠
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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/[email protected]/dist/leaflet.css" integrity="sha512-wcw6ts8Anuw10Mzh9Ytw4pylW8+NAD4ch3lqm9lzAsTxg0GFeJgoAtxuCLREZSC5lUXdVyo/7yfsqFjQ4S+aKw==" crossorigin=""/> <script src="https://unpkg.com/[email protected]/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>
以上是关于D3+Leaflet的主要内容,如果未能解决你的问题,请参考以下文章