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

Highcharts手绘线条实现:如何扩展或借助第三方库达成手绘效果?

如何给Highcharts添加手绘效果?

刚好研究过类似的需求!给你两种可行的思路:一种是直接扩展Highcharts的原生能力,另一种是借助第三方手绘库实现,下面详细拆解:

一、原生扩展:修改绘图路径+SVG滤镜

Highcharts底层基于SVG渲染,我们可以通过重写它的绘图方法,给图形添加随机偏移,再配合SVG滤镜增强手绘质感。

1. 给折线/曲线添加不规则偏移

重写折线系列的drawGraph方法,在生成路径时给每个坐标点加上小范围的随机值,模拟手绘的抖动感:

// 重写折线的绘图方法
Highcharts.seriesTypes.line.prototype.drawGraph = function() {
    // 获取原始路径
    const originalPath = this.getGraphPath();
    // 对路径的每个线段添加随机偏移
    const handDrawnPath = originalPath.map(segment => {
        // 只处理移动(M)和直线(L)指令
        if (segment[0] === 'M' || segment[0] === 'L') {
            return [
                segment[0],
                // X方向随机偏移±2像素
                segment[1] + (Math.random() - 0.5) * 4,
                // Y方向随机偏移±3像素
                segment[2] + (Math.random() - 0.5) * 6
            ];
        }
        return segment;
    });
    // 应用修改后的路径
    this.graph.attr({ d: handDrawnPath });
};

2. 让柱形/条形图边缘不规整

类似地,重写柱形系列的drawPoints方法,调整柱形的四个顶点坐标,让边缘呈现手绘的粗糙感:

// 重写柱形的绘图方法
Highcharts.seriesTypes.column.prototype.drawPoints = function() {
    this.points.forEach(point => {
        const { x, y, width, height } = point.shapeArgs;
        // 给四个顶点添加随机偏移
        const x1 = x + (Math.random() - 0.5) * 3;
        const x2 = x + width + (Math.random() - 0.5) * 3;
        const yTop1 = y + (Math.random() - 0.5) * 5;
        const yTop2 = y + (Math.random() - 0.5) * 5;
        const yBottom = y + height;

        // 重新构建柱形的SVG路径
        const handDrawnPath = [
            ['M', x1, yBottom],
            ['L', x1, yTop1],
            ['L', x2, yTop2],
            ['L', x2, yBottom],
            ['Z']
        ];
        point.graphic.attr({ d: handDrawnPath });
    });
};

3. 添加SVG滤镜增强质感

配合一个「噪点位移」滤镜,让整个图表看起来更像手绘在粗糙纸张上的效果:
首先在页面中添加一个隐藏的SVG定义滤镜:

<svg width="0" height="0" style="position: absolute; visibility: hidden;">
    <filter id="handDrawFilter">
        <!-- 生成分形噪点 -->
        <feTurbulence type="fractalNoise" baseFrequency="0.01" numOctaves="2" result="noise"/>
        <!-- 用噪点位移原图 -->
        <feDisplacementMap in="SourceGraphic" in2="noise" scale="3"/>
    </filter>
</svg>

然后把滤镜应用到Highcharts容器:

.highcharts-container {
    filter: url(#handDrawFilter);
}

二、第三方库方案:借助rough.js快速实现

如果不想自己折腾路径修改,可以用专门做手绘风格SVG的rough.js,思路是让Highcharts先生成基础图表,再用rough.js重新绘制关键图形元素。

实现步骤:

  1. 先初始化Highcharts图表,然后监听render或redraw事件;
  2. 获取图表中的SVG元素(比如折线、柱形的路径);
  3. 用rough.js重新绘制这些路径,并隐藏原有的图形:
// 初始化图表
const chart = Highcharts.chart('container', {
    // 你的图表配置项
    series: [{
        type: 'line',
        data: [12, 34, 23, 56, 45]
    }]
});

// 监听渲染完成事件
chart.on('render', function() {
    const svgEl = chart.container.querySelector('svg');
    // 创建rough.js的SVG绘制实例
    const roughCanvas = rough.svg(svgEl);
    
    // 处理折线:获取原始路径,用rough.js重绘
    const lineGraph = this.series[0].graph;
    const originalPath = lineGraph.attr('d');
    // 绘制手绘风格的折线, roughness控制粗糙程度
    roughCanvas.draw(originalPath, { roughness: 1.5, strokeWidth: 2 });
    // 隐藏原折线
    lineGraph.hide();

    // 处理柱形(如果有)
    this.series.forEach(series => {
        if (series.type === 'column') {
            series.points.forEach(point => {
                const originalPath = point.graphic.attr('d');
                roughCanvas.draw(originalPath, { roughness: 1.2, fill: '#2f7ed8', fillStyle: 'hachure' });
                point.graphic.hide();
            });
        }
    });
});

注意事项:

  • 如果图表有交互(比如缩放、tooltip),需要在redraw事件里也执行重绘逻辑;
  • 调整roughness参数可以控制手绘的粗糙程度,数值越大越不规则;
  • 数据量很大时,rough.js的重绘可能会有性能损耗,建议只在小数据量场景使用。

内容的提问来源于stack exchange,提问作者alpinist

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:34:17