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

修正D3.js/SVG可平铺图案:实现路径均匀一致填充

问题描述

现有一组不同尺寸的随机路径,需要为它们设置统一、均匀的填充图案。

当前填充效果:
当前填充效果

预期填充效果:
预期填充效果

尝试调整preserveAspectRatio和viewBox属性均未成功,且要求仅使用pattern实现需求(不使用clip-path克隆图案的方案)。

现有代码

JavaScript

const data = { 
    
    poly0: [{"x":107,"y":392.2},{"x":186,"y":361},{"x":257,"y":355.3},{"x":257,"y":333.9},{"x":107,"y":372.4}],
    poly1: [{"x":107,"y":406.5},{"x":257,"y":368},{"x":257,"y":355.3},{"x":186,"y":361},{"x":107,"y":392.2}],
    poly2: [{"x":107,"y":463.8},{"x":107,"y":521},{"x":257,"y":467},{"x":360,"y":527},{"x":488,"y":486},{"x":621,"y":540},{"x":677,"y":486},{"x":677,"y":453},{"x":677,"y":420.1},{"x":621,"y":433.9},{"x":488,"y":370.9},{"x":360,"y":435.5},{"x":257,"y":368},{"x":107,"y":406.5}],
    poly3: [{"x":257,"y":368},{"x":360,"y":435.5},{"x":488,"y":370.9},{"x":488,"y":338.5},{"x":360,"y":363.5},{"x":257,"y":333.9}],
    poly4: [{"x":488,"y":354.5},{"x":621,"y":386.3},{"x":677,"y":388.5},{"x":677,"y":362.5},{"x":621,"y":338.5},{"x":488,"y":338.5}],
    poly5: [{"x":488,"y":370.9},{"x":621,"y":433.9},{"x":677,"y":420.1},{"x":677,"y":388.5},{"x":621,"y":386.3},{"x":488,"y":354.5}]

};

let svg, g2, EPS = 1E-5, curve = d3.line().curve(d3.curveCatmullRom).x(d_ => { return d_.x; }).y(d_ => { return d_.y; });

svg = d3.select("#scene");

let colors = ["#005f73", "#0a9396", "#94d2bd", "#e9d8a6", "#ee9b00", "#ca6702", "#bb3e03", "#ae2012"];

let paths = svg.selectAll(".path")
.data(Object.keys(data))
.enter()
.append("path")
.attr("id", (d_) => { return `path_${d_}`; })
.attr("class", "path")
.attr("d", (d_) => { return generatePathFromPoints(data[d_], true); })
.attr("stroke", "#000000")
.attr("fill", "url(#star)");

function generatePathFromPoints(points_, closed_){

    let d = `M${points_[0].x} ${points_[0].y}`;

    for(let i = 1; i < points_.length; i++) { d += `L${points_[i].x} ${points_[i].y}`; }

    if(closed_) { d += "Z"; }

    return d;

}

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

<svg id="scene" viewBox="0 0 800 800" preserveAspectRatio="xMinYMin meet">
    <defs>
        <pattern id="star" viewBox="0 0 10 10" width="10%" height="10%" preserveAspectRatio="none">
            <polygon points="0,0 2,5 0,10 5,8 10,10 8,5 10,0 5,2" fill="#000000"/>
        </pattern>
    </defs>
</svg>
解决方案

问题根源在于SVG pattern的默认坐标系统:默认的patternUnits="objectBoundingBox"会让图案以每个路径的边界框为基准缩放重复,导致不同路径内的图案大小、排列不统一。

只需修改pattern的两个关键属性,即可实现全局统一的填充效果:

  1. 将patternUnits设置为userSpaceOnUse,让图案基于SVG全局用户空间坐标系统重复,而非单个路径的边界框;
  2. 把width和height从百分比改为固定像素值(比如20),确保图案的重复间隔固定,不随路径尺寸变化。

修改后的pattern代码:

<pattern id="star" viewBox="0 0 10 10" width="20" height="20" patternUnits="userSpaceOnUse">
    <polygon points="0,0 2,5 0,10 5,8 10,10 8,5 10,0 5,2" fill="#000000"/>
</pattern>

完整修改后的HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

<svg id="scene" viewBox="0 0 800 800" preserveAspectRatio="xMinYMin meet">
    <defs>
        <pattern id="star" viewBox="0 0 10 10" width="20" height="20" patternUnits="userSpaceOnUse">
            <polygon points="0,0 2,5 0,10 5,8 10,10 8,5 10,0 5,2" fill="#000000"/>
        </pattern>
    </defs>
</svg>

这样所有路径的填充图案就会保持统一的大小和均匀的排列,完全符合预期效果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 10:46:17