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

168
Visualizações
instant values for d3 enter selection and transitioned for update

I'm trying to avoid repeating code for the enter and update selections in d3. I have successfully used merge to get the right selection of all items that are present with the new data (after I have used append to add the new ones). Now I want to set some attributes such as r, cy and cx. I can do that on the merged selection but if I put them behind a transition the items that are just appearing animate in from 0,0 and I want them to just appear in the right place.

What I'm hoping for is some way to write all the attribute setting lines into one function and one time pass in the enter() selection and the next time pass in the transitioned merge so that I only have to write the lines for setting cx once. Here's what I have already followed by my guess at pseudo code

 const valueCircles = this.chartGroup.selectAll('.valueCircle')
        .data(values);

    valueCircles.enter()
        .append('circle')
        .attr('stroke-width', '1px')
        .attr('stroke', '#ffffff')
        .attr('opacity', '1')
        .attr('class', 'dots valueCircle')
        .merge(valueCircles)
        .transition()
        .duration(100)
        .attr('r', (d) => {
            if (d.y < 0.5 ) {
                return 5;
            } else {
                return 15;
            }
        })
        .attr('cx', (d) => {
            return timescale(new Date(d.x));
        })
        .attr('cy', (d) => {
                return valueScale(d.y)
        })

This is what I think I want to achieve

function setTheDynamicValues(aSelection) {
    aSelection
        .attr('cx', (d) => {
            return timescale(new Date(d.x));
        })
        .attr('cy', (d) => {
                return valueScale(d.y)
        })
}

function updateGraph(newData) {
   const valueCircles = this.chartGroup.selectAll('.valueCircle')
        .data(newData);

   setTheDynamicValues(valueCircles.enter());
   setTheDynamicValues(valueCircles.transition().duration(100));
}

Another way of describing this would be to make the duration of the transition 0 for the entering elements and 100 for existing elements so that new ones appear correct and existing ones have a visible transition.

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

0

First of all, D3 selections are immutable: that merge of yours is not doing anything. This would be the proper pattern:

//here, pay attention to "let" instead of const
let valueCircles = this.chartGroup.selectAll('.valueCircle')
    .data(values);

//our enter selection is called "valuesCirclesEnter"
const valueCirclesEnter = valueCircles.enter()
    .append('circle')
    etc...

//now, you merge the selections
valueCircles = valueCirclesEnter.merge(valueCircles);

From that point on, valueCircles contains both your updating and entering elements.

Now, back to your question:

An idiomatic D3 indeed has a lot of repetition, and that's a point lots of people complain about D3. But we can avoid some repetition with methods like selection.call. Also, since you want a transition for the update selection but none for the enter selection, you can simply drop the merge.

Here is a basic exemple, using a bit of your code:

const data1 = [{
  x: 100,
  y: 100
}, {
  x: 230,
  y: 20
}];
const data2 = [{
  x: 10,
  y: 10
}, {
  x: 50,
  y: 120
}, {
  x: 190,
  y: 100
}, {
  x: 140,
  y: 30
}, {
  x: 270,
  y: 140
}];
const svg = d3.select("svg");
draw(data1);
setTimeout(() => draw(data2), 1000);

function draw(values) {
  const valueCircles = svg.selectAll('.valueCircle')
    .data(values);

  valueCircles.enter()
    .append('circle')
    .attr("class", "valueCircle")
    .attr("r", 10)
    .call(positionCircles);

  valueCircles.transition()
    .duration(1000)
    .call(positionCircles)
};

function positionCircles(selection) {
  selection.attr("cx", d => d.x)
    .attr("cy", d => d.y)
}
<script src="https://d3js.org/d3.v7.min.js"></script>
<svg></svg>

In the snippet above, I'm positioning both the enter and update selections using a function called positionCircles; however, while for the enter selection I'm passing a simple selection, for the update selection I'm passing a transitioning selection. But the function is the same:

function positionCircles(selection) {
  selection.attr("cx", d => d.x)
    .attr("cy", d => d.y)
}
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