d3-drag
Drag-and-drop
是一種易學流行的交互手勢:將指針指向目標對象,按下並且拖動它到一個新的位置,然後釋放。D3 的 drag 提供了方便靈活並且抽象的拖拽交互。
例子 🌰:
◎ d3.drag()
創建一個新的拖拽行爲並返回自身。drag
既是一個對象,也是一個函數,通常通過 selection.call
被應用在選中的元素上。
var drag = d3.drag();
◎ drag(selection)
將拖拽應用到指定的 selection
。通常不用這個方法來應用拖拽,而是通過 selection.call
。例如,將拖拽實例應用到一個選擇集上:
d3.selectAll(".node").call(d3.drag().on("start", started));
在內部拖拽行爲使用 selection.on
將拖拽必需的事件綁定到元素上,事件名稱都帶有 .drag
,因此可以使用這個特殊的事件名來解綁拖拽事件:
selection.on(".drag", null);
◎ drag.container([container])
如果指定了 container
,則將拖拽行爲的容器訪問器設置爲指定的對象或方法。如果沒有指定 container
,則返回當前的容器訪問器,默認爲:
function container() {
return this.parentNode;
}
拖拽手勢的 container
定義了隨後 drag events 的座標系統,影響 event.x
和 event.y
。容器訪問器返回的元素隨後被傳遞給 d3.mouse
或 d3.touch
,因此需要的時候要定義好容器訪問器。
默認的容器訪問器返回接收到初始事件的元素的父節點,在拖動 SVG 或者 HTML 元素時,通常是合理的,因爲這些元素通常通過父元素定位。但是拖動 Canvas 中的元素時,你可能需要將容器訪問器設置爲 Canvas
自身:
function container() {
return this;
}
此外,設置容器訪問器時,還可以直接將元素設置爲參數:
drag.container(canvas)
◎ drag.subject([subject])
subject
譯爲主體,如果 subject
指定,則爲拖拽行爲指定主體訪問器。如果沒有指定,則返回當前的主體訪問器。默認爲:
function subject(d) {
return d == null ? {x: d3.event.x, y: d3.event.y} : d;
}
主體代表的是 the thing being dragged (當前被拖拽) 的東西。當接收到啓動輸入事件時被計算,比如 mousedown
或 touchstart
, 在拖拽啓動時立即被計算。
默認情況下,主體爲接收原始事件元素上的 datum
。 如果 datum 沒有定義,則主體爲輸入事件的座標。當在 SVG 中拖拽時,默認的主體爲當前元素綁定的數據;但在 Canvas 中默認的主體爲 Canvas 本身綁定的數據,此時自定義的主體訪問器就顯得有用了,比如,可以將自定義主體訪問器設置爲鼠標事件座標周圍一定半徑範圍內的圓。
◎ drag.on(typenames, [listener])
此方法用於設置用於拖動的指定類型名的事件偵聽器。如果 listener
指定,則將其設置爲對應的 typenames
的回調。
如果對應 typenames
已經存在事件監聽器則將其替換掉;如果 listener
爲 null
則表示移除對應的 typenames
上的事件監聽器。如果沒有指定 listener
,則返回第一個對應 typenames
的事件監聽器。
typenames
是一個或者由空格分割的多個 typename。type
必須爲以下幾種:
start
- 拖拽開始 (mousedown or touchstart)drag
- 拖拽中 (mousemove or touchmove)end
- 拖拽結束 (mouseup, touchend or touchcancel)
在拖拽過程中通過 drag.on
改變事件監聽器不會影響當前的拖拽手勢,相反,必須使用 event.on
。
◎ event.on(typenames, [listener])
與 drag.on
等價, 但是僅僅應用在當前的拖拽手勢。在拖拽手勢開始時會創建一個當前拖拽 event listeners 的 copy,這個副本會被綁定到當前拖拽手勢並且可以被 event.on
修改,這對於僅接收當前手勢的臨時監聽器很有用。
🌰:
//定義拖拽函數
var drag = d3.behavior.drag()
.on("drag", dragmove)
function dragmove(d) {
d3.select(this)
.attr("cx", d.cx = d3.event.x)
.attr("cy", d.cy = d3.event.y)
}
//繪製圓形
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", color)
.call(drag)
d3-zoom
◎ d3.behavior.zoom()
該行爲會自動在容器元素中創建事件監聽器來處理元素的縮放和平移動作,可支持鼠標事件和觸摸事件。
d3.behavior.zoom()
構造一個新的縮放行爲。構造之後,可以通過 selection.call()
將此行爲應用於選擇器:
var zoom = d3.behavior.zoom();
selection.call(zoom);
所有註冊的監聽器都使用 “zoom” 命名空間, 故如下可以移除縮放行爲:
selection.on(".zoom", null);
◎ zoom(selection)
應用縮放行爲到指定的選擇器 selection
,註冊所需的事件監聽器,支持縮放和拖拽行爲。
◎ zoom.translate([translate])
指定當前的縮放平移向量爲 translate
;如果未指定 translate
,返回當前平移向量,默認:[0, 0]
。
◎ zoom.scale([scale])
指定當前的縮放比例,如果未指定 scale
,則返回當前的縮放比例,默認爲1
。
Drag Events
當 drag event listener 被調用時, d3.event
會被設置爲當前的拖拽事件,event
對象暴露以下屬性:
- target - 相關聯的 drag behavior。
- type - 字符串 “start”, “drag” 或 “end”。
- subject - 通過 drag.subject 定義的 subject。
- x - subject 的 x 座標。
- y - subject 的 y 座標。
- dx - 與上一次拖拽相比 x 座標的變化。
- dy - 與上一次拖拽相比 y 座標的變化。
- identifier - 字符串 “mouse”, 或者表示 touch identifier 的數字。
- active - 當前活動的拖拽手勢的數量。
- sourceEvent - 底層原始事件比如 mousemove 或 touchmove。
event
對象也暴露了 event.on
方法。
🔗 參考文章: