内容简介:上一章我们了解了如何使用 gojs 完成基本的节点和连接线的绘制, gojs 中还可以对节点或边进行自由拖动, 编辑等功能; 本章将基于上一章编写的流程图代码, 为这些节点设置装饰器模板完成后的效果图:建议下载源码, 对照本文进行学习, 源码地址:
上一章我们了解了如何使用 gojs 完成基本的节点和连接线的绘制, gojs 中还可以对节点或边进行自由拖动, 编辑等功能; 本章将基于上一章编写的流程图代码, 为这些节点设置装饰器模板
完成后的效果图:
建议下载源码, 对照本文进行学习, 源码地址: github.com/muzqi/sampl…
选择节点装饰器
在默认情况下, 我们用鼠标点击某个节点. 该节点会被一个蓝色的框所包裹,
选择节点装饰器
, 如果我们想改变这个框的样式, 我们就需要为节点设置模板
编写模板
const nodeSelectionAdornmentTemplate =
// [1]
$(go.Adornment, go.Panel.Auto,
// [2]
$(go.Shape, {
fill: null,
stroke: 'yellow',
strokeWidth: 1,
strokeDashArray: [6, 6, 2, 2]
}),
// [3]
// { width: 500, height: 200 }
$(go.Placeholder))
复制代码
代码注释:
- 我们使用
go.Adornment对象, 创建一个模板, 这实际上跟我们之前学到的节点模板思路是完全一样的, 定义它的 布局方式 , 再定义它的 形状 等属性 - 定义形状, 在这里我们定义了一个描边为黄色的虚线选择节点装饰器
- 设置
go.Placeholder对象的目的是, 让装饰器自适应节点的大小; 反之, 我们可以自定义装饰器的大小
引入模板
我们来到定义节点模板的地方, 并为 go.Node 对象设置装饰器模板
diagram.nodeTemplateMap.add('node1',
$(go.Node, go.Panel.Position,
// ...
{
// [1]
selectable: true,
// [2]
selectionAdornmentTemplate: nodeSelectionAdornmentTemplate
}
// ...
)
)
复制代码
代码注释:
selectable selectionAdornmentTemplate
调整节点大小装饰器
用过 ps 的同学应该都知道, Ctrl + T 后, 能够唤出调整大小的操作装饰器, 我们现在需要给节点添加一个这样的装饰器, 让它支持 resize 操作
编写模板
const makeNodeResizeShapeOption = (cursor, alignment) => ({
cursor,
alignment,
desiredSize: new go.Size(12, 12),
fill: 'lightyellow',
stroke: 'yellow'
})
const nodeResizeAdornmentTemplate =
// [1]
$(go.Adornment, go.Panel.Spot,
$(go.Placeholder),
// [2]
$(go.Shape, makeNodeResizeShapeOption('nw-resize', go.Spot.TopLeft)),
$(go.Shape, makeNodeResizeShapeOption('ne-resize', go.Spot.TopRight)),
$(go.Shape, makeNodeResizeShapeOption('se-resize', go.Spot.BottomLeft)),
$(go.Shape, makeNodeResizeShapeOption('sw-resize', go.Spot.BottomRight))
)
复制代码
代码注释:
- 同样, 我们还是使用
go.Adornment来定义装饰器; 在这里, 我们布局方式使用了go.Panel.Spot - 我们定义了四个
go.Shape, 来表示装饰器的四个拖拽顶点
引入模板
diagram.nodeTemplateMap.add('node1',
$(go.Node, go.Panel.Position,
// ...
{
resizable: true,
resizeAdornmentTemplate: nodeResizeAdornmentTemplate
}
// ...
)
)
复制代码
resizeObjectName
调整大小装饰器引入时还可以传入一个 resizeObjectName 值, 表示指定需要应用装饰器的元素, 这个元素可以是 go.Shape go.Picture go.Text 任何 gojs 的元素
diagram.nodeTemplateMap.add('node1',
$(go.Node, go.Panel.Position,
// ...
{
resizable: true,
// [1]
resizeObjectName: 'TEXT'
resizeAdornmentTemplate: nodeResizeAdornmentTemplate
},
// ...
$(go.TextBlock,
// [2]
{ name: 'TEXT' }
// ...
)
)
)
复制代码
代码注释:
- 设置
resizeObjectName为TEXT - 将一个文字块元素的名字设置为
TEXT
如上图所示, 只有文字块被允许设置大小了
旋转节点装饰器
相比较前面的装饰器, 旋转节点装饰器存在一个巨坑;你会发现当你绘制出一个 把手 后, 你除了使用 Position 来绝对定位它, 否则你很难将其相对定位居中展示
官方的实例(其实他并没有被写到文档中去, 而是在demo文件中找到的方法)是将 go.RotatingTool 这个对象给改写掉了, 在初始化的时候, 就将 把手的位置默认居中
请看以下代码:
编写模板
// [1]
const makeTopRotatingTool = () => (
class TopRotatingTool extends go.RotatingTool {
updateAdornments(part) {
go.RotatingTool.prototype.updateAdornments.call(this, part)
var adornment = part.findAdornment('Rotating')
if (adornment !== null) {
// [2]
adornment.location = part.rotateObject.getDocumentPoint(new go.Spot(0.5, 0, 0, -30)) // above middle top
}
}
rotate(newangle) {
go.RotatingTool.prototype.rotate.call(this, newangle + 90)
}
}
)
// [3]
const nodeRotateAdornmentTemplate =
$(go.Adornment,
$(go.Shape, 'Circle',
{
cursor: 'pointer',
desiredSize: new go.Size(7, 7),
fill: 'lightyellow',
stroke: 'yellow'
}),
$(go.Shape,
{
geometryString: 'M3.5 7 L3.5 30',
isGeometryPositioned: true,
stroke: 'yellow',
strokeWidth: 1.5,
strokeDashArray: [4, 2]
})
)
// [4]
const diagram = $(go.Diagram, 'diagram', {
'initialContentAlignment': go.Spot.Center,
'undoManager.isEnabled': true,
'rotatingTool': $(makeTopRotatingTool())
})
复制代码
代码注释:
- 我们重新定义了一个类, 这个类继承了
go.RotatingTool - 我们在这个类中, 定义了 把手 的位置默认是在顶部居中
- 使用
go.Adornment对象制作模板, 这个模板只负责 把手 最终长成什么样子 - 在初始化
diagram的时候, 引用自定义的 工具 类makeTopRotatingTool
引用模板
diagram.nodeTemplateMap.add('node1',
$(go.Node, go.Panel.Position,
// ...
{
rotatable: true,
// [1]
// rotateObjectName: 'TEXT'
rotateAdornmentTemplate: nodeRotateAdornmentTemplate,
// [2]
locationSpot: go.Spot.Center
},
// ...
)
)
复制代码
代码注释:
rotateObjectName locationSpot
拖拽创建连接线
前面我们已经将所有节点的装饰器添加完成, 最后, 我们需要实现从一个节点到另一个节点, 手动拖出连接线的功能;
为了更清晰的展示这个功能, 我们重新建立一块画布, 单独讲解;
实现原理
在 gojs 模板中, 任何一个元素, 都具备这三个属性:
port
只要具备这三个属性, 任何元素都能够拖出或者接收连接线, 并使两个节点产生连接关系
简单实现
<div id="port" style="width: 1000px; height: 500px"></div> 复制代码
const portDiagram = $(go.Diagram, 'port', {
'initialContentAlignment': go.Spot.Center,
'undoManager.isEnabled': true
})
// 指定被创建的连接线的模板
portDiagram.linkTemplate = $(go.Link,
$(go.Shape, { stroke: 'black', strokeWidth: 3 })
)
// 指定被创建的节点的模板
portDiagram.nodeTemplate = $(go.Node,
new go.Binding('position'),
$(go.Shape,
{
fill: 'blue',
fromLinkable: true,
toLinkable: true
},
new go.Binding('portId', 'key')
)
)
portDiagram.model = new go.GraphLinksModel(
[
{
key: '1',
position: new go.Point(500, 0)
},
{
key: '2',
position: new go.Point(0, 0)
}
]
)
复制代码
细心的同学就会发现了, 现在我们的整个节点作为一个 port , 只要鼠标点击拖动节点, 就会拉出一条连接线, 但如果我们需要移动节点怎么办?
所以通常情况下, 我们会在节点中绘制几个点, 让这几个点具备拖拽接收连接线的功能;
改写上面的代码:
// ...
const makePort = (portId, spot) => (
$(go.Shape, {
cursor: 'pointer',
fill: 'red',
width: 10,
height: 10,
alignment: spot,
portId,
fromLinkable: true,
toLinkable: true
})
)
portDiagram.nodeTemplate =
$(go.Node, go.Panel.Spot,
new go.Binding('position'),
$(go.Shape, { fill: 'blue' }),
makePort('T', go.Spot.Top),
makePort('B', go.Spot.Bottom),
makePort('L', go.Spot.Left),
makePort('R', go.Spot.Right),
)
// ...
复制代码
实现效果如下:
下章继续讲解, 连接线的编辑模板
(未完待续)
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- C++源码流程图分析!
- R语言绘制流程图(二)
- 自己调研的常用开源流程图组件
- yEd 3.21 发布,流程图绘制工具
- BPMN学习第一步:简单的流程图
- 使用markdown画流程图/甘特图 - Mermaid
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
R for Data Science
Hadley Wickham、Garrett Grolemund / O'Reilly Media / 2016-12-25 / USD 39.99
http://r4ds.had.co.nz/一起来看看 《R for Data Science》 这本书的介绍吧!