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

如何在D3中实现适配带箭头矩形的散列图案并兼容PPT导出

解决带箭头矩形的散列图案遮罩问题

要解决散列图案超出箭头边界的问题,最直接的方法是利用SVG的裁剪路径(clipPath),将主形状作为裁剪区域,让散列图案仅在该区域内显示,完全适配箭头侧边的轮廓。

实现步骤

  • 创建一个裁剪路径,路径数据与主形状完全一致
  • 将散列图案的路径包裹在应用了该裁剪路径的<g>元素中
  • 确保裁剪路径的ID唯一,避免与其他元素冲突

修改后的完整代码

<!DOCTYPE html>

<!-- Add a svg area, empty -->
<svg id="area" height=500 width=500></svg>

<script>
  function calculateStripyRectD(
    x,
    y,
    width,
    height,
    stripeWidth,
    isPointedLeft,
    isPointedRight,
    pointWidth
  ) {
    const stripes = [];

    for (let yTop = 0; yTop < height + width; yTop += 5 * stripeWidth) {
      const yBottom = yTop + stripeWidth;

      let stripeTopStartX = yTop > height ? x + (yTop - height) : x;
      let stripeTopStartY = yTop > height ? y + height : y + yTop;
      let stripeTopEndX = yTop > width ? x + width : x + yTop;
      let stripeTopEndY = yTop > width ? y + yTop - width : y;

      let stripe2startX = yBottom > height ? x + (yBottom - height) : x;
      let stripe2startY = yBottom > height ? y + height : y + yBottom;
      let stripe2endX = yBottom > width ? x + width : x + yBottom;
      let stripe2endY = yBottom > width ? y + yBottom - width : y;

      stripes.push(`M ${stripeTopStartX}, ${stripeTopStartY} L ${stripeTopEndX}, ${stripeTopEndY}
    L ${stripe2endX}, ${stripe2endY} L ${stripe2startX}, ${stripe2startY}
    L ${stripeTopStartX}, ${stripeTopStartY}
    `);
    }

    return stripes
      .join(' ')
  }

  function rectangleWithOptionalPoints(
    width,
    height,
    isPointedLeft,
    isPointedRight,
    isStriped,
  ) {
    const pointWidth = 20;
    const stripeWidth = 1;

    let leftX = 0;
    let rightX = width;

    if (isPointedLeft) {
      leftX += pointWidth;
    }

    if (isPointedRight) {
      rightX -= pointWidth;
    }

    const mainPath = `
    M ${leftX - (isPointedLeft ? pointWidth : 0)} ${height / 2}
    L ${leftX} 0
    L ${rightX} 0
    L ${rightX + (isPointedRight ? pointWidth : 0)} ${height / 2}
    L ${rightX} ${height}
    L ${leftX} ${height}
    Z
  `;

    const stripes = isStriped ?
      calculateStripyRectD(
        leftX - pointWidth,
        0,
        width,
        height,
        stripeWidth,
        isPointedLeft,
        isPointedRight,
        pointWidth
      ) :
      undefined;

    return {
      main: mainPath,
      stripes,
    };
  }

  const renderBarGroup = () => {
    const barGroup = svg.append('g')
    // 创建裁剪路径
    const clipPath = svg.append('clipPath')
      .attr('id', 'bar-clip')
      .append('path')
      .attr('d', () => {
        const paths = rectangleWithOptionalPoints(
          200,
          25,
          true,
          true,
          true,
        );
        return paths.main;
      });

    // 应用裁剪路径的组,放置条纹
    const stripedGroup = barGroup.append('g')
      .attr('clip-path', 'url(#bar-clip)');

    stripedGroup
      .append('path')
      .attr('d', () => {
        const paths = rectangleWithOptionalPoints(
          200,
          25,
          true,
          true,
          true,
        );
        return paths.stripes;
      })
      .style('stroke', 'green');

    barGroup
      .append('path')
      .attr('d', () => {
        const paths = rectangleWithOptionalPoints(
          200,
          25,
          true,
          true,
          true,
        );

        return paths.main;
      })
      .attr('fill', 'none')
      .style('stroke', 'red');
  };

  var svg = d3.select("#area")
  renderBarGroup();

</script>

关键修改说明

  • 添加了<clipPath>元素,使用主形状的路径作为裁剪区域
  • 将散列图案路径放入带有clip-path属性的组中,确保条纹仅在主形状内部可见
  • 这种方法无需手动调整条纹坐标,完全适配箭头的不规则边界,同时导出到PowerPoint时也能保留正确的视觉效果

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 13:35:02