首頁  >  文章  >  web前端  >  使用D3.js創建物流地圖的步奏詳解

使用D3.js創建物流地圖的步奏詳解

php中世界最好的语言
php中世界最好的语言原創
2018-04-13 10:32:031850瀏覽

這次帶給大家使用D3.js創建物流地圖的步奏詳解,使用D3.js創建物流地圖的注意事項有哪些,下面就是實戰案例,一起來看一下。

製作想法

  1. 需要繪製一張中國地圖,做為背景。

  2. 需要主要城市的經緯座標,以繪製路張起點和終點。

  3. 接收到物流單的城市,繪製一個閃爍的標記。

  4. 已經有過物流單的目標城市,不再繪製路線。

  5. 每次新產生一筆物流單,都有一個標記沿著路線移向目標的動畫效果。

  6. 繪製結束後的數據,需要清理掉,以減少對瀏覽器的資源佔用。

# 開始擼碼

1.建立網頁範本

# 載入D3JS,為了方便調試,直接下載d3.js檔案在本地,實際使用的時候,可以換成載入路徑。注意,使用的是V4版的D3,和V3版有差異。

建立一個p塊,準備繪圖。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf8">
    <script type="text/javascript" src="../../static/d3/d3.js"></script>
    <title>地图</title>
  </head>
  <body>
    <p class="fxmap">
    </p>
  </body>
  <script type="text/javascript"></script>
</html>

建立SVG,以下所有程式碼放在<script></script>中

var width=1000 , height=800; // 定义SVG宽高
var svg = d3.select("body p.fxmap")
            .append("svg")
            .attr("width", "width) 
            .attr("height", height)
            .style("background","#000"); //

建立SVG圖形分組,以備呼叫

  1. gmp,保存背景地圖和起點標記。

  2. # mline,保存起點和目標之間的連線,以及目標點。

  3. # buttion,測試用的按鈕

gmap = svg.append("g").attr("id", "map").attr("stroke", "white").attr("stroke-width",1);
    mline = svg.append("g").attr("id", "moveto").attr("stroke", "#FFF").attr("stroke-width", 1.5).attr("fill","#FFF");
    button = svg.append("g").attr("id", "button").attr("stroke", "white").attr("stroke-width", 1).attr("fill", "white");

# 建立投影函數

  1. 經緯度不能直接用來繪圖,需要轉換成平面座標。 d3js提供了比較豐富的投影方法,本例中使用了geoEquirectangular()方法。

  2. projection 是將經緯度轉換為平面座標的方法

  3. path 是一種將經緯度轉換為連線繪製點座標的方法(省得自己再寫函數建構path路徑)

var projection = d3.geoEquirectangular()
              .center([465,395]) // 指定投影中心,注意[]中的是经纬度
              .scale(height)
              .translate([width / 2, height / 2]);
var path = d3.geoPath().projection(projection);

# 建立marker標記,以便多個連線終點呼叫

  1. 由於會有多個物流連線的終點,所以都放在一個marker標記中呼叫。

  2. 這個標記是由中間的 圓形 外圈 構成。外圈的閃爍效果另外創建。

marker = svg.append("defs")
          .append("marker")
          .append("marker")
          .attr("id", "pointer")
          .attr("viewBox","0 0 12 12")  // 可见范围
          .attr("markerWidth","12")    // 标记宽度
          .attr("markerHeight","12")    // 标记高度
          .attr("orient", "auto")     //
          .attr("markerUnits", "strokeWidth") // 随连接线宽度进行缩放
          .attr("refX", "6")       // 连接点坐标
          .attr("refY", "6")
    // 绘制标记中心圆
    marker.append("circle")
        .attr("cx", "6")
        .attr("cy", "6")
        .attr("r", "3")
        .attr("fill", "white");
    // 绘制标记外圆,之后在timer()中添加闪烁效果
    marker.append("circle")
        .attr("id", "markerC")
        .attr("cx", "6")
        .attr("cy", "6")
        .attr("r", "5")
        .attr("fill-opacity", "0")
        .attr("stroke-width", "1")
        .attr("stroke", "white");

繪製中國地圖,並標記起點(長沙)

# 地圖使用的經緯集為china.json,這個文件網路上有許多

// 记录长沙坐标
    var changsha = projection([112.59,28.12]);
    // 读取地图数据,并绘制中国地图
    mapdata = [];
    d3.json('china.json', function(error, data){
      if (error)
        console.log(error);
      // 读取地图数据
      mapdata = data.features;
      // 绘制地图
      gmap.selectAll("path")
        .data(mapdata)
        .enter()
        .append("path")
        .attr("d", path);
      // 标记长沙
      gmap.append("circle").attr("id","changsha")
        .attr("cx", changsha[0])
        .attr("cy", changsha[1])
        .attr("r", "6")
        .attr("fill", "yellow")
      gmap.append("circle").attr("id","changshaC")
        .attr("cx", changsha[0])
        .attr("cy", changsha[1])
        .attr("r", "10")
        .attr("stroke-width", "2")
        .attr("fill-opacity", "0");
    });

建立方法,繪製一條從指定起點到終點的連線,並在絡點繪製marker標記。

  1. # 方法需要輸入終點城市名稱(city)和經緯度(data)

  2. 呼叫先前建立的project()方法,將終點經緯度轉換為平面座標。

  3. 計算起點(長沙)和終點之前的距離,做為線條長度和動畫時間參數。

  4. 在線條上繪製一個圓形標記,並實現從起點到終點的移動動畫

  5. 標記移動到終點後,即刪除,節省資源。

  6. 如果線點在之前已經繪製過,則不繪製線條,只繪製移動標記。

  7. 每處理一次物流單,則城市記錄 1。

// 创建对象,保存每个城市的物流记录数量
    var citylist = new Object();
    // 创建方法,输入data坐标,绘制发射线
    var moveto = function(city, data){
      var pf = {x:projection([112.59,28.12])[0], y:projection([112.59,28.12])[1]};
      var pt = {x:projection(data)[0], y:projection(data)[1]};
      var distance = Math.sqrt((pt.x - pf.x)**2 + (pt.y - pf.y)**2);
      if (city in citylist){
        citylist[city]++;
      }else{
        mline.append("line")
            .attr("x1", pf.x)
            .attr("y1", pf.y)
            .attr("x2", pt.x)
            .attr("y2", pt.y)
            .attr("marker-end","url(#pointer)")
            .style("stroke-dasharray", " "+distance+", "+distance+" ")
            .transition()
            .duration(distance*30)
            .styleTween("stroke-dashoffset", function(){
              return d3.interpolateNumber(distance, 0);
            });
        citylist[city] = 1;
      };
      mline.append("circle")
        .attr("cx", pf.x)
        .attr("cy", pf.y)
        .attr("r", 3)
        .transition()
        .duration(distance*30)
        .attr("transform", "translate("+(pt.x-pf.x)+","+(pt.y-pf.y)+")")
        .remove();
    };

建立動畫隊例,實現標記外圈的閃爍效果

var scale = d3.scaleLinear();
    scale.domain([0, 1000, 2000])
      .range([0, 1, 0]);
    var start = Date.now();
    d3.timer(function(){
      var s1 = scale((Date.now() - start)%2000);
      // console.log(s1);
      gmap.select("circle#changshaC")
        .attr("stroke-opacity", s1);
      marker.select("circle#markerC")
        .attr("stroke-opacity", s1);
    });

創建測試按鈕和測試的目標城市數據

var cityordinate = {
      '哈尔滨':[126.5416150000,45.8088260000],
      '石家庄':[116.46,39.92],
      '北京':[116.39564503787867,39.92998577808024],
      '上海':[121.480539,31.235929],
      '广州':[113.271431,23.135336],
      '重庆':[106.558434,29.568996],
      '青岛':[120.38442818368189,36.10521490127382],
      '福州':[119.30347,26.080429],
      '兰州':[103.840521,36.067235],
      '贵阳':[106.636577,26.653325],
      '成都':[104.081534,30.655822],
      '西安':[108.946466,34.347269],
      '长春':[125.3306020000,43.8219540000],
      '台湾':[120.961454,23.80406],
      '呼和浩特':[111.7555090000,40.8484230000],
      '澳门':[113.5494640000,22.1929190000],
      '武汉':[114.3115820000,30.5984670000],
      '昆明':[102.71460113878045,25.049153100453159],
      '乌鲁木齐':[87.56498774111579,43.84038034721766],
      '益阳':[112.36654664522563,28.58808777988717],
      '南京':[118.77807440802562,32.05723550180587],
      '武昌':[114.35362228468498,30.56486029278519],
    };
    // 随机获得目标城市
    var cityname = [], total = 0;
    for (var key in cityordinate){
      cityname[total++] = key;
    };
    
    // 创建操作按钮,每次点击发射一条物流线
    button.append("circle")
        .attr("cx", width*0.9)
        .attr("cy", height*0.8)
        .attr("r", width/20)
        .attr("text","click")
        .attr("fill", "grey");
    button.append("text")
        .attr("x", width*0.87)
        .attr("y", height*0.81)
        .style("font-size", "30px")
        .text("click");
    button.on("click", function(){
      var _index = ~~(Math.random() * total);
      moveto(cityname[_index], cityordinate[cityname[_index]]);
    });

相信看了本文案例你已經掌握了方法,更多精彩請關注php中文網其它相關文章!

推薦閱讀:

$.ajax()方法如何從伺服器取得json資料

vue實作購物車的小球拋物線效果詳解

#

以上是使用D3.js創建物流地圖的步奏詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn