Узлы обновления направленного графа новыми данными

Я боролся с этой проблемой уже несколько дней и не могу найти решение для правильного обновления узлов.

Поскольку я использую Threejs для визуализации графика, я не смог найти в Интернете достаточно информации о том, как правильно этого добиться.

При первоначальном рендеринге все работает как положено. Проблема в том, что я добавляю новые узлы с помощью функции update.

Вновь добавленные узлы отсоединены от своих родителей, а созданным связям кажется, что им не хватает координат и сил.

В примере ниже я добавляю новый узел с помощью id: test.

Это то, что я пробовал до сих пор:

  let root = d3
    .stratify()
    .id((d) => d.id)
    .parentId((d) => d.linkedTo)(data)

  let nodes = root.descendants()
  let links = root.links()

  simulation = d3
    .forceSimulation(nodes)
    .force('charge', d3.forceManyBody().strength(-1000))
    .force('center', d3.forceCenter(0, 0))
    .force('collide', d3.forceCollide().radius(50).strength(0.9))
    .on('tick', ticked)

  simulation.force(
    'link',
    d3
      .forceLink(links)
      .id((d) => {
        return d.data._id
      })
      .distance(10)
      .strength(0.9)
  )

  // Render nodes and links three scene 
  links.forEach(renderLink)
  nodes.forEach(renderNode)

  function update(newData, oldData) {
    simulation.stop()

    const newRoot = d3
      .stratify()
      .id((d) => d.id)
      .parentId((d) => d.linkedTo)(newData)

    const newNodes = newRoot.descendants()
    const newLinks = newRoot.links()

    // Find nodes to remove and remove them
    const nodesToRemove = nodes.filter((node) => !newNodes.some((newNode) => newNode.id === node.id))

    // remove nodes from the three scene
    removeNodes(nodesToRemove)

    // Find links to remove and remove them
    const linksToRemove = links.filter(
      (link) =>
        !newLinks.some(
          (newLink) => newLink.source.id === link.source.id && newLink.target.id === link.target.id
        )
    )

    // remove links from the three scene
    removeLinks(linksToRemove)

    // Find new nodes
    const nodesToAdd = newNodes.filter((newNode) => !nodes.some((node) => node.id === newNode.id))

    nodes = [...nodes, ...nodesToAdd]

    // Find links to add and add them
    const linksToAdd = newLinks.filter(
      (newLink) =>
        !links.some((link) => {
          const sourceMathces = link.source.id === newLink.source.id
          const targetMathces = link.target.id === newLink.target.id

          return sourceMathces && targetMathces
        })
    )

    links = [...links, ...linksToAdd]

    simulation.nodes(nodes).force('link').links(links)
    simulation.alpha(0.5).restart()
  }

Спасибо!

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
0
58
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Исправление в основном связано с тем, как были добавлены новые ссылки, и с тем фактом, что каждая новая ссылка не была правильно создана с их новыми источниками и целями.

async function update(newData, oldData) => {
    // Create a map of existing nodes by their id
    const existingNodesMap = new Map(nodes.map((node) => [node.id, node]))
    // Create new root, nodes, and links
    const newRoot = d3
      .stratify()
      .id((d) => d.id)
      .parentId((d) => d.linkedTo)(newData)

    const newNodes = newRoot.descendants()
    const newLinks = newRoot.links()

    await Promise.all(
      newNodes.slice().map((newNode) => {
        if (!existingNodesMap.has(newNode.id)) {
          nodes.push(newNode)
          existingNodesMap.set(newNode.id, newNode)

          return renderNode(newNode) // Render new node
        }
      })
    )

    // Create a map of existing links by their source and target ids
    const existingLinksSet = new Set(links.map((link) => `${link.source.id}-${link.target.id}`))

    // Update the links array, avoiding duplicates and adding valid links
    await Promise.all(
      newLinks.slice().map((newLink) => {
        const source = existingNodesMap.get(newLink.source.id)
        const target = existingNodesMap.get(newLink.target.id)
        const linkId = `${newLink.source.id}-${newLink.target.id}`

        if (source && target && !existingLinksSet.has(linkId)) {
          newLink.source = source
          newLink.target = target
          links.push(newLink)
          existingLinksSet.add(linkId)

          return renderLink(newLink) // Render new link
        }
      })
    )

    // Restart the simulation with the updated nodes and links
    simulation.nodes(nodes)
    simulation.force('link').links(links)
    simulation.alpha(0.2).restart()
  }

Другие вопросы по теме