可視化圖表庫--goJS

 

GoJSNorthwoods Software的產品。
Northwoods Software創立於1995年,專一於交互圖控件和類庫。旗下四款產品:javascript

  • GoJS:用於在HTML上建立交互圖的純javaSCript庫
  • GoDiagram:用於WinForms的.NET圖控件。
  • GoXam:用於WPF/Silverlight的圖控件。( Silverlight是一個跨瀏覽器的、跨平臺的插件, 與flash競爭的富客戶端技術)
  • JGo:用於Swing/SWT中建立交互圖的java庫。

 

GoJS能夠作什麼? 

GoJS是一個實現交互類可視化圖表(好比流程圖,樹圖,關係圖,力導圖,思惟導圖等等)的JS庫。GoJS爲用戶交互提供了許多高級功能,如拖放,刪除,複製和粘貼,撤銷與重作,文本編輯,工具提示,上下文菜單,自動佈局,數據綁定和模型,事務狀態和撤銷管理,事件處理程序,命令以及用於自定義操做的可擴展工具系統等等。php

// gojs能夠繪製的圖形有css

柱狀圖 barCharts 線形圖 canvases.html 比賽場次圖 beatPaths.html 蠟燭圖 candlestickCharts.html
類層次結構 classHierarchy.html 詮釋comments.html 概念圖conceptMap.html 動效圖 constantSize.html
決策樹 decisionTree.html 距離圖 distances.html 雙圓 doubleCircle.html 雙樹doubleTree.html doubleTreeJSON.html
流程圖 draggableLink.html 家族圖譜 familyTree.html 進度圖gantt.html 家族圖譜genogram.html 順序功能圖grafcet.html
溫度計 thermometer.html 時間軸 tabs.html 縱向面板 swimLanesVertical.html
橫向面板swimLanes.html 狀態圖stateChartIncremental.html 平面表格spreadsheet.html 線形圖 sparklineGraphs.html
監控圖 shopFloorMonitor.html 序列化函數sequentialFunction.html 序列化圖表sequenceDiagram.html
座位圖 seatingChart.html
桑基圖 sankey.html (桑基圖定義:它主要用來表示原材料、能量等如何從初始形式通過中間過程的加工、轉化到達最終形式,以下所示爲最基本的事物狀態隨時間推移的變化)
圓形組roundedGroups.html 重組縮放regroupingScaled.html 雷達圖radialPartition.html 生成流程圖productionProcess.html
貨架圖planogram.html 管道圖pipes.html tab標籤頁 timeline.htmlhtml

更多實例參考java

https://gojs.net/latest/samples/index.htmlnode

 

爲何使用GoJS

用對象數據表達數據之間的邏輯關係,遠不如用圖像展現形象直觀 ,一圖勝千言,爲了更直觀地表達信息,咱們經常須要用圖形來展現數據以及邏輯關係。goJS圖表種類,交互行爲豐富,自定義模板靈活,已經有很是多的圖表例子,支持複雜的模板定義和數據綁定,足夠解決實際業務中的常見圖表需求。

web

如何使用GoJS

step1  下載gojs 源碼  http://gojs.net/latest/site.zip 並在頁面中引用算法

step2  在頁面中建立goJS圖表容器,必定要設置寬高,不然圖形繪製不出來編程

step3 建立GraphObject圖表實例,(定義樣式,交互,佈局,屬性)json

step4 定義圖表屬性及事件 節點樣式事件 鏈路樣式及事件

step5 綁定圖表節點和鏈路數據, 渲染圖表

綜合節點模板、連接模板、TreeModel和Treelayout,就生成了一張家族圖譜。

 

gojs概念

圖表(Diagram)

全部GoJS的屬性和方法都在go這個命名空間下。全部GoJS的類名,例如Diagram、Node、Panel、 Shape、TextBlock也都使用go做爲前綴,go.GraphObject.make來建立一個GoJS對象

GoJS圖表即最後看到的可視化視圖,它是由這些部分構成的:一個或多個可能有鏈接關係的、可能成組的節點。全部這些節點和鏈路彙集在相同或不一樣的層中,並呈現出必定的佈局(開發者預約好的或GoJS自動佈局)。

 

 Diagram(圖表屬性)

畫布圖表基本配置
畫布初始位置(定義以後就不能拖動了) initialContentAlignment: go.Spot.Center
初始座標 initialPosition: new go.Point(0, 0)
禁止移動節點 allowMove:false
禁止複製 allowCopy: false
禁止刪除 allowDelete:false
禁止選中  allowSelect:false
禁止縮放 allowZoom: false
禁止撤銷和重作 "undoManager.isEnabled": false

禁止水平拖動畫布

禁止水平滾動條

 

allowHorizontalScroll: false

禁止垂直拖動畫布

禁止垂直滾動條

allowVerticalScroll: false
只讀 isReadOnly: true
畫布初始化動畫時間 "animationManager.duration": 600
禁止畫布初始化動畫 "animationManager.isEnabled": false
畫布比例 scale:1.5
畫布最小比例 minScale:1.2,
畫布最大比例  maxScale:2.0,
顯示網格  "grid.visible":true,
禁止鼠標拖動區域選中 "dragSelectingTool.isEnabled" : false, 
畫布邊距padding Margin padding:80或者new go.Margin(2, 0)或new go.Margin(1, 0, 0, 1)

 


 
 
 
 

  
  

 

 


 
 
 
 

 

 

 

 

 

更多設置參見 https://gojs.net/latest/api/symbols/Diagram.html

 

MV架構

GoJs使用model-view(MV架構)的模式,Models做爲數據層來管理那些描述性的數據(JS數組對象),Diagrams則負責視圖層,將Nodes和Links的數據以可視化的方式渲染出來。Diagrams中的Nodes(節點)和Links(連線)呈現是由Model進行管理的。model和Diagrams實現了數據綁定,經過監聽Model數據,自動改變Nodes上的GraphObjects外觀和行爲。Model數據對象是一個普通的JavaScript對象。咱們編程操做只針對Model的數據層,而不是Diagrams的視圖層。能夠按照業務需求在Models數據對象上面添加任意屬性,通常不須要修改Diagram的prototype(原型)和GraphObject(繪圖單元)的classes(類).

 

數據綁定是指從源對象中提取值並在目標對象上設置屬性。目標對象就是圖形對象(GraphObject),源對象是模型中保存的js數據對象。

使用模板和數據綁定簡化了存儲在模型數據中的信息,靈活性很是強。固然並非全部的數據屬性都須要綁定使用

go.Binding VS 雙向數據綁定(Two-way data binding)

go.Binding綁定只將屬性的值從源數據轉移到目標對象。但有時咱們但願可以將GraphObject中的值傳輸回模型數據,使得模型數據與ui界面的圖標中的數據保持一致。這能夠經過使用TwoWay 綁定,它能夠完成從源數據到目標對象,以及從目標對象到源數據的值傳遞。

 

 

模型(Model)

每一個圖表都有一個數據模型,用於保存開發者程序的數據。
模型描述了節點之間的鏈接關係和組成員關係。用模型 Model.nodeDataArray 爲每一個數據項建立一個節點或組, 用模型 GraphLinksModel.linkDataArray 爲每一個數據項建立一個連接。並且,咱們能夠爲每一個數據對象添加所需的任何屬性。

Models的種類

自定義的node模板讓咱們的圖表看起來更美觀,若是要建立一個完整的關係圖,經過添加一些連線來表示這些獨立的節點之間的對應關係,同時這些節點可以進行自動定位和排版。在咱們的圖表裏爲了獲得這些連線,基本的Model已經知足不了需求。咱們必須從GOJS中的支持連線的另外兩個Models裏選擇,GraphLinksModel和TreeModel

GraphLinksModel中,除了model.nodeDataArray還有model.linkDataArray。它包含一個數組對象,經過」to」和」from」來描述沒一個連線。

GraphLinksModel容許兩個節點之間存在任何數量和任意方向的連線。好比A到B能夠連10條線,B到A能夠連3條以上反方向的線

TreeModel比GraphLinksModel更簡單,可是不能隨意的建利鏈接關係,就像2個節點之間有多條線,又或者有多個父級節點。

 

模板(Template)

模板聲明瞭每一個節點或鏈路的外觀、位置和行爲。

 Nodes模板

* Shape 預約義的或者自定義的幾何圖形 

 "Rectangle"--矩形, "RoundedRectangle"--圓角矩形, "Square"--正方形 "Ellipse"--橢圓  "Diamond"--菱形,  "Circle"--圓形   各類三角形 "TriangleRight", "TriangleDown", "TriangleLeft", "TriangleUp", "Triangle",

 "LineH", "LineV", "BarH", "BarV", "MinusLine", "PlusLine", "XLine"

* TextBlock 擁有各類各樣字體的文本(可編輯)
* Picture 圖片
* Panel 根據不一樣面板的類型,它能夠包含其餘位置或是尺寸不一樣的對象。(列如表格、 豎形列表和拉伸容器等)

TextBlocks不能包含圖片;Shapes不能包含文字。若是你想讓你的Node顯示文字,你必須使用TextBlocks。若是你想繪製一些幾何圖形,你就必須使用Shape。

myDiagram.nodeTemplate = $(
        go.Node,
        "Horizontal",
        { background: "#44CCFF" },
        $(
          go.Shape,
          "Rectangle",
          {
            portId: "",
            fromLinkable: true,
            toLinkable: true,
            cursor: "pointer",
            fill: "white",
            strokeWidth: 1
          },
          new go.Binding("figure"),
          new go.Binding("fill")
        ),
        $(go.Picture, { margin: 10, width: 50, height: 50, background: "red" }, new go.Binding("source"), new go.Binding("figure")),
        $(go.TextBlock, "Default Text", { margin: 12, stroke: "white", font: "bold 16px sans-serif" }, new go.Binding("text", "name"))
      );

 

全部的這些building block類都是由GraphObjects抽象對象衍生出來。由於GraphObject不是DOM元素,因此建立和修改它們對性能開銷不大。

 多個不一樣樣式的Node節點模板能夠經過myDiagram.nodeTemplateMap.add(go.Node)添加

 myDiagram.nodeTemplateMap.add("Center",
        $(go.Node, "Spot", { selectable: false, isLayoutPositioned: false, // the Diagram.layout will not position this node  locationSpot: go.Spot.Center }, $(go.Shape, "Circle", { fill: radBrush, strokeWidth: 0, stroke: null, desiredSize: new go.Size(200, 200) }), // no outline $(go.TextBlock, "Arrowheads", { margin: 1, stroke: "white", font: "bold 14px sans-serif" }) ));
 myDiagram.model =
        $(go.GraphLinksModel,
          { // this gets copied automatically when there's a link data reference to a new node key
            // and is then added to the nodeDataArray
 archetypeNodeData: {}, // the node array starts with just the special Center node nodeDataArray: [{ category: "Center", key: "Center" }], // the link array was created above  linkDataArray: linkdata }); }

links模板

 接下來咱們構造一個新的連線模板,在沒有爲連線指定樣式類型的條件下,默認的連線樣式。

      myDiagram.linkTemplate =
        $(go.Link,  // the whole link panel
 { routing: go.Link.Normal }, $(go.Shape, // the link shape // the first element is assumed to be main element: as if isPanelMain were true { stroke: "gray", strokeWidth: 2 }), $(go.Shape, // the "from" arrowhead new go.Binding("fromArrow", "fromArrow"), { scale: 2, fill: "#D4B52C" }), $(go.Shape, // the "to" arrowhead new go.Binding("toArrow", "toArrow"), { scale: 2, fill: "#D4B52C" }), { click: showArrowInfo, toolTip: // define a tooltip for each link that displays its information $("ToolTip", $(go.TextBlock, { margin: 4 }, new go.Binding("text", "", infoString).ofObject()) ) } );

 

面板(Panel)

每一個模板由GoJS中的面板Panel構成,面板自己做爲一個圖形對象GraphObject,保存其餘圖形對象做爲它的元素,同時,面板須要負責圖形對象的尺寸、位置。
每一個面板創建本身的座標系,面板中的元素按順序繪製,從而肯定了內部這些元素的z座標。
面板有不少種類,好比 Panel.Position,Panel.Auto,Panel.Vertical,Panel.Horizontal ,Panel.Spot ,Panel.Table,Panel.Viewbox, Panel.Link,Panel.Grid等等。

最簡單的面板是「Position」(Panel.Position)。每一個元素得到其正常大小
每一個元素的位置是由GraphObject.position屬性指定。若是沒有指定位置時,元件被定位在(0,0)。全部位置都是面板本身的座標系中,而不是在圖表範圍的座標系。位置可能包括負座標。
面板的大小恰好足以容納全部元素。

Panel.Vertical 面板的全部面板元件的排列垂直從上到下

構成面板的圖形對象有Shapes、Pictures、TextBlocks  Placeholder,它們都有默認模板。

 

圖表佈局

圖表(Diagram)在節點沒有指定座標的時候,圖表會顯示一個用網格形式排列的默認佈局。咱們能夠顯式的給每一個節點分配一個位置來給組織排序來解決這個混亂的組織結構,更容易的解決方案是,咱們會使用佈局來自動排列位置。

設置了佈局以後,會影響節點位置和鏈路屬性

 

常見的佈局有:

網格佈局 go.GridLayout

力導向佈局 go.ForceDirectedLayout fdLayout.html

 

 

樹形佈局 go.TreeLayout

徑向佈局(須要引RadialLayout.js) RadialLayout

 

佈局算法能夠重寫

myDiagram =
$(go.Diagram, "myDiagramDiv", // 畫布定義
    {layout:$(go.GridLayout, //自動佈局定義,設置爲網格佈局
              { comparer: go.GridLayout.smartComparer,//設置從小到大排序
                spacing: go.Size.parse("20 20"),//設置節點間隔
                comparer: function(a, b){ 
                    //重寫佈局算法,根據其餘屬性值從新增設置順序
                    var ay = a.data.type;
                    var by = b.data.type;
                    if(!!ay&&!!by){
                        if(ay > by) return -1;
                        if(ay < by) return 1;
                    }else if(!!ay){
                        return -1;
                    }else if(!!by){
                        return 1;
                    }    
                }
              });
    });

更多佈局方式

https://gojs.net/latest/intro/layouts.html

畫布事件

利用繪圖過程當中的一些DiagramListener能夠完成更多的數據交互體驗和業務邏輯

節點生成事件 ExternalObjectsDropped
線生成事件 LinkDrawn
線從新鏈接事件 LinkRelinked
刪除後事件 SelectionDeleted
刪除前事件 SelectionDeleting 
節點移動事件 SelectionMoved
節點修改
Modified
選擇節點更改完成
ChangedSelection


 
 
 
 
 
 

 

 

添加圖表事件的兩種方式

第一種在建立Diagram時註冊對應的事件的監聽

myDiagram = goObj(go.Diagram, "myDiagramDiv",  
{
  initialContentAlignment: go.Spot.Center,
  allowDrop: true, 
  "LinkDrawn": showLinkLabel,  
  "LinkRelinked": showLinkLabel,
  "animationManager.duration": 800, 
  "undoManager.isEnabled": true  
});
function showLinkLabel(e) {
  var label = e.subject.findObject("LABEL");
  if (label !== null) label.visible = (e.subject.fromNode.data.figure === "RoundedRectangle");
}

第二種在建立Diagram時完成後監聽對應的事件

myDiagram.addDiagramListener("Modified", function(e) {
var button = document.getElementById("SaveButton");
  if (button) button.disabled = !myDiagram.isModified;
  var idx = document.title.indexOf("*");
  if (myDiagram.isModified) {
    if (idx < 0) document.title += "*";
  } else {
    if (idx >= 0) document.title = document.title.substr(0, idx);
  }

});

 

事件應用舉例: 約束編程--若是是孤立節點則刪除 

      myDiagram.addDiagramListener("ExternalObjectsDropped", function(e) {
        var newnode = e.diagram.selection.first(); if (newnode.linksConnected.count === 0) { // when the selection is dropped but not hooked up to the rest of the graph, delete it  e.diagram.commandHandler.deleteSelection(); } });

 

更多事件參見 https://gojs.net/latest/api/symbols/DiagramEvent.html

 畫布工具欄

結合undoManager建立撤銷重作刪除的工具欄

 $('#deletePart').click(function(){
       if("undefined" == typeof myDiagram){
              result_prompt(0, "瀏覽器不兼容此功能,請使用高版本谷歌瀏覽器!");
              return false;
       }
       myDiagram.remove(Select_Port);
  });

  $('#undo-buttun').click(function(){
   if("undefined" == typeof myDiagram){
          result_prompt(0, "瀏覽器不兼容此功能,請使用高版本谷歌瀏覽器!");
          return false;
   }
   myDiagram.undoManager.undo();
  });

  $('#redo-buttun').click(function(){
   if("undefined" == typeof myDiagram){
          result_prompt(0, "瀏覽器不兼容此功能,請使用高版本谷歌瀏覽器!");
          return false;
   }
   myDiagram.undoManager.redo();
  });

 

項目中用到的幾個功能點實現

1.鼠標右鍵菜單

在myDiagram.nodeTemplate 下配置節點鼠標右鍵菜單
 {
          contextMenu: $(go.Adornment, "Vertical", new go.Binding("itemArray", "commands"), {
            itemTemplate: $(
              "ContextMenuButton",
              $(go.Shape, { figure: "RoundedRectangle", fill: "transparent", width: 40, height: 24, stroke: "gray", strokeWidth: 1, scale: 1.0, areaBackground: "transparent" }),
              $(go.TextBlock, { stroke: "deepskyblue", height: 24, width: 40, margin: 0, font: "bold 12px serif", textAlign: "center", verticalAlignment: go.Spot.Center }, new go.Binding("text")),
              {
                click: function(e, button) {
                  if (myDiagram.isReadOnly) return;
                  var cmd = button.data;
                  var nodedata = button.part.adornedPart.data;
                  // console.log(nodedata);
                  let curNode = myDiagram.findNodeForKey(nodedata.key);
                  options.contextMenu(curNode, cmd.text);
                  // console.log("On " + nodedata.text + "  " + cmd.text + ": " + cmd.action);
                }
              }
            )
          })
 }
        {
          text: "開始策略",
          figure: "Ellipse",
          fill: "#FEF7E7",
          stroke: '#FDCF90',
          info: "",
          type: "start",
          commands: [{ text: "查看", action: "view" }, { text: "刪除", action: "view" }],
        },

2.虛線及節點虛線框

{fromPort: "B", toPort: "T", from: -1, to: -3,category: "auditedDottedLine"}
// 自定義虛線樣式
  myDiagram.linkTemplateMap.add(
    "auditedDottedLine",
    $(
      go.Link,
      {
        selectable: true,
        selectionAdornmentTemplate: linkSelectionAdornmentTemplate
      },
      {
        relinkableFrom: true,
        relinkableTo: true,
        reshapable: true
      },
      {
        routing: go.Link.AvoidsNodes,
        curve: go.Link.JumpOver,
        corner: 5,
        toShortLength: 4
      },
      $(go.Shape, {
        isPanelMain: true,
        strokeWidth: 2,
        strokeDashArray: [3, 3]
      }),
      $(go.Shape, {
        toArrow: "Standard",
        stroke: null
      }),
      $(
        go.Panel,
        "Auto",
        $(
          go.Shape,
          "RoundedRectangle",
          new go.Binding("fill", "text", function(v) {
            return v ? "#F8F8F8" : null;
          }),
          {
            stroke: null,
            fill: null
          }
        ),
        $(
          go.TextBlock,
          {
            segmentIndex: 1,
            segmentFraction: 0.5,
            textAlign: "center",
            font: "10pt helvetica, arial, sans-serif",
            stroke: "blue",
            margin: 2,
            minSize: new go.Size(10, NaN)
            // editable: true
          },
          new go.Binding("text").makeTwoWay()
        )
      )
    )
  );
設置節點虛線邊框
    $(go.Shape, "Rectangle", { width: 40, height: 60, margin: 4, fill: null, strokeWidth: 2, strokeDashArray: [6, 6, 2, 2] }),
  myDiagram.nodeTemplate = $(
    go.Node,
    "Spot", $( go.Panel, "Auto", { name: "PANEL" }, new go.Binding("desiredSize", "size", go.Size.parse).makeTwoWay(go.Size.stringify), $( go.Shape, "Rectangle", { portId: "", fromLinkable: true, toLinkable: true, cursor: "pointer", fill: "white", stroke: "black", strokeWidth: 1 }, new go.Binding("figure"), new go.Binding("strokeDashArray"), new go.Binding("fill") ), )

 

3.自動補全

selectionChanged: function(eventPart) {
var dom = $$(".my-diagram-div canvas");
        dom.unbind("click", myFunction).bind("click", myFunction);
        function myFunction(e) {
          let position = {
            x: e.clientX,
            y: e.clientY
          };
          options.changeNodeSelection(eventPart.data, position);
          dom.unbind("click", myFunction);
        }
      }

 

let canvas = $(".my-diagram-div");
let selectHandlerDom = $('.select-handler');
            canvas.on('input propertychange','textarea',e => {
              selectHandlerDom.css({
                top:position.y + 20 +'px',
                left:position.x - 20 +'px',
                'z-index':10000
              });
              this.filterHandlerOptions(e.target.value);
            })
            selectHandlerDom.unbind('click').on('click','li',e => {
              let val = $(e.target).text()
              this.myDiagram.model.setDataProperty(data, 'text',val);
              canvas.find('textarea').val(val);
              
            })
            canvas.click(e => {
              selectHandlerDom.css({
                'z-index':-1
              })
            })

4.goJS版本太低操做節點時引發的事務執行出錯信息

http://zhonganphp-1251460743.cossh.myqcloud.com/a00000/common_js/gojs.js

5.去除水印

 

 

  1) 在文件中搜索7eba17a4ca3b1a8346,找到相似a.Jv=d[w.Jg("7eba17a4ca3b1a8346")][w.Jg("78a118b7")](d,w.um,4,4);這樣結構的代碼

  2) 將其註釋,替換成a.Jv=function(){return true;};

6.設置了佈局引發連線不美觀的問題

layout: $(go.TreeLayout, { angle: 90 }),

設置了佈局,連線的起點和重點就會受佈局的影響,能夠即便不保存節點的位置信息,繪製出來的圖形也按照必定規律排列


layout: $(go.LayeredDigraphLayout, { isInitial: false, direction: 90, columnSpacing: 50, isOngoing: false, layerSpacing: 50 }),

取消了佈局設置,須要保存節點的位置信息,才能還原出節點的連線位置信息

 
 

 7. 圖形對象part和data屬性,有些事件傳入的事件對象,不能直接獲取data屬性,要先索引part屬性,而後再去引用data屬性

      $(
        go.TextBlock,
        {
          font: "bold 11pt Helvetica, Arial, sans-serif",
          margin: 8,
          maxSize: new go.Size(300, NaN),
          wrap: go.TextBlock.WrapFit,
          editable: true,
          textEdited: function(textBlock, previousText, currentText) {
            console.log(textBlock,textBlock.part.data);
            options.changeNodeSelection(textBlock.part.data);
          }
        },

        new go.Binding("text").makeTwoWay()
      )

 

 8.下載canvas圖片

makeImageData方法經過HTMLCanvasElement.toDataURL()方法實現的

    downLoadImage(name) {
      // 不設置,下載的圖片殘缺不全
      // this.myDiagram.autoScale = go.Diagram.Uniform;
      var a = document.createElement("a");
      a.href = this.myDiagram.makeImageData({
        scale: 1,
        type: "image/png",
        maxSize: new go.Size(Infinity, Infinity)
      });
      a.download = name;
      a.click();
    },

9. goJS圖表實例重複初始化報錯

Invalid div id; div already has a Diagram associated with it.

解決方法:myDiagram.div=null;

 10.設置了樹形摺疊菜單以後,當樹形菜單有超過一級以上的葉子節點時,本該隱藏的葉子節點顯示出來,解決的要點,要向下面這樣設置顯示和隱藏

      myDiagram.nodeTemplate =
        $(go.Node, "Horizontal",
          {
            deletable: false,
            selectable: false,
            isTreeExpanded: false,//摺疊所有子節點
            // toolTip: tooltiptemplate,
          },

      myDiagram.addDiagramListener("InitialLayoutCompleted", function (e) {
        if (EditType != 'export') {
          // 只展現一級菜單
          e.diagram.findTreeRoots().each(function (r) { r.expandTree(2) });
        }
      });

 

 

一些小功能點的實現

添加圖例

 

      myDiagram.add(
        $(go.Part, "Table",
          { position: new go.Point(300, 10), selectable: false },
          $(go.TextBlock, "Key",
            { row: 0, font: "700 14px Droid Serif, sans-serif" }),  // end row 0
          $(go.Panel, "Horizontal",
            { row: 1, alignment: go.Spot.Left },
            $(go.Shape, "Rectangle",
              { desiredSize: new go.Size(30, 30), fill: bluegrad, margin: 5 }),
            $(go.TextBlock, "Males",
              { font: "700 13px Droid Serif, sans-serif" })
          ),  // end row 1
          $(go.Panel, "Horizontal",
            { row: 2, alignment: go.Spot.Left },
            $(go.Shape, "Rectangle",
              { desiredSize: new go.Size(30, 30), fill: pinkgrad, margin: 5 }),
            $(go.TextBlock, "Females",
              { font: "700 13px Droid Serif, sans-serif" })
          )  // end row 2
        ));
 上下兩行文字

 myDiagram.nodeTemplate =
        $(go.Node, "Auto",
          { deletable: false, toolTip: tooltiptemplate },
          new go.Binding("text", "name"),
          $(go.Shape, "Rectangle",
            {
              fill: "orange",
              stroke: "black",
              stretch: go.GraphObject.Fill,
              alignment: go.Spot.Center
            },
            new go.Binding("fill", "gender", genderBrushConverter)),
          $(go.Panel, "Vertical",
            $(go.TextBlock,
              {
                font: "bold 8pt Helvetica, bold Arial, sans-serif",
                alignment: go.Spot.Center,
                margin: 6
              },
              new go.Binding("text", "name")),
            $(go.TextBlock,
              new go.Binding("text", "kanjiName"))
          )
        );
展開摺疊按鈕效果實現 faultTree.html

 

myDiagram.nodeTemplate = $(
          ...
          $("TreeExpanderButton", { alignment: go.Spot.Right, alignmentFocus: go.Spot.Left, "ButtonBorder.figure": "Rectangle" })
...
框內摺疊  entityRelationship.html

      // define the Node template, representing an entity
      myDiagram.nodeTemplate =
        $(go.Node, "Auto",  // the whole node panel
          {
            selectionAdorned: true,
            resizable: true,
            layoutConditions: go.Part.LayoutStandard & ~go.Part.LayoutNodeSized,
            fromSpot: go.Spot.AllSides,
            toSpot: go.Spot.AllSides,
            isShadowed: true,
            shadowColor: "#C5C1AA"
          },
          new go.Binding("location", "location").makeTwoWay(),
          // whenever the PanelExpanderButton changes the visible property of the "LIST" panel,
          // clear out any desiredSize set by the ResizingTool.
          new go.Binding("desiredSize", "visible", function(v) { return new go.Size(NaN, NaN); }).ofObject("LIST"),
          // define the node's outer shape, which will surround the Table
          $(go.Shape, "Rectangle",
            { fill: lightgrad, stroke: "#756875", strokeWidth: 3 }),
          $(go.Panel, "Table",
            { margin: 8, stretch: go.GraphObject.Fill },
            $(go.RowColumnDefinition, { row: 0, sizing: go.RowColumnDefinition.None }),
            // the table header
            $(go.TextBlock,
              {
                row: 0, alignment: go.Spot.Center,
                margin: new go.Margin(0, 14, 0, 2),  // leave room for Button
                font: "bold 16px sans-serif"
              },
              new go.Binding("text", "key")),
            // the collapse/expand button
            $("PanelExpanderButton", "LIST",  // the name of the element whose visibility this button toggles
              { row: 0, alignment: go.Spot.TopRight }),
            // the list of Panels, each showing an attribute
            $(go.Panel, "Vertical",
              {
                name: "LIST",
                row: 1,
                padding: 3,
                alignment: go.Spot.TopLeft,
                defaultAlignment: go.Spot.Left,
                stretch: go.GraphObject.Horizontal,
                itemTemplate: itemTempl
              },
              new go.Binding("itemArray", "items"))
          )  // end Table Panel
        );  // end Node
拖拽回收站功能實現 動態建立節點和連線 flowBuilder.html 

      myDiagram.nodeTemplateMap.add("Recycle",
        $(go.Node, "Auto",
          {
            portId: "to", toLinkable: true, deletable: false,
            layerName: "Background", locationSpot: go.Spot.Center
          },
          new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
          { dragComputation: function(node, pt, gridpt) { return pt; } },
          { mouseDrop: function(e, obj) { myDiagram.commandHandler.deleteSelection(); } },
          $(go.Shape,
            { fill: "lightgray", stroke: "gray" }),
          $(go.TextBlock, "Drop Here\nTo Delete",
            { margin: 5, textAlign: "center" })
        ));
 提示工具

function makeTooltip(str) {  
// a helper function for defining tooltips for buttons
        return $("ToolTip",
          $(go.TextBlock, str));
}
建立組

    myDiagram.groupTemplate =
        $(go.Group, "Auto",
          { // define the group's internal layout
            layout: $(go.TreeLayout,
              { angle: 90, arrangement: go.TreeLayout.ArrangementHorizontal, isRealtime: false }),
            // the group begins unexpanded;
            // upon expansion, a Diagram Listener will generate contents for the group
            isSubGraphExpanded: false,
            // when a group is expanded, if it contains no parts, generate a subGraph inside of it
            subGraphExpandedChanged: function(group) {
              if (group.memberParts.count === 0) {
                randomGroup(group.data.key);
              }
            }
          },
          $(go.Shape, "Rectangle",
            { fill: null, stroke: "gray", strokeWidth: 2 }),
          $(go.Panel, "Vertical",
            { defaultAlignment: go.Spot.Left, margin: 4 },
            $(go.Panel, "Horizontal",
              { defaultAlignment: go.Spot.Top },
              // the SubGraphExpanderButton is a panel that functions as a button to expand or collapse the subGraph
              $("SubGraphExpanderButton"),
              $(go.TextBlock,
                { font: "Bold 18px Sans-Serif", margin: 4 },
                new go.Binding("text", "key"))
            ),
            // 設置  對象的目的是, 讓組自適應內部節點的大小;
            $(go.Placeholder,
              { padding: new go.Margin(0, 10) })
          )  // end Vertical Panel
        );  // end Groupgo.Placeholder
myDiagram.model.addNodeData({ key: name, isGroup: true, group: group });
交互面板

          var inspector = new Inspector("myInfo", myDiagram, {
            properties: {
              // key would be automatically added for nodes, but we want to declare it read-only also:
              "key": { readOnly: true, show: Inspector.showIfPresent },
              // fill and stroke would be automatically added for nodes, but we want to declare it a color also:
              "fill": { show: Inspector.showIfPresent, type: 'color' },
              "stroke": { show: Inspector.showIfPresent, type: 'color' }
            }
          });

 自定義tooltip

      // get tooltip text from the object's data
      function tooltipTextConverter(person) {
        var str = "";
        str += "Born: " + person.birthYear;
        if (person.deathYear !== undefined) str += "\nDied: " + person.deathYear;
        if (person.reign !== undefined) str += "\nReign: " + person.reign;
        return str;
      }

      // define tooltips for nodes
      var tooltiptemplate =
        $("ToolTip",
          { "Border.fill": "whitesmoke", "Border.stroke": "black" },
          $(go.TextBlock,
            {
              font: "bold 8pt Helvetica, bold Arial, sans-serif",
              wrap: go.TextBlock.WrapFit,
              margin: 5
            },
            new go.Binding("text", "", tooltipTextConverter))
        );

      myDiagram.nodeTemplate =
        $(go.Node, "Horizontal",
          {
            deletable: false,
            selectable: false,
            toolTip: tooltiptemplate,
          })

 

其它效果參見goJS的示例

1.各類箭頭樣式 arrowheads.html
2.全部的形狀shapes.html
3.自定義節點上下文 customContextMenu.html
4.自定義捲起摺疊 customExpandCollapse.html 
5.自定義選擇輸入框 customTextEditingTool.html
6.定義多個連線的入口和出口 dataFlow.html draggablePorts.html
   鼠標右鍵動態增刪端口 dynamicPorts.html
7.實體關係 連線會動態連接 避免交錯在一塊兒 entityRelationship.html
8.鼠標通過時顯示多行節點信息 dataVisualization.html
9.拖動排序 dragDropFields.html
10.限制節點在特定範圍內移動 且不能觸碰到邊緣 dragUnoccupied.html
11.手勢縮放功能 gestureBehavior.html
12.鼠標通過時顯示按鈕 hoverButtons.html

 

 經常使用的API

批量刪除連線
var removeLinks=[];
//首先拿到這個節點的對象
var node = myDiagram.findNodeForKey('key');
//獲取節點全部線
node.findLinksConnected().each(function(link) { 
     removeLinks.push(link.data);
    }
 );
myDiagram.model.removeLinkDataCollection(removeLinks);
監聽連線完成事件
myDiagram.addDiagramListener("LinkDrawn",function(e){
       (e.subject.data )    //這是這個線條的數據
 }) ;
監聽新拖拽到畫布的節點
diagram.addModelChangedListener(function(evt) {
    // ignore unimportant Transaction events
    if (!evt.isTransactionFinished) return;
    var txn = evt.object;  // a Transaction
    if (txn === null) return;
    // iterate over all of the actual ChangedEvents of the Transaction
    txn.changes.each(function(e) {
      // ignore any kind of change other than adding/removing a node
      if (e.modelChange !== "nodeDataArray") return;
      // record node insertions and removals
      if (e.change === go.ChangedEvent.Insert) {
        console.log(evt.propertyName + " added node with key: " + e.newValue.key);
      } else if (e.change === go.ChangedEvent.Remove) {
        console.log(evt.propertyName + " removed node with key: " + e.oldValue.key);
      }
    });
  });
經過key值去查找節點
myDiagram.findNodeForKey(key).data   //key值是節點的key
添加節點
let nodeData={ text: "Start", figure: "Ellipse", fill: "#00AD5F", info: "", type: "start" };
myDiagram.model.addNodeData(nodeData); // 須有位置信息
刪除節點
myDiagram.remove(part)
添加線
let linkData ={ from: newnode.data.key, to: oldnode.data.key, text: "true", side: "Left", isHighlighted:false};
myDiagram.model.addLinkData(linkData); // linkData是連線數據
 
查找該節點的下一級節點
key.findNodesOutOf() 
獲取當前畫布的json
myDiagram.model.toJson(); // 獲得結果爲json字符串
加載json刷新畫布
myDiagram.model = go.Model.fromJson(model); // 傳入參數model爲json字符串
獲取節點對象
var node=myDiagram.findNodeForKey('key');
獲取節點data
var nodeData=myDiagram.model.findNodeDataForKey('key');
獲取畫布所有節點
var nodes=myDiagram.nodes;
//遍歷輸出節點對象
nodes.each(function (node) {
console.log(node.data.text);
});
根據甲,找甲的子級元素
node.findTreeChildrenNodes().each(function(cNode) {
console.log(cNode.data)
});
獲取節點的線
var node=myDiagram.findNodeForKey('key');

node.findLinksConnected().each(function(link) {console.log(link.data)});
獲取從節點出來的線
var node=myDiagram.findNodeForKey('key');

node.findLinksOutOf().each(function(link) {console.log(link.data)});

 

更新節點
// 修改單個節點屬性
myDiagram.model.updateTargetBindings(node.data) 

// 批量修改節點屬性
myDiagram.model.nodeDataArray
myDiagram.model.linkDataArray
//修改完成調用如下方法完成重建
myDiagram.rebuildParts()

 

更新節點API

// 更新方式一
let curDataNode = myDiagram.model.findNodeDataForKey(this.clickNodeKey); curDataNode.nodeItem = this[obj.type + "Info"]; myDiagram.model.updateTargetBindings(curDataNode);
// 更新方式二 myDiagram.model.setDataProperty(curNode,
"data", curNode.data); console.log("curNode.data", curNode.data);

 

goJS資料

2.https://www.cnblogs.com/helloluckworld/articles/9592238.html 去除水印(實用)

3.goJS 繪製web流程圖  https://blog.csdn.net/kenhins/article/details/79043198 (收穫很大)

4.關於 Gojs 你可能用到的方法 / gojs自定義 / gojs

5.https://blog.csdn.net/sinat_20522337/article/details/79158122

6.https://juejin.im/post/5b875d85e51d4538c0220603

7.https://gojs.net/latest/intro/nodes.html  官方教程

8.https://blog.csdn.net/qq_29287561/article/details/81066004 畫布比例自適應

9. goJS入門教程    https://liuxiaofan.com/2018/03/16/3521.html

10. gojS事件  https://blog.csdn.net/pdw2009/article/details/82993971

11. gojs 初探  https://www.wengbi.com/thread_50581_1.html

12. gojs的一些使用技巧 https://blog.csdn.net/MEdwardM/article/details/52528236

 

 

 

相關文章
相關標籤/搜索