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.
Related
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
My version is gojs-1.7.22 and I am trying to load the sample productionProcess but its retrieving the following error:
"GraphObject.make requires a class function or GoJS class name or name of an object builder, not: ToolTip".
I am doing something wrong?
// Load libs
var $ = go.GraphObject.make; // for conciseness in defining templates
myDiagram = $(go.Diagram, "myDiagramDiv", // create a Diagram for the DIV HTML element
{
maxSelectionCount: 1, // users can select only one part at a time
"toolManager.hoverDelay": 10, // how quickly tooltips are shown
initialAutoScale: go.Diagram.Uniform, // scale to show all of the contents
"ChangedSelection": onSelectionChanged, // view additional information
});
function infoString(obj) {
var part = obj.part;
if (part instanceof go.Adornment) part = part.adornedPart;
var msg = "";
if (part instanceof go.Link) {
msg = "";
} else if (part instanceof go.Node) {
msg = part.data.text + ":\n\n" + part.data.description;
}
return msg;
}
var colors = {
"red": "#be4b15",
"green": "#52ce60",
"blue": "#6ea5f8",
"lightred": "#fd8852",
"lightblue": "#afd4fe",
"lightgreen": "#b9e986",
"pink": "#faadc1",
"purple": "#d689ff",
"orange": "#fdb400",
};
// A data binding conversion function. Given an name, return the Geometry.
// If there is only a string, replace it with a Geometry object, which can be shared by multiple Shapes.
function geoFunc(geoname) {
var geo = icons[geoname];
if (typeof geo === "string") {
geo = icons[geoname] = go.Geometry.parse(geo, true);
}
return geo;
}
myDiagram.nodeTemplate =
$(go.Node, "Spot",
{
locationObjectName: 'main',
locationSpot: go.Spot.Center,
toolTip:
$("ToolTip",
$(go.TextBlock, { margin: 4, width: 140 },
new go.Binding("text", "", infoString).ofObject())
)
},
new go.Binding("location", "pos", go.Point.parse).makeTwoWay(go.Point.stringify),
// The main element of the Spot panel is a vertical panel housing an optional icon,
// plus a rectangle that acts as the port
$(go.Panel, "Vertical",
$(go.Shape, {
name: 'icon',
width: 1, height: 1,
stroke: null, strokeWidth: 0,
fill: colors.blue
},
new go.Binding("fill", "color", function (c) { return colors[c]; }),
new go.Binding("width", "iconWidth"),
new go.Binding("height", "iconHeight"),
new go.Binding("geometry", "icon", geoFunc)),
$(go.Shape, {
name: 'main',
width: 40, height: 40,
margin: new go.Margin(-1, 0, 0, 0),
portId: "",
stroke: null, strokeWidth: 0,
fill: colors.blue
},
new go.Binding("fill", "color", function (c) { return colors[c]; }),
new go.Binding("width", "portWidth"),
new go.Binding("height", "portHeight"))
),
$(go.TextBlock, {
font: "Bold 14px Lato, sans-serif",
textAlign: "center",
margin: 3,
maxSize: new go.Size(100, NaN),
alignment: go.Spot.TopCenter,
alignmentFocus: go.Spot.BottomCenter
},
new go.Binding("text"))
);
// Some links need a custom to or from spot
function spotConverter(dir) {
if (dir === "left") return go.Spot.LeftSide;
if (dir === "right") return go.Spot.RightSide;
if (dir === "top") return go.Spot.TopSide;
if (dir === "bottom") return go.Spot.BottomSide;
if (dir === "rightsingle") return go.Spot.Right;
}
myDiagram.linkTemplate =
$(go.Link, {
toShortLength: -2,
fromShortLength: -2,
layerName: "Background",
routing: go.Link.Orthogonal,
corner: 15,
fromSpot: go.Spot.RightSide,
toSpot: go.Spot.LeftSide
},
// make sure links come in from the proper direction and go out appropriately
new go.Binding("fromSpot", "fromSpot", function (d) { return spotConverter(d); }),
new go.Binding("toSpot", "toSpot", function (d) { return spotConverter(d); }),
new go.Binding("points").makeTwoWay(),
// mark each Shape to get the link geometry with isPanelMain: true
$(go.Shape, { isPanelMain: true, stroke: colors.lightblue, strokeWidth: 10 },
new go.Binding("stroke", "color", function (c) { return colors[c]; })),
$(go.Shape, { isPanelMain: true, stroke: "white", strokeWidth: 3, name: "PIPE", strokeDashArray: [20, 40] })
);
myDiagram.model = go.Model.fromJson(document.getElementById("mySavedModel").value);
loop(); // animate some flow through the pipes
I am following the sample described in the following link
https://github.com/NorthwoodsSoftware/GoJS/blob/master/samples/productionProcess.html
The "ToolTip" builder was added in version 2.0. Try using the sample from the 1.7 version.
For the past couple days, I was struggling to use this highchart map type in my react project
https://jsfiddle.net/26tbkjov//
Can some one please help me out?
Please check what I achieved until now:
https://codesandbox.io/s/highcharts-react-demo-0m5ux
I am using those highcharts npm packages
"highcharts": "^7.1.2",
"highcharts-react-official": "^2.2.2",
I have tried many things and ended up in a dead path.. the following is the last thing i have tried:
import React from "react";
import mapData from '../../api/mapData';
import Highcharts from 'highcharts';
import HighchartsReact from 'highcharts-react-official';
require('highcharts/modules/map')(Highcharts);
class MyMap extends React.Component {
constructor(props) {
super(props);
this.state = {
mapValues: [],
modalClassic: false,
};
this.mapData = new mapData();
// preparing the config of map with empty data
this.options = {
title: {
text: 'Widget click by location',
style: {
color: '#fff'
},
},
chart:{
backgroundColor: 'transparent',
type: 'map',
map: null,
},
mapNavigation: {
enabled: true,
enableButtons: false
},
credits: {
enabled: false
},
colorAxis: {
dataClasses: [
{
from: 1,
color: '#C40401',
name: 'widget name one'
}, {
from: 2,
color: '#0200D0',
name: 'widget name two'
}
]
},
tooltip: {
pointFormatter: function() {
return this.name;
}
},
legend: {
align: 'right',
verticalAlign: 'top',
x: -100,
y: 70,
floating: true,
layout: 'vertical',
valueDecimals: 0,
backgroundColor: ( // theme
Highcharts.defaultOptions &&
Highcharts.defaultOptions.legend &&
Highcharts.defaultOptions.legend.backgroundColor
) || 'rgba(255, 255, 255, 0.85)'
},
series: [{
name: 'world map',
dataLabels: {
enabled: true,
color: '#FFFFFF',
format: '{point.postal-code}',
style: {
textTransform: 'uppercase'
}
},
tooltip: {
ySuffix: ' %'
},
cursor: 'pointer',
joinBy: 'postal-code',
data: [],
point: {
events: {
click: function(r){
console.log('click - to open popup as 2nd step');
console.log(r);
}
}
}
}]
};
}
/*
* Before mounting the component,
* update the highchart map options with the needed map data and series data
* */
componentWillMount = () => {
this.mapData.getWorld().then((r)=>{
this.setState({'mapData': r.data}, ()=>{
this.options.series[0].data = []; //make sure data is empty before fill
this.options['chart']['map'] = this.state.mapData; // set the map data of the graph (using the world graph)
// filling up some dummy data with values 1 and 2
for(let i in this.state.mapData['features']){
let mapInfo = this.state.mapData['features'][i];
if (mapInfo['id']) {
var postalCode = mapInfo['id'];
var name = mapInfo['properties']['name'];
var value = i%2 + 1;
var type = (value === 1)? "widget name one" : "widget name two";
var row = i;
this.options.series[0].data.push({
value: value,
name: name,
'postal-code': postalCode,
row: row
});
}
}
// updating the map options
this.setState({mapOptions: this.options});
});
});
}
render() {
return (
<div>
{(this.state.mapData)?
<HighchartsReact
highcharts={Highcharts}
constructorType={'mapChart'}
options={(this.state.mapOptions)? this.state.mapOptions: this.options}
/>
: ''}
</div>
);
}
}
export default MyMap;
If you want to use the USA map, you need to change the url to: "https://code.highcharts.com/mapdata/countries/us/us-all.geo.json" and the postal-code from US.MA to MA:
this.mapData.getWorld().then(r => {
...
for (let i in this.state.mapData["features"]) {
...
var postalCode = mapInfo.properties["postal-code"];
...
}
...
});
Live demo: https://codesandbox.io/s/highcharts-react-demo-jmu5h
To use the word map, you need to also change the part related with the postal-code and joinBy property:
series: [{
joinBy: ['iso-a2', 'code'],
...
}]
this.mapData.getWorld().then(r => {
...
for (let i in this.state.mapData["features"]) {
let mapInfo = this.state.mapData["features"][i];
if (mapInfo["id"]) {
var code = mapInfo["id"];
...
this.options.series[0].data.push({
"code": code,
...
});
}
}
...
});
Live demo: https://codesandbox.io/s/highcharts-react-demo-sxfr2
API Reference: https://api.highcharts.com/highmaps/series.map.joinBy
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'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);
}