一個可以簡單用 JS 操作 SVG 的框架。
推薦資料來源:
使用
主要會使用到包含:
Copy < line > elements for the edges
< text > elements for the labels
< circle > elements to represent the nodes
< g > elements as containers that move the nodes and labels together
1.選擇元素
Copy d3 .select ( '' )
d3 .selectAll ( '' )
2.設定屬性
Copy d3 .select ( '' ) .attr ( 'width' , 20 )
設定 style
Copy .style ( "fill" , "#69b3a2" )
3.新增元素
Copy d3 .select ( '' ) .append ( "svg" )
4.設定相關範圍,讓數值縮小
Copy const x = d3 .scaleLinear ()
.domain ([ 0 , 4000 ]) // 數值範圍
.range ([ 0 , width ]); // 實際顯示範圍
5.傳入資料並且遍歷
記得 append 前要用 selectAll 相同東西,不然不會顯示
Copy const data = [{ ... } ... ]
d3 .select ( '#test' )
.selectAll ( 'circle' )
.data (data)
.enter () // 類似forEach
.append ( "circle" )
6.添加座標軸
Copy const data = [{
case : 23 ,
} ... .]
let aScale = d3
.scaleLinear ()
.domain ([ 0 , d3 .max (data , (d) => d .cases)])
.range ([ 0 , 300 ]);
d3 .select ( "#scatterplot #x-axis" )
.call ( d3 .axisBottom (aScale) .ticks ( 5 ));
7. 加上動畫
Copy .transition ()
.duration ( 1000 )
地圖
typojson 比 geojson 檔案小。
以下範例讀取 typojson 然後用 相關套件轉換為geojson 並顯示到 d3 上
https://github.com/topojson/topojson-client/blob/master/README.md#feature
Copy d3 .json ( 'data/world.json' ) .then (world => {
let projection = d3 .geoWinkel3 () .scale ( 140 ) .translate ([ 365 , 225 ]);
let geoPath = d3 .geoPath (projection);
const svg = d3
.select ( "#map-chart" )
.append ( "svg" )
.attr ( "width" , 365 * 2 )
.attr ( "height" , 225 * 2 );
svg
.selectAll ( "path" )
.data ( topojson .feature (world , world . objects .countries).features)
.enter ()
.append ( "path" )
.attr ( "d" , geoPath)
.attr ( "class" , "country" );
});
加上地圖線
Copy var graticule = d3 .geoGraticule ();
svg
.append ( "path" )
.datum (graticule)
.attr ( "class" , "graticule line" )
.attr ( "d" , geoPath);
svg
.append ( "path" )
.datum ( graticule .outline)
.attr ( "class" , "graticule outline" )
.attr ( "d" , geoPath);
css
Copy .graticule {
fill : none ;
stroke : #777 ;
stroke-width : .5 px ;
stroke-opacity : .2 ;
pointer-events : none ;
}
.graticule.outline {
stroke-width : 2 px ;
}
更新 x 與 y 軸
merge 與 exit().remove() 是給傳入 .data 用的,如果是軸要用以下方式判斷
Copy if ( ! document .querySelector ( '.wrapper-group g' )) {
// 第一次 init
d3 .select ( ".wrapper-group" )
.attr ( "transform" , "translate(180, 10)" )
.append ( "g" )
.attr ( "id" , "x-axis" )
.attr ( "transform" , `translate(0, ${ this .height } )` )
.call ( d3 .axisBottom (xScale) .ticks ( 5 ));
d3 .select ( ".wrapper-group" )
.append ( "g" )
.attr ( "id" , "y-axis" )
.attr ( "transform" , "translate(0,0)" )
.call ( d3 .axisLeft (yScale) .ticks ( 5 ));
} else {
// 更新 axis
d3 .select ( ".wrapper-group #x-axis" )
.call ( d3 .axisBottom (xScale) .ticks ( 5 ));
d3 .select ( ".wrapper-group #y-axis" )
.call ( d3 .axisLeft (yScale) .ticks ( 5 ));
}
畫 x, y 軸標籤
必須要手動添加 text,如果沒有顯示試著加在 svg 標籤下
Copy // 畫 y 軸 標籤
d3 .select ( ".plot-svg" )
.append ( "g" )
.attr (
"transform" ,
"translate(" + this .width / 6 + ", " + this .height / 2 + ")"
)
.append ( "text" )
.attr ( "text-anchor" , "middle" )
.attr ( "transform" , "rotate(-90)" )
.text ( 'test' );
事件綁定
點擊後觸發顏色改變
Copy ......
.on ( 'click' , function (e) {
d3 .select ( this ) .style ( "fill" , 'black' );
})
讓顏色變深
Copy .on ( 'click' , function (e) {
d3 .select ( this ) .style ( "fill" , d3 .color ( d3 .select ( this ) .attr ( "fill" )) .darker ());
})
隱藏動畫
如果要讓隱藏和顯示有動畫,必須用 opacity,display: none
會沒作用
Copy d3 .select (ele)
.select ( "text" )
.transition ()
.duration ( 600 )
.attr ( "opacity" , switchOn ? 1 : 0 );
Forcing
類似於物體碰撞等物理效果
https://github.com/d3/d3-force
v3 之後的用法有改變
範例:
https://codepen.io/EasonWang01/pen/RwRoXZb https://bl.ocks.org/HarryStevens/f636199a46fc4b210fbca3b1dc4ef372