gojs Diagram Events(圖表事件)
事件(Events)
GoJS涵蓋了三種基本事件:DiagramEvents(圖表事件)、InputEvents(輸入事件)以及ChangedEvents(變更事件)。這一頁我們討論前兩種事件;至於最後一種事件請見 Changed Events。
1、圖表事件(Diagram Events)
DiagramEvent(圖表事件)表示一般使用者發起的對圖表的改變。你可以通過呼叫Diagram.addDiagramListener註冊圖表事件處理程式。各個圖表事件以名字區分。
目前定義了的圖表事件名稱包括:
-
"AnimationStarting", 一個動畫將要開始
-
"AnimationFinished", 一個動畫剛剛結束.
-
"BackgroundSingleClicked", 當我們用滑鼠左鍵單機一個Diagram的背景而不是一個Part時
-
"BackgroundDoubleClicked", 當我們用滑鼠左鍵雙擊一個Diagram的背景而不是一個Part時
-
"BackgroundContextClicked", 當我們用滑鼠右鍵單機一個Diagram的背景而不是一個Part時
-
"ChangingSelection", 在
-
"ChangedSelection", 在Diagram.selection集合改變之後
-
"ClipboardChanged", 當CommandHandler.copySelection改變了剪貼簿(但是Diagram沒有改變)
-
"ClipboardPasted", 當CommandHandler.pasteSelection從剪貼簿複製了Part到Diagram中;新的Part被放在了Diagram.selection集合中
-
"DocumentBoundsChanged", 當Diagram.documentBounds
-
"ExternalObjectsDropped", 當DraggingTool 從另一個Diagram複製了Part到當前的Diagram; 新的Part被放在了Diagram.selection集合中
-
"InitialLayoutCompleted", 在對圖表進行重大改動後第一個diagram佈局被完成時
-
"LayoutCompleted", 當圖表佈局完成時
-
"LinkDrawn", 當LinkingTool完成建立一個新的Link(連線線時), 也就是DiagramEvent.subject
-
"LinkRelinked", 當RelinkingTool完成重新連線已存在的Link時, 也就是DiagramEvent.subject
-
"LinkReshaped", 當LinkReshapingTool完成改變一個Link的路線時, 也就是DiagramEvent.subject
-
"Modified", Diagram.isModified屬性被設定為一個新的值時,不要在事件監聽裡修改Diagram或者它的Model
-
"PartCreated", 當ClickCreatingTool插入了一個新的Part, 也就是DiagramEvent.subject
-
"PartResized", 當ResizingTool調整了一個GraphObject的尺寸後, 也就是DiagramEvent.subject
-
"PartRotated", 當RotatingTool旋轉了一個GraphObject後, 也就是DiagramEvent.subject
-
"ObjectSingleClicked", 當滑鼠左鍵單機一個GraphObject時, 也就是DiagramEvent.subject
-
"ObjectDoubleClicked", 當滑鼠左鍵雙擊一個GraphObject時, 也就是DiagramEvent.subject
-
"ObjectContextClicked", 當滑鼠右鍵單擊一個GraphObject時, 也就是DiagramEvent.subject
-
"SelectionMoved", 當DraggingTool移動了某些Parts; 被移動了的Parts就存在於Diagram.selection集合中
-
"SelectionCopied", 當DraggingTool複製了某些Parts; 被複制了的Parts就存在於Diagram.selection集合中
-
"SelectionDeleting", 在CommandHandler.deleteSelection刪除Diagram.selection 的Parts之前
-
"SelectionDeleted", 在CommandHandler.deleteSelection刪除了Diagram.selection後, Diagram.selection變空了
-
"SelectionGrouped", 在CommandHandler.groupSelection在Diagram.selection中建立了一個新的Group, Diagram.selection現在含有這個新的Group之後
-
"SelectionUngrouped", 在CommandHandler.ungroupSelection移除了選中的Group但保留了它的Parts作為新的Diagram.selection之後
-
"SubGraphCollapsed", 當CommandHandler.collapseSubGraph收縮了選中的Groups, 使它們的Parts不可見後
-
"SubGraphExpanded", 當CommandHandler.expandSubGraph擴大了選中的Groups, 使它們的Parts可見之後
-
"TextEdited", 當TextEditingTool完成了文字的就地編輯後;被修改了的TextBlock就是DiagramEvent.subject
-
"TreeCollapsed", 當CommandHandler.collapseTree用subtrees(子樹)收縮了選中的節點, 使得子樹的節點和連線線不可見之後
-
"TreeExpanded", 當CommandHandler.expandTree用subtrees(子樹)展開了被選中的節點, 使得子樹的節點和連線線可見之後
-
"ViewportBoundsChanged", 當Diagram.viewportBounds的值改變了之後
更多詳細內容,請見文件DiagramEvent。
圖表事件並不一定與滑鼠/鍵盤或者觸控事件相對應。它們也不一定與圖表模型的變化相對應——要跟蹤這些變化,使用Model.addChangedListener或者Diagram.addModelChangedListener。當用戶做了什麼或者間接做了什麼時,圖表事件才會產生。
除了圖表事件監聽器之外,還有一些情況是,當發現一些變動足以表明一些屬性是事件處理程式。由於這些事件並不一定需要與任何特殊的輸入或者圖表事件對應,座椅這些事件處理程式就會有特定於情況的自定義引數。
一個非常常見的事件屬性是GraphObject.click,它指的是無論何時使用者點選一個物件時呼叫的一個非空的函式。它最常用於為按鈕指定行為,但是它與其他的點選事件屬性,雙擊和右鍵點選,對於任何GraphObject都是有用的。
另外一個常見的事件屬性是Part.selectionChanged,它指的是當Part.isSelected改變時呼叫的一個非空函式。在下面的示例中,事件處理函式有一個引數,該Part。由於函式能夠檢查Part.isSelected的當前值從而決定要做什麼,所以不需要其餘的引數。
模型的ChangedEvent事件比基於DiagramEvent更完成可靠。例如,當在程式碼裡為圖表增加一條連線線時,"LinkDrawn" 圖表事件不會被呼叫。圖表事件只有在使用者用 LinkingTool 新增一條新的連線線時才被呼叫。另外,連線線沒有被改變路線,因此Link.points不會被計算。事實上,建立一條新的連線線可能會使一個Layout失效,因此,所有的節點都可能會在不久後被移動。
有時候使用者對圖示做了一些改動,你需要更新資料庫。 通常,你會想要執行一個Model ChangedEvent監聽器, 通過呼叫Model.addChangedListener或者Diagram.addModelChangedListener, 然後把這些改變通知給模型層,再決定把哪些記錄到資料庫裡。請檢視關於Changed Events和Update Demo的討論.
這個示例展示了幾個圖表事件:"ObjectSingleClicked"(單機物件),"BackgroundDoubleClicked"(雙擊背景), 和"ClipboardPasted"(剪貼簿複製)。
例子:
function showMessage(s) {
document.getElementById("diagramEventsMsg").textContent = s;
}
// 為diagram新增一個“物件單機”事件
diagram.addDiagramListener("ObjectSingleClicked",
function(e) {
var part = e.subject.part;
//如果滑鼠單機的不是連線線,則顯示資訊:"Clicked on" + 滑鼠點選的目標的key值
if (!(part instanceof go.Link)) showMessage("Clicked on " + part.data.key);
}
);
//為diagram新增“背景雙擊”事件
diagram.addDiagramListener("BackgroundDoubleClicked",
function(e) {
//顯示資訊: “Double-clicked at” + 點選的點的座標值
showMessage("Double-clicked at " + e.diagram.lastInput.documentPoint);
}
);
//為diagram新增“剪貼簿複製貼上”事件
diagram.addDiagramListener("ClipboardPasted",
function(e) {
//複製某個節點Part後,貼上時,顯示資訊:“Pasted” + 複製貼上的節點數量
showMessage("Pasted " + e.diagram.selection.count + " parts");
}
);
var nodeDataArray = [
{ key: "Alpha" },
{ key: "Beta", group: "Omega" },
{ key: "Gamma", group: "Omega" },
{ key: "Omega", isGroup: true },
{ key: "Delta" }
];
var linkDataArray = [
{ from: "Alpha", to: "Beta" }, // 從Group外指向Group內
{ from: "Beta", to: "Gamma" }, // 這條連線線是Group內部的
{ from: "Omega", to: "Delta" } // 從Group指向一個節點
];
diagram.model = new go.GraphLinksModel(nodeDataArray, linkDataArray);
2、輸入事件
當發生低階HTML DOM事件時,GoJS會將鍵盤/滑鼠/觸控事件資訊規範化轉換為一個能夠被傳遞給各種事件處理方法且為後面的檢查而儲存的新的 InputEvent(輸入事件)。
一個輸入事件,用InputEvent.key存放鍵盤事件, 用InputEvent.button存放滑鼠事件, 用InputEvent.viewPoint存放滑鼠和觸控事件, 用InputEvent.modifiers存放鍵盤和滑鼠事件。
圖表的事件處理程式同時也記錄InputEvent.documentPoint,也就是滑鼠事件發生時的文件座標 InputEvent.viewPoint ,以及事件發生時的以毫秒為單位的時間戳 InputEvent.timestamp。
輸入事件類還未特定型別的事件提供了很多很便利的屬性。比如,InputEvent.control (如果按下控制鍵)和InputEvent.left (如果按下左/主滑鼠按鈕)。
一些工具在滑鼠點選的點可以找到當前的GraphObject(圖形物件)。這些圖形物件就被記為InputEvent.targetObject。
3、高階輸入事件
一些工具能檢測一系列的輸入事件以組成一些更抽象的使用者事件。比如說,“點選”(滑鼠迅速的按下並放開)和“懸停”(滑鼠靜止不動一段時間)。這些工具會為當前滑鼠所在的點對應的GrapgObject呼叫一個事件處理程式(如果有的話)。這個事件處理程式被當做物件的一個屬性值。它還會沿著 GraphObject.panel的鏈向上冒泡知道這個Part結束。這允許了一個“點選”事件在一個Panel上被申明並應用,即使實際的點選是發生在Panel內部的元素上的。如果滑鼠所在的點沒有物件,那時間就會發生在最外層的圖表上。
類似的點選事件屬性包括 GraphObject.click, GraphObject.doubleClick, 和 GraphObject.contextClick。即便沒有GraphObject時,這些事件也會發生——事件會發生在圖表的背景上發生:Diagram.click, Diagram.doubleClick, 和 Diagram.contextClick。這些都是你可以設定為事件處理程式的函式。這些事件是由滑鼠事件和觸控事件引起的。
類似的滑鼠移入事件屬性包括GraphObject.mouseEnter, GraphObject.mouseOver和GraphObject.mouseLeave。但是隻有Diagram.mouseOver會被應用到圖表上。
類似的滑鼠懸停事件屬性包括 GraphObject.mouseHover和GraphObject.mouseHold。等價的圖表屬性是Diagram.mouseHover和Diagram.mouseHold.
拖拽操作也有對應的事件屬性:GraphObject.mouseDragEnter, GraphObject.mouseDragLeave, 和GraphObject.mouseDrop. 他們適用於靜止的物件,而不是被拖動中的物件。同時,他們也適用於觸控事件的拖拽,而不僅僅是滑鼠事件的拖拽。
下面的示例展示了三個高階輸入事件:點選節點、進入/離開group(組)。
function showMessage(s) {
document.getElementById("inputEventsMsg").textContent = s;
}
diagram.nodeTemplate =
$(go.Node, "Auto",
$(go.Shape, "Ellipse", { fill: "white" }),
$(go.TextBlock,
new go.Binding("text", "key")),
{ click: function(e, obj) { showMessage("Clicked on " + obj.part.data.key); } }
);
diagram.groupTemplate =
$(go.Group, "Vertical",
$(go.TextBlock,
{ alignment: go.Spot.Left, font: "Bold 12pt Sans-Serif" },
new go.Binding("text", "key")),
$(go.Panel, "Auto",
$(go.Shape, "RoundedRectangle",
{ name: "SHAPE",
parameter1: 14,
fill: "rgba(128,128,128,0.33)" }),
$(go.Placeholder, { padding: 5 })
),
{ mouseEnter: function(e, obj, prev) { // 改變group的背景畫筆
var shape = obj.part.findObject("SHAPE");
if (shape) shape.fill = "red";
},
mouseLeave: function(e, obj, next) { // 回覆原始的畫筆
var shape = obj.part.findObject("SHAPE");
if (shape) shape.fill = "rgba(128,128,128,0.33)";
} });
var nodeDataArray = [
{ key: "Alpha" },
{ key: "Beta", group: "Omega" },
{ key: "Gamma", group: "Omega" },
{ key: "Omega", isGroup: true },
{ key: "Delta" }
];
var linkDataArray = [
{ from: "Alpha", to: "Beta" }, // 從Group外指向Group內
{ from: "Beta", to: "Gamma" }, // 這條連線線是Group內部的
{ from: "Omega", to: "Delta" } // 從Group指向一個節點
];
diagram.model = new go.GraphLinksModel(nodeDataArray, linkDataArray);
3、點選與選中
這個示例同時展示了“點選”和“selectionChanged”事件:
function showMessage(s) {
document.getElementById("changeMethodsMsg").textContent = s;
}
diagram.nodeTemplate =
$(go.Node, "Auto",
{ selectionAdorned: false },
$(go.Shape, "Ellipse", { fill: "white" }),
$(go.TextBlock,
new go.Binding("text", "key")),
{
click: function(e, obj) { showMessage("Clicked on " + obj.part.data.key); },
selectionChanged: function(part) {
var shape = part.elt(0);
shape.fill = part.isSelected ? "red" : "white";
}
}
);
var nodeDataArray = [
{ key: "Alpha" }, { key: "Beta" }, { key: "Gamma" }
];
var linkDataArray = [
{ from: "Alpha", to: "Beta" },
{ from: "Beta", to: "Gamma" }
];
diagram.model = new go.GraphLinksModel(nodeDataArray, linkDataArray);
試著按下“Ctrl-A”可以全選所有的物件。注意 GraphObject.click事件屬性與Part.selectionChanged事件屬性的區別。當節點上發生什麼事情時,兩個方法都能被呼叫。GraphObject.click事件會在使用者點選節點時發生,選中了節點。但是Part.selectionChanged事件在沒有點選事件(或者任何滑鼠事件)時就會發生——這是由於節點的一個屬性值變了