I’m trying to visualize an entity diagram using the Go.js library. I found an example on their website that is as close as possible to what I want to do.
I modified it by setting up links not between entities, but between their fields, but after that the links did not work correctly – the inscriptions displaying the types of connections between the fields of entities disappeared.
<!DOCTYPE html>
<html lang="en">
<body>
<script src="https://unpkg.com/[email protected]/release/go.js"></script>
<script src="https://unpkg.com/[email protected]/dist/extensions/Figures.js"></script>
<script src="https://unpkg.com/[email protected]/dist/extensions/Themes.js"></script>
<script id="code">
function init() {
const $ = go.GraphObject.make;
myDiagram = new go.Diagram(
'myDiagramDiv',
{
allowDelete: false,
allowCopy: false,
layout: $(go.ForceDirectedLayout, { isInitial: false }),
'undoManager.isEnabled': true,
}
);
myDiagram.themeManager.set('light', {
colors: {
primary: '#f7f9fc',
green: '#62bd8e',
blue: '#3999bf',
purple: '#7f36b0',
red: '#c41000',
},
});
myDiagram.themeManager.set('dark', {
colors: {
primary: '#4a4a4a',
green: '#429e6f',
blue: '#3f9fc6',
purple: '#9951c9',
red: '#ff4d3d',
},
});
// the template for each attribute in a node's array of item data
const itemTempl = $(go.Panel,
'Horizontal',
{ margin: new go.Margin(2, 0),
},
$(go.Shape,
{ desiredSize: new go.Size(15, 15),
strokeWidth: 0,
margin: new go.Margin(0, 5, 0, 0),
portId: '',
// fromLinkable: true,
// toLinkable: true
},
new go.Binding('portId', 'name'),
new go.Binding('figure', 'figure'),
new go.ThemeBinding('fill', 'color').ofData()
),
$(go.TextBlock,
{ font: '14px sans-serif', stroke: 'black' },
new go.Binding('text', 'name'),
new go.Binding('font', 'iskey', (k) => (k ? 'italic 14px sans-serif' : '14px sans-serif')),
new go.ThemeBinding('stroke', 'text')
)
);
// define the Node template, representing an entity
myDiagram.nodeTemplate = $(go.Node,
'Auto', // the whole node panel
{
selectionAdorned: true,
resizable: true,
layoutConditions: go.LayoutConditions.Standard & ~go.LayoutConditions.NodeSized,
fromSpot: go.Spot.LeftRightSides,
toSpot: go.Spot.LeftRightSides,
},
new go.Binding('location', 'location').makeTwoWay(),
// whenever the PanelExpanderButton changes the visible property of the "LIST" panel,
// clear out any desiredSize set by the ResizingTool.
new go.Binding('desiredSize', 'visible', (v) => new go.Size(NaN, NaN)).ofObject('LIST'),
// define the node's outer shape, which will surround the Table
$(go.Shape, 'RoundedRectangle', { stroke: '#e8f1ff', strokeWidth: 3 }, new go.ThemeBinding('fill', 'primary')),
$(go.Panel,
'Table',
{ margin: 8, stretch: go.Stretch.Fill },
$(go.RowColumnDefinition, { row: 0, sizing: go.Sizing.None }),
// the table header
$(go.TextBlock,
{
row: 0,
alignment: go.Spot.Center,
margin: new go.Margin(0, 24, 0, 2), // leave room for Button
font: 'bold 18px sans-serif',
},
new go.Binding('text', 'key'),
new go.ThemeBinding('stroke', 'text')
),
// the collapse/expand button
$('PanelExpanderButton',
'LIST', // the name of the element whose visibility this button toggles
{ row: 0, alignment: go.Spot.TopRight },
new go.ThemeBinding('ButtonIcon.stroke', 'text')
),
$(go.Panel,
'Table',
{ name: 'LIST', row: 1, alignment: go.Spot.TopLeft },
$(go.Panel,
'Vertical',
{
row: 1,
name: 'NonInherited',
alignment: go.Spot.TopLeft,
defaultAlignment: go.Spot.Left,
itemTemplate: itemTempl,
},
new go.Binding('itemArray', 'items')
),
)
) // end Table Panel
); // end Node
// define the Link template, representing a relationship
myDiagram.linkTemplate = $(go.Link, // the whole link panel
{
selectionAdorned: true,
layerName: 'Background',
reshapable: true,
routing: go.Routing.AvoidsNodes,
corner: 5,
curve: go.Curve.JumpOver,
},
$(go.Shape, // the link shape
{ stroke: '#f7f9fc', strokeWidth: 3 },
new go.ThemeBinding('stroke', 'link')
),
$(go.TextBlock, // the "from" label
{
textAlign: 'center',
font: 'bold 14px sans-serif',
stroke: 'black',
segmentIndex: 0,
segmentOffset: new go.Point(NaN, NaN),
segmentOrientation: go.Orientation.Upright,
},
new go.Binding('text', 'text'),
new go.ThemeBinding('stroke', 'text')
)
);
// create the model for the E-R diagram
const nodeDataArray = [
{
key: 'Products',
location: new go.Point(250, 250),
items: [
{ name: 'ProductID', iskey: true, color: 'purple'},
{ name: 'ProductName', iskey: false, color: 'blue'},
{ name: 'ItemDescription', iskey: false, color: 'blue'},
{ name: 'WholesalePrice', iskey: false, color: 'green'},
{ name: 'ProductPhoto', iskey: false, color: 'red'},
]
},
{
key: 'Suppliers',
location: new go.Point(500, 0),
items: [
{ name: 'SupplierID', iskey: true, color: 'purple'},
{ name: 'CompanyName', iskey: false, color: 'blue'},
{ name: 'ContactName', iskey: false, color: 'blue'},
{ name: 'Address', iskey: false, color: 'blue'},
{ name: 'ShippingDistance', iskey: false, color: 'green'},
{ name: 'Logo', iskey: true, color: 'red'},
]
}
];
const linkDataArray = [
{ from: 'Products', fromPort: 'ProductID', to: 'Suppliers', toPort: 'Logo', text: '0..N', toText: '1' },
{ from: 'Products', fromPort: 'ProductID', to: 'Suppliers', toPort: 'Address', text: '0..N', toText: '1' },
{ from: 'Products', to: 'Suppliers', text: '0..N', toText: '1'},
];
myDiagram.model = new go.GraphLinksModel({
copiesArrays: true,
copiesArrayObjects: true,
nodeDataArray: nodeDataArray,
linkDataArray: linkDataArray,
linkFromPortIdProperty: "fromPort",
linkToPortIdProperty: "toPort",
});
}
const changeTheme = () => {
const myDiagram = go.Diagram.fromDiv('myDiagramDiv');
if (myDiagram) {
myDiagram.themeManager.currentTheme = document.getElementById('theme').value;
}
};
window.addEventListener('DOMContentLoaded', init);
</script>
<div id="myDiagramDiv" style="background-color: rgb(243, 244, 246); border: 1px solid black; width: 100%; height: 700px; position: relative; -webkit-tap-highlight-color: rgba(255, 255, 255, 0);">
<canvas tabindex="0" width="1246" height="698" style="position: absolute; top: 0px; left: 0px; z-index: 2; user-select: none; touch-action: none; width: 1246px; height: 698px;">
</canvas>
<div style="position: absolute; overflow: auto; width: 1246px; height: 698px; z-index: 1;">
<div style="position: absolute; width: 1px; height: 1px;">
</div>
</div>
</div>
</body>
</html>