本篇大綱:d3.brush( )、brush 的 API 們、範例
今天我們要來看本系列的最後一個互動效果,那就是 — Brush 刷子啦
!Brush 的功能是用來選取(刷取) 圖表上的區間段
,接著再看我們想對此區間段內的元素做什麼事 (變色、移位、放大縮小等等)。基本上的效果會像這個樣子,長方形的部分就是我們用 brush 選起來的區間~
了解 brush 怎麼運作之後,我們現在來看看官方文件提供哪些 API 給 brush這個功能吧!由於 d3.brush 主要只是用來建立選取區間,相對來說是個容易一點的功能,因此 D3 提供來處理 brush 效果的 API 們也比較少,以下就是全部的 API
下面我一樣會介紹幾個比較常用的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(事件, 方法 )
我們一樣先看到官方文件的解說:
這個方法是用來監聽 brush 事件,而 brush 事件又可以分成三種
因此,我們可以針對不同的事件使用不同的方法
svg.append("g")
.attr("class", "brush")
.call(d3.brush()
.on("start brush", brushed)
.on('end' brushEnd)
)
一旦我們開始監聽 brush event 之後,每個 event 就會包含以下幾種屬性
target
- 觸發brush 行為的元素type
-目前的事件為何,例如 start、brush、endselection
- 目前綁定node節點的 brush 選取集合。這個集合一般是包含數字的陣列,如果brush是二維,此集合的屬性值會是[[x0, y0], [x1, y1]]。我們會運用 event.selection 來判斷DOM元素是否在brush的範圍內
sourceEvent
- 原生事件,例如 mousemove 或 touchmovemode
- 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")
現在的畫面是這樣
接著,我們來建立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;
}
這樣就完成囉~
除了改變元素的顏色之外,brush 效果通常是用來搭配 zoom 效果進行圖表的縮放,不過這個要用完整圖表來示範比較清楚,所以我們就留到之後的範例來解講吧
終於講完 D3 全部的的互動效果了(累倒),明天開始我們就要進入另一個大重點:軸線跟比例尺!學會了之後就可以畫各種想畫的圖表啦~~
最後一樣附上本章的程式碼與圖表 Github 、 Github Page,需要的人請自行取用~