Example with multiple input ports
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
Spring Flo Sample
|
||||
</div>
|
||||
<div id="flo-container">
|
||||
<flo-editor (floApi)="editorContext = $event" [metamodel]="metamodel" [renderer]="renderer" [editor]="editor" [paletteSize]="paletteSize" [(dsl)]="dsl" [paperPadding]="20" (validationMarkers)="markersChanged($event)">
|
||||
<flo-editor (floApi)="editorContext = $event" [metamodel]="metamodel" [renderer]="renderer" [editor]="editor" [paletteSize]="paletteSize" [paletteEntryPadding]="{width: 4, height: 4}" [(dsl)]="dsl" [paperPadding]="20" (validationMarkers)="markersChanged($event)">
|
||||
<div id="controls" class="controls">
|
||||
<button class="button" id="clearGraph" (click)="editorContext.clearGraph()">Create New Flow</button>
|
||||
<!-- let's use the 'x' control on the nodes themselves when they are selected
|
||||
|
||||
@@ -27,6 +27,23 @@ const joint : any = Flo.joint;
|
||||
*/
|
||||
export class Editor implements Flo.Editor {
|
||||
|
||||
get highlighting() {
|
||||
return {
|
||||
connecting: {
|
||||
name: 'addParentClass',
|
||||
options: {
|
||||
className: 'connecting'
|
||||
}
|
||||
},
|
||||
'default': {
|
||||
name: 'addClass',
|
||||
options: {
|
||||
className: 'highlighted'
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
constructor(private modelService : BsModalService) {}
|
||||
|
||||
createHandles(context : Flo.EditorContext, createHandle : (owner : dia.CellView, kind : string, action : () => void, location : dia.Point) => void, owner : dia.CellView) {
|
||||
|
||||
@@ -29,6 +29,11 @@ const metamodelData: Array<RawMetadata> = [{
|
||||
{id: 'withSubDir', name: 'withSubDir', description: 'With subdirectories', defaultValue: true, type: 'boolean'},
|
||||
{id: 'type', name: 'type', description: 'Type of file watching', type: 'enum', options: ['tough', 'so-so', 'easy']}
|
||||
],
|
||||
}, {
|
||||
name: 'multi', group: 'processor', description: 'Custom element with multiple inputs and outputs',
|
||||
properties: [
|
||||
{id: 'inputChannel', name: 'input-channel', description: 'input channel name', type: 'string'}
|
||||
],
|
||||
}, {
|
||||
name: 'transform', group: 'processor', description: 'Apply an expression to modify incoming messages',
|
||||
properties: [
|
||||
|
||||
@@ -29,6 +29,234 @@ const HANDLE_ICON_MAP = new Map<string, string>()
|
||||
const DECORATION_ICON_MAP = new Map<string, string>()
|
||||
.set(Constants.ERROR_DECORATION_KIND, 'icons/error.svg');
|
||||
|
||||
const IMAGE_W = 120;
|
||||
const IMAGE_H = 40;
|
||||
|
||||
const PORT_RADIUS = 2;
|
||||
|
||||
joint.shapes.flo.Multi = joint.shapes.basic.Generic.extend({
|
||||
|
||||
markup:
|
||||
'<g class="stream-module">' +
|
||||
'<g class="shape">' +
|
||||
'<rect class="box"/>' +
|
||||
'<text class="label"/>' +
|
||||
'<text class="label2"/>' +
|
||||
'</g>' +
|
||||
'<g class="port1-group">' +
|
||||
'<circle class="input-port1" />' +
|
||||
'<g class="label-group">' +
|
||||
'<rect class="port1-label-rect"/>' +
|
||||
'<text class="port1-label"></text>' +
|
||||
'</g>' +
|
||||
'</g>' +
|
||||
'<g class="port2-group">' +
|
||||
'<circle class="input-port2" />' +
|
||||
'<g class="label-group">' +
|
||||
'<rect class="port2-label-rect"/>' +
|
||||
'<text class="port2-label"></text>' +
|
||||
'</g>' +
|
||||
'</g>' +
|
||||
'<g class="port3-group">' +
|
||||
'<circle class="input-port3" />' +
|
||||
'<g class="label-group">' +
|
||||
'<rect class="port3-label-rect"/>' +
|
||||
'<text class="port3-label"></text>' +
|
||||
'</g>' +
|
||||
'</g>' +
|
||||
'<g class="port4-group">' +
|
||||
'<circle class="input-port4" />' +
|
||||
'<g class="label-group">' +
|
||||
'<rect class="port4-label-rect"/>' +
|
||||
'<text class="port4-label"></text>' +
|
||||
'</g>' +
|
||||
'</g>' +
|
||||
'<g class="port5-group">' +
|
||||
'<circle class="input-port5" />' +
|
||||
'<g class="label-group">' +
|
||||
'<rect class="port5-label-rect"/>' +
|
||||
'<text class="port5-label"></text>' +
|
||||
'</g>' +
|
||||
'</g>' +
|
||||
'<rect class="output-port"/>' +
|
||||
'</g>',
|
||||
|
||||
defaults: joint.util.defaultsDeep({
|
||||
|
||||
type: joint.shapes.flo.NODE_TYPE,
|
||||
position: {x: 0, y: 0},
|
||||
size: { width: IMAGE_W, height: IMAGE_H },
|
||||
attrs: {
|
||||
'.': {
|
||||
magnet: false,
|
||||
},
|
||||
'.box': {
|
||||
width: IMAGE_W,
|
||||
height: IMAGE_H,
|
||||
rx: 2,
|
||||
ry: 2,
|
||||
// 'fill-opacity':0, // see through
|
||||
stroke: '#6db33f',
|
||||
fill: '#eeeeee',
|
||||
'stroke-width': 2,
|
||||
},
|
||||
'.input-port1': {
|
||||
id: 'in-port-1',
|
||||
port: 'input',
|
||||
ref: '.box',
|
||||
refCx: 0,
|
||||
refCy: 1 * 0.17,
|
||||
r: PORT_RADIUS,
|
||||
magnet: true,
|
||||
class: 'input-port1 flo-input-port'
|
||||
},
|
||||
'.port1-label': {
|
||||
ref: '.input-port1',
|
||||
'ref-x': 10,
|
||||
'ref-y': 0,
|
||||
text: 'port-1',
|
||||
class: 'port1-label flo-port-label'
|
||||
},
|
||||
'.port1-label-rect': {
|
||||
ref: '.port1-label',
|
||||
refWidth: 1,
|
||||
refHeight: 1,
|
||||
refX: 0,
|
||||
refY: 0,
|
||||
class: 'port1-label-rect flo-port-label-bg'
|
||||
},
|
||||
'.input-port2': {
|
||||
id: 'in-port-2',
|
||||
port: 'in-port-2',
|
||||
r: PORT_RADIUS,
|
||||
ref: '.box',
|
||||
refCx: 0,
|
||||
refCy: 2 * 0.17,
|
||||
magnet: true,
|
||||
class: 'input-port2 flo-input-port'
|
||||
},
|
||||
'.port2-label': {
|
||||
ref: '.input-port2',
|
||||
'ref-x': 10,
|
||||
'ref-y': 0,
|
||||
text: 'port-2',
|
||||
class: 'port2-label flo-port-label'
|
||||
},
|
||||
'.port2-label-rect': {
|
||||
ref: '.port2-label',
|
||||
refWidth: 1,
|
||||
refHeight: 1,
|
||||
refX: 0,
|
||||
refY: 0,
|
||||
class: 'port2-label-rect flo-port-label-bg'
|
||||
},
|
||||
'.input-port3': {
|
||||
id: 'in-port-3',
|
||||
port: 'input',
|
||||
r: PORT_RADIUS,
|
||||
ref: '.box',
|
||||
refCx: 0,
|
||||
refCy: 3 * 0.17,
|
||||
magnet: true,
|
||||
class: 'input-port3 flo-input-port'
|
||||
},
|
||||
'.port3-label': {
|
||||
ref: '.input-port3',
|
||||
'ref-x': 10,
|
||||
'ref-y': 0,
|
||||
text: 'port-3',
|
||||
class: 'port3-label flo-port-label'
|
||||
},
|
||||
'.port3-label-rect': {
|
||||
ref: '.port3-label',
|
||||
refWidth: 1,
|
||||
refHeight: 1,
|
||||
refX: 0,
|
||||
refY: 0,
|
||||
class: 'port3-label-rect flo-port-label-bg'
|
||||
},
|
||||
'.input-port4': {
|
||||
id: 'in-port-4',
|
||||
port: 'input',
|
||||
r: PORT_RADIUS,
|
||||
ref: '.box',
|
||||
refCx: 0,
|
||||
refCy: 4 * 0.17,
|
||||
magnet: true,
|
||||
class: 'input-port4 flo-input-port'
|
||||
},
|
||||
'.port4-label': {
|
||||
ref: '.input-port4',
|
||||
'ref-x': 10,
|
||||
'ref-y': 0,
|
||||
text: 'port-4',
|
||||
class: 'port4-label flo-port-label'
|
||||
},
|
||||
'.port4-label-rect': {
|
||||
ref: '.port4-label',
|
||||
refWidth: 1,
|
||||
refHeight: 1,
|
||||
refX: 0,
|
||||
refY: 0,
|
||||
class: 'port4-label-rect flo-port-label-bg'
|
||||
},
|
||||
'.input-port5': {
|
||||
id: 'in-port-5',
|
||||
port: 'input',
|
||||
r: PORT_RADIUS,
|
||||
ref: '.box',
|
||||
refCx: 0,
|
||||
refCy: 5 * 0.17,
|
||||
magnet: true,
|
||||
class: 'input-port5 flo-input-port'
|
||||
},
|
||||
'.port5-label': {
|
||||
ref: '.input-port5',
|
||||
'ref-x': 10,
|
||||
'ref-y': 0,
|
||||
text: 'port-5',
|
||||
class: 'port5-label flo-port-label'
|
||||
},
|
||||
'.port5-label-rect': {
|
||||
ref: '.port5-label',
|
||||
refWidth: 1,
|
||||
refHeight: 1,
|
||||
refX: 0,
|
||||
refY: 0,
|
||||
class: 'port5-label-rect flo-port-label-bg'
|
||||
},
|
||||
'.output-port': {
|
||||
port: 'output',
|
||||
height: 8, width: 8,
|
||||
magnet: true,
|
||||
fill: '#eeeeee',
|
||||
transform: 'translate(' + (IMAGE_W - 4) + ',' + ((IMAGE_H / 2) - 4) + ')',
|
||||
stroke: '#34302d',
|
||||
'stroke-width': 1,
|
||||
},
|
||||
'.label': {
|
||||
'ref-x': 0.5, // jointjs specific: relative position to ref'd element
|
||||
'ref-y': 0.525,
|
||||
'y-alignment': 'middle',
|
||||
'x-alignment': 'middle',
|
||||
ref: '.box', // jointjs specific: element for ref-x, ref-y
|
||||
fill: 'black',
|
||||
'font-size': 14
|
||||
},
|
||||
'.label2': {
|
||||
'y-alignment': 'middle',
|
||||
'ref-x': 0.15, // jointjs specific: relative position to ref'd element
|
||||
'ref-y': 0.2, // jointjs specific: relative position to ref'd element
|
||||
ref: '.box', // jointjs specific: element for ref-x, ref-y
|
||||
fill: 'black',
|
||||
'font-size': 20
|
||||
},
|
||||
'.shape': {
|
||||
}
|
||||
}
|
||||
}, joint.shapes.basic.Generic.prototype.defaults)
|
||||
});
|
||||
|
||||
/**
|
||||
* @author Alex Boyko
|
||||
* @author Andy Clement
|
||||
@@ -46,8 +274,8 @@ export class Renderer implements Flo.Renderer {
|
||||
});
|
||||
}
|
||||
|
||||
createDecoration(kind : string) : dia.Element {
|
||||
return new joint.shapes.flo.ErrorDecoration({
|
||||
createDecoration(kind : string, parent: dia.Cell) : dia.Element {
|
||||
const error = new joint.shapes.flo.ErrorDecoration({
|
||||
size: {width: 16, height: 16},
|
||||
attrs: {
|
||||
'image': {
|
||||
@@ -55,9 +283,19 @@ export class Renderer implements Flo.Renderer {
|
||||
}
|
||||
}
|
||||
});
|
||||
if (parent instanceof joint.dia.Element) {
|
||||
const pt = (<dia.Element> parent).getBBox().topRight().offset(-error.size().width, 0);
|
||||
error.position(pt.x, pt.y);
|
||||
} else {
|
||||
// TODO: do something for the link perhaps?
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
createNode(metadata : Flo.ElementMetadata, props : Map<string, any>): dia.Element {
|
||||
createNode(viewerDescriptor: Flo.ViewerDescriptor, metadata : Flo.ElementMetadata, props : Map<string, any>): dia.Element {
|
||||
if (metadata.name === 'multi') {
|
||||
return new joint.shapes.flo.Multi();
|
||||
}
|
||||
return new joint.shapes.flo.Node();
|
||||
}
|
||||
|
||||
@@ -76,17 +314,66 @@ export class Renderer implements Flo.Renderer {
|
||||
}
|
||||
|
||||
createLink(source : Flo.LinkEnd, target : Flo.LinkEnd, metadata : Flo.ElementMetadata, props : Map<string, any>) : dia.Link {
|
||||
return new joint.shapes.flo.Link(joint.util.deepSupplement({
|
||||
const link = new joint.shapes.flo.Link(joint.util.deepSupplement({
|
||||
smooth: true,
|
||||
attrs: {
|
||||
'.': {
|
||||
//filter: { name: 'dropShadow', args: { dx: 1, dy: 1, blur: 2 } }
|
||||
},
|
||||
'.connection': { 'stroke-width': 3, 'stroke': 'black', 'stroke-linecap': 'round' },
|
||||
'.marker-arrowheads': { display: 'none' },
|
||||
'.tool-options': { display: 'none' }
|
||||
'.connection': {'stroke-width': 3, 'stroke': 'black', 'stroke-linecap': 'round'},
|
||||
'.marker-arrowheads': {display: 'none'},
|
||||
'.tool-options': {display: 'none'}
|
||||
},
|
||||
}, joint.shapes.flo.Link.prototype.defaults));
|
||||
}));
|
||||
return link;
|
||||
}
|
||||
|
||||
handleLinkEvent?(context: Flo.EditorContext, event: string, link: dia.Link) {
|
||||
switch (event) {
|
||||
case 'change:target':
|
||||
this.updateTargetLabel(link, context.getPaper());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
updateTargetLabel(link: joint.dia.Link, paper: dia.Paper) {
|
||||
const view = paper.findViewByModel(link.getTargetElement());
|
||||
const portElement = view ? view.findBySelector(link.target().selector) : undefined;
|
||||
const labelText = portElement && portElement.length ? portElement[0].getAttribute('id') : undefined;
|
||||
setTimeout(() => {
|
||||
let idx = -1;
|
||||
for (let i = 0; idx < 0 && i < link.labels().length; i++) {
|
||||
if (link.labels()[i].attrs.text.id === 'target-channel-label') {
|
||||
idx = i;
|
||||
}
|
||||
}
|
||||
if (idx >= 0) {
|
||||
link.removeLabel(idx);
|
||||
}
|
||||
if (labelText) {
|
||||
link.appendLabel({
|
||||
attrs: {
|
||||
text: {
|
||||
id: 'target-channel-label',
|
||||
text: labelText,
|
||||
class: 'link-channel-label',
|
||||
'text-anchor': 'end'
|
||||
},
|
||||
rect: {
|
||||
class: 'link-channel-label'
|
||||
}
|
||||
},
|
||||
position: {
|
||||
args: {
|
||||
keepGradient: true,
|
||||
ensureLegibility: true
|
||||
},
|
||||
distance: -20,
|
||||
offset: 20
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
isSemanticProperty(propertyPath : string, element : dia.Cell) : boolean {
|
||||
|
||||
@@ -9,3 +9,56 @@ h1 {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
font-size: 250%;
|
||||
}
|
||||
|
||||
.connecting .flo-input-port {
|
||||
fill: #aa1111;
|
||||
r: 4;
|
||||
}
|
||||
|
||||
.connecting .label-group {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.label-group {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.flo-input-port {
|
||||
fill: #eeeeee;
|
||||
stroke: #34302d;
|
||||
stroke-width: 1px;
|
||||
}
|
||||
|
||||
.flo-port-label {
|
||||
text-anchor: start;
|
||||
fill: black;
|
||||
}
|
||||
|
||||
.flo-port-label-bg {
|
||||
fill: lightblue;
|
||||
stroke: lightblue;
|
||||
stroke-width: 7px;
|
||||
rx: 3;
|
||||
ry: 3;
|
||||
refWidth: 1;
|
||||
refHeight: 1;
|
||||
}
|
||||
|
||||
.joint-link:hover .link-channel-label {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.link-channel-label {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.available-magnet {
|
||||
stroke-width: 2px;
|
||||
}
|
||||
|
||||
.joint-element.highlighted rect {
|
||||
stroke: #34302d;
|
||||
stroke-width: 3;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user