Как добавить маркеры в линейную диаграмму d3 с двумя наборами данных - PullRequest
0 голосов
/ 27 мая 2020

Вот мой код JS для построения линейной диаграммы для двух наборов данных, и я использую библиотеку d3 и структуру Vue.

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

Кто-нибудь может сказать мне, как добавить точечные маркеры в координаты диаграммы.

var app = new Vue({
  el: "#app",
  data: () => {
    return {
      data1: [{
          ser1: 0.3,
          ser2: 4
        },
        {
          ser1: 2,
          ser2: 16
        },
        {
          ser1: 3,
          ser2: 8
        }
      ],
      data2: [{
          ser1: 1,
          ser2: 7
        },
        {
          ser1: 4,
          ser2: 1
        },
        {
          ser1: 6,
          ser2: 8
        }
      ],
      margin: {
        top: 10,
        right: 30,
        bottom: 30,
        left: 50
      },
      width: null,
      height: null
    }
  },
  mounted() {
    this.width = 460 - this.margin.left - this.margin.right;
    this.height = 400 - this.margin.top - this.margin.bottom;
    
    this.createSvg();
  },
  methods: {
    createSvg() {
      var svg = d3.select("#my_dataviz")
        .append("svg")
        .attr("width", this.width + this.margin.left + this.margin.right)
        .attr("height", this.height + this.margin.top + this.margin.bottom)
        .attr("fill", "blue")
        .append("g")
        .attr("transform",
          "translate(" + this.margin.left + "," + this.margin.top + ")");

      var x = d3.scaleLinear().range([0, this.width]);
      var xAxis = d3.axisBottom().scale(x);
      svg.append("g")
        .attr("transform", "translate(0," + this.height + ")")
        .attr("class", "myXaxis")

      var y = d3.scaleLinear().range([this.height, 0]);
      var yAxis = d3.axisLeft().scale(y);
      svg.append("g")
        .attr("class", "myYaxis");

      this.update(svg, x, y, xAxis, yAxis, this.data1)
    },
    updateData(data) {
      var svg = d3.select("#my_dataviz");

      var x = d3.scaleLinear().range([0, this.width]);
      var xAxis = d3.axisBottom().scale(x);

      var y = d3.scaleLinear().range([this.height, 0]);
      var yAxis = d3.axisLeft().scale(y);

      this.update(svg, x, y, xAxis, yAxis, data);
    },
    update(svg, x, y, xAxis, yAxis, data) {
      // Create the X axis:
      x.domain([0, d3.max(data, function(d) {
        return d.ser1
      })]);
      svg.selectAll(".myXaxis").transition()
        .duration(3000)
        .call(xAxis);

      // create the Y axis
      y.domain([0, d3.max(data, function(d) {
        return d.ser2
      })]);
      svg.selectAll(".myYaxis")
        .transition()
        .duration(3000)
        .call(yAxis);

      // Create a update selection: bind to the new data
      var u = svg.selectAll(".lineTest")
        .data([data], function(d) {
          return d.ser1
        });

      // Updata the line
      u
        .enter()
        .append("path")
        .attr("class", "lineTest")
        .merge(u)
        .transition()
        .duration(3000)
        .attr("d", d3.line()
          .x(function(d) {
            return x(d.ser1);
          })
          .y(function(d) {
            return y(d.ser2);
          }))
        .attr("fill", "none")
        .attr("stroke", "steelblue")
        .attr("stroke-width", 2.5)
    }
  }
});
<!DOCTYPE html>
<meta charset="utf-8">

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://d3js.org/d3.v4.js"></script>



<div id="app">
  <button @click="updateData(data1)">Dataset 1</button>
  <button @click="updateData(data2)">Dataset 2</button>

  <div id="my_dataviz"></div>
</div>
 

Приведенный выше фрагмент - это код HTML, включающий Vue и библиотеку d3. js.

1 Ответ

1 голос
/ 28 мая 2020

После обучения у D3 я взял код из этого примера и этого примера и изменил его так, чтобы он работал с Vue.

I ' Если вы включили фрагмент ниже, вам не нужно передавать столько переменных с помощью этого кода, и вы можете стилизовать линию и маркеры с помощью css.

new Vue({
  el: "#app",
  data: () => {
    return {
      data1: [{
          ser1: 0.3,
          ser2: 4
        },
        {
          ser1: 2,
          ser2: 16
        },
        {
          ser1: 3,
          ser2: 8
        }
      ],
      data2: [{
          ser1: 1,
          ser2: 7
        },
        {
          ser1: 4,
          ser2: 1
        },
        {
          ser1: 6,
          ser2: 8
        }
      ],
      xAxis: null,
      yAxis: null,
      margin: {
        top: 50,
        right: 50,
        bottom: 50,
        left: 50
      }
    }
  },
  methods: {
    updateData(data) {

      var width = 460 - this.margin.left - this.margin.right;
      var height = 400 - this.margin.top - this.margin.bottom;


      var xScale = d3.scaleLinear()
        .domain([0, Math.max.apply(Math, data.map(x => x.ser1))])
        .range([0, width]);

      var yScale = d3.scaleLinear()
        .domain([0, Math.max.apply(Math, data.map(x => x.ser2))])
        .range([height, 0]);


      // Select the section we want to apply our changes to


      var line = d3.line()
        .x(function(d) {
          return xScale(d.ser1);
        }) // set the x values for the line generator
        .y(function(d) {
          return yScale(d.ser2);
        }) // set the y values for the line generator 

      let svg = d3.select("#graph").transition().duration(750);

      // Make the changes
      svg.select(".line") // change the line
        .duration(750)
        .attr("d", line(data));

      svg.select(".x.axis") // change the x axis
        .duration(750)
        .call(d3.axisBottom(xScale));

      svg.select(".y.axis") // change the y axis
        .duration(750)
        .call(d3.axisLeft(yScale));

      d3.select("svg").selectAll(".dot")
        .data(data)
        .transition()
        .duration(750)
        .attr("cx", function(d) {
          return xScale(d.ser1)
        })
        .attr("cy", function(d) {
          return yScale(d.ser2)
        })

    },
    createSvg(data) {
      var width = 460 - this.margin.left - this.margin.right;
      var height = 400 - this.margin.top - this.margin.bottom;

      var xScale = d3.scaleLinear()
        .domain([0, Math.max.apply(Math, data.map(x => x.ser1))])
        .range([0, width]);

      var yScale = d3.scaleLinear()
        .domain([0, Math.max.apply(Math, data.map(x => x.ser2))])
        .range([height, 0]);

      // 7. d3's line generator
      var line = d3.line()
        .x(function(d) {
          return xScale(d.ser1);
        }) // set the x values for the line generator
        .y(function(d) {
          return yScale(d.ser2);
        }) // set the y values for the line generator 

      // 1. Add the SVG to the page and employ #2
      var svg = d3.select("#graph").append("svg")
        .attr("width", width + this.margin.left + this.margin.right)
        .attr("height", height + this.margin.top + this.margin.bottom)
        .attr("fill", "blue")
        .append("g")
        .attr("transform", "translate(" + this.margin.left + "," + this.margin.top + ")");


      // 3. Call the x axis in a group tag
      this.xAxis = svg.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
        .call(d3.axisBottom(xScale)); // Create an axis component with d3.axisBottom

      this.yAxis = svg.append("g")
        .attr("class", "y axis")
        .call(d3.axisLeft(yScale));

      svg.append("path")
        .datum(data)
        .attr("class", "line")
        .attr("d", line);

      svg.selectAll(".dot")
        .data(data)
        .enter().append("circle")
        .attr("class", "dot")
        .attr("cx", function(d, i) {
          return xScale(d.ser1)
        })
        .attr("cy", function(d) {
          return yScale(d.ser2)
        })
        .attr("r", 5);
    }
  },
  mounted() {
    this.createSvg(this.data1);
  }
});
.line {
  fill: none;
  stroke: steelblue;
  stroke-width: 3;
}

.dot {
  fill: steelblue;
  stroke: #fff;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://d3js.org/d3.v4.min.js"></script>

<div id="app">
  <button type="button" @click="updateData(data1)">Data 1</button>
  <button type="button" @click="updateData(data2)">Data 2</button>
  <div id="graph"></div>
</div>
...