iT邦幫忙

2021 iThome 鐵人賽

DAY 16
0
Modern Web

三十天成為D3.js v7 好手系列 第 16

Day16-D3 的 Brush 刷子

  • 分享至 

  • xImage
  •  

本篇大綱:d3.brush( )、brush 的 API 們、範例

今天我們要來看本系列的最後一個互動效果,那就是 — Brush 刷子啦!Brush 的功能是用來選取(刷取) 圖表上的區間段,接著再看我們想對此區間段內的元素做什麼事 (變色、移位、放大縮小等等)。基本上的效果會像這個樣子,長方形的部分就是我們用 brush 選起來的區間~

https://ithelp.ithome.com.tw/upload/images/20210928/20134930q7xNkb5oWP.jpg

了解 brush 怎麼運作之後,我們現在來看看官方文件提供哪些 API 給 brush這個功能吧!由於 d3.brush 主要只是用來建立選取區間,相對來說是個容易一點的功能,因此 D3 提供來處理 brush 效果的 API 們也比較少,以下就是全部的 API

https://ithelp.ithome.com.tw/upload/images/20210928/20134930khqP6V00KZ.jpg

下面我一樣會介紹幾個比較常用的API,想了解更多的人歡迎自行上官網查看~

d3.brush( )、d3.brushX( )、d3.brushY( )

我們先來看看最主要用來建立 brush 的方法 — d3.brush( )。當我們使用 d3.brush( )時,它會建立一個二維 brush 並自動帶入svg的滑鼠跟觸控事件,我們就能用滑鼠或手指觸控來進行操作。

除了使用d3.brush( ) 之外,如果你只想建立一維X軸向的brush,可以用 d3.brushX( ) 這個API;反之如果想建立一維Y軸向的brush,則是使用d3.brushY( )。

建立好brush之後,我們接著使用 selection.call( )的方法把建立好的 brush 綁定到選定的DOM元素上,然後就可以使用 brush.on(事件,方法) 來監聽 brush 事件

svg.append("g")
    .attr("class", "brush")
    .call(d3.brush().on("brush", brushed));

brush.on(事件, 方法 )

我們一樣先看到官方文件的解說:
https://ithelp.ithome.com.tw/upload/images/20210928/20134930AXV1zZNe3I.jpg

這個方法是用來監聽 brush 事件,而 brush 事件又可以分成三種

  • start
  • brush
  • end

因此,我們可以針對不同的事件使用不同的方法

svg.append("g")
    .attr("class", "brush")
    .call(d3.brush()
            .on("start brush", brushed)
						.on('end' brushEnd)
          )

一旦我們開始監聽 brush event 之後,每個 event 就會包含以下幾種屬性
https://ithelp.ithome.com.tw/upload/images/20210928/20134930tBEKT0YyrU.jpg

  • target - 觸發brush 行為的元素
  • type -目前的事件為何,例如 start、brush、end
  • selection - 目前綁定node節點的 brush 選取集合。這個集合一般是包含數字的陣列,如果brush是二維,此集合的屬性值會是[[x0, y0], [x1, y1]]。我們會運用 event.selection 來判斷DOM元素是否在brush的範圍內
  • sourceEvent - 原生事件,例如 mousemove 或 touchmove
  • mode - brush當下的狀態,例如 drag、space、handle、center 等等.

brush.extent([[x0, y0], [x1, y1]])

這個方法是用來設定可以刷取的範圍,[x0, y0] 是設定左上角位置,[x1, y1]則是設定右下角位置。一般來說會設定的跟svg一樣大或是稍微大一點

svg.append("g")
    .attr("class", "brush")
    .call(d3.brush()
            .extent( [ [0,0], [width, height] ])
            .on("start brush", brushed)
          )

brush.handleSize([size])

這個方法則是用來設置 brush 把柄的大小。沒有特別設定的話,其預設尺寸為6。這個方法必須要在用selection.call( ) 呼叫並綁定brush 之前就使用。


實際範例

看完上面brush能使用的方法後,我們直接來實際操作看看吧!首先,我們在畫面上建立兩個圓點

// html
<div class="chartContainer"></div>

// js
const data = [{r:20, x:200, y:120},{r:35, x:350, y:280}]

// svg
const svg = d3.select('.chartContainer')
        .append('svg')
        .attr('width', 500)
        .attr('height', 500);

// 放上點點
const dots = svg.selectAll('circle')
                .data(data)
                .enter()
                .append('circle')
                .attr('r', d => d.r)
                .attr('cx', d => d.x)
                .attr('cy', d => d.y)
                .style("fill", "#19d3a2")

現在的畫面是這樣
https://ithelp.ithome.com.tw/upload/images/20210928/20134930567rYsvAuj.jpg

接著,我們來建立brush吧~由於我們希望被brush選到後圓點點會變色,因此我們在css 設定一個 selected 來處理變色的事情,然後在刷子運作時把這個class賦予到圓點上

// css 檔案 或 style 加上
.selected{
  fill: blue !important
}

// 加上brush
svg.append("g")
.attr("class", "brush")
.call(d3.brush()
        .extent( [ [0,0], [600,600] ]) // extent限制刷子的活動區塊,理想是比畫布稍大
        .on("start brush", brushed) // brush 事件
      )

// brush 的功能
// 加上event參數,就能用 event.selection
// selection會產出一個二維陣列,分別代表`x0`, `x1`, `y0`, `y1`,左上到右下的位置,讓你有辦法重新計算目前位置的extent,進而進行其他操作。
function brushed(event){
    console.log(event)
    const extent = event.selection
    dots.classed('selected', d => {return isBrushed(extent, d.x, d.y)})
}

接下來,因為畫面上有兩個點點,我們要設定刷子的範圍刷到哪個圓點時,圓點才要變色,因此我們要設定isbrushed的方法確認圓點是否在brush選到的區塊內

// 設定圓點是否在brush選到的區塊內
function isBrushed(brush_coors, cx, cy){
  let x0 = brush_coors[0][0],
      x1 = brush_coors[1][0],
      y0 = brush_coors[0][1],
      y1 = brush_coors[1][1]

    // 如果圓點在brush的範圍內,就會傳true;反之則回傳false
    console.log(x0 <= cx && cx <= x1 && y0 <= cy && cy <= y1)
    return x0 <= cx && cx <= x1 && y0 <= cy && cy <= y1; 
}

這樣就完成囉~
https://i.imgur.com/BJq4vYI.gif

除了改變元素的顏色之外,brush 效果通常是用來搭配 zoom 效果進行圖表的縮放,不過這個要用完整圖表來示範比較清楚,所以我們就留到之後的範例來解講吧

終於講完 D3 全部的的互動效果了(累倒),明天開始我們就要進入另一個大重點:軸線跟比例尺!學會了之後就可以畫各種想畫的圖表啦~~


Github Page 圖表與 Github 程式碼

最後一樣附上本章的程式碼與圖表 GithubGithub Page,需要的人請自行取用~


上一篇
Day15-D3 的 Zoom 縮放
下一篇
Day17-D3 的 Scale( ) 比例尺
系列文
三十天成為D3.js v7 好手30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言