Example with multiple input ports

This commit is contained in:
BoykoAlex
2019-11-25 11:12:44 -05:00
parent a9de335b24
commit 5a242f36ee
5 changed files with 371 additions and 9 deletions

View File

@@ -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

View File

@@ -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) {

View File

@@ -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: [

View File

@@ -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 {

View File

@@ -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;
}