本文主要介紹了使用D3.js創建物流地圖的範例程式碼,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟著小編過來看看吧,希望能幫助大家。
範例圖
製作想法
#需要繪製一張中國地圖,做為背景。
需要主要城市的經緯座標,以繪製路張起點和終點。
接收到物流單的城市,繪製一個閃爍的標記。
已經有過物流單的目標城市,不再繪製路線。
每次新產生一筆物流單,都有一個標記沿著路線移向目標的動畫效果。
繪製結束後的數據,需要清理掉,以減少對瀏覽器的資源佔用。
開始擼碼
#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,以下所有程式碼放在3f1c4e4b6b16bbbd69b2ee476dc4f83a2cacc6d41bbb37262a98f745aa00fbf0中
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圖形分組,以備呼叫
gmp,儲存背景地圖和起點標記。
mline,保存起點和目標之間的連線,以及目標點。
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");
建立投影函數
經緯度不能直接用來繪圖,需要轉換成平面座標。 d3js提供了比較豐富的投影方法,本例中使用了geoEquirectangular()方法。
projection 是將經緯度轉換為平面座標的方法
path 是一種將經緯度轉換為連線繪製點座標的方法(省得自己再寫函數建構path路徑)
var projection = d3.geoEquirectangular() .center([465,395]) // 指定投影中心,注意[]中的是经纬度 .scale(height) .translate([width / 2, height / 2]); var path = d3.geoPath().projection(projection);
建立marker標記,以便多個連線終點呼叫
由於會有多個物流連線的終點,所以都放在一個marker標記中呼叫。
這個標記是由中間的 圓形 + 外圈 構成。外圈的閃爍效果另外創建。
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標記。
方法需要輸入終點城市名稱(city)和經緯度(data)
呼叫先前建立的project()方法,將終點經緯度轉換為平面座標。
計算起點(長沙)和終點之前的距離,做為線條長度和動畫時間參數。
在線條上繪製一個圓形標記,並實現從起點到終點的移動動畫。
標記移動到終點後,即刪除,節省資源。
如果線點在之前已經繪製過,則不繪製線條,只繪製移動標記。
每處理一次物流單,則城市記錄+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]]); });
相關推薦:
#以上是D3.js建立物流地圖實例分享的詳細內容。更多資訊請關注PHP中文網其他相關文章!