# 欢迎来到 Spring FLO 维基!

Spring FLO 是用于图表编辑器的一组Angular JS (opens new window)指令,该编辑器能够以图形方式表示 DSL 并同步该 DSL 的图形和文本表示。图形表示是用Joint JS (opens new window)图形对象完成的,文本表示可以是普通的 HTML 元素(例如<textarea>),也可以是基于CodeMirror (opens new window)的功能丰富的编辑器,可通过 FLO 指令获得。

# 如何在应用程序中嵌入 Spring FLO!

Spring FLO 可以通过flo-editor指令在任何有角的应用程序中使用。该指令的控制器创建/填充floFlo)和definitionDefinition)对象。这些对象是消费客户机与 FLO 进行互操作的方式。definition对象是用于读/写 DSL 文本表示的双向绑定。flo对象是一个双向绑定,用于处理 DSL 的图形表示(包括控制编辑器功能,例如缩放、网格、布局等)。

在 Spring-FLOrepo:https://github.com/spring-projects/spring-flo/tree/master/samples/spring-flo-sample 的 samples 子文件夹中有一个示例项目-这个示例将在下面的文档中被引用,以提供一个指针来指示每个特性的实际使用情况。

将 FLO 嵌入到 Angular 应用程序中的第一步是简单地在页面或 Angular 模板中使用flo-editor指令。

<flo-editor></flo-editor>

上面的结果是一个带有编辑器框架的页面:空的调色板和空的画布。有关更复杂的配置,请参见样本使用情况 (opens new window)。FLO 为编辑器和图形交互定义了 UI,但需要客户端的领域知识才能真正有用。实际上,消费客户端可以提供三种服务来控制 FLO 的行为,其中只有一种是强制性的:

  1. 定义由图形表示的元素类型并在域 DSL 文本格式和图形格式之间进行双向转换的服务(必需的)
  2. 定义图上节点和链接的可视化表示的服务
  3. 控制图形编辑功能的服务

实现应该由客户机以角服务的形式提供,并遵守延伸点 (opens new window)中详细说明的特定契约。这些服务是:元模型服务(必需的),渲染服务编辑服务

许多服务功能都有合理的缺省值。在这一节中,我们将讨论一些重要的问题,其中只有一些是强制性的。

为了在调色板中填充内容,FLO 需要了解你的域。在你的图表中,你要连接在一起的“事物”是什么?实现元模型服务load()函数将向 FLO 提供该信息。

app.factory('MyPageMetamodelService', ['$log', function($log) {
  return {
    load: function() { $log.info('Return descriptions of the domain specific model elements'); }
  };
}]);

样本包括更完整的元模型服务 (opens new window)。一旦定义,服务可以通过名称提供给父作用域(通过父控制器$scope.metamodelServiceName = 'MyPageMetamodelService';.)或直接提供给flo-editor指令(通过metamodel-service-name``<flo-editor>元素上的属性)。让我们修改flo-editor指令:

<flo-editor metamodel-service-name="MyPageMetamodelService">
</flo-editor>

这也是样本index.html (opens new window)的工作方式。将元模型服务连接到编辑器后,将基于从元模型服务获得的元模型对象填充调色板。然后,你应该能够在画布上放置节点,用链接连接节点,并移动它们。请注意,节点和链接的可视化表示可能与期望的相去甚远。实现渲染服务使你能够自定义该外观和感觉(在没有提供的呈现服务的情况下,FLO 执行一些非常基本的呈现)。一个基本的呈现服务将实现createnode()createlink()函数(另见JS API 联合 DOCS (opens new window)),以获得调色板和画布上形状的正确外观和感觉。

app.factory('MyPageRenderService', ['$log', function($log) {
  return {
    createNode: function(metadata) { $log.info('Create and return new Joint JS joint.dia.Element for a graph node'); },
    createLink: function(source, target, metadata, props) { $log.info('Create and return new Joint JS joint.dia.Link for a link between graph nodes'); }
  };
}]);

样本包括更完整的渲染服务 (opens new window)。与元模型服务一样,将其连接到flo-editor指令

<flo-editor
  metamodel-service-name="MyPageMetamodelService" 
  render-service-name="MyPageRenderService">
</flo-editor>

有了基本的渲染处理,我们可以进一步定制:

  • 当形状被选中时,在形状周围添加“句柄”。“句柄”是通常放置在形状交互周围的小形状,它将对相关形状执行一些编辑操作,例如删除、调整大小或编辑属性。
  • 在节点和链接上提供带有验证指示器(错误/警告)的图形验证。
  • 编辑器操作工具栏可能很不错。

在 Render-Service 上实现更多功能可以支持这些特性中的一些特性,但有些特性需要实现最终的键服务编辑服务:

app.factory('MyPageEditorService', ['$log', function($log) {
  return {
    createHandles: function(flo, createHandle, selected) { $log.info('Create handles around selected element'); },
    validateLink: function(flo, cellViewS, portS, cellViewT, portT, end, linkView) { $log.info('Validate link');},
    validateNode: function(flo, node) { $log.info('Validate Node'); },
    preDelete: function(flo, deletedElement) { $log.info('Delete links incident with element being deleted '); },
    interactive: true, /* Consult Joint JS Paper #interactive property doc. Make elements interactive */
    allowLinkVertexEdit: false /* Disallow creation and editing of 'bend-points' in links */
  };
}]);

样本包括更完整的编辑服务 (opens new window)。呈现句柄和验证标记(装饰)必须由呈现服务提供,因为它们是编辑器服务所需要的。在 Spring-FLO 中没有定义用于呈现句柄和错误标记装饰形状的开箱即用呈现。因此,如果在编辑器服务中定义validateNode()createHandles(),则必须在呈现服务中实现createDecoration()createHandle

app.factory('MyPageRenderService', ['$log', function($log) {
  return {
    createHandle: function(kind, parent) { $log.info('Implement handle node creation'); },
    createDecoration: function(kind, parent) { $log.info('Implement error decoration node creation'); },
    createNode: function(metadata) { $log.info('Create and return new Joint JS joint.dia.Element for a graph node'); },
    createLink: function(source, target, metadata, props) { $log.info('Create and return new Joint JS joint.dia.Link for a link between graph nodes'); }
  };
}]);

可以通过 Transclusion 在flo-editor指令中以 HTML 形式添加新的工具栏操作,这可能是我们的编辑器服务也插入的情况:

<flo-editor
  metamodel-service-name="MyPageMetamodelService" 
  render-service-name="MyPageRenderService"
  editor-service-name="MyPageEditorService">
  <div>
    <button ng-click="flo.deleteSelectedNode()" ng-disabled="!flo.getSelection()">Delete</button>
    <button ng-click="flo.noPalette = !flo.noPalette" ng-class="{on:!flo.noPalette}">Palette</button>
  </div>
</flo-editor>

注意 HTML 中各种处理程序属性中的flo对象引用。flo-editor指令的控制器将使用用于操作 FLO 编辑器内容的函数填充flo对象。

在这个阶段,图形编辑器应该是功能齐全的,但是文本 DSL 呢?

将图形转换为文本 DSL,将文本 DSL 转换为图形的功能必须由客户机提供,这样才能正常工作。这两个函数(GraphToText()texttograph())必须在元模型服务中实现,让我们将它们添加到前面的定义中:

app.factory('MyPageMetamodelService', ['$log', function($log) {
  return {
    load: function() { $log.info('Implement load and return metamodel object!'); },
    textToGraph: function(flo, definition) { $log.info('Convert text (definition.text) to graph (flo.getGraph())'); },
    graphToText: function(flo, definition) { $log.info('Convert graph (flo.getGraph()) to text (definition.text)'); }
  };
}]);

该示例包括用于“demo”DSL 的图到文本 (opens new window)文本到图形 (opens new window)的基本实现,这些实现由元模型服务示例 (opens new window)使用。FLO 编辑器在内部维护definition对象中的文本 DSL,它只保留在 UI 中公开。文本 DSL 可以通过普通 HTML 元素显示,例如<textarea>或基于dsl-editor指令的高级CodeMirror (opens new window)。让我们在dsl-editor指令的帮助下修改 HTML,使其具有文本 DSL UI。

<flo-editor
  metamodel-service-name="MyPageMetamodelService" 
  render-service-name="MyPageRenderService"
  editor-service-name="MyPageEditorService">
  <div>
    <button ng-click="flo.deleteSelectedNode()" ng-disabled="!flo.getSelection()">Delete</button>
    <button ng-click="flo.noPalette = !flo.noPalette" ng-class="{on:!flo.noPalette}">Palette</button>
  </div>
  <textarea dsl-editor></textarea>
</flo-editor>

上面的 HTML 转换为一个页面,其中包含用于按钮(布局和显示/隐藏调色板)的工具栏,用于 DSL 的文本区和用于 DSL 的图形表示的 FLO 编辑器。

# 所有的扩展点:

# 元模型服务

该服务支持使用 FLO 的域来指定在图中连接在一起的元素的种类,以及图应该如何转换为文本表示形式。样例元模型服务在这里 (opens new window)

# texttograph(FLO,定义)

基于来自definition对象的 DSL 的文本表示设置flo对象的图形内容。将文本转换为相应的联合 JS 图内容。将通过flo对象函数(如flo.createLink()flo.createNode())填充图形,并使用flo.clearGraph

# GraphtoText(FLO,(定义)

将当前从flo对象获得的图形转换为文本表示,然后在definition对象上设置文本表示(作为text属性)。

# load()

返回一个 promise,该 promise 解析为metamodel对象。metamodel对象布局是元素group名称的映射到属于这个group的元素的映射。属于group的元素的映射是元素的name和元素的元数据对象 (opens new window)之间的映射

# 刷新()(可选)

刷新元模型并返回一个 promise,该 promise 被解析为与load()相同的结果。刷新也应该触发事件到metamodel更改侦听器。

# encodeTextToDSL(text)(可选)

将 DSL 元素属性值的文本编码为 DSL 所需的格式。示例是将多行文本转换为 DSL 格式所需的单行文本。用于以人类可读的格式显示属性值。

# decodeTextFroMDSL(dsl)(可选)

<gtr="94"/>从 DSL 格式中解码 DSL 元素属性值文本。例如,将单行文本转换为多行文本,即替换转义换行符。用于为用户通过 UI 输入的 DSL 元素设置属性值。

# subscribe(listener)(可选)

将一个侦听器添加到metamodel事件。(参见[元模型侦听器] (#metamodel-listener))

# unsubscribe(listener)(可选)

删除metamodel事件监听器。(参见元模型侦听器

# isvalidPropertyValue(element, key, value)(可选)

检查是否允许为指定元素上的键指定该值。例如:如果键取整数,则不允许使用字母字符。

# Render Service

服务负责基于元数据(来自元模型服务)的图形元素的可视化表示。此服务是可选的示例呈现服务在这里 (opens new window).

# createNode(metadata, properties) (可选)

创建联合 JS 图节点模型对象的实例(joint.dia.Element)。可能影响节点模型对象类型的参数是元素的metadata和属性映射(如果有传入的话)。

创建一个联合 JS Graph 链接模型对象的实例(joint.dia.Link)。可能影响链接模型对象类型的参数是元素的metadata、属性映射(如果有传入)、源元素和目标元素

# createHandle(kind, parent) (可选)

创建联合 JS 图节点模型对象的实例(joint.dia.Element)。句柄的一个示例是显示在与父形状交互的旁边的形状,该形状导致在父形状上进行一些编辑操作。可能影响句柄模型对象类型的参数是kind类型的string(用户定义,i。e.deleteresize等。)和句柄的parent元素。只有在实现了 Editor ServicecreateHandles()函数的情况下,框架才调用该函数。

# createDecoration(kind, parent) (可选)

创建一个联合 JS 图节点模型对象的实例(joint.dia.Element)。装饰的一个例子是显示在父形状上的验证标记。可能影响装饰模型对象种类的参数是kind类型的string和装饰的parent元素。注意,kind参数来自框架(与createHandle函数不同)。只有在实现了 Editor ServicevalidateNode()函数的情况下,框架才调用该函数。(目前装饰只是验证错误标记)。

# initializeNewNode(node, context) (可选)

对新创建的图node执行任何附加的初始化,当node已经添加到联合 JS 图中并在画布上呈现时,E。g.元素的 SVG DOM 结构是可用的。context参数是一个对象,其papergraph属性适用于node。当 SVG DOM 附加到页面 DOM 时,在节点上执行任何类型的初始化都是有用的。例如:将字符串标签放入形状中,在形状上使用角度指示,添加 DOM 侦听器等。

link已经添加到联合 JS 图并在画布上呈现时,执行新创建的图link的任何附加初始化。g.元素的 SVG DOM 结构是可用的。context参数是一个对象,其papergraph属性适用于link。当链接的 SVG DOM 附加到页面 DOM 时,在链接上执行任何类型的初始化都是有用的。例如:在形状上使用角度指令,添加 DOM 侦听器等。

# initializeNewHandle(handle, context) (可选)

handle已添加到联合 JS 图并在画布上呈现时,对新创建的图handle执行任何附加的初始化。g.元素的 SVG DOM 结构是可用的。context参数是一个对象,其papergraph属性适用于handle。当一个句柄形状的 SVG DOM 被追加到页面 DOM 时,对它执行任何类型的初始化都是有用的。例如:将字符串标签放入形状中,在形状上使用角度指示,添加 DOM 侦听器等。

# initializeNewDecoration(decoration, context) (可选)

decoration已添加到联合 JS 图并在画布上呈现时,对新创建的图decoration执行任何附加的初始化。g.元素的 SVG DOM 结构是可用的。context参数是一个对象,其papergraph属性适用于decoration。当装饰形状的 SVG DOM 附加到页面 DOM 时,对它执行任何类型的初始化都是有用的。例如:将字符串标签放入形状中,在形状上使用角度指示,添加 DOM 侦听器等。

# getNodeView() (可选)

返回joint.dia.ElementView的实例。它也可以是function(element)形式的函数,该函数接受一个元素模型,并应该返回一个负责将该模型呈现到屏幕上的对象。在正常情况下,这个功能不需要实现,由框架创建的联合 JS 视图对象应该足够了。如果不同的节点需要不同的联合 JS 视图,或者视图有一些特殊的呈现(I。e.嵌入的 HTML 元素)。参见联合 JS 文件选项 (opens new window)

# getLinkView() (可选)

返回联合 js 的实例joint.dia.LinkView。默认值为joint.dia.LinkView。它也可以是function(link)窗体的函数,它接受一个链接模型,并且应该返回一个负责将该模型呈现到屏幕上的对象。在正常情况下,这个功能不需要实现,由框架创建的联合 JS 视图对象应该足够了。如果不同的链接需要不同的联合 JS 视图,或者视图有一些特殊的呈现(I。e.模式应用于行-joint.shapes.flo.PatternLinkView)。参见联合 JS 文件选项 (opens new window)

# layout(paper) (可选)

负责布局可以从传入paper参数(paper.model)中派生出的联合 JS 图。

负责处理event上发生的、属于在联合 JS 中传递的link对象的paperevent参数是一个string,具有可能值:'add''remove'或联合 JS 本地链接更改事件,例如'change:source''change:target'等。参见联合 JS Link 活动 (opens new window)

# isSemanticProperty(propertyPath, element) (可选)

对于string属性路径propertyPathelement上如果图形需要执行一些基于propertyPath值变化的可视化更新(对于props下的属性不需要trueelement上)。可视更新由RefreshVisuals()执行。属性路径propertyPath是相对于联合 JS 元素attrs属性

# refreshVisuals(element, propertyPath, paper) (可选)

执行一些图形的可视化更新,或者更有可能,传入的element基于propertyPath指定的变更属性显示在联合 js 上paper<

# getLinkAnchorPoint(linkView, view, port, reference) (可选)

此函数允许你自定义链接的锚点是什么。函数必须返回一个点(带有xy属性),链接在这个点上锚定到元素。该函数获取链接视图、元素视图、链接应该粘贴的port(SVG 元素)和一个参考点(链接另一侧的最近顶点或锚点)。

# 编辑器服务

负责为 FLO 编辑器提供丰富的编辑功能的服务,例如围绕选定形状的句柄、自定义的拖放行为、实时和静态验证。此服务是可选的示例编辑服务在这里 (opens new window)

# createHandles(flo, createHandle, selected) (可选)

当节点被选中并且可以显示句柄时调用。句柄通常是selected编辑器交互中flo联合 JS 节点周围的小形状,用于修改selected节点上的属性,即调整大小或删除句柄。调用createHandle(selected, kind, clickHandlerFunction, coordinate)函数创建一个句柄。kind参数是一种string类型的句柄,clickHandlerFunction是在单击句柄时执行的,coordinate是放置句柄形状的位置。注意,如果实现了这个函数,那么 Render ServicecreateHandle(...)函数也必须实现。当需要时,框架将自动删除句柄,因此在客户端无需担心这一点。

# validatePort(paper, view, portView)(可选)

如果用户单击端口,请决定是否创建链接。portView是表示端口的 DOM 元素,view是端口的父联合 JS 视图对象,在联合 JSpaper中显示

决定是否允许或不允许源视图/端口(cellViewS/portS)和目标视图/端口(cellViewT/portT)之间的连接。end要么是'source'要么是'target',它告诉我们拖动链接的哪一端。这对于定义例如从元素 A 的端口输出开始的链接是否可以指向 Elmement B 的端口引脚很有用。

# calculateDragDescriptor(flo, draggedView, targetUnderMouse, coordinate, context) (可选)

coordinate上拖动一个节点draggedView时调用。还有floObject 参数和contextObject,它目前仅具有boolean属性palette来表示是否在调色板或画布上进行拖放。函数应该返回一个拖动描述符对象

# handleNodeDropping(flo, dragDescriptor) (可选)

在拖动的节点被拖放时执行必要的图形操作。dragDescriptor拖动描述符应该具有强制信息,说明正在拖动的内容和正在丢弃的位置。flo对象参数将有助于对图进行必要的修改

# showDragFeedback(flo, dragDescriptor) (可选)

当将一个节点拖过某个图元素(节点或链接)时,任何自定义的视觉反馈都可以由该函数绘制。dragDescriptor参数有一个拖动描述符对象,其中包含有关正在进行拖动的完整信息,并且flo对象将有助于使用联合 JS

# hideDragFeedback(flo, dragDescriptor) (可选)

删除由showdragfeedback()绘制的任何自定义视觉反馈。具有相同的参数。

# validateNode(flo, node) (可选)

返回一个javascript数组的string错误消息,这些错误消息是在node编辑器

# preDelete(flo, deletedElement) (可选)

之前调用的指定删除deletedElement允许在此之前进行额外的 tidyup。例如:删除与将要删除的元素相关的任何依赖的联合 JS 图元素。

# interactive (可选)

如果设置为false,则禁用与元素和链接的交互。如果它是一个函数,那么它将在单元格视图的作用下被调用,并调用它在('pointerdown''pointermove',...)中求值的方法的名称。如果这样的函数返回的值是假的,则将禁用该操作的交互。对于链接,交互对象的一些特殊属性对于禁用默认行为非常有用。这些性质是:vertexAddvertexMovevertexRemovearrowheadMove。通过将这些属性中的任何一个设置为 false,你可以禁用链接上的相关默认操作。

# allowLinkVertexEdit (可选)

如果设置为false链接顶点(或弯曲点)的创建或编辑(例如移动)在编辑器中是不允许的。

# 数据结构引用:

# FLO

这个对象是由flo-editor指令控制器创建的,它包含各种特定于编辑器的属性和函数。

# scheduleUpdateGraphRepresentation()

基于文本 DSL 表示,调度图 DSL 表示的异步更新。####UpdateGraphRepresentation()基于文本 DSL 表示异步更新图形 DSL 表示。将返回一个承诺,当更新完成时,该承诺将得到解决。

# updateGraphRepresentation()

基于图形 DSL 表示异步更新文本 DSL 表示(definition对象)。将返回一个承诺,该承诺在更新完成时得到解决。####PerformLayout()在画布上排列图形的节点和链接。

# updateTextRepresentation()

基于图的DSL表示法,异步更新文本DSL表示法(definition对象)。当更新完成时,会返回一个承诺,这个承诺会被解决。

# performLayout()

在画布上安排图形的节点和链接。

# ClearGraph()

清除了所有节点和链接的画布。与此同步还会导致文本 DSL 表示被清除。

# getgraph()

返回对画布内容的joint.dia.Graph对象实例的引用(图形模型,请参见联合 JS 图形 API (opens new window)

# getpaper()

返回对画布的 joint.dia.paper 对象实例的引用(图形视图对象,参见联合 JS 纸 API (opens new window)

# enableSyncing(enable)

基于传递的boolean参数enable启用或禁用文本和图形 DSL 表示同步机制。当文本 DSL 表示 UI 折叠时非常有用。

# getSelection()

返回画布上当前选择的图形模型元素(节点或链接)

# zoomPercent(percent)

画布上的缩放值的Angular getter/setter函数。如果提供了整数number参数,则设置缩放百分比值。如果缺少参数,返回整数百分比值(getter模式)。

# gridSize(gridSize)

角度 getter/setter 函数,用于画布上的缩放值。如果提供了整数number参数,则设置 zoom% 值。如果参数丢失(getter 模式)#####GridSize 角度 getter/setter 函数,则返回整数 % 值,用于画布网格大小(以像素为单位)。如果提供了整数number参数gridSize,则设置网格宽度值。如果参数丢失(getter 模式),则返回当前网格大小值.请注意,将网格宽度设置为1会关闭网格。无效的gridSize值被忽略

# getMinZoom()

返回整数number缩放百分比的最小允许值。用于设置缩放控件的适当范围。画布上的缩放控件所需的(如果设置为显示的话).默认情况下,该值等于5(5%)。

# getMaxZoom()

返回整数number最大允许缩放百分比的值。用于设置缩放控件的适当范围。画布上的缩放控件所需的(如果设置为显示的话).默认情况下,该值等于400(400%)。

# getZoomStep()

返回整数number缩放 % 递增/递减步骤。画布上的缩放控件所需的(如果设置为显示的话).默认情况下,该值等于5(5% 的递增/递减值)。

# fitToPage()

将整个图形放入画布的视口中(即不需要滚动来寻找画布上的内容)。适当地调整缩放级别和滚动位置

# readOnlyCanvas(newValue)

将整个图形适合 Canvas 的视口(即无需滚动来查找 Canvas 上的内容)。为画布“只读”属性调整缩放级别和滚动位置 ####readonlycanvas 角度 getter/setter 函数。只读画布不允许任何用户编辑画布上任何形状的交互。根据传入的newValue参数设置只读属性,结果画布立即切换只读状态的行为。如果参数丢失(getter 模式),则返回当前的“只读”状态值。

# createNode(metadata, properties, location)

基于图节点metadata对象(参见元素元数据)、properties键-值对映射和画布上的位置(对象带有xy属性)创建并返回新创建的联合 JS 图节点(对象)。新的节点还被添加到 FLO 画布联合 JS,因此也被添加到联合 JS,并在此函数返回结果之前立即出现在画布上。####CREATELINK(源、目标、元数据、属性);基于图形链接sourcetarget之间创建并返回新创建的 JS 联合图形链接(实例joint.dia.Link)(类型为joint.dia.Element的节点)metadata对象(参见元素元数据),properties键值对映射。新的链接还被添加到 FLO 画布联合 JS,因此也被添加到联合 JS,并在此函数返回结果之前立即出现在画布上。

根据图形链接的metadata'对象(见[Element Metadata](#element-metadata))、properties'键值对地图,在source'和target'节点(类型为joint.dia.Element')之间创建并返回新的Joint JS图形链接(joint.dia.Link实例)。新的链接也被添加到Flo画布的Joint JSgraph中,因此也被添加到Joint JSpaper`中,并在此函数返回结果之前立即出现在画布上。

# 定义

此对象保存与 DSL 的文本表示相关的数据。通常,对于 DSL 文本,这个对象至少应该具有text类型的string属性,但是它也可以具有其他属性,这些属性可以由客户机的元模型服务图-文本转换函数添加。

# 元模型侦听器

通常通过 HTTP 请求异步加载元模型对象。如果服务缓存了元数据,那么注册侦听器可能会很有用。如果元模型发生了变化,FLO 编辑器调色板将自动重建自身。

{
  metadataError: function(data) {
    /* Error loading metadata has occurred */
  },
  metadataRefresh: function() {
    /* Metadata is about to be refreshed */
  },
  metadataChanged: function(data) {
    /* New metadata is available */
  }
}

# 拖动描述符

API 客户机可以自由地向此对象添加额外的属性(即可能有助于绘制视觉反馈)

{
  context: context, /* String 'palette' or 'canvas' */
  source: {
    cell: draggedNode, /* Joint JS graph node being dragged */
    selector: selector, /* Optional. Joint JS CSS class selector for the subelement of the dragged node*/,
    port: portType /* Optional. Involved port DOM element type attribute value == port Joint JS markup 'type' property */
 },
 target: {
   cell: targetNode, /* Joint JS graph node target under mouse element */
   selector: selector, /* Optional. Joint JS CSS class selector for the element under mouse within the targetNode */
   port: portType /* Optional. Sub-element under mouse is a port. Port DOM element type attribute value == port Joint JS markup 'type' property */
 },
};

# 联合 JS 图节点标记

model: /* Joint JS model object for a module shape */
  ...
  attributes:
    ...    
    angle:  0,  /* Joint JS property - rotation angle */
            
    id:     "02be8001-ea1e-4f30-a94e-9503da5964b5"  /* Joint JS property - element model UUID
            
    position:       /* Joint JS property - coordinates of the shape's bounding rectangle */
      x:  119                                     
      y:  46
                
    size:           /* Joint JS property - size of the shape's bounding rectangle */
      height: 40                                  
      width:  120
                
    type:   "sinspctr.IntNode"  /* Flo property - internal, type (node, link, handle, decoration, etc) */
            
    z:      1   /* Joint JS property - z-index of the shape
            
    ports:              /* Joint JS property - internal, ports available on the shape */
      input:
        id: "input"
      output:
        id: "output"
      tap:
        id: "tap"
                    
      attrs:  /* Joint JS property - user defined rendering constructs and semantic properties */
            
        .               /*\                                                                 */
        .border         /* \                                                                */
        .box            /*  \                                                               */
        .input-port     /*   \                                                              */
        .label1         /*    \___User defined rendering constructs implied by the markup   */ 
        .label2         /*    /                                                             */
        .output-port    /*   /                                                              */
        .shape          /*  /                                                               */
        .stream-label   /* /                                                                */
        .tap-port       /*/                                                                 */
                                 
        metadata:                   /* Flo property. Node metadata supplied by Metamodel Service */
                                    
        props:                      /* Flo property. Semantic properties of the element. Name <-> value pair map */
          dir:    "/Users/x/tmp"
          file:   "temp.tmp"
          debug:  true
                    
      ...
  ...
...

# 元素元数据

由元模型服务提供的图形元素元数据

metadata: {
                
  get:    function(), /* function taking property key string as a parameter */ 
                      /* Returns promise that resolves to the metadata object of the property */
                      /* See snippet below showing the format of a property metadata */
                                                            
  group:  "source",   /* Category/Group of an element. Translates into palette groups of elements */

  name:   "file",     /* Name or Type of an element (should be unique within its group) */
                                                                                
  metadata:  { /* Additional metadata for the element */
    titleProperty: 'props/title', /* Property to be displayed at the top of all properties in properties Div */
    noEditableProps: false, /* If true then element doesn't have properties to edit and properties Div is not shown */
    allow-additional-properties: true, /* Allows user to create new properties for element in the properties Div */
  }

}

元素的属性元数据应该如下所示

  properties: {
        info: {
            defaultValue:       null,
            description:        "General information about the file",
            id:                 "info",
            name:               "info",
            shortDescription:   "File Info"
        },
            
        language: {
            defaultValue:       "English"
            description:        "Language of the file contents",
            id:                 "language",
            name:               "language",
            shortDescription:   "Text Language"
        },
        ...