How to align the node in center based on the background grid

I want to set node position in the center of every rectangle while drag from palette it should automatically fit according to rectangle size.

this.node = goInstance(go.Node, “Auto”,

        { rotatable: true, width:100,height:100, selectable: true,

        }, 

grid: this._goInstance(go.Panel, “Grid”,

             { gridCellSize: new go.Size(100, 100) },

and I have set the
this.diagram.toolManager.draggingTool.isGridSnapEnabled = true;

Set https://gojs.net/latest/api/symbols/DraggingTool.html#gridSnapCellSpot to Spot.Center.

$(go.Diagram, . . .,
  { "draggingTool.gridSnapCellSpot": go.Spot.Center })

You probably also want to set Node.locationSpot and Node.locationObjectName.
https://gojs.net/latest/intro/nodes.html#PositionAndLocation

I believe that what I suggested above works well. Here’s a complete sample:

<!DOCTYPE html>
<html>
<head>
  <title>Minimal GoJS Editor</title>
  <!-- Copyright 1998-2021 by Northwoods Software Corporation. -->
  <script src="https://unpkg.com/gojs"></script>
  <script id="code">
    function init() {
      var $ = go.GraphObject.make;

      // initialize main Diagram
      myDiagram =
        $(go.Diagram, "myDiagramDiv",
          {
            grid: $(go.Panel, "Grid",
              { gridCellSize: new go.Size(100, 100) },
              $(go.Shape, "LineH"),
              $(go.Shape, "LineV")
            ),
            "draggingTool.isGridSnapEnabled": true,
            "draggingTool.gridSnapCellSpot": go.Spot.Center,
            "undoManager.isEnabled": true
          });

      myDiagram.nodeTemplate =
        $(go.Node, "Spot",
          { locationSpot: go.Spot.Center, locationObjectName: "SHAPE" },
          new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
          $(go.Shape, "Circle",
            { name: "SHAPE", width: 30, height: 30, fill: "white", stroke: "gray", strokeWidth: 2 },
            new go.Binding("stroke", "color")),
          $(go.TextBlock,
            { alignment: go.Spot.Left, alignmentFocus: go.Spot.Right },
            new go.Binding("text"))
        );

      // initialize Palette
      myPalette =
        $(go.Palette, "myPaletteDiv",
          {
            nodeTemplateMap: myDiagram.nodeTemplateMap,
            model: new go.GraphLinksModel([
              { text: "R", color: "red" },
              { text: "G", color: "green" },
              { text: "B", color: "blue" },
              { text: "O", color: "orange" }
            ])
          });

      // 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: 100px; background-color: floralwhite; border: solid 1px black"></div>
      <div id="myOverviewDiv" style="margin: 2px 0 0 0; width: 100px; height: 100px; background-color: whitesmoke; 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">
  </textarea>
</body>
</html>
1 Like

yes thanks for the response you are correct but problem is here I am using html Palette and when I am dropping the node first time it is not working but after dropped when I will move the node it is working fine.

You will need to customize your HTML drag-and-drop code to get that behavior which is built into our Diagram-to-Diagram dragging implementation, which does not use HTML drag-and-drop.

This could be useful:
https://gojs.net/latest/api/symbols/Point.html#snapToGrid

Your code doesn’t seem to address your problem of implementing the HTML drag-and-drop.

Hi,
private onDrop(event) {

    if (event.hasOwnProperty('signal')) {

        const stateData = this.editor.assignSignal(event.droppedLocation)

    } else {

        let droppedCategory = event.dataTransfer.getData('id');

        this.editor.createNode(droppedCategory, event.droppedLocation);

    }

}

using event I am getting event.drppedLocation
and added to the model
public createNode(shape, droppedLocation) {

    let SLDShape = new SLDNode(shape);

    //console.log(SLDShape);

    SLDShape.location = go.Point.stringify(droppedLocation);

    SLDShape.signalAssigned = false;

    let sld = SLDShape;
    this.diagram.model.addNodeData(sld)

}

I doubt while dropping the node I am not getting exact location that’s what node is not coming in the center is there any while drop the node it will fit in the grid cell center.

is there any first time while I will drag the node I will git the nearest cell size location and assign to the node same location.

Have you converted the drop point into document coordinates in the same manner that the HTML Drag Drop sample does? Have you debugged it to make sure the values are correct? Do you then snap that point to the center of each grid cell?

have a look my below code ondrop I am calling this function and passing drop location this.properties.onDrop(event);
div1.addEventListener(“drop”, (event) => {

        event.preventDefault();

        console.log(event.dataTransfer);

        let draggedId = event.dataTransfer.getData('id');

        let signals = event.dataTransfer.getData('signal-data');

        let dragged = JSON.parse(event.dataTransfer.getData('dragged-data'));

        console.log(signals);

        var can = event.target;

        var pixelratio = this.diagram.computePixelRatio();

        // if the target is not the canvas, we may have trouble, so just quit:

        if (!(can instanceof HTMLCanvasElement)) return;

        var bbox = can.getBoundingClientRect();

        var bbw = bbox.width;

        if (bbw === 0) bbw = 0.001;

        var bbh = bbox.height;

        if (bbh === 0) bbh = 0.001;

        var mx = event.clientX - bbox.left * ((can.width / pixelratio) / bbw) - dragged['offsetX'];

        var my = event.clientY - bbox.top * ((can.height / pixelratio) / bbh) - dragged['offsetY'];

        var point = this.diagram.transformViewToDoc(new go.Point(mx, my));

        this.diagram.startTransaction('new node');

        this.dropLocation = point;

        event['droppedLocation'] = point;

        if (signals != "undefined") {

            event['signal'] = JSON.parse(signals);

        }

        if (this.properties.onDrop) {

            this.properties.onDrop(event);    

        }

        console.log(this.diagram.model.nodeDataArray);

        this.automaticConnection();

        this.diagram.commitTransaction('new node');

        // remove dragged element from its old location

    }, false);

And when you debug that code, is the dropLocation sensible?
You’ll want to call Point.snapToGrid.
If your Node.locationSpot is go.Spot.Center, you’ll want to add half the grid cell width and half the grid cell height.

the drop location is sensible I am getting look like this {G: -88.58305415968732, H: -141.5, s: false}

the grid cell height and width i have given 55 and 55 and Yes I have given locationspot center.
where I need to call Point.snapTogrid function
is it inside ondrop function the above I have showed you . and where I have to add
add half the grid cell with and half the grid cell height.

public registerDefaultTemplate(nodeDTOList) {
const goInstance = go.GraphObject.make;
this.node = goInstance(go.Node, “Auto”,
{
rotatable: true, rotateObjectName: “FIGURE”,
locationSpot: go.Spot.Center, selectable: true, width: 55, height: 55,
},

OK, if you have the correct point in document coordinates for the center of a grid cell, then you can either set Node.location directly on the Node that was created for you for the particular data object that you added to the model, or you can set the data property and allow binding to determine the node location.

my mistake actually the point I am getting it is not center of grid cell size
CellSize = new go.Size(55, 55);
let suppose while drag the node I am getting this location point
{G: -88.58305415968732, H: -141.5, s: false}

so after that how can align node in the center of every grid cell size automatically when I drag n number of node and If will fix the location then every node will drop same location
please explain some line of code will appreciate

    const p = myDiagram.transformViewToDoc(...);
    myDiagram.commit(diag => {
      const org = diag.grid.gridOrigin;
      const sz = diag.grid.gridCellSize;
      p.snapToGrid(org.x + sz.width/2, org.y + sz.height/2, sz.width, sz.height);
      diag.model.addNodeData({ loc: go.Point.stringify(p) })
    });

This assumes the node is something like:

    myDiagram.nodeTemplate =
      $(go.Node, . . .,
        { locationSpot: go.Spot.Center },
        new go.Binding("location", "loc", go.Point.parse),
        . . .

Node.location is always in document coordinates, so you do not need to call transformViewToDoc.

It isn’t clear to me that you are adding a geometry node and a label node, both within a group.

Thanks Walter,

I do not understand why you are implementing the node that you show using three separate nodes: a Group and two simple Nodes. Do you expect to have multiple independently selectable instances of geometry nodes and multiple instances of label nodes within a group? Did you want users to be able to move them, copy them, delete them independently of each other within a group? And maybe move them to other groups? If so, then I suppose using separate Nodes within a Group does make sense. But if not, there are other ways to handle multiple items within a data object: GoJS Item Arrays-- Northwoods Software

If you formatted your code, it would be much more readable. Surround your code with lines consisting of only triple backquotes.

Why does your label template have a geometryString data property? And showGeo property? You need to make sure there is a 1-to-1 mapping of Bindings that use a data property and properties on the data, other than standard ones named by model properties such as Model.nodeKeyProperty.

You need to be setting the loc property on the shape node data object. You don’t want to align the text node, do you? But you do need to assign a location to the text which presumably should not be the same as the shape node’s location.

Have you set Group.layout in your group template? You probably should not be doing so.