Skip to content

Commit 0dfd157

Browse files
authored
support hidden node attributes and text formatters (#19)
1 parent 861cebc commit 0dfd157

File tree

3 files changed

+171
-28
lines changed

3 files changed

+171
-28
lines changed
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
import React from 'react';
2+
import { GRAPH_ACTIONS } from '../../../src/constants';
3+
import Component from '../../base-component';
4+
5+
var name = 'Node Attributes Graph';
6+
var config = {
7+
title: `Basic/${name}`
8+
};
9+
10+
export default {
11+
title: config.title,
12+
component: Component,
13+
parameters: {
14+
docs: {}
15+
}
16+
};
17+
18+
const GRAPH_ENUM = {
19+
NODE: {
20+
HELLO: 0,
21+
WORLD: 1,
22+
},
23+
EDGE: {
24+
HELLO_TO_WORLD: 0,
25+
}
26+
};
27+
28+
const GRAPH_SCHEMA = {
29+
nodes: {
30+
[GRAPH_ENUM.NODE.HELLO]: {
31+
name: 'Hello',
32+
headerTextFormatter: (attributes) => `Hello ${attributes.foo}`,
33+
outPorts: [
34+
{
35+
name: 'output',
36+
type: GRAPH_ENUM.EDGE.HELLO_TO_WORLD,
37+
textFormatter: (attributes) => `output (${attributes.foo})`
38+
}
39+
],
40+
attributes: [
41+
{
42+
name: 'foo',
43+
type: 'TEXT_INPUT'
44+
}
45+
]
46+
},
47+
[GRAPH_ENUM.NODE.WORLD]: {
48+
name: 'World',
49+
inPorts: [
50+
{
51+
name: 'input',
52+
type: GRAPH_ENUM.EDGE.HELLO_TO_WORLD,
53+
textFormatter: (attributes) => `input (${attributes.foo})`
54+
}
55+
],
56+
attributes: [
57+
{
58+
name: 'foo',
59+
type: 'TEXT_INPUT',
60+
hidden: true
61+
}
62+
]
63+
}
64+
},
65+
edges: {
66+
[GRAPH_ENUM.EDGE.HELLO_TO_WORLD]: {
67+
from: GRAPH_ENUM.NODE.HELLO,
68+
to: GRAPH_ENUM.NODE.WORLD,
69+
}
70+
}
71+
};
72+
73+
var GRAPH_DATA = {
74+
nodes: {
75+
1234: {
76+
id: 1234,
77+
nodeType: GRAPH_ENUM.NODE.HELLO,
78+
name: 'Hello',
79+
posX: 200,
80+
posY: 200,
81+
attributes: {
82+
foo: 'bar'
83+
}
84+
},
85+
1235: {
86+
id: 1235,
87+
nodeType: GRAPH_ENUM.NODE.WORLD,
88+
name: 'World',
89+
posX: 500,
90+
posY: 200,
91+
attributes: {
92+
foo: 'bar'
93+
}
94+
},
95+
},
96+
edges: {
97+
'1234,0-1235,0': {
98+
edgeType: GRAPH_ENUM.EDGE.HELLO_TO_WORLD,
99+
from: 1234,
100+
to: 1235,
101+
inPort: 0,
102+
outPort: 0,
103+
}
104+
}
105+
};
106+
107+
export const NodeAttributesGraphExample = (args) => {
108+
return <Component schema={GRAPH_SCHEMA} options={{
109+
initialData: GRAPH_DATA,
110+
passiveUIEvents: false,
111+
includeFonts: true,
112+
defaultStyles: {
113+
edge: {
114+
connectionStyle: 'smoothInOut'
115+
},
116+
background: {
117+
color: '#20292B',
118+
gridSize: 10
119+
}
120+
}
121+
}} />;
122+
};
123+
124+
document.querySelector('#root').setAttribute('style', 'position: fixed; width: 100%; height: 100%');
125+
document.body.setAttribute('style', 'margin: 0px; padding: 0px;');
126+
127+
setTimeout(() => {
128+
const graph = document.querySelector('.pcui-graph').ui;
129+
graph.on(GRAPH_ACTIONS.UPDATE_NODE_ATTRIBUTE, (data) => {
130+
graph.updateNodeAttribute(1235, data.attribute, data.node.attributes[data.attribute]);
131+
});
132+
}, 500);

src/graph-view-node.js

Lines changed: 37 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,16 @@ class GraphViewNode {
3333
var outHeight = (nodeSchema.outPorts.length * 25) + 10;
3434
if (outHeight > portHeight) portHeight = outHeight;
3535
}
36-
if (nodeSchema.attributes && nodeSchema.attributes.length > 0) {
37-
attributeHeight = nodeSchema.attributes.length * 32 + 10;
36+
const visibleAttributes = nodeSchema.attributes && nodeSchema.attributes.filter(a => !a.hidden);
37+
if (visibleAttributes && visibleAttributes.length > 0) {
38+
attributeHeight = visibleAttributes.length * 32 + 10;
3839
}
3940
var rectSize = { x: this.getSchemaValue('baseWidth'), y: rectHeight + portHeight + attributeHeight };
4041

4142
var labelName;
42-
if (nodeSchema.outPorts || nodeSchema.inPorts) {
43+
if (nodeSchema.headerTextFormatter) {
44+
labelName = nodeSchema.headerTextFormatter(nodeData.attributes);
45+
} else if (nodeSchema.outPorts || nodeSchema.inPorts) {
4346
labelName = nodeData.attributes && nodeData.attributes.name ? `${nodeData.attributes.name} (${nodeSchema.name})` : nodeSchema.name;
4447
} else {
4548
labelName = nodeData.attributes && nodeData.attributes.name || nodeData.name;
@@ -196,13 +199,13 @@ class GraphViewNode {
196199
id: `in${i}`,
197200
group: 'in',
198201
edgeType: port.edgeType,
199-
markup: `<circle class="port-body" edgeType="${port.type}"></circle><circle class="port-inner-body" visibility="hidden"></circle>`,
202+
markup: `<circle class="port-body" id="${nodeData.id}-in${i}" edgeType="${port.type}"></circle><circle class="port-inner-body" visibility="hidden"></circle>`,
200203
attrs: {
201204
'.port-body': {
202205
stroke: this._graphSchema.edges[port.type].stroke || this._config.defaultStyles.edge.stroke
203206
},
204207
text: {
205-
text: port.name,
208+
text: port.textFormatter ? port.textFormatter(nodeData.attributes) : port.name,
206209
fill: this.getSchemaValue('textColorSecondary'),
207210
'font-size': 14
208211
}
@@ -242,14 +245,14 @@ class GraphViewNode {
242245
nodeSchema.outPorts.forEach((port, i) => rect.addPort({
243246
id: `out${i}`,
244247
group: 'out',
245-
markup: `<circle class="port-body" edgeType="${port.type}"></circle><circle class="port-inner-body" visibility="hidden"></circle>`,
248+
markup: `<circle class="port-body" id="${nodeData.id}-out${i}" edgeType="${port.type}"></circle><circle class="port-inner-body" visibility="hidden"></circle>`,
246249
attrs: {
247250
type: port.type,
248251
'.port-body': {
249252
stroke: this._graphSchema.edges[port.type].stroke || this._config.defaultStyles.edge.stroke
250253
},
251254
text: {
252-
text: port.name,
255+
text: port.textFormatter ? port.textFormatter(nodeData.attributes) : port.name,
253256
fill: this.getSchemaValue('textColorSecondary'),
254257
'font-size': 14
255258
}
@@ -258,8 +261,8 @@ class GraphViewNode {
258261
}
259262

260263
var containers = [];
261-
if (nodeSchema.attributes) {
262-
nodeSchema.attributes.forEach((attribute, i) => {
264+
if (visibleAttributes) {
265+
visibleAttributes.forEach((attribute, i) => {
263266
const container = new this._graphView.pcui.Container({ class: 'graph-node-container' });
264267
const label = new this._graphView.pcui.Label({ text: attribute.name, class: 'graph-node-label' });
265268
let input;
@@ -387,16 +390,28 @@ class GraphViewNode {
387390
return arr;
388391
}
389392

390-
updateAttribute(attribute, value) {
391-
if (attribute === 'name') {
392-
var labelName;
393-
if (this.nodeSchema.outPorts || this.nodeSchema.inPorts) {
394-
labelName = `${value} (${this.nodeSchema.name})`;
395-
} else {
396-
labelName = value;
397-
}
398-
this.model.attr('label/text', labelName);
393+
updateFormattedTextFields() {
394+
if (this.nodeSchema.headerTextFormatter) {
395+
this.model.attr('label/text', this.nodeSchema.headerTextFormatter(this.nodeData.attributes));
399396
}
397+
if (this.nodeSchema.outPorts) {
398+
this.nodeSchema.outPorts.forEach((port, i) => {
399+
if (port.textFormatter) {
400+
document.getElementById(`${this.nodeData.id}-out${i}`).parentElement.parentElement.querySelector('tspan').innerHTML = port.textFormatter(this.nodeData.attributes);
401+
}
402+
});
403+
}
404+
if (this.nodeSchema.inPorts) {
405+
this.nodeSchema.inPorts.forEach((port, i) => {
406+
if (port.textFormatter) {
407+
document.getElementById(`${this.nodeData.id}-in${i}`).parentElement.parentElement.querySelector('tspan').innerHTML = port.textFormatter(this.nodeData.attributes);
408+
}
409+
});
410+
}
411+
}
412+
413+
updateAttribute(attribute, value) {
414+
this.nodeData.attributes[attribute] = value;
400415
const attributeElement = document.querySelector(`#nodediv_${this.model.id}`).querySelector(`#input_${attribute}`);
401416
if (attributeElement) {
402417
attributeElement.ui.suspendEvents = true;
@@ -408,6 +423,7 @@ class GraphViewNode {
408423
attributeElement.ui.error = false;
409424
attributeElement.ui.suspendEvents = false;
410425
}
426+
this.updateFormattedTextFields();
411427
}
412428

413429
updateNodeType(nodeType) {
@@ -431,7 +447,9 @@ class GraphViewNode {
431447
break;
432448
}
433449
case 'updateAttribute': {
434-
document.querySelector(`#nodediv_${this.model.id}`).querySelector(`#input_${attribute.name}`).ui.on('change', (value) => {
450+
const attributeElement = document.querySelector(`#nodediv_${this.model.id}`).querySelector(`#input_${attribute.name}`);
451+
if (!attributeElement) break;
452+
attributeElement.ui.on('change', (value) => {
435453
if (attribute.name === 'name') {
436454
var nameTaken = false;
437455
Object.keys(this._graphView._graphData.get('data.nodes')).forEach((nodeKey) => {
@@ -446,13 +464,6 @@ class GraphViewNode {
446464
return;
447465
}
448466
attributeElement.ui.error = false;
449-
var labelName;
450-
if (this.nodeSchema.outPorts || this.nodeSchema.inPorts) {
451-
labelName = `${this.nodeSchema.name} (${value})`;
452-
} else {
453-
labelName = value;
454-
}
455-
this.model.attr('label/text', labelName);
456467
}
457468
callback(this.nodeData.id, attribute, value);
458469
});

src/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,7 @@ class Graph extends Element {
370370
node.attributes[attributeKey] = value;
371371
}
372372
if (JSON.stringify(node.attributes[attributeKey]) === JSON.stringify(prevAttributeValue)) return;
373-
this.updateNodeAttribute(nodeId, attribute.name, prevAttributeValue);
373+
this.updateNodeAttribute(nodeId, attribute.name, value);
374374
this._dispatchEvent(
375375
GRAPH_ACTIONS.UPDATE_NODE_ATTRIBUTE,
376376
{
@@ -634,7 +634,7 @@ class Graph extends Element {
634634
this.updateNodePosition(nodeId, { x: node.posX, y: node.posY });
635635
});
636636
this.on(GRAPH_ACTIONS.UPDATE_NODE_ATTRIBUTE, ({ node }) => {
637-
this._graphData.set(`data.nodes.${nodeId}`, node);
637+
this._graphData.set(`data.nodes.${node.id}`, node);
638638
});
639639
this.on(GRAPH_ACTIONS.ADD_EDGE, ({ edge, edgeId }) => {
640640
if (Number.isFinite(edge.inPort)) {

0 commit comments

Comments
 (0)