Skip to main content

Day27 互動

一、監聽器

D3可以在元素上增加監聽器,語法為 selection.on(type, function)

寫起來會非常的似曾相識,簡直就像在寫jquery一樣。比如以下程式,點擊元素後將文字”Click Me"修改為”Thank You"

<p id="mytest">
Click Me
</p>
var mytest = d3.select("#mytest")
.on("click", function(){
d3.select(this).text("Thank You")
})

另外滑鼠事件還有:

mouseover 游標移入 mousemove 游標移動 mousedown 滑鼠點擊按下 mouseup 滑鼠點擊放開

以下為游標移入移出時修改文字的範例

mytest.on("mouseover", function(){
d3.select(this).text("Right Here")
})
.on("mouseout", function(){
d3.select(this).text("Click Me")
})

程式範例連結:http://jsfiddle.net/upstairs0102/nwxk6ouj/

二、取得游標座標

在事件函式當中,可以使用 d3.mouse(this) 來取得滑鼠游標座標,格式為陣列 [x,y]

另一種方式是d3.event.xd3.event.y各別取得xy座標。

在以下範例首先繪製一個矩形。

var svg = d3.select("body").append("svg")
.attr("width", 500)
.attr("height", 500)

var rect = svg.append("rect")
.attr("fill", "steelblue")
.attr("width", 50)
.attr("height", 50)
.attr("x", 100)
.attr("y", 100)

接著在矩形上增加一個點擊事件,並輸出滑鼠游標座標。

當滑鼠在矩最右上角點擊時,會輸出陣列[150,50](x座標150、y座標為100)

rect.on("click", function(){
console.log(d3.mouse(this)) // [50,50]
})

在範例中再做一些變化,這裡我們希望游標移過矩形上方時,會隨著游標的移動、在游標的右側以文字顯示目前游標的座標,而移出矩形時文字的消失。

首先繪製一個隱藏的<text>在畫面當中,所以要設定屬性display為”none”

var text = svg.append("text")
.attr("display", "none")

在矩形上增加mouseove事件,當游標經過時設定<text>的座標為游標x軸+50、游標y軸座標,並將display設為null將文字顯示出來。當游標移出時再重新把display設為”none”隱藏。

rect
.on("mousemove", function(){
var x = d3.mouse(this)[0]
var y = d3.mouse(this)[1]

text.attr("display", null) // 取消隱藏
.attr("x", x + 20)
.attr("y", y)
.text("[" + x + "," + y + "]")
})
.on("mouseout", function(){
text.attr("display", "none")
})

程式範例連結:http://jsfiddle.net/upstairs0102/o5rz1e8m/

在D3當中除了滑鼠事件之外,還有鍵盤、行動裝置的點擊事件。

三、拖曳

拖曳事件在D3當中的寫法不太一樣,除了拖曳動作之外,還有縮放(zoom)動作都是屬於d3.behavior當中的方法。

建立一個拖曳行為的語法為 d3.behavior.drag

建立拖曳行為後首先要使用origin設定拖曳的起點座標。

在拖曳行為當中可建立監聽事件:

dragstart 拖曳開始事件 dragend 拖曳結束事件 drag 拖曳事件(開始及結束之間)

以下程式範例中建立一個拖曳行為。

這一個拖曳行為是要給圓形元素使用的,所以在取得座標時,origin中設定的起始座標為圓心座標(cx及cy)、而drag拖曳事件中將拖曳對象的cx及cy。

var drag = d3.behavior.drag()
.origin(function(d,i){
return {x: d.cx, y: d.cy}
})
.on("dragstart", function(d){
console.log("拖曳開始")
})
.on("dragend", function(d){
console.log("拖曳結束")
})
.on("drag", function(d){
d3.select(this)
.attr("cx", d.cx = d3.event.x) // d3.event.x取得游標x座標
.attr("cy", d.cy = d3.event.y) // d3.event.y取得游標y座標
})

其中比較要注意的是,如果沒有設定origin,拖曳座標會等同滑鼠座標,滑鼠游標點擊時,無論點擊的位置在圓形的哪一個位置,圓形會移動到圓心和游標對齊。

接著,將兩個圓形元素加入到畫布中,並使用call將拖曳行為加入即完成。

var circles = [{cx: 150, cy: 200, r: 30},
{cx: 250, cy: 200, r: 30}]

svg.selectAll("circle")
.data(circles)
.enter()
.append("circle")
.attr("cx", function(d){ return d.cx })
.attr("cy", function(d){ return d.cy })
.attr("r", function(d){ return d.r })
.attr("fill", "steelblue")
.call(drag)

範例程式連結:http://jsfiddle.net/upstairs0102/m073ncb5/