D3js не удаляет элемент при выходе

#d3.js

#d3.js

Вопрос:

У меня есть функция, которая отображает текстовый элемент с помощью tspan. Моя проблема в том, что функция draw() добавляет новый текстовый элемент, а не удаляет старый при перерисовке.

 function draw(params) {
    let g = d3.select(`#msr_${Id}`);

    const value = params.Value;

    const [a, b, c, d, x, y] = params.Matrix;
    const matrix = [a, b, c, d, x   params.Coord[0], y   params.Coord[1]];

    let text = g
      .append("text")
      .attr("font-weight", params.Font.Weight)
      .attr("font-size", params.Font.Size)
      .attr("font-family", params.Font.Family)
      .attr("text-decoration", params.Font.Decoration)
      .attr("transform", `matrix(${matrix})`)
      .selectAll("text");

    let desc = text.select("tspan").data([params.MsrName]);
    desc
      .enter()
      .append("tspan")
      .text((d) => d);

    let textValue = text.select("tspan").data([value]);
    textValue
      .enter()
      .append("tspan")
      .text((d) => d);

    g.exit().remove();
  }
 

Комментарии:

1. Вы надеетесь выйти из tspans или удалить / заменить / обновить предыдущий родительский текстовый элемент? Если первое, то создание нового родительского text элемента при каждом цикле рисования означает, что все будет введено и ничего не выйдет (поскольку родительский элемент является новым и не имеет дочерних элементов для выхода).

2. Я бы хотел обновить / заменить tspan. Я пытался добавить text.exit().remove() или desc.exit().remove(), но ничего не изменилось.

Ответ №1:

Я решаю эту проблему, создавая группу svg вручную.

  <g id={`msr_${Id}`}>
      <text id={`msr_txt_${Id}`}>
        <tspan id={`msr_desc_${Id}`}></tspan>
        <tspan id={`msr_value_${Id}`}></tspan>
      </text>
    </g>
 

Вот код:

 let g = d3.select(`#msr_${Id}`);

    let text = g
      .select(`#msr_txt_${Id}`)
   

    let desc = text.select(`#msr_desc_${Id}`).data([name]);
    desc.text((d) => d);
    desc.exit().remove();
    
    let textValue = text.select(`#msr_value_${Id}`).data([value]);
    textValue.text((d) => d);
    textValue.exit().remove();
    
    g.exit().remove()
 

Ответ №2:

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

 function draw(params) {
    // I am assuming that you have access to the svg

    const value = params.Value;

    const [a, b, c, d, x, y] = params.Matrix;
    const matrix = [a, b, c, d, x   params.Coord[0], y   params.Coord[1]];

    
    // #1. make sure that the container exists
    if (!d3.select(`#msr_${Id}`).node()) {
        d3.select(svg).append('g')
            .attr('id', `#msr_${Id}`)
            .append('text')
            .attr('id', `#msr_desc_${Id}`);
    }    

    // #2 - update the text element
    const text = d3.select(`#msr_desc_${Id}`)
      .attr("font-weight", params.Font.Weight)
      .attr("font-size", params.Font.Size)
      .attr("font-family", params.Font.Family)
      .attr("text-decoration", params.Font.Decoration)
      .attr("transform", `matrix(${matrix})`);

    // #3 - update the tspan elements
    let desc = text.selectAll("tspan")
        .data([[params.MsrName, `msr_desc_${Id}`], [value, `msr_value_${Id}`]]);

    desc
      .enter()
      .append("tspan")
      .merge(desc)
      .attr('id', (d) => d[1])
      .text((d) => d[0]);

    desc.exit().remove();
  }