javascriptd3.jsvisualizationdiagram

In a diagram, relations are always deleted from last to first instead of selected


I have a basic diagram in D3.js, containing objects and relations between objects initialized in these arrays :

      let objectsData = [
        { id: 1, x: 150, y: 150, type: "circle", color: "#ff6b6b" },
        { id: 2, x: 300, y: 200, type: "rect", color: "#4ecdc4" },
        { id: 3, x: 500, y: 150, type: "circle", color: "#45b7d1" },
        { id: 4, x: 400, y: 350, type: "rect", color: "#96ceb4" },
        { id: 5, x: 200, y: 400, type: "circle", color: "#feca57" },
      ];

      let relationsData = [
        { source: 1, target: 2 },
        { source: 2, target: 3 },
        { source: 3, target: 4 },
        { source: 4, target: 5 },
      ];

When my updateRelations() method is first called, everything is displayed correctly, but as I click relations to remove them, they are always removed from last to first in the relationsData table, it's never the one that's been clicked that is removed :

const relations = svg.append("g").attr("class", "relations");

  function updateRelations() {

    const relationGroups = relations.selectAll(".relation-group").data(relationsData);

    const enterGroups = relationGroups
    .enter()
    .append("g")
    .attr("class", "relation-group")
    .style("cursor", "pointer")
    .on("click", function (event, d) {
      event.stopPropagation();
      const index = relationsData.indexOf(d);
      if (index > -1) {
        relationsData.splice(index, 1);
        updateRelations();
      }
    });

    // Add visible line
    enterGroups
      .append("line")
      .attr("class", "relation");

    const allGroups = enterGroups.merge(relationGroups);

    allGroups.selectAll(".relation")
    .attr("x1", (d) => getObjectById(d.source).x)
    .attr("y1", (d) => getObjectById(d.source).y)
    .attr("x2", (d) => getObjectById(d.target).x)
    .attr("y2", (d) => getObjectById(d.target).y);

    relationGroups.exit().remove();
  }

  function getObjectById(id) {
    return objectsData.find((obj) => obj.id === id);
  }

At first I thought it was my index variable that was miscalculated (like : it would always be -1), but its value seems correct.


Solution

  • You could use findIndex to match by property.

    //Add unique id
    let relationsData = [
        { id: 'rel1', source: 1, target: 2 },
        { id: 'rel2', source: 2, target: 3 },
        { id: 'rel3', source: 3, target: 4 },
        { id: 'rel4', source: 4, target: 5 },
    ];
    
    
    function updateRelations() {
        //Use key function with id 
        const relationGroups = relations.selectAll(".relation-group").data(relationsData, d => d.id);
    
        {....}
     
       const enterGroups = relationGroups
        .enter()
        .append("g")
        .attr("class", "relation-group")
        .style("cursor", "pointer")
        .on("click", function (event, d) {
          event.stopPropagation();
          //Use findIndex to match
          const index = relationsData.findIndex(rel => rel.id === d.id);
          if (index > -1) {
            relationsData.splice(index, 1);
            updateRelations();
          }
        });
    
        {...}
    }