GoJS是一个用于实现交互式图表的JavaScript库。
因为GoJS是一个依赖于HTML5特性的JavaScript库,所以您需要确保您的页面声明它是一个HTML5文档。
当然,你需要加载库:
. . .
您可以从这里下载GoJS以及所有文档和示例。或者你可以直接链接到一个CDN提供的GoJS库,如:
每个GoJS图(Diagram)都包含在一个指定了大小的 当我们创建图(Diagram)对象时,需要在JS代码中传入上述 这样就成功创建了一个空的图! 注意,go是所有GoJS类型的“命名空间”。所有使用GoJS类的代码,如Diagram、Node、Panel、Shape、TextBlock,都将以“go.”作为前缀。 本文将通过示例向您展示如何使用go.GraphObject.make来构建GoJS对象。使用$作为go.GraphObject.make的缩写会非常方便,如果您已经在代码的其它地方使用了$,那么您可以在此处选择不同的短变量名,例如$$或MAKE或GO。 我们在图(Diagram)中看到的节点(Node)和链接(Link)其实是数据可视化的结果,这些数据是由模型(Model)管理的。 GoJS有一个模型-视图(model-view)架构,其中模型保存描述节点和链接的数据(JavaScript对象数组),而图充当视图,使用实际的节点和链接对象来可视化这些数据。模型(Model)是您在编辑后加载并保存的内容。 您可以在模型的数据对象上添加需要的任何属性;但您不能向Diagram和GraphObject类的原型添加或修改属性。 下面是一个模型和图的例子: 生成的效果图(截图)如下 : 图显示了模型中的三个节点。我们可以尝试以下操作: 1.在上图中单击并拖动背景以平移视图。 2.单击节点以选择它,或按下并拖动节点以移动它。 3.要创建一个选择框,请在背景上单击并按住,然后开始拖动。 4.使用Ctrl-C和Ctrl-V或Ctrl-拖放 复制所选内容。 5.按Delete键删除所选节点。 6.在触控设备上,按下并按住键会弹出上下文菜单。 7.由于启用了撤消管理器,Ctrl-Z和Ctrl-Y将具备撤消和重做功能。 我们可以通过创建由GraphObjects组成的模板(templates)并在这些对象上设置属性来设置节点的样式。我们可以通过以下几个构建块类来创建一个节点: 1.Shape, 形状:使用颜色显示预定义的或自定义的几何图形 2.TextBlock, 文本块:以各种字体显示文本(可以设置是否允许编辑) 3.Picture, 图片:显示图像,包括SVG文件 4.Panel, 面板:容纳其他对象集合的容器,这些对象可以根据面板的类型以不同的方式定位和调整大小(如表、垂直堆栈和拉伸容器) 所有这些构建块都派生自GraphObject抽象类,所以我们可以称它们为GraphObjects或objects或elements。请注意,GraphObject不是HTML DOM元素,因此创建或修改这些对象的开销要小得多。 我们希望模型数据的属性能够影响节点,这是通过数据绑定实现的。我们可以将GraphObjects的属性与模型数据绑定起来,这样就能通过修改模型数据的值来更改节点中GraphObjects的外观和行为。模型数据对象是普通的JavaScript对象。您可以选择在模型中的节点数据上使用任何您喜欢的属性名称。 默认的节点模板很简单:一个包含一个文本块的节点。在TextBlock的text属性和model的key属性之间有一个数据绑定。在代码中,模板看起来像这样: 文本块、形状和图片是GoJS的基本构建块。文本块不能包含图像;形状不能包含文本。如果您希望您的节点显示一些文本,您必须使用文本块。如果你想绘制或填充一些几何图形,你必须使用一个形状。 更常见的节点模板的骨架看起来是这样的: GraphObject在面板中的嵌套深度可以是任意的,而且每个类都有自己独特的属性集可以利用。 现在我们已经了解了如何创建节点模板,让我们来看一个实际示例。我们将创建一个在组织图中常见的简单模板——带文字的图像。考虑以下节点模板: 该代码生成如下图: 当一个图像没有加载或者当一个名称没有设置时,我们可能想要显示一些“默认”状态。本例中的“空”节点数据用于显示节点模板在没有绑定数据上的任何属性的情况下也可以很好地工作,如第四个节点所示。 使用自定义节点模板,我们的关系图将变得非常美观,但也许我们还需要显示更多内容。下面,我们将通过添加一些链接来显示各个节点之间的关系,以及自动定位节点的布局来创建一个完整的组织结构图。 为了在图中添加链接,我们将不得不在GoJS中选择另外两种模型中的一种,这两种模型都支持链接。这两个是GraphLinksModel和TreeModel。 在GraphLinksModel模型当中,除了model.nodeDataArray,还有一个model.linkDataArray。它包含一个JavaScript对象数组,每个对象通过指定“from”和“to”节点键来描述一个链接。下面是节点A-->节点B和节点B-->节点C的例子: GraphLinksModel允许在节点之间有任意数量的链接,并且可以沿着任何方向进行。比如从A到B可能有十个链接,从B到A可能还有三个链接。 TreeModel的工作原理有点不同。树模型中的链接不是维护一个单独的链接数据数组,而是通过指定节点数据的“parent”来创建的。然后从这个关联创建链接。下面是一个相同的TreeModel示例,节点a链接到节点B,节点B链接到节点C: TreeModel比GraphLinksModel更简单,但是它不能建立任意的链接关系,比如同一两个节点之间的多个链接,或者拥有多个父节点。我们的组织图是一个简单的层次树状结构,因此我们将为本例选择TreeModel。 首先,我们将通过给TreeModel添加更多节点并在数据中指定键和父节点的方式来完成数据。 正如您所看到的,TreeModel自动创建必要的链接来关联节点,但是很难区分谁是谁的父节点。 图有一个默认的布局,它接受所有没有位置的节点,并为它们提供位置,将它们排列在一个网格中。我们可以明确地为每个节点提供一个位置,以整理这种混乱的组织结构,但在我们的案例中,采用了一个更简单的解决方案:使用一个自动提供良好位置的布局。 我们想要显示一个层次结构,并且已经使用了TreeModel,所以最自然的布局选择是TreeLayout。TreeLayout默认是从左到右流动的,所以要让它从上到下流动(在组织图中很常见),我们将角度(angle)属性设置为90。 在GoJS中使用布局通常很简单。每种布局都有许多影响结果的属性。每个布局都有一些示例(比如TreeLayout演示)来展示其属性。 GoJS还有其他一些布局,你可以在这里读到。 将布局添加到图和模型中,我们可以看到这样的效果: 我们的图开始看起来像一个合格的组织图了,但是我们可以用链接做得更好。 我们将构建一个新的链接模板,它将更适合我们的宽的、方正的节点。链接是一种不同类型的部件(Part),不像节点。链接的主要元素是形状(Shape)。我们的链接想要这样的效果:它的笔画比正常的要粗一些,是深灰色而不是黑色,不要箭头。我们将把链接的routing属性从Normal改为Orthogonal(正交),并给它一个corner值,这样直角的转角就是圆角。 将链接模板与节点模板、TreeModel和TreeLayout结合起来,我们最终得到了一个完整的组织图。 下面重复完整的js代码,效果图如下: 您可能想要阅读更多教程,比如GraphObject操作教程和交互性教程。还可以考虑查看示例以了解使用GoJS时可能出现的一些图表,或者阅读技术介绍以深入了解GoJS的组件。 官方教程:https://gojs.net/latest/learn/index.html https://gitee.com/lanying100/GoJS-primary
var $ = go.GraphObject.make;
var myDiagram =
$(go.Diagram, "myDiagramDiv");
图(Diagram)和模型(Model)
// 1.给go.GraphObject.make起简称
var $ = go.GraphObject.make;
// 2.创建Diagram对象
var myDiagram =
$(go.Diagram, "myDiagramDiv",
{ // 启用撤销(Ctrl-Z)和重做(Ctrl-Y)功能
"undoManager.isEnabled": true
});
// 3.创建Model对象
var myModel = $(go.Model);
// 给Model对象配置数据:对于该数组中的每一个对象,Diagram都会创建一个Node来表示它
myModel.nodeDataArray = [
{ key: "Alpha" },
{ key: "Beta" },
{ key: "Gamma" }
];
// 4.将Model传入Diagram
myDiagram.model = myModel;
节点的式样
myDiagram.nodeTemplate =
$(go.Node,
$(go.TextBlock,
// TextBlock.text 绑定到了 Node.data.key
new go.Binding("text", "key"))
);
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"))
);
var $ = go.GraphObject.make;
var myDiagram =
$(go.Diagram, "myDiagramDiv",
{ // 启用Ctrl-Z撤消,Ctrl-Y重做
"undoManager.isEnabled": true
});
// 定义一个简单的节点模板
myDiagram.nodeTemplate =
$(go.Node, "Horizontal",
// 整个节点将有一个浅蓝色的背景
{ background: "#44CCFF" },
$(go.Picture,
// 图片通常应该有明确的宽度和高度。
// 这张图片有一个红色的背景,只有当没有设置数据源或者当图像部分透明时才可见
{ margin: 10, width: 50, height: 50, background: "red" },
// Picture.source 绑定到了数据模型的"source"属性
new go.Binding("source")),
$(go.TextBlock,
"Default Text", // TextBlock.text的初始值
// 文字周围留出一些空间,白色的笔画,大一些的粗体字体:
{ margin: 12, stroke: "white", font: "bold 16px sans-serif" },
// TextBlock.text 绑定到了数据模型的"name"属性
new go.Binding("text", "name"))
);
var model = $(go.Model);
model.nodeDataArray =
[ // 注意,每个节点数据对象保存它需要的任何属性;
// 在这个应用程序中,我们添加了“name”和“source”属性
{ name: "谷歌浏览器", source: "images/chrome.png" },
{ name: "火狐浏览器", source: "images/firefox.png" },
{ name: "IE浏览器", source: "images/ie.png" },
{ /* 空的节点数据 */ }
];
myDiagram.model = model;
各种各样的Model
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;
var model = $(go.TreeModel);
model.nodeDataArray =
[
{ key: "A" },
{ key: "B", parent: "A" },
{ key: "C", parent: "B" }
];
myDiagram.model = model;
var $ = go.GraphObject.make;
var myDiagram =
$(go.Diagram, "myDiagramDiv",
{ "undoManager.isEnabled": true });
// 我们之前定义的模板
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”和“parent”属性名是必需的,
// 但你可以为你的应用添加任何你需要的数据属性
{ 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;
图(Diagram)的布局
// define a TreeLayout that flows from top to bottom
myDiagram.layout =
$(go.TreeLayout,
{ angle: 90, layerSpacing: 35 });
var $ = go.GraphObject.make;
var myDiagram =
$(go.Diagram, "myDiagramDiv",
{
"undoManager.isEnabled": true,
layout: $(go.TreeLayout, // 指定一个Diagram.layout来排列我们的树
{ angle: 90, layerSpacing: 35 })
});
// 我们之前定义的模板
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)的模板
// 定义一个不带箭头的垂直(正交)路由的链接模板
myDiagram.linkTemplate =
$(go.Link,
// 默认的 routing是 go.Link.Normal
// 默认的 corner 是 0
{ routing: go.Link.Orthogonal, corner: 5 },
// 链接路径,是一个 Shape
$(go.Shape, { strokeWidth: 3, stroke: "#555" })
// 如果我们想要一个箭头,我们还需要添加另一个定义了toArrow的形状:
// $(go.Shape, { toArrow: "Standard", stroke: null }
);
var $ = go.GraphObject.make;
var myDiagram =
$(go.Diagram, "myDiagramDiv",
{
"undoManager.isEnabled": true,
layout: $(go.TreeLayout,
{ angle: 90, layerSpacing: 35 })
});
// 我们之前定义的模板
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"))
);
// 定义一个不带箭头的垂直(正交)路由的链接模板
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;
Learn More
参考网址
完整Demo源码