javascript - 彩色交叉区域

标签 javascript reactjs d3.js frontend

如何将d3.js中两条线之间截取的图形区域设置为蓝色。 我使用 d3.area 表示橙色区域,使用 d3.line 表示线条。有 d3 函数吗?

enter image description here

const svg = select(svgRef.current);
  const { width, height } =
    dimensions || wrapperRef.current.getBoundingClientRect();

  const xScale = scaleLinear()
    .domain([min(data, (d) => d.x), max(data, (d) => d.x)])
    .range([0, width]);

  const yScale = scaleLinear()
    .domain([0, max(data, (d) => d.high)])
    .range([height, 0]);

  const xAxis = axisBottom(xScale);
  svg.append("g").attr("transform", `translate(0, ${height})`).call(xAxis);

  const yAxis = axisLeft(yScale);
  svg.append("g").call(yAxis);

  const areaGenerator = area()
    .defined((d) => true)
    .x((d) => xScale(d.x))
    .y0((d) => yScale(d.low))
    .y1((d) => yScale(d.high))
    .curve(curveMonotoneX);

  const areaData1 = areaGenerator(data);

  svg.append("path")
    .attr("class", "layer")
    .style("fill", "orange")
    .attr("d", areaData1);

  const line = d3.line().x(p => xScale(p.x)).y(p => yScale(p.y));
  svg.append("path").attr("class", "line1").attr("stroke", "black").attr("d", line(points[0]));
  svg.append("path").attr("class", "line2").attr("stroke", "black").attr("d", line(points[1]));

最佳答案

已经解决了! 非常感谢迈赫迪!

现在可以了!

enter image description here

下面是使用 React JS 的完整源代码:

import React, { useEffect, useRef, useState } from "react";
import {
  select,
  axisBottom,
  min,
  max,
  scaleLinear,
  axisLeft,
  area,
  line,
  curveMonotoneX,
} from "d3";
import useResizeObserver from "./useResizeObserver";

const data = [
  { x: 0, low: 100, high: 245 },
  { x: 3, low: 97, high: 244 },
  { x: 5, low: 94, high: 243 },
  { x: 8, low: 92, high: 242 },
  { x: 10, low: 90, high: 240 },
  { x: 13, low: 88, high: 237 },
  { x: 16, low: 85, high: 234 },
  { x: 18, low: 83, high: 232 },
  { x: 20, low: 80, high: 230 },
  { x: 22, low: 79, high: 225 },
  { x: 25, low: 69, high: 220 },
  { x: 28, low: 49, high: 215 },
  { x: 30, low: 0, high: 210 },
  { x: 40, low: 0, high: 120 },
  { x: 49, low: 0, high: 0 },
];

const points = [
  [
    { x: 0, y: 0 },
    { x: 10, y: 70 },
    { x: 20, y: 150 },
    { x: 25, y: 180 },
    { x: 30, y: 245 },
  ],
  [
    { x: 14, y: 0 },
    { x: 27, y: 100 },
    { x: 30, y: 150 },
    { x: 38, y: 245 },
  ],
];

function StackedBarChart() {
  const svgRef = useRef();
  const wrapperRef = useRef();
  const dimensions = useResizeObserver(wrapperRef);
  const [init, setInit] = useState(false);

  useEffect(() => {
    if (data.length && points.length && !init) {
      setInit(true);
      const svg = select(svgRef.current);
      const { width, height } =
        dimensions || wrapperRef.current.getBoundingClientRect();

      const xScale = scaleLinear()
        .domain([min(data, (d) => d.x), max(data, (d) => d.x)])
        .range([0, width]);

      const yScale = scaleLinear()
        .domain([0, max(data, (d) => d.high)])
        .range([height, 0]);

      const xAxis = axisBottom(xScale);
      svg.append("g").attr("transform", `translate(0, ${height})`).call(xAxis);

      const yAxis = axisLeft(yScale);
      svg.append("g").call(yAxis);

      const areaGenerator = area()
        .defined((d) => true)
        .x((d) => xScale(d.x))
        .y0((d) => yScale(d.low))
        .y1((d) => yScale(d.high))
        .curve(curveMonotoneX);

      const areaData1 = areaGenerator(data);

      const lineGenerator = line()
        .x((p) => xScale(p.x))
        .y((p) => yScale(p.y));

      const polygon1 = points.map((point) =>
        point.map((item) => [item.x, item.y])
      );
      const arrPolygons = [...polygon1[0].reverse(), ...polygon1[1]];

      const clip = svg.append("g").append("clipPath").attr("id", "clip");
      clip
        .selectAll("#pol1")
        .data([arrPolygons])
        .enter()
        .append("polygon")
        .attr("id", "pol1")
        .attr("points", (d) => {
          return d.map((i) => [xScale(i[0]), yScale(i[1])]).join(" ");
        });

      const areaChart1 = svg
        .append("path")
        .attr("id", "area1")
        .attr("class", "layer1")
        .style("fill", "orange")
        .attr("d", areaData1);

      const areaChart = svg
        .append("path")
        .attr("id", "area")
        .attr("class", "layer")
        .attr("clip-path", "url(#clip)")
        .style("fill", "blue")
        .attr("d", areaData1);

      svg
        .append("path")
        .attr("class", "line1")
        .attr("d", lineGenerator(points[0]));
      svg
        .append("path")
        .attr("class", "line2")
        .attr("d", lineGenerator(points[1]));
    }
  }, [data, dimensions, init, points]);

  return (
    <>
      <div ref={wrapperRef} style={{ marginBottom: "2rem" }}>
        <svg ref={svgRef} />
      </div>
    </>
  );
}

export default StackedBarChart;

关于javascript - 彩色交叉区域,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61156161/

相关文章:

javascript - 将样式表链接到 ID

javascript - 无法使用 Express.js 和 gridfs-stream 捕获错误

reactjs - ref 值未定义 ReactJs

javascript - 在哪里/如何存储数据集合

javascript - tinyMCE 编辑器版本 3 上传图像选项

javascript - 动态创建 Google map LatLng 类

reactjs - 在 redux 中,为什么我们必须在 reducer 中保持状态不可变?

javascript - D3 .rangeBands() 返回 NaN

animation - 加载时动画 D3 圆环图

javascript - 组的 D3 v4 更新模式