GoJS set layout from bottom to top, and drop nodes on top - javascript

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

Related

Hide edge labels in vis.js-network

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>

Make highcharts fullscreen also fullscreen the div wrapping the chart

Is there a way to make the div wrapping the chart part of the fullscreen as well?
This is my code: fiddle
THis code only fulscreens the chart. When I try and do to point the div I need in the fullscreen:
Highcharts.FullScreen = function(container) {
this.init(ontainer.parentNode.parentNode);
};
My fullscreen is getting cut off and also not adding the parent div to the full screen. Is there to make the whole div with id yo and the other div inside (<div>Random Data and text.......</div>) as part of the fullscreen?
You can connect the content of a custom element through chart.renderer.text().add() by specifying this element with the html() method:
chart.renderer.text(selector.html(), 0, 0).add();
...hiding this element through css, set the display: none:
.random_data {
display: none;
}
This is the piece of code to add:
function (chart) {
chart.renderer
.text($(".random_data").html(), 10, 10)
.css({
color: "green",
fontSize: "12px",
})
.add();
}
JavaScript:
let chart = Highcharts.chart(
"container",
{
chart: {
type: "column",
},
title: {
text: "",
},
xAxis: {
categories: ["one", "two", "three"],
},
plotOptions: {
column: {
pointPadding: 0.2,
borderWidth: 0,
},
},
yAxis: {
title: {
text: "",
},
endOnTick: false,
},
series: [
{
name: "books",
data: [
["one", 64161.71548379661],
["two", 3570.6197029028076],
["three", -200.70625619033547],
],
marker: {
symbol: "circle",
},
},
],
},
function (chart) {
chart.renderer
.text($(".random_data").html(), 10, 10)
.css({
color: "green",
fontSize: "12px",
})
.add();
}
);
let btn = document.getElementById("btn");
btn.addEventListener("click", function () {
Highcharts.FullScreen = function (container) {
console.log(container.parentNode.parentNode);
this.init(container.parentNode); // main div of the chart
};
Highcharts.FullScreen.prototype = {
init: function (container) {
if (container.requestFullscreen) {
container.requestFullscreen();
} else if (container.mozRequestFullScreen) {
container.mozRequestFullScreen();
} else if (container.webkitRequestFullscreen) {
container.webkitRequestFullscreen();
} else if (container.msRequestFullscreen) {
container.msRequestFullscreen();
}
},
};
chart.fullscreen = new Highcharts.FullScreen(chart.container);
});
CSS:
.random_data {
display: none;
}
HTML:
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://code.highcharts.com/highcharts.js"></script>
<div id="yo">
<div class="random_data">Random Data and text.......</div>
<div id="container" style="height: 400px; margin-top: 1em;"></div>
</div>
<button id="btn">
Show full screen
</button>

gojs makeImageData using nodejs

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

How to fix the binding of the "location" property of member elements within a group in the palette?

I've been tweaking the Floor Planner project from GoJS and I want to make my own customized item (grouped elements) in the palette area. I was able to generate an item but the elements within the group are not reacting to the node template map I've set-up as seen in the screenshot below:
What I was expecting is to have a grouped element like this:
This is how I set-up my template maps:
For the blue lines
function makeBlueLine() {
var $ = go.GraphObject.make;
return $(go.Node, "Auto",
{
contextMenu: makeContextMenu(),
selectionObjectName: "SHAPE",
selectionAdorned: false,
resizeAdornmentTemplate: makeWallPartResizeAdornment(),
locationSpot: go.Spot.Left,
toolTip: makeNodeToolTip(),
resizable: true,
resizeObjectName: "SHAPE",
rotatable: true,
doubleClick: function (e) { if (e.diagram.floorplanUI) e.diagram.floorplanUI.hideShow("selectionInfoWindow"); },
},
new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
new go.Binding("visible", "showOnPlan"),
new go.Binding("angle", "angle"),
$(go.Shape,
{ name: "SHAPE", fill: "blue", stroke: "#000", strokeWidth: 1, height: 1, figure: "Rectangle" },
new go.Binding("width", "length").makeTwoWay(),
new go.Binding("stroke", "isSelected", function (s, obj) {
return s ? "green" : "blue";
}).ofObject(),
),
);
}
For the Group
function makeLineContainer() {
var $ = go.GraphObject.make;
return $(go.Group, "Vertical",
{
//isSubGraphExpanded: false,
contextMenu: makeContextMenu(),
doubleClick: function (e) {
if (e.diagram.floorplanUI) e.diagram.floorplanUI.hideShow("selectionInfoWindow");
},
toolTip: makeGroupToolTip()
},
new go.Binding("location", "loc"),
$(go.Panel, "Auto",
$(go.Shape, "RoundedRectangle", { fill: "rgba(0,0,0,0)", stroke: null, name: 'SHAPE', strokeCap: 'square' },
new go.Binding("fill", "isSelected", function (s, obj) {
return s ? "rgba(128, 128, 128, 0.10)" : "rgba(0,0,0,0)";
}).ofObject()
),
$(go.Placeholder, { padding: 5 })
)
)
}
This is my model array set-up:
BLUE_LINE_DATA_ARRAY = [
{
category: "LineParent",
key: "Type1",
isGroup: true,
},
{
category: "BlueLine",
group: "Type1",
loc: '0 0',
angle: 90,
length: 50,
key: "G1",
},
{
category: "BlueLine",
group: "Type1",
loc: '10 10',
angle: 0,
length: 50,
key: "G2",
},
];
For the palette initialization, I haven't done any change except adding the group template map there. Here's the template mapping I've made:
this.nodeTemplateMap.add("BlueLine", makeBlueLine());
this.groupTemplateMap.add("LineParent", makeLineContainer());
I couldn't find what I'm missing. I've also checked on the macros.html sample and everything looks similar.
I just tried implementing such a sample, but I was unable to encounter any problems with groups in a Palette. Here's my code:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- Copyright 1998-2019 by Northwoods Software Corporation. -->
<script src="go.js"></script>
<script>
function init() {
var $ = go.GraphObject.make;
// initialize main Diagram
myDiagram =
$(go.Diagram, "myDiagramDiv",
{ "undoManager.isEnabled": true });
myDiagram.nodeTemplate =
$(go.Node, "Auto",
new go.Binding("location", "location", go.Point.parse).makeTwoWay(go.Point.stringify),
$(go.Shape,
{ fill: "white", stroke: "gray", strokeWidth: 2 },
new go.Binding("stroke", "color")),
$(go.TextBlock,
{ margin: 4 },
new go.Binding("text").makeTwoWay())
);
// initialize Palette
myPalette =
$(go.Palette, "myPaletteDiv",
{ nodeTemplateMap: myDiagram.nodeTemplateMap });
myPalette.model.nodeDataArray = [
{ key: 1, group: 3, text: "blue node", color: "blue", location: "30 0" },
{ key: 2, group: 3, text: "orange node", color: "orange", location: "0 40" },
{ key: 3, isGroup: true, text: "GROUP" }
];
// initialize Overview
myOverview =
$(go.Overview, "myOverviewDiv",
{ observed: myDiagram, contentAlignment: go.Spot.Center });
load();
}
// save a model to and load a model from Json text, displayed below the Diagram
function save() {
var str = myDiagram.model.toJson();
document.getElementById("mySavedModel").value = str;
}
function load() {
var str = document.getElementById("mySavedModel").value;
myDiagram.model = go.Model.fromJson(str);
}
</script>
</head>
<body onload="init()">
<div style="width: 100%; display: flex; justify-content: space-between">
<div style="display: flex; flex-direction: column; margin: 0 2px 0 0">
<div id="myPaletteDiv" style="flex-grow: 1; width: 120px; background-color: whitesmoke; border: solid 1px black"></div>
<div id="myOverviewDiv" style="margin: 2px 0 0 0; width: 120px; height: 100px; background-color: lightgray; border: solid 1px black"></div>
</div>
<div id="myDiagramDiv" style="flex-grow: 1; height: 400px; border: solid 1px black"></div>
</div>
<div id="buttons">
<button id="loadModel" onclick="load()">Load</button>
<button id="saveModel" onclick="save()">Save</button>
</div>
<textarea id="mySavedModel" style="width:100%;height:200px">
{ "class": "go.GraphLinksModel",
"nodeDataArray": [
{"key":1, "text":"hello", "color":"green", "location":"0 0"},
{"key":2, "text":"world", "color":"red", "location":"70 0"}
],
"linkDataArray": [
{"from":1, "to":2}
]}
</textarea>
</body>
</html>
Note how the group appears in the Palette, and when a copy is dropped in the main Diagram. Each of the two member nodes are located according to the binding, and they remain in that relative location, until the user moves a member node in the main diagram.
Tried to look into this some more but unfortunately, I still haven't found a definitive reason or cause of the issue. However, I did find a workaround but it will costed me the ability to have multiple palettes for the floor planner. So basically, I changed the palette constructor of the floor planner package to follow the pattern of the samples for palette found in GoJS website.
How it was declared first:
function FloorplanPalette(div, floorplan, nodeDataArray) {
go.Palette.call(this, div);
var $ = go.GraphObject.make;
this.model = $(go.GraphLinksModel, { nodeDataArray: nodeDataArray });
this.contentAlignment = go.Spot.Center;
this.nodeTemplateMap = floorplan.nodeTemplateMap;
this.groupTemplateMap = floorplan.groupTemplateMap;
this.toolManager.contextMenuTool.isEnabled = false;
// add this new FloorplanPalette to the "palettes" field of its associated Floorplan
floorplan.palettes.push(this);
} go.Diagram.inherit(FloorplanPalette, go.Palette);
My change:
function FloorplanPalette(div, floorplan, nodeDataArray) {
var $ = go.GraphObject.make;
myPalette =
$(go.Palette, div, // must name or refer to the DIV HTML element
{
nodeTemplateMap: floorplan.nodeTemplateMap,
groupTemplateMap: floorplan.groupTemplateMap,
contentAlignment: go.Spot.Center,
});
myPalette.model = new go.GraphLinksModel(nodeDataArray);
}

JointJS ports are non-functional

Here is a JSFiddle showing the issue: https://jsfiddle.net/Bronzdragon/xpvt214o/399003/
graph = new joint.dia.Graph;
var paper = new joint.dia.Paper({
el: document.getElementById('myholder'),
model: graph,
width: 800,
height: 600,
});
var rect = new joint.shapes.basic.Rect({
attrs: {rect: {fill: 'lightblue'}},
size: { width: 200, height: 100 },
ports: {
groups: {
'inputs': {
position: { name: 'left' },
attrs: {circle: {fill: 'lightgreen'}},
magnet: 'passive'
},
'outputs': {
position: { name: 'right' },
attrs: {circle: {fill: 'pink'}},
magnet: true,
}
},
items:[ { group: 'inputs' }, { group: 'outputs' } ]
}
});
rect.position(100, 50);
rect.addTo(graph);
var rect2 = rect.clone();
rect2.position(400, 100);
rect2.addTo(graph);
I'm defining an JointJS element (called rect), with two ports on it, and adding them to the graph. The elements themselves are functional, but the ports aren't. When dragging off of an active magnet (the pink circle), it should create a link. Instead it moves the element.
I've followed the JointJS guide in creating a shape, and adding ports. These ports I've added seem to be completely inactive though. I do not know what I'm doing wrong.
I have emailed the JointJS team, and they came back to me with the following (Thank you very much, Roman!):
Thank you for reaching out to us! You were nearly there. The magnet attribute meant to be set on a specific shape DOM element. Similar to fill, refX, xlinkHref etc.
var rect = new joint.shapes.basic.Rect({
attrs: {rect: {fill: 'lightblue' }, root: { magnet: false }},
size: { width: 200, height: 100 },
ports: {
groups: {
'inputs': {
position: { name: 'left' },
attrs: {circle: {fill: 'green', magnet: 'passive' }},
},
'outputs': {
position: { name: 'right' },
attrs: {circle: {fill: 'red', magnet: true }},
}
},
items:[ { group: 'inputs' }, { group: 'outputs' } ]
}
});
Also, If you are new to JointJS I recommend you to read our online tutorials (https://resources.jointjs.com/tutorial). I suggest using standard shapes over basic, as the standard shapes are newer and reflecting the best JointJS techniques.

Categories