GoJS繪圖基礎(chǔ)探索筆記

最近又因?yàn)楣ぷ餍枰隽它c(diǎn)GoJS研究如下
發(fā)現(xiàn)這個(gè)東西非常有用簡直是可視化神器
官網(wǎng)教程很清楚但是根本沒有中文Api (╯‵□′)╯︵┻━┻

Reference:
https://gojs.net/latest/learn/
https://segmentfault.com/a/1190000005182494

GoJS是一個(gè)可視化JavaScript庫,用于瀏覽器中創(chuàng)建交互圖形。
GoJS不依賴于任何JS庫或框架(例如bootstrap、jquery等),可與任何HTML或JS框架配合工作,甚至可以不用框架。

Part1:基礎(chǔ)介紹及代碼構(gòu)建

簡單地講,GoJS的繪圖基于Html5的Canvas元素。一個(gè)Gojs文件基本構(gòu)成包括畫布,數(shù)據(jù)模型,模型內(nèi)節(jié)點(diǎn)等。

Step1:創(chuàng)建畫布(Html)

<div id="stDiagram2" style="width:800px; height:300px; background-color: #DAE4E4;margin-bottom: 10px;"></div>

需給定id,長寬。Gojs會(huì)在該div中創(chuàng)建canvas。

Step2:初始化畫布(Js)

var myDiagram = new go.Diagram("stDiagram");

var $ = go.GraphObject.make;
var myDiagram =
$(go.Diagram, "stDiagram",
{   ... });

其中常用屬性:

  • initialContentAlignment: go.Spot.Center, // 畫布內(nèi)居中顯示
  • "grid.visible": true, //畫布上面是否出現(xiàn)網(wǎng)格
  • allowZoom: false, //畫布是否可以縮放
    更多初始化畫布的參數(shù)請參考官方api。

注意:
GraphObject.make為GoJS定義的靜態(tài)函數(shù),用于生成對象并賦予其類。
GraphObject.make的第一個(gè)參數(shù)必須是一個(gè)類類型。通常是一個(gè)字符串,可以設(shè)定TextBlock.text,Shape.figure,Picture.source或Panel.type。

Step3:定義模型數(shù)據(jù)(Js)

var myModel = $(go.Model);
 // model中的數(shù)據(jù)每一個(gè)js對象都代表著一個(gè)相應(yīng)的模型圖中的元素
myModel.nodeDataArray = [
      { key: "Amos"},
      { key: "Saint"},
];
myDiagram.model = myModel; //將模型數(shù)據(jù)綁定到畫布圖上
基本圖.png

Gojs中的數(shù)據(jù)模型分三種。

  • Model:最基本的(不帶連線,如上面的例子)
  • GraphLinksModel :連線圖
  • TreeModel:樹形圖

GraphLinksModel中用model.linkDataArray為node節(jié)點(diǎn)連線保存數(shù)據(jù)模型信息。在連線圖中,可以設(shè)定節(jié)點(diǎn)的連接方式。

var myModel = $(go.GraphLinksModel);
myModel.nodeDataArray = [
    { key: "Amos"},
    { key: "Saint"}
];
myModel.linkDataArray = [
    { from: "Amos", to: "Saint" }
];
myDiagram.model = myModel;
連線圖.png

Step4:定義node節(jié)點(diǎn)(Js)

myDiagram.nodeTemplate =
$(go.Node, "Horizontal",
    {
          locationSpot: go.Spot.Center, // 節(jié)點(diǎn)內(nèi)居中顯示
          background: "indigo" //每個(gè)節(jié)點(diǎn)背景色
    },
        ...
);

在...中,可以加入$(go.TextBlock,{ ... }), $(go.Picture,{ ... }), $(go.Shape,{ ... }), $(go.Panel,{ ... }),四種節(jié)點(diǎn)。分別為文本快(可編輯),圖片,圖形,面板(來保存其他Node的集合) 。

Shape包括Rectangle(矩形)、RoundedRectangle(圓角矩形),Ellipse(橢圓形),Triangle(三角形),Diamond(菱形),Circle(圓形)等可以直接調(diào)用的形狀。(GoJS默認(rèn)提供了很多形狀然而Api寫的很一般,需要自己去官方文檔進(jìn)行對照O.O)

$(go.Shape,
    "RoundedRectangle",
        { margin: 10, width: 50, height: 50, figure: "Club",
          stroke: "#C2185B", fill: "#F48FB1", strokeWidth: 3
        },
        new go.Binding("figure", "fig")),

Picture比較簡單,根據(jù)url獲取圖片。

$(go.Picture,
    { margin: 10, width: 50, height: 50, background: "#44CCFF" },
    new go.Binding("source", "url")),

TextBlock可設(shè)置寬高換行,以及可編輯性。

$(go.TextBlock,
        "default text",
        { margin: 12, stroke: "white", font: "14px sans-serif" },
        new go.Binding("text", "name"))

Panel為節(jié)點(diǎn)合集,見下一小節(jié)。

對應(yīng)數(shù)據(jù)模型:
在數(shù)據(jù)模型中,通過設(shè)定上段代碼Binding的屬性,對節(jié)點(diǎn)進(jìn)行設(shè)置。

var myModel = $(go.Model);
myModel.nodeDataArray = [
    { fig:"Spade", url:"amos.jpg", name: "Amos"},
    { fig:"Heart", url:"st.jpg", name: "Saint"},
];
myDiagram.model = myModel;
有shape,picture和textblock的節(jié)點(diǎn).png

Step5:增加node節(jié)點(diǎn)(Js)
通過Diagram.add可以在模型中增加node節(jié)點(diǎn)。

myDiagram.add($(
    go.Part, 'Horizontal',
    $(go.TextBlock,
        { text: '一個(gè)文本塊'}
    ),
    $(go.TextBlock,
        { text: '一個(gè)有顏色的文本塊', background: '#1ad', stroke: '#FFF', width:150, height:20, textAlign: 'center', alignment: go.Spot.Center, margin:10 }
    ),
    $(go.TextBlock,
        { text: '一個(gè)可編輯文本塊', background: '#FFF', width:150, height:20, alignment: go.Spot.Center, textAlign: 'center', editable: true, margin:10 }
    ),
));
添加文本節(jié)點(diǎn).png

Part2:面板Panel

面板中可以包含自己的node元素。每個(gè)面板建立自己的坐標(biāo)系。面板有很多種類,諸如:

  • Panel.Position
  • Panel.Vertical
  • Panel.Horizo??ntal
  • Panel.Auto
  • Panel.Spot
  • Panel.Table
  • Panel.Viewbox
  • Panel.Link
  • Panel.Grid

常用的有位置面板Panel.Position,縱向面板Panel.Vertical,橫向面板Panel.Horizo??ntal,表面板Panel.Table。

Panel.Position:
每個(gè)元素的位置是由position屬性指定,默認(rèn)定位在(0,0)左上角。

myDiagram.add($(
    go.Part,
    go.Panel.Position,
    {
        background: '#eee',
        //position: new go.Point(0, 0), //定位面板相對diagram的位置
    },
    $(go.TextBlock,
        {text: '0, 0', background: '#6bc1ff' }
    ),
    $(go.TextBlock,
        {text: '100, 100', background: '#6bc1ff', position: new go.Point(100, 100) }
    ),
    $(go.Shape,
    {width: 50,height: 50,stroke: "#3385ff",fill: '#6bc1ff', position: new go.Point(100, 0) }
    ),
));
位置面板.png

Panel.Vertical:
面板的所有元素垂直從上到下排列。
Panel.Horizo??ntal:
類似縱向面板,排列不同。
垂直和水平兩個(gè)面板支持Panel.defaultAlignment和Panel.defaultStretch屬性,可以不必設(shè)置每個(gè)元素的對齊方式。

go.Panel.Horizontal,
{
    background: '#eee', defaultAlignment: go.Spot.Bottom
},
底部對齊的垂直面板.png

Panel.Table:
表格面板中具有GraphObject.row和GraphObject.column屬性,面板會(huì)按照節(jié)點(diǎn)的行和列確定大小。
row和column的計(jì)數(shù)從0開始。

go.Panel.Table,
{
    //position: new go.Point(0, 0),
    background: '#eee',
},
$(go.TextBlock,
    {text: '一行一列', row: 0, column: 0, margin: 2, background: '#6bc1ff'}
),
表面版.png

當(dāng)設(shè)置了行或列的長寬時(shí),可以通過設(shè)置alignment: go.Spot.Left/Right/Center來設(shè)定表格內(nèi)元素對齊方式。

$(go.RowColumnDefinition,
    { column: 0, width: 200, background: '#eee', }
),
$(go.Shape,
    'RoundedRectangle',
    { stroke: "#3385ff", fill: '#6bc1ff', row: 0, column: 0, alignment: go.Spot.Left, }
),
不同對齊方式.png

通過columnSpan和rowSpan屬性,可以合并單元格。

$(go.TextBlock,
    {text: '頂標(biāo)題', row: 0, column: 0, columnSpan: 3, 
    stretch: go.GraphObject.Horizontal, margin: 2, background: '#6bc1ff'}
),
合并單元格.png

Part3:數(shù)據(jù)綁定

GraphObject中的各種屬性都可以進(jìn)行數(shù)據(jù)綁定。在第一節(jié)我們建立基本模型圖時(shí)已經(jīng)用了數(shù)據(jù)綁定功能。
通常,在Template(nodeTemplate和linkTemplate)中,定義go.Binding的屬性,并在DataArray(nodeDataArray和linkDataArray)中設(shè)定對應(yīng)值。

Template中:

myDiagram2.nodeTemplate =
$(go.Node, "Auto",
  new go.Binding('location', 'loc'),
  $(go.Shape,
    { figure: "RoundedRectangle", fill: "white" },
    new go.Binding('fill', 'color'),
    new go.Binding('stroke', 'stroke')),
  $(go.TextBlock,
    { margin: 5 },
    new go.Binding('text', 'text')),
);
myDiagram2.linkTemplate = 
$(go.Link,
    $(go.Shape,
        new go.Binding('stroke', 'stroke'),
        new go.Binding('strokeWidth', 'thick')
    ),
    $(go.Shape,
        { toArrow: 'OpenTriangle', fill: null}
    )
)

DataArray中:

myModel2.nodeDataArray = [
    { key: "Amos", text: 'Amos', color: '#ff7a7a', stroke: "#ff4141", loc: new go.Point(0, 0) },
    { key: "Saint", text: 'Saint', color: '#6bc1ff', stroke: "#3385ff", loc: new go.Point(100, 100)}
];
myModel2.linkDataArray = [
    { from: "Amos", to: "Saint", stroke: '#333', thick: 2 }
];

設(shè)定數(shù)據(jù)綁定時(shí),可以通過轉(zhuǎn)換函數(shù)的第三個(gè)參數(shù)綁定構(gòu)造函數(shù)。

new go.Binding('location', 'loc', go.Point.parse),

此處,go.Point.parse為一組二維數(shù)組。

myModel2.nodeDataArray = [
    { key: "Amos", text: 'Amos', color: '#ff7a7a', stroke: "#ff4141", loc: '0, 0' },
    { key: "Saint", text: 'Saint', color: '#6bc1ff', stroke: "#3385ff", loc: '100, 100'}
];

Part4:事件觸發(fā)(拖拽為例)

官方api:(PS,Gojs的官方api用的是monokai配色,好評(píng))

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

Gojs具備三種基本事件:

  • 針對圖表的“基礎(chǔ)事件”DiagramEvent。
  • 處理鼠標(biāo)鍵盤的“輸入事件”InputEvents。
  • 以及改變元素屬性的“更改事件”ChangedEvent。

Gojs提供各種函數(shù)處理圖表的交互行為。

由于上一篇研究的是Html5拖拽交互行為,此處依舊以輸入事件的拖拽為例。在這里將官方Planogram的例子進(jìn)行簡化,并按步驟生成。
最終效果為:


拖拽事件.png

針對拖拽,Gojs提供GraphObject.mouseDragEnter, GraphObject.mouseDragLeave, GraphObject.mouseDrop 三種操作。分別對應(yīng)鼠標(biāo)拖拽進(jìn)入,離開,與釋放。

Step1:創(chuàng)建畫布(Html)
我們可以把拖拽事件看成將一些物品放置在桌子上。我們需要?jiǎng)?chuàng)建兩個(gè)畫布,第一個(gè)放置于左側(cè)用來存放物品,第二個(gè)用于充當(dāng)桌子。在這個(gè)例子中,我們設(shè)定了三類物品,四張桌子。
Html構(gòu)成如下:

<div style="width: 150px;height:450px;float: left;border:1px solid #bef;">
    <div id="myPalette" style="width: 140px; height: 450px"></div>
</div>
<div id="stDiagram" style="float: left; width:800px; height:450px; border:1px solid #666; margin-bottom: 10px; margin-left: 20px;"></div>

Step2:初始化圖表(JS)
我們將主圖表以網(wǎng)格方式呈現(xiàn),并在Diagram中定義allowDrop: true屬性,使其可拖放。

var CellSize = new go.Size(50, 50);
var myDiagram =
$(go.Diagram, "stDiagram",
{
    //define grid size
    grid: $(go.Panel, "Grid",
      { gridCellSize: CellSize },
      $(go.Shape, "LineH", { stroke: "lightgray" }),
      $(go.Shape, "LineV", { stroke: "lightgray" })
    ),
    //allow drop on diagram
    allowDrop: true,
    //support grid snapping when dragging
    "draggingTool.isGridSnapEnabled": true,
    "draggingTool.gridSnapCellSpot": go.Spot.Center,
});

"draggingTool.isGridSnapEnabled": true,讓拖放可以對齊網(wǎng)格進(jìn)行。

網(wǎng)格.png

Step3:創(chuàng)建桌子和物品(JS)
在Template中,設(shè)定mouseDragEnter, mouseDragLeave, mouseDrop所觸發(fā)的交互行為。
首先,對桌子所在的groupTemplate進(jìn)行定義。以灰色的方形顯示桌子。

    var groupFill = "rgba(128,128,128,0.2)";
    var groupStroke = "gray";
myDiagram.groupTemplate =
  $(go.Group,
    {
      layerName: "Background",
      resizable:  false,
      locationSpot: new go.Spot(0, 0, CellSize.width/2, CellSize.height/2)
    },
    //save/load the point that is the top-left corner of the node, not the location
    new go.Binding("position", "pos", go.Point.parse),

    $(go.Shape, "Rectangle",  // the rectangular shape around the members
      { name: "SHAPE",
        fill: groupFill,
        stroke: groupStroke,
      },
      new go.Binding("desiredSize", "size", go.Size.parse)),
  );
    myDiagram.model = new go.GraphLinksModel([
      { key: "G1", isGroup: true, pos: "0 0", size: "200 200" },
      { key: "G2", isGroup: true, pos: "200 0", size: "200 200" },
      { key: "G3", isGroup: true, pos: "0 200", size: "200 200" },
      { key: "G4", isGroup: true, pos: "200 200", size: "200 200" }
    ]);

此時(shí)生成4張桌子,并可進(jìn)行拖拽。

桌子.png

接下來,通過設(shè)定nodeTemplate定義左側(cè)物品模板。設(shè)定物品為圓角方塊。

    myDiagram.nodeTemplate =
    $(go.Node, "Auto",
        {
            // set the node to center
            locationSpot: new go.Spot(0, 0, CellSize.width / 2, CellSize.height / 2),
            resizable: false,
        },
        new go.Binding("position", "loc", go.Point.parse),

        $(go.Shape,
            { name: "SHAPE", figure: "RoundedRectangle", fill: "white", minSize: CellSize},
            new go.Binding('fill', 'color'),
            new go.Binding('stroke', 'stroke')),
        $(go.TextBlock,
            { alignment: go.Spot.Center, font: 'bold 16px sans-serif' },
            new go.Binding('text', 'key')),
    );
    var green = '#B2FF59';
    var blue = '#81D4FA';
    var yellow = '#FFEB3B';

    var myModel = $(go.GraphLinksModel);
    myModel.nodeDataArray = [
      { key: "a", color: green },
      { key: "b", color: blue },
      { key: "c", color: yellow }
    ];
物品.png

Step4:設(shè)置交互(JS)
基本模板節(jié)點(diǎn)定義完畢后,我們開始通過GraphObject.mouseDragEnter, GraphObject.mouseDragLeave, GraphObject.mouseDrop進(jìn)行簡單的拖拽交互。
針對物品,改變物品位置時(shí),可以通過updateTargetBindings();更新物品屬性值。

myDiagram.nodeTemplate =
    $(go.Node, "Auto",
        {
            // set the node to center
            locationSpot: new go.Spot(0, 0, CellSize.width / 2, CellSize.height / 2),
            resizable: false,
            mouseDragLeave: function(e, node) {
                // assign new property values to the GraphObjects
                node.updateTargetBindings();
            },
        },
    );

對于桌子,為了更好地顯示交互效果,我們設(shè)定,當(dāng)有物品拖入桌子上方時(shí)改變桌子顏色。

    var dropFill = "rgba(128,255,255,0.2)";
    var dropStroke = "red";

在這里,定義一個(gè)新函數(shù)以判斷是否需要改變顏色為高亮。后面,通過鼠標(biāo)交互行為我們將觸發(fā)這個(gè)函數(shù)。

    function highlightGroup(grp, show) {
      if (!grp) return;
      if (show) {  // check that the drop may really happen into the Group
          grp.isHighlighted = true;
          return;
      }
      grp.isHighlighted = false;
    }

當(dāng)物品拖放至桌子時(shí),改變顏色為高亮,拖放完畢后恢復(fù)原貌。

myDiagram.groupTemplate =
      $(go.Group,

        ……

        { // highlight group when dragover or dragdrop
          mouseDragEnter: function(e, grp, prev) { highlightGroup(grp, true); },
          mouseDragLeave: function(e, grp, next) { highlightGroup(grp, false); },
          mouseDrop: function(e, grp) {
            var ok = grp.addMembers(grp.diagram.selection, true);
            if (!ok) grp.diagram.currentTool.doCancel();
          }
        },

        ……

      new go.Binding("fill", "isHighlighted", function(h) { return h ? dropFill : groupFill; }).ofObject(),
      new go.Binding("stroke", "isHighlighted", function(h) { return h ? dropStroke: groupStroke; }).ofObject())
      );

至此,基本的拖拽效果設(shè)置完畢。


基本拖拽.png

這里的例子主要展示通過mouseDragEnter,mouseDragLeave,mouseDrop如何進(jìn)行交互行為。還可以通過一些其他設(shè)置進(jìn)行細(xì)化。請參考官方Planogram的代碼。

總結(jié)

GoJS很強(qiáng)大,基本滿足常見的各類圖表生成與交互行為。只是目前沒有找到完善的中文文檔,有機(jī)會(huì)的話多嘗試翻譯幾篇給大家。
就醬。
(′?ω?`)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容