Node localisation with go.Binding('location', 'loc', go.Point.parse) does'n work anymore

Hello,
I successfully create a diagram with node template using go.Binding(‘location’, ‘loc’, go.Point.parse) to position nodes in gojs-diagram component (gojs-angular).
But if I take the same configuration in a simple gojs diagram is not working. Nodes are not positionned.
What am I missing ?

Could you show us how your simple diagram is initialized? What’s your model data?

import {AfterViewInit, Component, ElementRef, OnInit, ViewChild} from ‘@angular/core’;
import * as go from “gojs”;
import {DiagramService} from “…/services/diagram.service”;

@Component({
selector: ‘app-test’,
templateUrl: ‘./test.component.html’,
styleUrls: [’./test.component.css’]
})
export class TestComponent implements AfterViewInit {
@ViewChild(‘pvDiagramContainer’, { static: true })
pvDiagramContainer?: ElementRef;
public diagramNodeData: Array<go.ObjectData> = [];
public diagramLinkData: Array<go.ObjectData> = [];

constructor(public diagramService: DiagramService) { }

ngAfterViewInit(): void {
this.diagramNodeData = [
{id: ‘mainGroup’, isGroup: true},
// line 1
{id: ‘Hold’, text: “Hold”, group: “mainGroup”, category: “edited”, loc: “10 10” },
{id: ‘Holding’, text: “Holding”, group: “mainGroup”, category: “edited”, loc: “150 10” },
{id: ‘Pausing’, text: “Pausing”, group: “mainGroup”, category: “edited”, loc: “450 10” },
// line 2
{id: ‘Stopping’, text: “Stopping”, group: “mainGroup”, category: “edited”, loc: “10 100” },
{id: ‘Running’, text: “Running”, group: “mainGroup”, category: “edited”, loc: “300 100” },
{id: ‘Paused’, text: “Paused”, group: “mainGroup”, category: “edited”, loc: “550 60” },
// line 3
{id: ‘Stopped’, text: “Stopped”, group: “mainGroup”, category: “edited”, loc: “10 200”},
{id: ‘Restarting’, text: “Restarting”, group: “mainGroup”, category: “edited”, loc: “300 200”},
// line 4
{id: ‘Aborted’, text: “Aborted”, category: “edited”, loc: “300 300”},
{id: ‘Aborting’, text: “Aborting”, category: “edited”, loc: “550 300”}
];

this.diagramLinkData = [
  {key: 0, from: 'Hold', to: 'Running', text: "Unhold", category: "textLink", fromSpot: "Bottom", toSpot: "TopLeft" },
  {key: 1, from: 'Holding', to: 'Hold', category: "simpleLink"},
  {key: 2, from: 'Pausing', to: 'Paused', category: "simpleLink", fromSpot: "Right", toSpot: "Top" },
  {key: 3, from: 'Stopping', to: 'Stopped', category: "simpleLink" },
  {key: 4, from: 'Running', to: 'Holding', text: "Hold", category: "otherStrangeLink", fromSpot: "Top", toSpot: "Right"},
  {key: 5, from: 'Running', to: 'Pausing', text: "Pause", category: "textLink", fromSpot: "TopRight", toSpot: "Left" },
  {key: 6, from: 'Paused', to: 'Running', text: "Unpause", category: "textLink", fromSpot: "Bottom", toSpot: "Right" },
  {key: 7, from: 'Running', to: 'Stopping', text: "Stop", category: "textLink"},
  {key: 8, from: 'Stopped', to: 'Restarting', text: "Start", category: "textLink"},
  {key: 9, from: 'Restarting', to: 'Running', category: "simpleLink"},
  {key: 10, from: 'Aborted', to: 'Stopped', text: "Clean", category: "textLink", fromSpot: "Left", toSpot: "Bottom"},
  {key: 11, from: 'Aborting', to: 'Aborted', category: "simpleLink"},
  {key: 12, from: 'mainGroup', to: 'Aborting', text: "Abort", category: "textLink", fromSpot: "Right", toSpot: "Right"}
];
console.log(this.diagramNodeData)
console.log(this.diagramLinkData)
this.initDiagram();

}

initDiagram(): void {
if (this.pvDiagramContainer == null) {
alert(‘container is null’)
} else {
this.diagramService.initDiagram(
this.pvDiagramContainer.nativeElement,
this.diagramNodeData,
this.diagramLinkData,
null
);
}
}

}

import { Injectable } from ‘@angular/core’;
import * as go from ‘gojs’;
import {stringify} from “querystring”;

@Injectable({
providedIn: ‘root’,
})
export class DiagramService {
protected readonly $ = go.GraphObject.make;
protected diagram: go.Diagram | undefined;

constructor() {}
/**

  • Delete the selection
    */
    public deleteSelection() {
    if (this.diagram == null) {
    alert(‘this.diagram == null’);
    } else {
    this.diagram.commandHandler.deleteSelection();
    }
    }

initDiagram(
container: HTMLDivElement,
nodeDataArray: Array<go.ObjectData>,
linkDataArray: Array<go.ObjectData>,
contextualMenu: HTMLUListElement | null
) {
this.diagram = this.createDefaultDiagram(
container,
nodeDataArray,
linkDataArray,
contextualMenu
);
}

protected createDefaultDiagram(
container: HTMLDivElement,
nodeDataArray: Array<go.ObjectData>,
linkDataArray: Array<go.ObjectData>,
contextualMenu: HTMLUListElement | null
): go.Diagram {
const diagram = this.$(go.Diagram, container);
diagram.model = this.createDiagramModel(nodeDataArray, linkDataArray);
diagram.undoManager.isEnabled = false;
diagram.scrollMode = go.Diagram.DocumentScroll;
diagram.allowCopy = false;
diagram.allowReshape = false;
let editedTemplate = this.$(
go.Node,
this.getStateNodeInitializer(),
this.getStateLocalisationBinding(),
this.getStateShape(’#2E75B6’),
this.getStateTextBlock(’#FFFFFF’, true),
{
click: (e: any, obj: any) => {
window.alert('Edit diagram of ’ + obj.part.data.text);
},
}
);

let nodeTemplateMap = new go.Map<string, go.Node>();
nodeTemplateMap.add("edited", editedTemplate);
diagram.nodeTemplateMap = nodeTemplateMap;

//
// init links templates
//
let simpleLinkTemplate = this.$(
  go.Link, // the whole link panel
  this.getLinkLocalisationBinding('fromSpot'),
  this.getLinkLocalisationBinding('toSpot'),
  this.getLinkProperties(),
  this.getLinkFromShape(),
  this.getLinkToShape()
);
let textLinkTemplate = this.$(
  go.Link, // the whole link panel
  { routing: go.Link.AvoidsNodes },
  this.getLinkLocalisationBinding('fromSpot'),
  this.getLinkLocalisationBinding('toSpot'),
  this.getLinkFromShape(),
  this.getLinkToShape(),
  this.$(
    go.TextBlock, // this is a link label
    {
      stroke: 'white',
      background: 'rgb(170, 170, 170)',
      minSize: new go.Size(60, 20),
      maxSize: new go.Size(200, 20),
      overflow: go.TextBlock.OverflowEllipsis,
      verticalAlignment: go.Spot.Center,
      textAlign: 'center',
    },
    new go.Binding('text', 'text')
  )
);
let linkTemplateMap = new go.Map<string, go.Link>();
linkTemplateMap.add('simpleLink', simpleLinkTemplate);
linkTemplateMap.add('textLink', textLinkTemplate);
diagram.linkTemplateMap = linkTemplateMap;

//
// init group template
//
diagram.groupTemplate = this.$(
  go.Group,
  'Vertical',
  this.$(
    go.Panel,
    'Auto',
    this.$(
      go.Shape,
      'Rectangle', // surrounds the Placeholder
      { parameter1: 14, fill: 'whitesmoke', strokeDashArray: [5, 2] }
    ),
    this.$(
      go.Placeholder, // represents the area of all member parts,
      { padding: 20 }
    ) // with some extra padding around them
  ),
  this.$(
    go.TextBlock, // group title
    { alignment: go.Spot.Right, font: 'Bold 12pt Sans-Serif' },
    new go.Binding('text', 'key')
  )
);

return diagram;

}

private getStateNodeInitializer(): string {
return ‘Auto’;
}

private getStateLocalisationBinding(): go.Binding {
return new go.Binding(‘location’, ‘loc’, go.Point.parse);
}

private getStateShape(color: string): go.Shape {
return this.$(go.Shape, ‘Ellipse’, {
stroke: color,
fill: color,
});
}

private getStateTextBlock(color: string, clickable: boolean): go.TextBlock {
return this.$(
go.TextBlock,
{
cursor: clickable ? ‘pointer’ : ‘default’,
margin: 8,
editable: false,
maxSize: new go.Size(200, 20),
overflow: go.TextBlock.OverflowEllipsis,
stroke: color,
},
new go.Binding(‘text’).makeTwoWay()
);
}

private getLinkLocalisationBinding(property: string): go.Binding {
return new go.Binding(property, property, go.Spot.parse);
}

private getLinkProperties(): any {
return {
routing: go.Link.Orthogonal,
fromSpot: go.Spot.Left,
toSpot: go.Spot.Right,
}; // link route should avoid nodes
}

private getLinkFromShape(): go.Shape {
return this.$(go.Shape, { stroke: ‘rgb(46, 117, 182)’ });
}

private getLinkToShape(): go.Shape {
return this.$(go.Shape, {
toArrow: ‘Standard’,
stroke: ‘rgb(46, 117, 182)’,
});
}

/**

  • Uses GoJS to create the model data that will be represented by Nodes and Links
  • @returns go.Model
    */
    protected createDiagramModel(
    nodeDataArray: Array<go.ObjectData>,
    linkDataArray: Array<go.ObjectData>
    ): go.Model {
    return this.$(go.GraphLinksModel, {
    nodeKeyProperty: ‘id’,
    linkKeyProperty: ‘key’, // IMPORTANT! must be defined for merges and data sync when using GraphLinksModel
    nodeDataArray: nodeDataArray,
    linkDataArray: linkDataArray,
    });
    }
    }

Ok, so it’s not actually a simple JS-only configuration. You’re still passing things around in Angular.

You need to make sure the node and link data arrays that get passed into your createDiagramModel method are correct. You should be able to debug that. Also, I notice you have an extra line in between the linkKeyProperty and nodeDataArray initializers.

I don’t understand.
here is my html. As you can see I’m not using anymore the …/>
The node are placed by order and not by the loc (for example the ‘Aborted’ must be in the same line of ‘Aborting’)

> 
> 
> <!--Initialization Diagram Container-->
> <div class="container-fluid">
>   <div
>     #pvDiagramContainer
>     class="diagramContainerStyle"
>     automation-id="div_PhysicalView"
>   ></div>
>   <!--  Initialization Menu-->
>   <ul #contextMenu id="contextMenu" class="menu list-group-horizontal">
>     <div class="row menu-item">
>       <li>
>         <input class="span-checkBox" type="checkbox" checked /><span
>         class="span-textBlock"
>       >None</span
>       >
>       </li>
>     </div>
>   </ul>
> </div>

If you’re still using the createDiagramModel function, you should add a breakpoint and make sure that the data being passed into it includes “loc” properties. What you’re seeing is the default Diagram.layout, which ignores any Nodes that already have a location. That means the Binding is not taking effect, which is why I wonder if the data is being provided correctly.