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 &copy; <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的主要内容,如果未能解决你的问题,请参考以下文章

使用 D3 和 Leaflet 重复 SVG

可视化项目阶段总结 Node.js+d3+Leaflet

d3.js,openlayer,Leaflet或其他,哪些适合Web GIS的开发?

Leaflet插件对TopoJson的解析和支持

单击geojson多边形到传单地图时添加的更新d3图表

将 d3.js 与 Apache Zeppelin 一起使用