# D3

一個可以簡單用 JS 操作 SVG 的框架。

## 推薦資料來源：

{% embed url="<https://www.gapminder.org/data/>" %}

## 使用

主要會使用到包含：

```javascript
<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.選擇元素

```javascript
d3.select('')
d3.selectAll('')
```

2.設定屬性

```javascript
d3.select('').attr('width', 20)
```

設定 style

```javascript
.style("fill", "#69b3a2")
```

3.新增元素

```javascript
d3.select('').append("svg")
```

4.設定相關範圍，讓數值縮小

```javascript
const x = d3.scaleLinear()
    .domain([0, 4000]) // 數值範圍
    .range([ 0, width ]); // 實際顯示範圍
```

5.傳入資料並且遍歷

> 記得 append 前要用 selectAll 相同東西，不然不會顯示

```javascript
const data = [{...}...]

d3.select('#test')
    .selectAll('circle')
    .data(data)
    .enter() // 類似forEach
    .append("circle")
```

6.添加座標軸

```javascript
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\. 加上動畫

```javascript
    .transition()
    .duration(1000)
```

## 地圖

typojson 比 geojson 檔案小。

以下範例讀取 typojson 然後用 相關套件轉換為geojson 並顯示到 d3 上

<https://github.com/topojson/topojson-client/blob/master/README.md#feature>

```javascript
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");
});
```

### 加上地圖線

```javascript
    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

```css
.graticule {
    fill: none;
    stroke: #777;
    stroke-width: .5px;
    stroke-opacity: .2;
    pointer-events: none;
}
.graticule.outline {
    stroke-width: 2px;
  }
```

{% embed url="<https://github.com/d3/d3-geo/blob/master/README.md#geoGraticule>" %}

{% embed url="<https://bl.ocks.org/mbostock/3664049>" %}

### &#x20;更新 x 與 y 軸

> merge 與 exit().remove() 是給傳入 .data 用的，如果是軸要用以下方式判斷

```javascript
    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 標籤下

```javascript
      // 畫 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');
```

## 事件綁定

點擊後觸發顏色改變

```javascript
      ......
      .on('click', function(e) {
        d3.select(this).style("fill", 'black');
      })
```

讓顏色變深

```javascript
      .on('click', function(e) {
        d3.select(this).style("fill", d3.color(d3.select(this).attr("fill")).darker());
      })
```

## 隱藏動畫

如果要讓隱藏和顯示有動畫，必須用 opacity，`display: none` 會沒作用

```javascript
      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>
