带有交替标签的简单d3.js折线图

ycl3bljg  于 2023-06-23  发布在  其他
关注(0)|答案(1)|浏览(121)

简单的d3折线图...需要的线跨越整个SVG和标签要锚定到路径线本身。如果有可选的代码添加标记以及加分。先谢谢你。

<html>
    <head>
        <script src="https://d3js.org/d3.v5.min.js"></script>
        <script>
            function createLineChart(data,id) {
            var svg = d3.select("body").append("svg")
            .attr("width", 800)
            .attr("height", 600);

            var line = d3.line()
            .x(function(d, i) { return i * 50 + 50; })
            .y(function(d) { return 300 - d; });

            svg.append("path")
            .datum(data)
            .attr("d", line)
            .attr("stroke", "black")
            .attr("stroke-width", 2)
            .attr("fill", "none");
            
            data.forEach(function(d, i) {
            if (i > 0) {
                var percentChange = (d - data[i - 1]) / data[i - 1] * 100;
                var color = percentChange >= 0 ? "green" : "red";
                var y = percentChange >= 0 ? d - 15 : d + 15;

                svg.append("text")
                .text(percentChange.toFixed(1) + "%")
                .attr("x", i * 50 + 50)
                .attr("y", y)
                .attr("text-anchor", "middle")
                .attr("fill", color);
            }
            });

            }
        </script>

    </head>

    <body>
            
    </body>
    <script>
        var data = [10, 20, 15, 40, 50, 60];
        createLineChart(data);
    </script>
</html>
neskvpey

neskvpey1#

我想你需要了解的主要内容是d3 scalesselections(特别是joins)。特别是:

  • 我们将定义SVG的宽度w和高度h,然后定义比例以适应SVG的路径。
  • 我们将使用这些数据来根据数据定义每个路径、标记和文本。
createLineChart([10, 20, 15, 40, 50, 60], { mark_points: true })

function createLineChart(data, opts = {}) {
  let { w = 800, h = 500, mark_points = false } = opts;
  let pad = 50;
  
  let x_scale = d3
    .scaleLinear()
    .domain([0, data.length - 1])
    .range([pad, w - pad]);
  let [ymin, ymax] = d3.extent(data);
  let y_scale = d3
    .scaleLinear()
    .domain([ymin, ymax])
    .range([h - pad, pad]);
    
  let svg = d3.select('#container')
    .append("svg")
    .attr("width", w)
    .attr("height", h)
    .style("border", "solid 1px black");

  let line = d3
    .line()
    .x(function (d, i) {
      return x_scale(i);
    })
    .y(function (d) {
      return y_scale(d);
    });

  svg
    .append("path")
    .datum(data)
    .attr("d", line)
    .attr("stroke", "black")
    .attr("stroke-width", 2)
    .attr("fill", "none");

  svg
    .selectAll("circle")
    .data(data)
    .join("circle")
    .attr("cx", (_, i) => x_scale(i))
    .attr("cy", (d) => y_scale(d))
    .attr("r", 5)
    .attr("fill", "black");

  if (mark_points) {
    svg
      .selectAll("text")
      .data(data)
      .join("text")
      .attr("x", (_, i) => x_scale(i))
      .attr("y", (d) => y_scale(d))
      .attr("dx", -3)
      .attr("dy", 12)
      .attr("font-size", 16)
      .attr("text-anchor", "end")
      .attr("fill", (_, i) =>
        data[i] < data[i - 1]
          ? "red"
          : data[i] == data[i - 1]
          ? "blue"
          : "green"
      )
      .text(function (_, i) {
        if (i > 0) {
          let change = (data[i] - data[i - 1]) / data[i - 1];
          return d3.format("0.2%")(change);
        } else {
          return "";
        }
      });
  }

  svg
    .append("g")
    .attr("transform", `translate(0, ${h - pad})`)
    .call(d3.axisBottom(x_scale).ticks(data.length));
  svg
    .append("g")
    .attr("transform", `translate(${pad})`)
    .call(d3.axisLeft(y_scale).ticks(5));
}
<script src="https://d3js.org/d3.v7.min.js"></script>
<div id="container"></div>

相关问题