web-dev-qa-db-ja.com

パス/ポリゴンに丸みを帯びた角を適用する

数週間以内に開始しなければならないプロジェクトの情報を収集しています。このプロジェクトには、ユーザーが事前定義された形状を追加したり、形状を自分で形成したりできるブラウザベースの描画ツールが含まれています。シェイプは、Illustratorのような変換ツール(ハンドル)を使用して、選択可能で、自由にスケーラブルで、回転可能である必要があります。私たちが念頭に置いている事前定義された形状は、長方形、楕円、半楕円、および(二等辺)三角形です。

これまでのところ、これを達成するためにRaphaelJSまたはFabricJSを考えていましたが、...すべての形状(ポリゴン/パス)は特定のコーナー半径で描画する必要があります。また、スケーリング中はコーナー半径を維持する必要があるため、歪みは発生しません。ユーザーは入力によって丸めを指定できます。

いくつかの障害/質問があります:

  • 私が言及した形状にコーナー半径を適用するための均一な数式はありますか?それとも、すべての形状をミニプロジェクト自体として扱う必要がありますか?パスまたはポリゴンとして返したいので、SVGまたはキャンバスで描画できます。
  • 変換ハンドルをドラッグすることによるすべてのスケールまたは回転操作は、更新された形状を取得するための(大規模な)計算になります。長方形は最も簡単に実現でき、楕円を除いて、他のすべての形状は計算が非常に難しくなります。プロセスをスピードアップする方法はありますか?

ユーザーがフローチャートを描いて、提供されているほぼすべての形状にコーナー半径を適用できるサイトを見つけました。それはとてもスムーズに動作するので、彼らがどのようにそれをしたかを釘付けにすることはできません。リンク: https://www.lucidchart.com/ (試用ボタン)

今のところ、私は少し無知です、私は数学で平凡だと思います。おそらく誰かが私を正しい方向に押して、いくつかの経験を共有することができますか?

前もって感謝します。

ところで。このプロジェクトでは、パフォーマンスが重要です。図面の出力はSVG形式である必要があります。

16
MaPaBa

私は同じような問題を抱えることになり、簡単な解決策を見つけることができませんでした。結局、AdobeIllustratorの操作に基づいてかなり一般的なコーナーラウンド関数を作成しました。円弧の代わりにベジェ曲線を使用しますが、結果はかなりまともだと思います。

これは、SVG画像の座標空間で、またはコーナーとその隣接物の間の距離の一部として指定された半径での丸めをサポートします。

これを使用するには、プロジェクトにrounding.jsを含め、関数を呼び出します。

roundPathCorners(pathString, radius, useFractionalRadius)

コードといくつかのテストパスはここにあります: http://embed.plnkr.co/kGnGGyoOCKil02k04snu/preview

これは、Plnkrの例がどのようにレンダリングするかです。

SVG Path Rounding Examples

36
Yona Appletree

開始点は sing-svg-curves-to-imitate-rounded-corners である可能性があります。原則は、すべてのコーナーを略記の相対立方体で変換することです。この例は非常に基本的なものであり、2つの可能なコーナーケースでのみ機能します。

コーナー置換のようにこれを拡張して、他のパスセグメントもカバーするように拡張することは可能だと思います。すべてのセグメントには曲線上の座標点があり、sセグメントに置き換える必要があります。数学は、このソリューションの興味深い部分になる可能性があります。

2
Timo Kähkönen

この質問はしばらくの間ありましたが、立ち寄ってこの解決策を試す人もいます。

var BORDER_RADIUS = 20;

function roundedPath( /* x1, y1, x2, y2, ..., xN, yN */ ){
    context.beginPath();
    if (!arguments.length) return;

    //compute the middle of the first line as start-stop-point:
    var deltaY = (arguments[3] - arguments[1]);
    var deltaX = (arguments[2] - arguments[0]);
    var xPerY = deltaY / deltaX;
    var startX = arguments[0] + deltaX / 2;
    var startY = arguments[1] + xPerY * deltaX / 2;

    //walk around using arcTo:
    context.moveTo(startX, startY);
    var x1, y1, x2, y2;
    x2 = arguments[2];
    y2 = arguments[3];
    for (var i = 4; i < arguments.length; i += 2) {
        x1 = x2;
        y1 = y2;
        x2 = arguments[i];
        y2 = arguments[i + 1];
        context.arcTo(x1, y1, x2, y2, BORDER_RADIUS);
    }

    //finally, close the path:
    context.arcTo(x2, y2, arguments[0], arguments[1], BORDER_RADIUS);
    context.arcTo(arguments[0], arguments[1], startX, startY, BORDER_RADIUS);
    context.closePath();
}

秘訣は、最初の行の途中で開始(および停止)してから、非常にうまく説明されているarcTo関数を使用することです ここ

今、あなたは「ただ」あなたのすべての形を多角形として表現する方法を見つけなければなりません。

2