I'm trying to generate a gojs diagram image using server side nodejs.
Here is my script below, but I can't figure out why makeImageData just returns null? How can I make it return base64 image data.
const go = require("gojs");
var $ = go.GraphObject.make; // for conciseness in defining templates
const myDiagram =
$(go.Diagram, '', // No DOM, so there can be no DIV!
{
viewSize: new go.Size(400,400), // Set this property in DOM-less environments
layout: $(go.LayeredDigraphLayout)
});
myDiagram.nodeTemplate =
$(go.Node, "Auto", // the Shape will go around the TextBlock
$(go.Shape, "RoundedRectangle", { strokeWidth: 0, fill: "white" },
// Shape.fill is bound to Node.data.color
new go.Binding("fill", "color")),
$(go.TextBlock,
{ margin: 8, font: "bold 14px sans-serif", stroke: '#333' }, // Specify a margin to add some room around the text
// TextBlock.text is bound to Node.data.key
new go.Binding("text", "key"))
);
myDiagram.model = new go.GraphLinksModel(
[
{ key: "Alpha", color: "lightblue" },
{ key: "Beta", color: "orange" },
{ key: "Gamma", color: "lightgreen" },
{ key: "Delta", color: "pink" }
],
[
{ from: "Alpha", to: "Beta" },
{ from: "Alpha", to: "Gamma" },
{ from: "Beta", to: "Beta" },
{ from: "Gamma", to: "Delta" },
{ from: "Delta", to: "Alpha" }
]);
myDiagram.addDiagramListener('InitialLayoutCompleted', function() {
console.log(myDiagram.makeImageData({
background:'white',
scale:1,
type: 'image/png',
}));
});
The answer was given here: https://forum.nwoods.com/t/gojs-makeimagedata-using-nodejs/14596/2
I assume you started from
https://gojs.net/latest/intro/nodeScript.html.
The problem is that if you want to render images you need to use the
HTML DOM. But the Node.js environment does not provide an
implementation of the HTML DOM unless you use Puppeteer or something
like that.
So this page would be more appropriate:
https://gojs.net/latest/intro/serverSideImages.html
Related
I´m trying to make a tree layout diagram to display an achievements list like the one in minecraft but I can´t find the way to use gojs components on my typescript proyect.
Here is the code:
import go from 'gojs';
import { useEffect, useState } from 'react';
import GoalModel from '../../models/goalModel';
import { ReactDiagram } from 'gojs-react';
const ipcRenderer = window.require("electron").ipcRenderer
function GoalsList(){
const [goalsList, setGoalsList] = useState<GoalModel[]>([])
useEffect(() => {
ipcRenderer.send("getGoals")
}, [])
ipcRenderer.on("goals", (e: any, goals: GoalModel[]) => {
console.log(goals)
setGoalsList(goals)
})
function makeDiagram(){
const $ = go.GraphObject.make;
// set your license key here before creating the diagram: go.Diagram.licenseKey = "...";
const diagram =
$(go.Diagram,
{
'undoManager.isEnabled': true, // must be set to allow for model change listening
// 'undoManager.maxHistoryLength': 0, // uncomment disable undo/redo functionality
'clickCreatingTool.archetypeNodeData': { text: 'new node', color: 'lightblue' },
model: new go.GraphLinksModel(
{
linkKeyProperty: 'key' // IMPORTANT! must be defined for merges and data sync when using GraphLinksModel
})
});
// define a simple Node template
diagram.nodeTemplate =
$(go.Node, 'Auto', // the Shape will go around the TextBlock
new go.Binding('location', 'loc', go.Point.parse).makeTwoWay(go.Point.stringify),
$(go.Shape, 'RoundedRectangle',
{ name: 'SHAPE', fill: 'white', strokeWidth: 0 },
// Shape.fill is bound to Node.data.color
new go.Binding('fill', 'color')),
$(go.TextBlock,
{ margin: 8, editable: true }, // some room around the text
new go.Binding('text').makeTwoWay()
)
);
diagram.layout =
$(go.TreeLayout,
{
layerSpacing: 20,
nodeSpacing:100
})
return diagram
};
return (
<div>
<h1>Objetivos</h1>
<div>
<ReactDiagram //The error shows up here
initDiagram={makeDiagram}
divClassName='diagram-component'
nodeDataArray={[
{ key: 0, text: 'Alpha', color: 'lightblue', loc: '0 0' },
{ key: 1, text: 'Beta', color: 'orange', loc: '150 0' },
{ key: 2, text: 'Gamma', color: 'lightgreen', loc: '0 150' },
{ key: 3, text: 'Delta', color: 'pink', loc: '150 150' }
]}
linkDataArray={[
{ key: -1, from: 0, to: 1 },
{ key: -2, from: 0, to: 2 },
{ key: -3, from: 1, to: 1 },
{ key: -4, from: 2, to: 3 },
{ key: -5, from: 3, to: 0 }
]}
/>
</div>
</div>
);}
export default GoalsList
Im getting the error when I use the ReactDiagram component from gojs in my typescript file.
Anyone has any idea on how to fix it?
Error here
I would like to simply show/hide the labels of the edges of my vis.js-network - is this possible?
I have tried to update the edges in the vis.js-data structure:
Delete the label property - doesn't work
Set the label to undefined - doesn't work
Set the label to '' - doesn't work
Set the label to ' ' - works
I would prefer a network-wise toggle of some kind, but I haven't found one.
Is there a better way of doing this?
An alternative to updating the label property on each edge is to change the font color to be transparent for all edges. The setOptions() method can be used to update the options and will apply all edges in the network. The options edges.font.color and edges.font.strokeColor should both be updated, then returned to their original values to display the edges.
Example below and also at https://jsfiddle.net/rk9s87ud/.
var nodes = new vis.DataSet([
{ id: 1, label: "Node 1" },
{ id: 2, label: "Node 2" },
{ id: 3, label: "Node 3" },
{ id: 4, label: "Node 4" },
{ id: 5, label: "Node 5" },
]);
var edges = new vis.DataSet([
{ from: 1, to: 2, label: 'Edge 1' },
{ from: 2, to: 3, label: 'Edge 2' },
{ from: 3, to: 4, label: 'Edge 3' },
{ from: 4, to: 5, label: 'Edge 4' },
]);
var container = document.getElementById("mynetwork");
var data = {
nodes: nodes,
edges: edges,
};
var options = {
nodes: {
// Set any other options, for example node color to gold
color: 'gold'
},
edges: {
font: {
// Set to the default colors as per the documentation
color: '#343434',
strokeColor: '#ffffff'
}
}
}
var hiddenEdgeTextOptions = {
edges: {
font: {
// Set the colors to transparent
color: 'transparent',
strokeColor: 'transparent'
}
}
};
var network = new vis.Network(container, data, options);
var displayLabels = true;
document.getElementById('toggleLabels').onclick = function() {
if(displayLabels){
// Apply options for hidden edge text
// This will override the existing options for text color
// This does not clear other options (e.g. node.color)
network.setOptions(hiddenEdgeTextOptions);
displayLabels = false;
} else {
// Apply standard options
network.setOptions(options);
displayLabels = true;
}
}
#mynetwork {
width: 600px;
height: 160px;
border: 1px solid lightgray;
}
<script src="https://visjs.github.io/vis-network/standalone/umd/vis-network.min.js"></script>
<button id="toggleLabels">Toggle labels</button>
<div id="mynetwork"></div>
I have a GOJS application up and running and i'm trying to bind a parameter in my data to the group property.
If I manually set the group property in the data then it works exactly as I would expect and the nodes appear as part of the group, but if the group is set using binding then no group connection seems to be made.
What am I missing?
example showing the group being set within the data
var nodes = []
var nodeObj ={
key:"groupObject",
text:"group",
isGroup:true
}
nodes.push(nodeObj)
nodeObj = {
key:"node1",
text:"node1",
group:"groupObject"
}
nodes.push(nodeObj)
nodeObj = {
key:"node2",
text:"node2",
group:"groupObject"
}
nodes.push(nodeObj)
}
const initDiagram = () => {
const $ = go.GraphObject.make;
const diagram =
$(go.Diagram,
{
'undoManager.isEnabled': true,
'clickCreatingTool.archetypeNodeData': { text: 'new node', color: 'lightblue' },
model: $(go.GraphLinksModel,
{
linkKeyProperty: 'key'
})
});
diagram.nodeTemplate =
$(go.Node, 'Auto',
$(go.Shape, 'RoundedRectangle',
{ name: 'SHAPE', fill: 'white', strokeWidth: 0 },
new go.Binding('fill', 'color')),
$(go.TextBlock,
{ margin: 8, editable: true, stroke:"black" },
new go.Binding('text').makeTwoWay()
)
);
diagram.groupTemplate =
$(go.Group, "Vertical", $(go.GridLayout,{wrappingColumn:1}),
$(go.TextBlock, // group title
{ alignment: go.Spot.Center, font: "Bold 15pt Sans-Serif" },
new go.Binding("text")),
$(go.Panel, "Auto",
$(go.Shape, "RoundedRectangle", // surrounds the Placeholder
{fill: "lightblue" }),
$(go.Placeholder,
{ padding: 5}),
)
);
return diagram;
}
This works ^^^
Now if I set the group parameter in the data to "groupName" instead of group, then bind group to groupName in the init function, the nodes no longer appear as part of the group
var nodes = []
var nodeObj ={
key:"groupObject",
text:"group",
isGroup:true
}
nodes.push(nodeObj)
nodeObj = {
key:"node1",
text:"node1",
groupName:"groupObject" //this line has changed
}
nodes.push(nodeObj)
nodeObj = {
key:"node2",
text:"node2",
groupName:"groupObject" //This line has changed
}
nodes.push(nodeObj)
}
const initDiagram = () => {
const $ = go.GraphObject.make;
const diagram =
$(go.Diagram,
{
'undoManager.isEnabled': true,
'clickCreatingTool.archetypeNodeData': { text: 'new node', color: 'lightblue' },
model: $(go.GraphLinksModel,
{
linkKeyProperty: 'key'
})
});
diagram.nodeTemplate =
$(go.Node, 'Auto',
new go.Binding('group','groupName'), //this line has changed
$(go.Shape, 'RoundedRectangle',
{ name: 'SHAPE', fill: 'white', strokeWidth: 0 },
new go.Binding('fill', 'color')),
$(go.TextBlock,
{ margin: 8, editable: true, stroke:"black" },
new go.Binding('text').makeTwoWay()
)
);
diagram.groupTemplate =
$(go.Group, "Vertical", $(go.GridLayout,{wrappingColumn:1}),
$(go.TextBlock, // group title
{ alignment: go.Spot.Center, font: "Bold 15pt Sans-Serif" },
new go.Binding("text")),
$(go.Panel, "Auto",
$(go.Shape, "RoundedRectangle",
{fill: "lightblue" }),
$(go.Placeholder,
{ padding: 5}),
)
);
return diagram;
}
Bindings are used to keep the properties of the GraphObjects of one Part up-to-date with properties on that Part's model data. Bindings are not used for maintaining relationships between Parts. Only models know how to interpret and maintain relationships.
If you want to use the data property "groupName" instead of "group" to refer to the node's containing group, set GraphLinksModel.nodeGroupKeyProperty to "groupName". Preferably before you set Model.nodeDataArray.
Also, please read https://gojs.net/latest/intro/dataBinding.html#ChangingGraphStructure.
I have several groups with nodes and I'd like to make these groups non-intersecting on moving. What I need to do for that? There is an example of my group template.
$(go.Group, "Auto",
{
layout: $(go.LayeredDigraphLayout, {
direction: 0,
columnSpacing: 10,
initializeOption: go.LayeredDigraphLayout.InitDepthFirstOut,
aggressiveOption: go.LayeredDigraphLayout.AggressiveMore
}),
minSize: new go.Size(800, 30),
computesBoundsIncludingLocation: true,
computesBoundsIncludingLinks: true,
computesBoundsAfterDrag: true,
isSubGraphExpanded: true
},
$(go.Shape, "Rectangle", [
{
fill: null,
stroke: "gray",
strokeWidth: 2
},
new go.Binding('fill', '', function (group) {
return group.data.isEditable ? '#eee' : '#F7EAEC';
}).ofObject('')
]),
$(go.Panel, "Vertical",
{ defaultAlignment: go.Spot.Left },
$(go.Panel, "Horizontal",
{ defaultAlignment: go.Spot.Top },
$(go.TextBlock,
{ font: "Bold 18px Sans-Serif", textAlign: "left" },
new go.Binding("text", "name"))
),
$(go.Placeholder,
{ padding: new go.Margin(10, 10), margin: 0 })
)
);
The optimization that is needed is in treating groups as atomic objects. There is no need to test whether any of the member nodes of a group also overlap any nodes when one has already checked the whole group.
Implementing that is just adding two lines to the navig function in that sample, https://gojs.net/latest/samples/dragUnoccupied.html.
function isUnoccupied(r, node) {
var diagram = node.diagram;
// nested function used by Layer.findObjectsIn, below
// only consider Parts, and ignore the given Node and any Links
function navig(obj) {
var part = obj.part;
if (part === node) return null;
if (part instanceof go.Link) return null;
// add these two checks:
if (part.isMemberOf(node)) return null;
if (node.isMemberOf(part)) return null;
return part;
}
// only consider non-temporary Layers
var lit = diagram.layers;
while (lit.next()) {
var lay = lit.value;
if (lay.isTemporary) continue;
if (lay.findObjectsIn(r, navig, null, true).count > 0) return false;
}
return true;
}
// a Part.dragComputation function that prevents a Part from being dragged to overlap another Part
function avoidNodeOverlap(node, pt, gridpt) {
if (node.diagram instanceof go.Palette) return gridpt;
// this assumes each node is fully rectangular
var bnds = node.actualBounds;
var loc = node.location;
// use PT instead of GRIDPT if you want to ignore any grid snapping behavior
// see if the area at the proposed location is unoccupied
var r = new go.Rect(gridpt.x - (loc.x - bnds.x), gridpt.y - (loc.y - bnds.y), bnds.width, bnds.height);
// maybe inflate R if you want some space between the node and any other nodes
r.inflate(-0.5, -0.5); // by default, deflate to avoid edge overlaps with "exact" fits
// when dragging a node from another Diagram, choose an unoccupied area
if (!(node.diagram.currentTool instanceof go.DraggingTool) &&
(!node._temp || !node.layer.isTemporary)) { // in Temporary Layer during external drag-and-drop
node._temp = true; // flag to avoid repeated searches during external drag-and-drop
while (!isUnoccupied(r, node)) {
r.x += 10; // note that this is an unimaginative search algorithm --
r.y += 10; // you can improve the search here to be more appropriate for your app
}
r.inflate(0.5, 0.5); // restore to actual size
// return the proposed new location point
return new go.Point(r.x - (loc.x - bnds.x), r.y - (loc.y - bnds.y));
}
if (isUnoccupied(r, node)) return gridpt; // OK
return loc; // give up -- don't allow the node to be moved to the new location
}
function init() {
var $ = go.GraphObject.make;
myDiagram =
$(go.Diagram, "myDiagramDiv",
{
"undoManager.isEnabled": true,
// support creating groups with Ctrl-G
"commandHandler.archetypeGroupData": { isGroup: true, text: "NEW GROUP" }
});
myDiagram.nodeTemplate =
$(go.Node, "Auto",
{ // avoid overlapping other nodes
dragComputation: avoidNodeOverlap
},
$(go.Shape,
{ fill: "white", portId: "", fromLinkable: true, toLinkable: true, cursor: "pointer" },
new go.Binding("fill", "color")),
$(go.TextBlock,
{ margin: 8, editable: true },
new go.Binding("text").makeTwoWay())
);
myDiagram.groupTemplate =
$(go.Group, "Vertical",
{ // avoid overlapping other nodes
dragComputation: avoidNodeOverlap,
// support ungrouping by Ctrl-Shift-G
ungroupable: true
},
$(go.TextBlock,
{ font: "bold 14pt sans-serif", editable: true },
new go.Binding("text").makeTwoWay()),
$(go.Panel, "Auto",
$(go.Shape, { fill: "lightgray" }),
$(go.Placeholder, { padding: 5 })
)
);
myDiagram.model = new go.GraphLinksModel(
[
{ key: 1, text: "Alpha", color: "lightblue" },
{ key: 2, text: "Beta", color: "orange" },
{ key: 3, text: "Gamma", color: "lightgreen" },
{ key: 4, text: "Delta", color: "pink" }
],
[
{ from: 1, to: 2 },
{ from: 1, to: 3 },
{ from: 2, to: 2 },
{ from: 3, to: 4 },
{ from: 4, to: 1 }
]);
}
To create a Group, select some nodes and type Control-G.
Set this in your nodeTemplate:
myDiagram.nodeTemplate =
$(go.Node, "Auto",
{ dragComputation: avoidNodeOverlap });
You can check a solution here:
https://gojs.net/latest/samples/dragUnoccupied.html
I want to have two groups which have vertical layout in a diagram, each group have some nodes which can be dragged and dropped into another group, and i want to drop the node on the top of the group.
this is what i want:
beforedrop
afterdrop
I searched gojs api and tried to use go.LayeredDigraphLayout, gojs LayeredDigraphLayout, the api said set the direction to 270 is upwards, but seems not work..
my nodes still layout from top to bottom, and when i drop the node, it moves to the bottom...
this is what i got:
before
after
here is my code:
function init() {
var $ = go.GraphObject.make; // for conciseness in defining templates
myDiagram = $(go.Diagram, "myDiagramDiv",
{
initialContentAlignment: go.Spot.Center,
layout: $(go.GridLayout, { wrappingColumn: 2 }),
"undoManager.isEnabled": true
});
myDiagram.groupTemplateMap.add("Group",
$(go.Group, "Auto",
{ resizable: false,
computesBoundsAfterDrag: true,
layout: $(go.LayeredDigraphLayout,
{ columnSpacing: 5, direction: 180}),
mouseDrop: function(e, grp) {
grp.addMembers(grp.diagram.selection, true);
},
},
$(go.Shape, { fill: "white", stroke: "lightgray",width:200 }),
$(go.Placeholder, { padding: 10 })
));
myDiagram.nodeTemplate =
$(go.Node, "Auto",
{
mouseDrop: function(e, grp) {
grp.diagram.currentTool.doCancel();
}
},
$(go.Shape, "RoundedRectangle",
new go.Binding("fill", "color")),
$(go.TextBlock, { margin: 3 },
new go.Binding("text", "key"))
);
myDiagram.model = new go.GraphLinksModel(
[
{ key: "G1", isGroup: true, category: "Group" },
{ key: "G2", isGroup: true, category: "Group" },
{ key: "Alpha", color: "lightblue", group: "G1" },
{ key: "Beta", color: "orange", group: "G1" },
{ key: "Gamma", color: "lightgreen", group: "G1" },
{ key: "Delta", color: "pink", group: "G1" },
{ key: "Alpha2", color: "lightblue", group: "G2" },
{ key: "Beta2", color: "orange", group: "G2" },
{ key: "Gamma2", color: "lightgreen", group: "G2" },
{ key: "Delta2", color: "pink", group: "G2" }
]);
}
<script src="https://gojs.net/latest/release/go.js"></script>
<body onload="init()">
<div id="myDiagramDiv" style="flex-grow: 1; height: 500px; border: solid 1px black"></div>
</body>
i put the code on git, just a html: GoJS_Layout_git
can anyone help me with this problem? many thanks
You need to make each Group.layout sort the nodes in the order that you want. LayeredDigraphLayout won't help you there, since it is supposed to re-order the nodes in a layer to reduce link crossings.
Instead, use GridLayout or TreeLayout and set their respective sorting and comparer properties. The latter must be a function that compares two Nodes (when GridLayout) or two LayoutVertexes (when TreeLayout) for sorting purposes. There are examples of this in the documentation, such as at https://gojs.net/latest/api/symbols/TreeLayout.html#comparer