Обновление гистограммы нажатием кнопки - PullRequest
1 голос
/ 01 октября 2019

Я новичок в D3-v5 и пытаюсь создать гистограмму с кнопкой обновления (случайные значения). Я создал все вещи, как показано ниже:

  <body>
    <button onclick="updateData()">Update</button>
    <!-- Bar Chart for SVG-->
    <svg width ="500" height="500" id="svg2">
    </svg>
<script src="https://d3js.org/d3.v5.min.js"></script>

<script>
  //Bar Chart
  //Creating data
  let data2 = [
      {name: 'A', value: Math.floor(Math.random() * 100)},
      {name: 'B', value: Math.floor(Math.random() * 100)},
      {name: 'C', value: Math.floor(Math.random() * 100)},
      {name: 'D', value: Math.floor(Math.random() * 100)},
      {name: 'E', value: Math.floor(Math.random() * 100)},
      {name: 'F', value: Math.floor(Math.random() * 100)},
      {name: 'G', value: Math.floor(Math.random() * 100)},
      {name: 'H', value: Math.floor(Math.random() * 100)},
      {name: 'I', value: Math.floor(Math.random() * 100)},
      {name: 'J', value: Math.floor(Math.random() * 100)}
  ]
  //Creating svg, margin, width, height
  let svg2 = d3.select("#svg2")
  let margin = 30;
  let width = 500 - 2 * margin;
  let height = 500 - 2 * margin;

  //Creating chart by using g in svg2.
  let chart2 = svg2.append('g')
      .attr('transform', 'translate(30, 30)');
  //yScale
  let yScale2 = d3.scaleLinear()
      .range([height, 0])
      .domain([0, 100]);

  //append g to create y axis
  chart2.append('g')
       .call(d3.axisLeft(yScale2));

  //xScale
  let xScale2 = d3.scaleBand()
      .range([0, width])
      .domain(data2.map((d) => d.name))
      .padding(0.2);

  //append g to create x axis
  chart2.append('g')
      .attr('transform', 'translate(0, 440)')
      .call(d3.axisBottom(xScale2));

  //Creating color scale using scaleOrdinal and schemeCategory10
  let colorScale = d3.scaleOrdinal(d3.schemeCategory10)

  //Selecting all in chart2 to set/append rectangular, and axis.
  chart2.selectAll()
      .data(data2)
      .enter()
      .append('rect')
      .attr('x', (d) => xScale2(d.name))
      .attr('y', (d) => yScale2(d.value))
      .attr('height', (d) => height - yScale2(d.value))
      .attr('width', xScale2.bandwidth())

  //Putting colors on the bar
  chart2.selectAll('rect')
      .style('fill', d => colorScale(d.name));

  function updateData(){
    let data2 = [
        {name: 'A', value: Math.floor(Math.random() * 100)},
        {name: 'B', value: Math.floor(Math.random() * 100)},
        {name: 'C', value: Math.floor(Math.random() * 100)},
        {name: 'D', value: Math.floor(Math.random() * 100)},
        {name: 'E', value: Math.floor(Math.random() * 100)},
        {name: 'F', value: Math.floor(Math.random() * 100)},
        {name: 'G', value: Math.floor(Math.random() * 100)},
        {name: 'H', value: Math.floor(Math.random() * 100)},
        {name: 'I', value: Math.floor(Math.random() * 100)},
        {name: 'J', value: Math.floor(Math.random() * 100)}
    ]
    let u2 = chart2.selectAll()
        .data(data2)
    u2
      .enter()
      .append('rect')
      .merge(u2)
      .transition()
      .duration(1000)
        .attr('x', (d) => xScale2(d.name))
        .attr('y', (d) => yScale2(d.value))
        .attr('height', (d) => height - yScale2(d.value))
        .attr('width', xScale2.bandwidth())

    chart2.selectAll('rect')
        .style('fill', d => colorScale(d.name));

  }

</script>

Однако, когда я нажимаю кнопку обновления в HTML, происходит переход и наложение диаграммы, как показано на рисунке ниже, transitioning overlapping.

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

Какие вещи мне нужно отредактировать или добавить ..?

Может кто-нибудь мне помочьздесь ??

Спасибо! :)

1 Ответ

1 голос
/ 01 октября 2019

Это ...

let u2 = chart2.selectAll()

... - это то же самое, что и ...

let u2 = chart2.selectAll(null)

... что является лучшим способом гарантировать ваш выбор ввода всегда имеет все элементов в массиве данных. Вы можете прочитать об этом здесь: Выбор нуля: что является причиной выбора 'selectAll (null)' в D3.js?

Очевидно, это не то, что вы хотите. Итак, простое исправление:

let u2 = chart2.selectAll("rect")

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

Вот ваш код с этим изменением:

<body>
  <button onclick="updateData()">Update</button>
  <!-- Bar Chart for SVG-->
  <svg width="500" height="500" id="svg2">
    </svg>
  <script src="https://d3js.org/d3.v5.min.js"></script>

  <script>
    //Bar Chart
    //Creating data
    let data2 = [{
        name: 'A',
        value: Math.floor(Math.random() * 100)
      },
      {
        name: 'B',
        value: Math.floor(Math.random() * 100)
      },
      {
        name: 'C',
        value: Math.floor(Math.random() * 100)
      },
      {
        name: 'D',
        value: Math.floor(Math.random() * 100)
      },
      {
        name: 'E',
        value: Math.floor(Math.random() * 100)
      },
      {
        name: 'F',
        value: Math.floor(Math.random() * 100)
      },
      {
        name: 'G',
        value: Math.floor(Math.random() * 100)
      },
      {
        name: 'H',
        value: Math.floor(Math.random() * 100)
      },
      {
        name: 'I',
        value: Math.floor(Math.random() * 100)
      },
      {
        name: 'J',
        value: Math.floor(Math.random() * 100)
      }
    ]
    //Creating svg, margin, width, height
    let svg2 = d3.select("#svg2")
    let margin = 30;
    let width = 500 - 2 * margin;
    let height = 500 - 2 * margin;

    //Creating chart by using g in svg2.
    let chart2 = svg2.append('g')
      .attr('transform', 'translate(30, 30)');
    //yScale
    let yScale2 = d3.scaleLinear()
      .range([height, 0])
      .domain([0, 100]);

    //append g to create y axis
    chart2.append('g')
      .call(d3.axisLeft(yScale2));

    //xScale
    let xScale2 = d3.scaleBand()
      .range([0, width])
      .domain(data2.map((d) => d.name))
      .padding(0.2);

    //append g to create x axis
    chart2.append('g')
      .attr('transform', 'translate(0, 440)')
      .call(d3.axisBottom(xScale2));

    //Creating color scale using scaleOrdinal and schemeCategory10
    let colorScale = d3.scaleOrdinal(d3.schemeCategory10)

    //Selecting all in chart2 to set/append rectangular, and axis.
    chart2.selectAll()
      .data(data2)
      .enter()
      .append('rect')
      .attr('x', (d) => xScale2(d.name))
      .attr('y', (d) => yScale2(d.value))
      .attr('height', (d) => height - yScale2(d.value))
      .attr('width', xScale2.bandwidth())

    //Putting colors on the bar
    chart2.selectAll('rect')
      .style('fill', d => colorScale(d.name));

    function updateData() {
      let data2 = [{
          name: 'A',
          value: Math.floor(Math.random() * 100)
        },
        {
          name: 'B',
          value: Math.floor(Math.random() * 100)
        },
        {
          name: 'C',
          value: Math.floor(Math.random() * 100)
        },
        {
          name: 'D',
          value: Math.floor(Math.random() * 100)
        },
        {
          name: 'E',
          value: Math.floor(Math.random() * 100)
        },
        {
          name: 'F',
          value: Math.floor(Math.random() * 100)
        },
        {
          name: 'G',
          value: Math.floor(Math.random() * 100)
        },
        {
          name: 'H',
          value: Math.floor(Math.random() * 100)
        },
        {
          name: 'I',
          value: Math.floor(Math.random() * 100)
        },
        {
          name: 'J',
          value: Math.floor(Math.random() * 100)
        }
      ]
      let u2 = chart2.selectAll("rect")
        .data(data2)
      u2
        .enter()
        .append('rect')
        .merge(u2)
        .transition()
        .duration(1000)
        .attr('x', (d) => xScale2(d.name))
        .attr('y', (d) => yScale2(d.value))
        .attr('height', (d) => height - yScale2(d.value))
        .attr('width', xScale2.bandwidth())

      chart2.selectAll('rect')
        .style('fill', d => colorScale(d.name));

    }
  </script>
...