You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在React JS中绘制可变描边宽度的平滑样条曲线

在React中实现D3样条曲线的渐变描边宽度

我已经能用D3.js绘制样条曲线,代码如下:

<html>
<head>
    <script src="https://d3js.org/d3.v7.min.js"></script>
    <style>
        .graph-container {
            width: 100%;
            height: 800px;
            position: relative;
        }
    </style>
</head>
<body>
    <div id="graph-container" class="graph-container"></div>
    <script>
        // 定义样条曲线的数据点
        const data = [
            { x: 0, y: 80, r: 12 },
            { x: 100, y: 100, r: 40 },
            { x: 200, y: 30, r: 6 },
            { x: 300, y: 50, r: 8 },
            { x: 400, y: 40, r: 10 },
            { x: 500, y: 80, r: 12 },
        ];

        // 设置SVG容器
        const svgWidth = 600;
        const svgHeight = 200;
        const svg = d3.select('#graph-container')  // 选择graph-container容器
            .append('svg')
            .attr('width', svgWidth)
            .attr('height', svgHeight);

        // 创建样条生成器
        const line = d3.line()
            .x((d) => d.x)
            .y((d) => d.y)
//            .curve(d3.curveMonotoneX);
            .curve(d3.curveCardinal);

        // 绘制样条曲线
        svg.append('path')
            .datum(data)
            .attr('d', line)
            .attr('fill', 'none')
            .attr('stroke', 'green')
            .attr('stroke-width', (d) => d.r);
    </script>
</body>
</html>

样条曲线效果展示

我的需求是让样条曲线的各线段拥有不同的描边宽度,且线段间能平滑过渡至下一个控制点。但发现使用D3的.attr('stroke-width', (d) => d.r)无法实现该效果,请问如何在React JS中完成此需求?


解决方法

SVG的stroke-width是路径全局属性,无法直接为路径片段设置不同宽度并平滑过渡。最可靠的实现方式是用D3 Area生成器模拟可变宽度的曲线,具体实现如下:

React + D3 完整代码

import React, { useEffect, useRef } from 'react';
import * as d3 from 'd3';

const VariableWidthSpline = () => {
  const containerRef = useRef(null);

  useEffect(() => {
    if (!containerRef.current) return;

    // 清空容器内容
    d3.select(containerRef.current).selectAll('*').remove();

    // 定义数据点
    const data = [
      { x: 0, y: 80, r: 12 },
      { x: 100, y: 100, r: 40 },
      { x: 200, y: 30, r: 6 },
      { x: 300, y: 50, r: 8 },
      { x: 400, y: 40, r: 10 },
      { x: 500, y: 80, r: 12 },
    ];

    const svgWidth = 600;
    const svgHeight = 200;

    // 创建SVG容器
    const svg = d3.select(containerRef.current)
      .append('svg')
      .attr('width', svgWidth)
      .attr('height', svgHeight);

    // 转换数据:为每个点计算上下边界(基于r值的一半)
    const areaData = data.map(point => ({
      x: point.x,
      yTop: point.y - point.r / 2,
      yBottom: point.y + point.r / 2,
    }));

    // 创建Area生成器,使用与原曲线一致的样条类型
    const areaGenerator = d3.area()
      .x(d => d.x)
      .y0(d => d.yTop)
      .y1(d => d.yBottom)
      .curve(d3.curveCardinal);

    // 绘制可变宽度的平滑曲线
    svg.append('path')
      .datum(areaData)
      .attr('d', areaGenerator)
      .attr('fill', 'green')
      .attr('stroke', 'none');

  }, []);

  return (
    <div 
      ref={containerRef} 
      style={{ 
        width: '100%', 
        height: '800px', 
        position: 'relative' 
      }} 
    />
  );
};

export default VariableWidthSpline;

实现说明

  1. 数据转换:将每个数据点的r(原描边宽度)拆分为上下边界的偏移量(r/2),得到区域路径的上下轮廓坐标。
  2. Area生成器:使用D3的area()生成器,基于转换后的数据生成与原样条曲线类型一致的平滑闭合区域。
  3. 视觉呈现:填充该区域即可模拟出宽度随数据点平滑变化的曲线,区域边缘会自动实现相邻点间的宽度过渡,完全满足需求。

内容的提问来源于stack exchange,提问作者Chang L.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 02:35:05