【 D3.js 入門系列 --- 10.2 】 可拖動的地圖
阿新 • • 發佈:2019-01-30
轉載請註明出處,謝謝。
本節是結合9.2節 和10節 的內容製作的一個可力學導向的中國地圖,使用者可以拖動中國的各個省份。
1. 定義各函式
projection 函式是用於將三維地圖的座標投影到二維所用的投影函式。具體可見: 10節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();
path 函式用於繪製地圖路徑,裡面要傳入投影函式 projection 。具體可見: 10節
force 是定義力學圖的 layout 。具體可見: 9.2節
color 是顏色函式。
2. 讀取資料
和前幾節一樣,用 d3.json() 讀取檔案,後面兩句是用於檢測錯誤,以及輸出錯誤資訊。d3.json("china_simplify.json", function(error, root) { if (error) return console.error(error); console.log(root.features); }
3. 轉換資料
讀取後的檔案資訊都存在變數 root 中,上面的程式碼是將 root 中的資料分別轉換為力學圖所需要的點和線,存在變數 nodes 和 links 中。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] ) ); });
第1-2行: 定義變數 nodes 和 links
第4-10行: 對於 root.features 中存有每一個省的資料, root.features.forEach() 即對每一個省的資料,執行後面的無名函式,函式裡面是計算出各省的中點,儲存在 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)
};
}
4. 繪製地圖
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行: 繪製連線各省的線條。
5. 力學圖的結合
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 + ")";
});
});
這裡和
9.2節 一樣,tick 指的是時間間隔,也就是每一個時間間隔之後就重新整理一遍畫面,重新整理的內容寫在後面的無名函式 function 中, function 函式中寫上作圖的內容。這裡看到了吧,第7-9行裡是用於平移的,平移的引數為 d.x 和 d.y 。
結果圖:
拖動試試吧,哈哈:
自己用滑鼠試試吧,點選下面的連結,完整程式碼請右鍵點選瀏覽器後選擇檢視:
謝謝閱讀。