可拖动的地图

本文结合地图和力导向图制作可拖动的地图,用户可用鼠标拖动各省。

地理数据使用:china_simplify.json

定义函数

  var projection = d3.geo.mercator()
            .center([107, 31])
            .scale(850)
              .translate([width/2, height/2]);
  
  var path = d3.geo.path()
          .projection(projection);
  
  var force = d3.layout.force().size([width, height]);
  
  var color = d3.scale.category20();

读取数据

d3.json("china_simplify.json", function(error, root) {
    
    if (error) 
      return console.error(error);
    console.log(root.features);
}

转换数据

    var nodes = [];
    var links = [];
    
    root.features.forEach(function(d, i) {
      var centroid = path.centroid(d);
      centroid.x = centroid[0];
      centroid.y = centroid[1];
      centroid.feature = d;
      nodes.push(centroid);
    });
    
    var triangles = d3.geom.voronoi().triangles(nodes);
    
    triangles.forEach(function(d,i){
      links.push( edge( d[0] , d[1] ) );
      links.push( edge( d[1] , d[2] ) );
      links.push( edge( d[2] , d[0] ) );
    });

读取后的文件信息都存在变量 root 中,上面的代码是将 root 中的数据分别转换为力学图所需要的点和线,存在变量 nodes 和 links 中。

第1–2行: 定义变量 nodes 和 links

第4–10行: 对于 root.features 中存有每一个省的数据, root.features.forEach() 即对每一个省的数据,执行 function 无名函数,函数里计算出各省的中点,保存在 centroid.x 和 centroid.y 中,再把其他信息赋值给 centroid.feature,最后插入到 nodes 中。

第12行: 对 nodes 中的顶点进行三角剖分,即用三角形来连接各顶点,结果保存在 triangles 中。

第14–18行: 将三角形的各边存到 links 变量中。其中的 edge 函数的实现为:

  function edge(a, b) {
    var dx = a[0] - b[0], dy = a[1] - b[1];
    return {
      source: a,
      target: b,
      distance: Math.sqrt(dx * dx + dy * dy)
    };
  }

绘制地图

    force.gravity(0)
      .charge(0)
      .nodes(nodes)
      .links(links)
      .linkDistance(function(d){ return d.distance; })
      .start();
    
    var node = svg.selectAll("g")
            .data(nodes)
            .enter().append("g")
            .attr("transform", function(d) { return "translate(" + -d.x + "," + -d.y + ")"; })
                .call(force.drag)
                .append("path")
                .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
                .attr("stroke","#000")
                .attr("stroke-width",1)
                .attr("fill", function(d,i){
                    return color(i);
                })
                .attr("d", function(d){
                  return path(d.feature);
                } );
    
    var link = svg.selectAll("line")
            .data(links)
            .enter()
            .append("line")
            .attr("class","link")
            .attr("x1",function(d) { return d.source.x; } )
            .attr("y1",function(d) { return d.source.y; } )
            .attr("x2",function(d) { return d.target.x; } )
            .attr("y2",function(d) { return d.target.y; } );

第 1 – 6 行: 对 force 的各参数进行设定。

第 8 – 22 行: 绘制各顶点,即中国各省。其中要注意,第11行和第14行,是完全相反的两个平移函数,不错,这么做就是为了移过去,再移回来,即初始时显示的是各省拼成的完整的地图且显示在最初设定的位置,因为拖拽的过程中变化的量是 d.x 和 d.y ,所以要这么做。这里有点难理解,请好好体会一下,如有疑问,请在下面留言。另外,第12行是调用 force.drag 函数。

第 24 – 32 行: 绘制连接各省的线条。

结合力导向图

     force.on("tick", function() {
          link.attr("x1", function(d) { return d.source.x; })
              .attr("y1", function(d) { return d.source.y; })
              .attr("x2", function(d) { return d.target.x; })
              .attr("y2", function(d) { return d.target.y; });

         node.attr("transform", function(d) {
            return "translate(" + d.x + "," + d.y + ")";
         });
    });

tick 指的是时间间隔,也就是每一个时间间隔之后就刷新一遍画面,刷新的内容写在后面的无名函数 function 中, function 函数中写上作图的内容。这里看到了吧,第7-9行里是用于平移的,平移的参数为 d.x 和 d.y 。

结果

拖动试试?

源代码

下载地址:mapforce.zip

在线演示

委托名片直接发送邮件(需邮箱客户端)点击复制邮箱地址14721230383项目委托、技术支持,欢迎与我们联系。休息日7:00 ~ 11:0012:00 ~ 22:00工作日11:00 ~ 11:4016:00 ~ 22:00

Copyright 2014-2016, DecemberCafe, All Rights Reserved