1. ホーム
  2. javascript

[解決済み] SVGで「スクイグリーライン」を描画する

2022-02-09 09:18:27

質問

任意のSVGに四角い線を引く方法を考えています。 path 要素で構成されています。パスはReact Componentによって生成されます。例えば、私は次のような線を再現しようとしています。 この質問で :

SVGやJavaScriptで生成されたパスで、これを簡単に行う方法はありますか?

を使用して一連の曲線を結合することを検討したことがあります。 s しかし、その場合、カーブに沿ってポイントを計算する必要があります。また、変位フィルタのようなものも考えましたが、何から手をつければいいのかよくわかりません。

どのように解決するのですか?

最も簡単な方法は、パスに沿ってステップを踏むことだと思います。そして、各ステップで、2次ベジェ曲線とその中間にある曲線に直交する制御点を挿入します。そして、次のステップでは、制御点のある側を切り替えます。

function makeSquiggle(squigglePathId, followPathId, squiggleStep, squiggleAmplitude)
{
  var followPath = document.getElementById(followPathId);
  var pathLen = followPath.getTotalLength();

  // Adjust step so that there are a whole number of steps along the path
  var numSteps = Math.round(pathLen / squiggleStep);

  var pos = followPath.getPointAtLength(0);
  var newPath = "M" + [pos.x, pos.y].join(',');
  var side = -1;
  for (var i=1; i<=numSteps; i++)
  {
    var last = pos;
    var pos = followPath.getPointAtLength(i * pathLen / numSteps);

    // Find a point halfway between last and pos. Then find the point that is
    // perpendicular to that line segment, and is squiggleAmplitude away from
    // it on the side of the line designated by 'side' (-1 or +1).
    // This point will be the control point of the quadratic curve forming the
    // squiggle step.
    
    // The vector from the last point to this one
    var vector = {x: (pos.x - last.x),
                  y: (pos.y - last.y)};
    // The length of this vector
    var vectorLen = Math.sqrt(vector.x * vector.x + vector.y * vector.y);
    // The point halfwasy between last point and tis one
    var half = {x: (last.x + vector.x/2),
                y: (last.y + vector.y/2)};
    // The vector that is perpendicular to 'vector'
    var perpVector = {x: -(squiggleAmplitude * vector.y / vectorLen),
                      y: (squiggleAmplitude * vector.x / vectorLen)};
    // No calculate the control point position
    var controlPoint = {x: (half.x + perpVector.x * side),
                        y: (half.y + perpVector.y * side)};
    newPath += ("Q" + [controlPoint.x, controlPoint.y, pos.x, pos.y].join(','));
    // Switch the side (for next step)
    side = -side;
  }
  var squigglePath = document.getElementById(squigglePathId);
  squigglePath.setAttribute("d", newPath);
}


makeSquiggle("squiggle", "follow", 25, 20);
#follow {
  fill: none;
  stroke: grey;
  stroke-width: 2;
}

#squiggle {
  fill: none;
  stroke: red;
  stroke-width: 2;
}
<svg width="500" height="400">
  <path id="follow" d="M 50,300 C 100,100 300,0, 350,250 L 450,200"/>
  <path id="squiggle" d="M0,0"/>
</svg>