bumbeishvili / org-chart

Highly customizable org chart. Integrations available for Angular, React, Vue
https://stackblitz.com/edit/web-platform-o5t1ha
MIT License
928 stars 330 forks source link

Temporarily remove all unhighlighted nodes #335

Closed RaphCodec closed 7 months ago

RaphCodec commented 12 months ago

Looking at the futuristic example I see that the mark root botton hides all unhiglighted nodes. Is there a way to easily modify this function to temporarily remove all unhighlighed nodes? My goal is to make a straigt line of the people highlighted, whereas that fucntion currently leaves people in their current postition. I kow an important part of the functionality has to do with the code below. Please let me know if any clarification is needed.

    .linkUpdate(function (d, i, arr) {
        const oneH = d3
          .selectAll('.link')
          .filter((d) => d.data._upToTheRootHighlighted)
          .size();
        d3.select(this)
          .attr('stroke', (d) =>
            d.data._upToTheRootHighlighted ? '#E27396' : oneH
              ? 'none'
              : '#000000'
          )
          .attr('stroke-width', (d) =>
            d.data._upToTheRootHighlighted ? 5 : 3
          );

        if (d.data._upToTheRootHighlighted) {
          d3.select(this).raise();
        }
      })
      .nodeUpdate(function (d, i, arr) {
        const oneH = d3
          .selectAll('.link')
          .filter((d) => d.data._upToTheRootHighlighted)
          .size();

        d3.select(this).style('opacity', (d) => {
          if (d.data._upToTheRootHighlighted) return 1;
          if (oneH) return 0;
          return 1;
        });

        d3.select(this)
          .select('.node-rect')
          .attr('stroke', (d) =>
            d.data._highlighted || d.data._upToTheRootHighlighted
              ? '#E27396'
              : 'none'
          )
          .attr(
            'stroke-width',
            d.data._highlighted || d.data._upToTheRootHighlighted ? 15 : 3
          );
      })
bumbeishvili commented 12 months ago

That's not as easy as it sounds

  1. if you want to hide, but they still take the space, then you can just check if it's highlighted, set zero opacity or something, otherwise don't do anything

  2. If you want them to be completelly removed, you have to manipulate the data, pass new data and rerender graph

RaphCodec commented 12 months ago

Ok. I will try that. Thanks for the help, the library is great.

RaphCodec commented 7 months ago

I found a way to do it. I have the fololowing functions that find the children and ancestors in the data and remove them. I tried getNodeChildren but kept running into an error saying "Uncaught TypeError: Cannot read properties of undefined (reading 'push')". Not sure if I was doing something wrong. Anyay the way I did it was using the following.

function findChildren(parent, selected) {
              for (const item of data) {
                if (item.parentId === parent) {
                  selected.push(item.name);
                  findChildren(item.id, selected);
                }
              }
            }

        function findAncestorsLineage(nodeId, selected) {
            for (const item of data) {
                if (item.id === nodeId) {
                    // Found the current node, add its parent to selected
                    const parentId = item.parentId;
                    if (parentId) {
                        selected.push(parentId);
                        // Recursively find ancestors of the parent
                        findAncestorsLineage(parentId, selected);
                    }
                    break; // Stop searching once we reach the root node (parent ID is null or undefined)
                }
            }
        }

        function findChildrenLineage(parentId, selected) {
            for (const item of data) {
                if (item.parentId === parentId) {
                    // Found a child node, add its ID to selected
                    selected.push(item.id);
                    // Recursively find children of the current child
                    findChildrenLineage(item.id, selected);
                }
            }
        }

        //Removes all currenlty selected nodes
        function removeNodes() {
          currentlySelected = [...new Set(currentlySelected)]
            for ( id in currentlySelected) {
              chart.removeNode(currentlySelected[id])
            }

            to_pop = [];

            for (const id of currentlySelected) {
              to_pop.push(data.filter(item => item.id === id)[0].name)
              findChildren(id, to_pop)
            }

            for (person in to_pop) {
              names.pop(person)
            }

            to_pop = []
            currentlySelected = []
        }

function showLineage() {
            currentlySelected = [...new Set(currentlySelected)]; //making sure all values in array are unique
            // Check if the array is empty or has more than one element
            if (currentlySelected.length === 0 || currentlySelected.length > 1) {
                // Display an alert if the array is empty or has more than one element
                alert("Please select one person. There may only be one person selected at a time.");
            } else {
                to_keep = []

                for (const id of currentlySelected) {
                    to_keep.push(data.filter(item => item.id === id)[0].id)
                    findChildrenLineage(id, to_keep)
                    }
                for (const id of currentlySelected) {
                    to_keep.push(data.filter(item => item.id === id)[0].id)
                    findAncestorsLineage(id, to_keep)
                    }

                to_keep = [...new Set(to_keep)];

                currentlySelected = data
                    .filter(obj => !to_keep.includes(obj.id)) // Filter out IDs present in to_keep
                    .map(obj => obj.id);

                removeNodes()

                to_keep = []
            }
        }

Those delete all nodes not in the lineage so that the tree looks more clean. I ended up not needing to add nodes back so didn't solve that part. Only issue is that the console logs ids that are not in the tree since their parent is removed but the id is still in the loop. other than that it works as I want it to, in case anyone else wants to do something similiar. Thanks again.