GoJS教程

有关视频教程,请参阅我们的YouTube视频 有关本文教程,请继续阅读

GoJS 是一个用于实现交互式图的JavaScript库 该页面将向您展示使用GoJS的基本知识

由于GoJS 是依赖HTML5特性的JavaScript库,所以你需要确保你的页面声明它是一个HTML5文档。当然,您需要加载库:

<!DOCTYPE html>  <!-- HTML5 document type -->
<html>
<head>
  <!-- use go-debug.js when developing and go.js when deploying -->
  <script src="go-debug.js"></script>
  . . .
      

你可以从此处下载 GoJS 以及所有文档和示例。或者,您可以直接链接到CDN提供的GoJS库, 例如:

<script src="https://unpkg.com/gojs/release/go-debug.js"></script>

每个GoJS图都包含在HTML元素中,在你的HTML页面中,你可以给它一个显示的大小:

<!-- The DIV for a Diagram needs an explicit size or else we will not see anything.
     In this case we also add a background color so we can see that area. -->
<div id="myDiagramDiv"
     style="width:400px; height:150px; background-color: #DAE4E4;"></div>
      

在JavaScript代码中,你在制作图时传递<div>id

var $ = go.GraphObject.make;
var myDiagram =
  $(go.Diagram, "myDiagramDiv");
      

这将创建一个空图

注意,go是所有GoJS类型所在的“命名空间”。GoJS类的所有代码使用,例如Diagram、Node、Panel、Shape或TextBlock都将以 "go."作为前缀。

本文将通过示例向你展示如何使用go.GraphObject.make构建GoJS对象 更多细节请阅读 构建GoJs对象 使用 $ 作为 go.GraphObject.make 的缩写非常方便,我们将从现在使用它 如果你使用 $ 作为其他变量, 你可以选择不同的短变量名例如$$MAKEGO.

图和模型

图的节点和链接是由模型数据的可视化 GoJS 具有 model-view 架构, 模型保存描述节点和链接的数据(JavaScript对象数组)Diagrams充当视图,使用实际的节点和链接对象来可视化这些数据. 模型,而不是图,是您在编辑后加载并保存的内容。 你可以在模型数据对象上添加应用所需的任何属性;你不能向Diagram和GraphObject类的原型添加或修改属性。

下面是一个模型和图的例子,下面是它生成的实际图:

var $ = go.GraphObject.make;
var myDiagram =
  $(go.Diagram, "myDiagramDiv",
    { // enable Ctrl-Z to undo and Ctrl-Y to redo
      "undoManager.isEnabled": true
    });

var myModel = $(go.Model);
// for each object in this Array, the Diagram creates a Node to represent it
myModel.nodeDataArray = [
  { key: "Alpha" },
  { key: "Beta" },
  { key: "Gamma" }
];
myDiagram.model = myModel;
      

这个图显示了该模型中的三个节点,可以进行一些交互

节点样式

通过创建由GraphObject组成的模板并在这些对象上设置属性来设置节点的样式。 要创建Node, 我们可以使用几个构建基块类:

所有这些构建基块均来自 GraphObject 抽象类, 因此我们随便将它们称为GraphObjects或对象或元素. 请注意,GraphObject 不是 HTML DOM元素,因此创建或修改此类对象的开销要少得多。

我们希望模型数据属性影响我们的节点,这是通过数据绑定来完成的。数据绑定使我们可以通过将GraphObject上的属性自动设置为从模型数据中获取的值来更改GraphObject在Nodes中的外观和行为。模型数据对象是普通的JavaScript对象。您可以选择在模型的节点数据上使用所需的任何属性名称。

默认的Node模板很简单: 一个包含一个TextBlock的Node. TextBlock的text 属性和模型数据的 key属性之间存在数据绑定。在代码中,模板看起来像这样:

myDiagram.nodeTemplate =
  $(go.Node,
    $(go.TextBlock,
      // TextBlock.text is bound to Node.data.key
      new go.Binding("text", "key"))
  );
      

TextBlocks,Shape和Pictures是GoJS的原始构建块. TextBlocks 不能包含图像; Shapes 不能包含文本. 如果要让节点显示一些文本,则必须使用TextBlock. 如果要绘制或填充一些几何图形,则必须使用Shape.

更一般地,Node模板的框架看起来像这样:

myDiagram.nodeTemplate =
  $(go.Node, "Vertical", // second argument of a Node (or any Panel) can be a Panel type
    /* set Node properties here */
    { // the Node.location point will be at the center of each node
      locationSpot: go.Spot.Center
    },

    /* add Bindings here */
    // example Node binding sets Node.location to the value of Node.data.loc
    new go.Binding("location", "loc"),

    /* add GraphObjects contained within the Node */
    // this Shape will be vertically above the TextBlock
    $(go.Shape,
      "RoundedRectangle", // string argument can name a predefined figure
      { /* set Shape properties here */ },
      // example Shape binding sets Shape.figure to the value of Node.data.fig
      new go.Binding("figure", "fig")),

    $(go.TextBlock,
      "default text",  // string argument can be initial text string
      { /* set TextBlock properties here */ },
      // example TextBlock binding sets TextBlock.text to the value of Node.data.text
      new go.Binding("text"))
  );
      

Panel中GraphObjects的嵌套可以任意深,每个类都有其自己独特的属性集可以使用,但这只是大致的意思

既然我们已经了解了如何制作Node模板,那么让我们来看一个实时示例。我们将制作一个在组织结构图中常见的简单模板-名称旁边的图像。考虑以下节点模板:

var $ = go.GraphObject.make;
var myDiagram =
  $(go.Diagram, "myDiagramDiv",
    { // enable Ctrl-Z to undo and Ctrl-Y to redo
      "undoManager.isEnabled": true
    });

// define a simple Node template
myDiagram.nodeTemplate =
  $(go.Node, "Horizontal",
    // the entire node will have a light-blue background
    { background: "#44CCFF" },
    $(go.Picture,
      // Pictures should normally have an explicit width and height.
      // This picture has a red background, only visible when there is no source set
      // or when the image is partially transparent.
      { margin: 10, width: 50, height: 50, background: "red" },
      // Picture.source is data bound to the "source" attribute of the model data
      new go.Binding("source")),
    $(go.TextBlock,
      "Default Text",  // the initial value for TextBlock.text
      // some room around the text, a larger font, and a white stroke:
      { margin: 12, stroke: "white", font: "bold 16px sans-serif" },
      // TextBlock.text is data bound to the "name" property of the model data
      new go.Binding("text", "name"))
  );

var model = $(go.Model);
model.nodeDataArray =
[ // note that each node data object holds whatever properties it needs;
  // for this app we add the "name" and "source" properties
  { name: "Don Meow", source: "cat1.png" },
  { name: "Copricat", source: "cat2.png" },
  { name: "Demeter",  source: "cat3.png" },
  { /* Empty node data */  }
];
myDiagram.model = model;
      

该代码产生以下图表:

当并非所有信息都存在时,例如当图像未加载或名称未知时,我们可能希望显示一些“默认”状态。此示例中的“空”节点数据用于显示节点模板可以很好地工作,而无需绑定数据上的任何属性。

各种模型

使用自定义节点模板,我们的图变得很漂亮,但是也许我们想展示更多。也许我们希望组织结构图显示Don Meow确实是卡特尔的老板。因此,我们将通过添加一些链接以显示各个节点之间的关系以及一个自动放置节点的布局来创建完整的组织结构图。

为了使我们的图中的链接,基本 Model 不会削减它. 们将不得不在GoJS中选择其他两个模型之一,它们都支持Links. 这些是GraphLinksModelTreeModel. (此处阅读有关模型的更多信息.)

在GraphLinksModel中model.linkDataArray除了 model.nodeDataArray. 它包含一个JavaScript对象数组,每个JavaScript对象都通过指定“ to”和“ from”节点键来描述链接。这是一个示例,其中节点A链接到节点B,节点B链接到节点C

var model = $(go.GraphLinksModel);
model.nodeDataArray =
[
  { key: "A" },
  { key: "B" },
  { key: "C" }
];
model.linkDataArray =
[
  { from: "A", to: "B" },
  { from: "B", to: "C" }
];
myDiagram.model = model;
      

GraphLinksModel允许您在节点之间建立任意数量的链接,并且链接方向不限。从A到B可能有十个链接,从B到A的相反三个链接.

TreeModel的工作原理略有不同。代替维护链接数据的单独数组,树模型中的链接是通过为节点数据指定“父”来创建的。然后从该关联中创建链接。这是与TreeModel相同的示例,其中节点A链接到节点B,节点B链接到节点C:

var model = $(go.TreeModel);
model.nodeDataArray =
[
  { key: "A" },
  { key: "B", parent: "A" },
  { key: "C", parent: "B" }
];
myDiagram.model = model;
      

TreeModel比GraphLinksModel简单,但是它不能建立任意链接关系,例如相同两个节点之间的多个链接或具有多个父级。我们的组织图是一个简单的分层树状结构,因此在此示例中我们将选择TreeModel。

首先,我们将通过使用TreeModel添加更多的节点并在数据中指定键和父代来完成数据。

var $ = go.GraphObject.make;
var myDiagram =
  $(go.Diagram, "myDiagramDiv",
    { "undoManager.isEnabled": true });

// the template we defined earlier
myDiagram.nodeTemplate =
  $(go.Node, "Horizontal",
    { background: "#44CCFF" },
    $(go.Picture,
      { margin: 10, width: 50, height: 50, background: "red" },
      new go.Binding("source")),
    $(go.TextBlock, "Default Text",
      { margin: 12, stroke: "white", font: "bold 16px sans-serif" },
      new go.Binding("text", "name"))
  );

var model = $(go.TreeModel);
model.nodeDataArray =
[ // the "key" and "parent" property names are required,
  // but you can add whatever data properties you need for your app
  { key: "1",              name: "Don Meow",   source: "cat1.png" },
  { key: "2", parent: "1", name: "Demeter",    source: "cat2.png" },
  { key: "3", parent: "1", name: "Copricat",   source: "cat3.png" },
  { key: "4", parent: "3", name: "Jellylorum", source: "cat4.png" },
  { key: "5", parent: "3", name: "Alonzo",     source: "cat5.png" },
  { key: "6", parent: "2", name: "Munkustrap", source: "cat6.png" }
];
myDiagram.model = model;
      

图的布局

如您所见,TreeModel自动创建必要的Link来关联Node,但是很难确定谁是谁。

图具有默认布局,该布局采用所有没有位置的节点并为其指定位置,并将它们排列在网格中。我们可以显式地为每个节点提供一个位置,以整理出这种组织混乱的情况,但是在我们的情况下,作为一种更简单的解决方案,我们将使用一种布局,该布局会自动为我们提供良好的位置。

我们想要显示一个层次结构,并且已经在使用TreeModel,因此最自然的布局选择是TreeLayout。TreeLayout默认为从左到右流动,因此要使其从上到下流动(这在组织图中是常见的),我们将angle属性设置为90。

GoJS中使用布局通常很简单。每种布局都有许多影响结果的属性。每个布局都有一些示例(例如 TreeLayout示例)来展示其属性。

// define a TreeLayout that flows from top to bottom
myDiagram.layout =
  $(go.TreeLayout,
    { angle: 90, layerSpacing: 35 });
      

GoJS 还有其他几种布局,您可以在此处阅读.

到目前为止,将布局添加到图和模型中,我们可以看到结果:

var $ = go.GraphObject.make;
var myDiagram =
  $(go.Diagram, "myDiagramDiv",
    {
      "undoManager.isEnabled": true,
      layout: $(go.TreeLayout, // specify a Diagram.layout that arranges trees
                { angle: 90, layerSpacing: 35 })
    });

// the template we defined earlier
myDiagram.nodeTemplate =
  $(go.Node, "Horizontal",
    { background: "#44CCFF" },
    $(go.Picture,
      { margin: 10, width: 50, height: 50, background: "red" },
      new go.Binding("source")),
    $(go.TextBlock, "Default Text",
      { margin: 12, stroke: "white", font: "bold 16px sans-serif" },
      new go.Binding("text", "name"))
  );

var model = $(go.TreeModel);
model.nodeDataArray =
[
  { key: "1",              name: "Don Meow",   source: "cat1.png" },
  { key: "2", parent: "1", name: "Demeter",    source: "cat2.png" },
  { key: "3", parent: "1", name: "Copricat",   source: "cat3.png" },
  { key: "4", parent: "3", name: "Jellylorum", source: "cat4.png" },
  { key: "5", parent: "3", name: "Alonzo",     source: "cat5.png" },
  { key: "6", parent: "2", name: "Munkustrap", source: "cat6.png" }
];
myDiagram.model = model;
      

我们的图表开始看起来像是正确的组织结构图,但是我们可以通过链接做得更好。

链接模板

我们将构建一个新的Link模板,该模板将更适合我们宽阔的Boxy节点. 一个Link是一种不同的部分,而不是像一个节点。链接的主要元素是链接的形状,并且必须是一个形状,其形状将由GoJS动态计算。我们的链接将仅由这种形状组成,其笔触比正常的笔触要粗一些,并且深灰色而不是黑色。与默认链接模板不同,我们将没有箭头。然后,将链接routing属性从Normal更改为Orthogonal,并为其赋予一个corner值,以使直角转角变圆。

// define a Link template that routes orthogonally, with no arrowhead
myDiagram.linkTemplate =
  $(go.Link,
    // default routing is go.Link.Normal
    // default corner is 0
    { routing: go.Link.Orthogonal, corner: 5 },
    // the link path, a Shape
    $(go.Shape, { strokeWidth: 3, stroke: "#555" })

    // if we wanted an arrowhead we would also add another Shape with toArrow defined:
    // $(go.Shape, { toArrow: "Standard", stroke: null }
    );
      

将我们的Link模板与Node模板,TreeModel和TreeLayout结合在一起,我们终于有了完整的组织图。下面重复完整的代码,结果图如下

var $ = go.GraphObject.make;

var myDiagram =
  $(go.Diagram, "myDiagramDiv",
    {
      "undoManager.isEnabled": true,
      layout: $(go.TreeLayout,
                { angle: 90, layerSpacing: 35 })
    });

// the template we defined earlier
myDiagram.nodeTemplate =
  $(go.Node, "Horizontal",
    { background: "#44CCFF" },
    $(go.Picture,
      { margin: 10, width: 50, height: 50, background: "red" },
      new go.Binding("source")),
    $(go.TextBlock, "Default Text",
      { margin: 12, stroke: "white", font: "bold 16px sans-serif" },
      new go.Binding("text", "name"))
  );

// define a Link template that routes orthogonally, with no arrowhead
myDiagram.linkTemplate =
  $(go.Link,
    { routing: go.Link.Orthogonal, corner: 5 },
    $(go.Shape, // the link's path shape
      { strokeWidth: 3, stroke: "#555" }));

var model = $(go.TreeModel);
model.nodeDataArray =
[
  { key: "1",              name: "Don Meow",   source: "cat1.png" },
  { key: "2", parent: "1", name: "Demeter",    source: "cat2.png" },
  { key: "3", parent: "1", name: "Copricat",   source: "cat3.png" },
  { key: "4", parent: "3", name: "Jellylorum", source: "cat4.png" },
  { key: "5", parent: "3", name: "Alonzo",     source: "cat5.png" },
  { key: "6", parent: "2", name: "Munkustrap", source: "cat6.png" }
];
myDiagram.model = model;
      

学到更多

您可能需要阅读更多教程,例如 GraphObject Manipulation 教程和 Interactivity 教程. 您也可以在 YouTube上观看教程.

还可以考虑查看 示例 以查看 GoJS可能提供的一些图表 或者阅读 技术介绍 以深入了解 GoJS的组件。