Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

312
Visualizações
No se puede actualizar la posición de los nodos usando d3 force y Svelte

Estoy tratando de crear una red simple usando D3 force y Svelte.

La posición de la red debe depender de las dimensiones del contenedor calculadas mediante bind:clientWidth y bind:clientHeight . Quiero decir que si el contenedor de la red tiene ancho = 200, alto = 300, entonces el centro de la red debe ser x = 100, y = 150.

El código que crea el gráfico es este:

 export let width; export let height; let svg; let simulation; let zoomTransform = zoomIdentity; let links = $network.links.map(d => cloneDeep(d)); let nodes = $network.nodes.map(d => cloneDeep(d)); simulation = forceSimulation(nodes) .force( "link", forceLink( links.map(l => { return { ...l, source: nodes.find(n => n.id === l.source), target: nodes.find(n => n.id === l.source) }; }) ) ) .force( "collision", forceCollide() .strength(0.2) .radius(120) .iterations(1) ) .force("charge", forceManyBody().strength(0)) .force("center", forceCenter(width / 2, height / 2)) .on("tick", simulationUpdate); // .stop() // .tick(100) function simulationUpdate() { simulation.tick(); nodes = nodes.map(n => cloneDeep(n)); links = links.map(l => cloneDeep(l)); } $: { simulation .force("center") .x(width / 2) .y(height / 2); } </script> <svg bind:this={svg} viewBox={`${0} ${0} ${width} ${height}`} {width} {height}> {#if simulation} <g> {#each links as link} <Link {link} {nodes} /> {/each} </g> {:else} null {/if} {#if simulation} <g> {#each nodes as node} <Node {node} x={node.x} y={node.y} /> {/each} </g> {:else} null {/if} </svg>

Es muy simple: el width y la height son accesorios. Creó algunas tiendas locales y las actualizó con nuevos datos. Dado que el width y la height son dinámicos, forceCenter la fuerza del centro de fuerza en un bloque reactivo.

Luego, para dibujar los nodos, uso un componente Node con prop nodes , x , y . Sé que puedo usar solo nodes o solo x,y pero fue una prueba. El problema es que la posición de los nodos nunca cambia, incluso si cambian el width y la height .

Entonces, si cambia el tamaño de la ventana, el gráfico no se vuelve a calcular, pero debería hacerlo. ¿Por qué?

AQUÍ un ejemplo de trabajo completo

¡Gracias!

about 4 years ago · Juan Pablo Isaza
1 Respostas
Responde à pergunta

0

Uno de los problemas es que reemplaza las referencias de nodes / links . Esto implica que la simulación ocurre en objetos a los que ya no tienes ninguna referencia, mientras renderizas un conjunto diferente de objetos, que después del primer tic nunca volverá a cambiar.

Un enfoque sería agregar objetos separados que se usan para actualizar el DOM generado por Svelte.

p.ej

 let links = $network.links.map(d => cloneDeep(d)); let nodes = $network.nodes.map(d => cloneDeep(d)); // Initial render state let render = { links, nodes, } // ... function simulationUpdate() { // (No need to call tick, a tick has already happened here) render = { nodes: nodes.map(d => cloneDeep(d)), links: links.map(d => cloneDeep(d)), }; }

Ajuste each de los bucles. También debe hacer que los enlaces tengan clave de bucle, o ajustar el código del componente de Link para hacer que sourceNode / targetNode reactivo en lugar de const :

 {#each render.links as link (link)} ... {#each render.nodes as node}

(Usar el link en sí mismo como clave provoca una nueva representación de todos los elementos porque los enlaces se clonan, por lo que ninguno de los objetos es idéntico).

Además, es posible que deba llamar al restart cuando cambie el centro para asegurarse de que se aplique correctamente:

 $: { simulation .force("center") .x(width / 2) .y(height / 2); simulation.restart(); }

Como alternativa a tener objetos separados para renderizar, puede usar la {#key} para hacer que el DOM se vuelva a renderizar (para gráficos grandes, esto puede tener un impacto negativo). Solo necesita alguna variable para cambiar y usar eso como disparador:

 let renderKey = false; // ... function simulationUpdate() { renderKey = !renderKey; }
 {#if simulation} {#key renderKey} <g> {#each links as link} <Link {link} {nodes} /> {/each} </g> <g> {#each nodes as node} <Node {node} x={node.x} y={node.y} /> {/each} </g> {/key} {/if}
about 4 years ago · Juan Pablo Isaza Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda