使用D3.js創(chuàng)建物流地圖的示例代碼
本文介紹了使用D3.js創(chuàng)建物流地圖的示例代碼,分享給大家,具體如下:
示例圖

制作思路
- 需要繪制一張中國地圖,做為背景。
- 需要主要城市的經(jīng)緯坐標(biāo),以繪制路張起點和終點。
- 接收到物流單的城市,繪制一個閃爍的標(biāo)記。
- 已經(jīng)有過物流單的目標(biāo)城市,不再繪制路線。
- 每次新產(chǎn)生一筆物流單,都有一個標(biāo)記沿路線移向目標(biāo)的動畫效果。
- 繪制結(jié)束后的數(shù)據(jù),需要清理掉,以減少對瀏覽器的資源占用。
開始擼碼
1.創(chuàng)建網(wǎng)頁模板
加載D3JS,為了方便調(diào)試,直接下載d3.js文件在本地,實際使用的時候,可以換成加載路徑。注意,使用的是V4版的D3,和V3版有差異。
創(chuàng)建一個DIV塊,準(zhǔn)備繪圖。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf8">
<script type="text/javascript" src="../../static/d3/d3.js"></script>
<title>地圖</title>
</head>
<body>
<div class="fxmap">
</div>
</body>
<script type="text/javascript"></script>
</html>
創(chuàng)建SVG,以下所有代碼放在<script></script>中
var width=1000 , height=800; // 定義SVG寬高
var svg = d3.select("body div.fxmap")
.append("svg")
.attr("width", "width)
.attr("height", height)
.style("background","#000"); //
創(chuàng)建SVG圖形分組,以備調(diào)用
- gmp,保存背景地圖和起點標(biāo)記。
- mline,保存起點和目標(biāo)之間的連線,以及目標(biāo)點。
- 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");
創(chuàng)建投影函數(shù)
- 經(jīng)緯度不能直接用來繪圖,需要轉(zhuǎn)換成平面坐標(biāo)。d3js提供了比較豐富的投影方法,本例中使用了geoEquirectangular()方法。
- projection 是將經(jīng)緯度轉(zhuǎn)換為平面坐標(biāo)的方法
- path 是將經(jīng)緯度轉(zhuǎn)換為連線繪制點坐標(biāo)的方法(省得自己再寫函數(shù)構(gòu)造path路徑)
var projection = d3.geoEquirectangular()
.center([465,395]) // 指定投影中心,注意[]中的是經(jīng)緯度
.scale(height)
.translate([width / 2, height / 2]);
var path = d3.geoPath().projection(projection);
創(chuàng)建marker標(biāo)記,以便多個連線終點調(diào)用
- 由于會有多個物流連線的終點,所以都放在一個marker標(biāo)記中調(diào)用。
- 這個標(biāo)記是由中間的 圓形 + 外圈 構(gòu)成。外圈的閃爍效果另外創(chuàng)建。
marker = svg.append("defs")
.append("marker")
.append("marker")
.attr("id", "pointer")
.attr("viewBox","0 0 12 12") // 可見范圍
.attr("markerWidth","12") // 標(biāo)記寬度
.attr("markerHeight","12") // 標(biāo)記高度
.attr("orient", "auto") //
.attr("markerUnits", "strokeWidth") // 隨連接線寬度進行縮放
.attr("refX", "6") // 連接點坐標(biāo)
.attr("refY", "6")
// 繪制標(biāo)記中心圓
marker.append("circle")
.attr("cx", "6")
.attr("cy", "6")
.attr("r", "3")
.attr("fill", "white");
// 繪制標(biāo)記外圓,之后在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");
繪制中國地圖,并標(biāo)記起點(長沙)
地圖使用的經(jīng)緯集為china.json,這個文件網(wǎng)上有很多
// 記錄長沙坐標(biāo)
var changsha = projection([112.59,28.12]);
// 讀取地圖數(shù)據(jù),并繪制中國地圖
mapdata = [];
d3.json('china.json', function(error, data){
if (error)
console.log(error);
// 讀取地圖數(shù)據(jù)
mapdata = data.features;
// 繪制地圖
gmap.selectAll("path")
.data(mapdata)
.enter()
.append("path")
.attr("d", path);
// 標(biāo)記長沙
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");
});
創(chuàng)建方法,繪制一條從指定起點到終點的連線,并在絡(luò)點繪制marker標(biāo)記。
- 方法需要輸入終點城市名稱(city)和經(jīng)緯度(data)
- 調(diào)用之前建立的project()方法,將終點經(jīng)緯度轉(zhuǎn)換為平面坐標(biāo)。
- 計算起點(長沙)和終點之前的距離,做為線條長度和動畫時間參數(shù)。
- 在線條上繪制一個圓形標(biāo)記,并實現(xiàn)從起點到終點的移動動畫。
- 標(biāo)記移動到終點后,即刪除,節(jié)省資源。
- 如果線點在之前已經(jīng)繪制過,則不繪線條,只繪制移動標(biāo)記。
- 每處理一次物流單,則城市記錄+1。
// 創(chuàng)建對象,保存每個城市的物流記錄數(shù)量
var citylist = new Object();
// 創(chuàng)建方法,輸入data坐標(biāo),繪制發(fā)射線
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();
};
創(chuàng)建動畫隊例,實現(xiàn)標(biāo)記外圈的閃爍效果
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);
});
創(chuàng)建測試按鈕和測試的目標(biāo)城市數(shù)據(jù)
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],
};
// 隨機獲得目標(biāo)城市
var cityname = [], total = 0;
for (var key in cityordinate){
cityname[total++] = key;
};
// 創(chuàng)建操作按鈕,每次點擊發(fā)射一條物流線
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]]);
});
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
詳解Javacript和AngularJS中的Promises
這篇文章主要介紹了詳解Javacript和AngularJS中的Promises的相關(guān)資料,promise是Javascript異步編程很好的解決方案。,需要的朋友可以參考下2016-02-02
用js實現(xiàn)每隔一秒刷新時間的實例(含年月日時分秒)
下面小編就為大家?guī)硪黄胘s實現(xiàn)每隔一秒刷新時間的實例(含年月日時分秒)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-10-10
實用的js 焦點圖切換效果 結(jié)構(gòu)行為相分離
行為層是由js來實現(xiàn)的,這里的工作只是搭建了一個簡單的骨架,如果要讓效果圖美觀些并符合設(shè)計要求,就要發(fā)揮css的強大作用了。2010-06-06
npm install報錯無法創(chuàng)建packge.json文件的解決辦法
當(dāng)你在運行 npm install 時遇到錯誤,提示無法找到 package.json 文件,也沒有創(chuàng)建一個 package.json 文件,只創(chuàng)建了一個package-lock.json文件,本文給大家介紹詳細(xì)的解決辦法,需要的朋友可以參考下2024-02-02
JavaScript的Set數(shù)據(jù)結(jié)構(gòu)詳解
這篇文章主要為大家介紹了JavaScript的Set數(shù)據(jù)結(jié)構(gòu),具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2022-01-01
腳本之家貼圖轉(zhuǎn)換+轉(zhuǎn)貼工具用到的js代碼超級推薦
[紅色]腳本之家貼圖轉(zhuǎn)換+轉(zhuǎn)貼工具用到的js代碼超級推薦...2007-04-04

