5

クロスブラウザパスノーマライザーを実装する方法を見つけようとしました。ここで説明されているネイティブの方法があり、機能の例はここにありますが、最新のOperaでのみ機能します(IE、FF、Safari、Chromeでは機能しません)。

ネイティブの方法ではpathElm.normalizedPathSegList、すべての相対座標を絶対座標に変換し、すべてのパスセグメントタイプを次のタイプのサブセットとして表します:M、L、C、z。

javascriptコードとそのjsfiddled機能例を1つだけ見つけましたが、IEとFFでのみ機能します。Chromeで「キャッチされないエラー:INDEX_SIZE_ERR:DOM例外1」が発生します。これをOpera、Safari、Chromeでも機能するように修正するにはどうすればよいですか、それともSVGパスを正規化する他の方法はありますか?

4

3 に答える 3

3

編集:これを使用しないでください!さらにテストしたところ、A->C 変換はすべての場合に信頼できるわけではなく、他のパス コマンドの組み合わせも失敗することがわかりました。代わりにこれを使用してください!

最終的に、Safari、Opera、IE9、Firefox、および Chrome で動作するようになりました: http://jsfiddle.net/timo2012/M6Bhh/41/

この関数は SVG パスのデータを正規化し、すべてのパス セグメントが M、C、L、および z (= 絶対座標、つまりすべての相対座標が絶対座標に変換されることを意味します) に変換されるようにします。他のすべてのセグメントは自明で 100% 正確ですが、円弧 (A) は特殊なケースであり、円弧を線 (L)、2 次曲線 (Q)、または 3 次曲線 (C) に変換するかどうかを選択できます。最も正確なのは線ですが、解像度の独立性が失われます。何らかの理由で二次方程式は特定の円弧で失敗しますが、三次方程式はより正確です。

次のパスがあるとします。

<svg width="400" height="400">
    <path stroke="red" stroke-width="3" d="M30 30 S40 23 23 42 L23,42 C113.333,113.333 136.667,113.333 150,80 t40,50 T230,240 q20 20 54 20 s40 23 23 42 t20,30 a20,30 0,0,1 -50,-50"/>
</svg>

次を使用して正規化します。

var path = document.querySelector('path');
path.normalizePath(3, 0.1); // 3 = C = cubic curves. Best alternative, rather good accuracy and path data remains reasonable sized

正規化されたバージョンは次のとおりです。

<svg width="400" height="400">
    <path stroke="red" stroke-width="3" d="M 30 30 C 30 30 40 23 23 42 L 23 42 C 113.333 113.333 136.667 113.333 150 80 C 150 80 163.333 96.6667 190 130 C 216.667 163.333 230 200 230 240 C 243.333 253.333 261.333 260 284 260 C 284 260 324 283 307 302 C 307 302 313.667 312 327 332 C 324.811 336.924 321.997 341.154 318.719 344.448 C 315.441 347.741 311.762 350.033 307.893 351.194 C 304.024 352.355 300.04 352.361 296.169 351.213 C 292.298 350.064 288.616 347.783 285.333 344.5 C 282.05 341.217 279.23 336.996 277.035 332.078 C 274.839 327.161 273.311 321.642 272.537 315.839 C 271.763 310.035 271.759 304.06 272.525 298.254 C 273.291 292.448 274.811 286.924 277 282"/>
</svg>

両方を重ねて配置すると、結果は次のようになります (赤が正規化され、黒がオリジナルです)。

正規化されたパスと元の

その他の可能性は次のとおりです。

path.normalizePath(1,0.5); // A->L, Many lines, high accuracy. Very good accuracy, but not so resolution independent, because when scaled, the corners become visible

path.normalizePath(1,40); // A->L, Few lines, less accuracy

path.normalizePath(2,0.5); // A->Q, quadratic curves. I tested this, but not good. Fails in some cases.

そして、これにはどのような利点がありますか?

パス データを正規化するためのネイティブな方法は、まだすべてのブラウザに実装されていないため、これまでのところ独自に行っています。また、ネイティブな方法が実装されている場合、すべてのブラウザーが同じように機能するかどうかはわかりません。SVG のドキュメントでは円弧を線に変換することについて述べていますが、SVG の主な利点である解像度の独立性が失われるため、これは良い方法ではありません。アークの正規化がどのように行われるかを完全に制御する必要があり、このスクリプトはその方​​法を提供します。

データが正規化されると、ビットマップ イメージの座標とまったく同じ方法でデータを変更できます。Illustrator の方法でパスをワープ (アーク、アーチ、バルジ、シェル、フラグ、ウェーブ、フィッシュ、ライズ、フィッシュアイ、インフレート、スクイーズ、ツイスト) したい場合、または遠近感を実現するためにパスを歪めたい場合は、正規化されたパス データを変更できます。確実に。

このコードは、YannickBochatay のスクリプトに基づいており、よりクロス ブラウザーにしました。

于 2012-10-21T16:11:05.450 に答える
1

編集:Raphaëlのバグを修正し、アニメーション化された複雑なパスとアニメーション化されていない複雑なパスを使用して徹底的なテストを行ったので、パスの正規化にRaphaëlを使用するのが賢明だと思います。バグの説明とその修正はここにあります:https ://stackoverflow.com/a/13079377/1691517 。Raphaëlのpath2curve関数は、すべてのパスコマンド(A、つまりArc)を正規化された形式(つまり、3次曲線)に簡単に変換できます。Cubicsがすべてのパスコマンドを表すことができるのは素晴らしいことです!


Raphael.path2curve()もう1つの方法は、新しいRaphaëlを使用することです。これは、すべてのパスコマンドを3次曲線に変換する興味深い関数ですが、いくつかのバグがあります。次の画像はバグを視覚化したものです。

ここに画像の説明を入力してください

機能例はこちらで、コードは次のとおりです。

<style>path {fill:none}</style>
<script src="http://cdnjs.cloudflare.com/ajax/libs/raphael/2.1.0/raphael-min.js"></script>
<div id="res" style="width:800px"></div>
<div id="raphael"></div>

<script>
window.onload = function () {
var paper = Raphael("raphael", 400, 400);
var original_path = "M30 30 S40 23 23 42 L23,42 C113.333,113.333 136.667,113.333 150,80 t40,50 T230,240 q20 20 54 20 s40 23 23 42 t20,30 a20,30 0,0,1 -50,-50";
var arr=Raphael.path2curve(original_path);
var normalized_path = arr.toString();

var path1 = paper.path(normalized_path).attr({stroke: "red", "stroke-width":6});
var path2 = paper.path(original_path).attr({stroke: "black", "stroke-width":2});

document.getElementById("res").innerHTML="ORIGINAL PATH (black):<br>"+original_path+"<br><br>NORMALIZED PATH (red):<br>"+normalized_path;
}
</script>​

Raphaëlでパスの正規化を行うことができれば非常に便利です。これは、大量のブラウザーをサポートし、DOMパスセグメントの代わりに配列を使用するためです(=速度と下位互換性)。バグレポートを作成しました。将来のリリースで修正されることを願っています。

于 2012-10-23T16:29:41.007 に答える
1

Opera、Safari、および Chrome での DOM 例外の理由を見つけたと思います。

SVG docは、リストから指定された項目を返すと述べています。getItem() 返品された商品は商品そのものであり、コピーではありません。アイテムに加えられた変更は、すぐにリストに反映されます。

同様appendItem() に、リストの最後に新しいアイテムを挿入します。newItem が既にリストにある場合は、このリストに挿入される前に、以前のリストから削除されます。挿入されたアイテムはアイテムそのものであり、コピーではありません。

したがって、これは元のアイテムを指します。

seg = path1.pathSegList.getItem(i);

そして、このアイテムを使用して他のパスのセグメントリストに追加すると

newpath.pathSegList.appendItem(seg);

すべてのブラウザには、元のセグメントをどうするかという独自の意見があります。IE9 と FF は、元のパス 1 のセグメント リストをそのまま残します (または、少なくともインデックス (上記の例では i) を保持します)。Safari、Chrome、および Opera は、パス 1 のセグメント リストから seg を削除します。SVG のドキュメントでは、アイテム (以前のリストから削除された) が明確に説明されているため、IE9 と FF の実装が間違っているようです。したがって、アイテムが以前のリストから削除されたのか、それともインデックスのみが保持されているのかは (まだ) よくわかりません (これは後で確認します)。

編集:これを確認し、IE9 と FF が元のパス (path1) のセグメント リストをそのまま残していることを確認します。セグメントが他のパスのセグメント リストに追加されると、インデックスも保持されます。Safari、Chrome、および Opera での動作は異なります。項目が他のリストに追加されると元のリストから削除され、これまでのところもちろんインデックスも更新されます (古いインデックスは追加後に無効になります)。違いを確認するjsfiddleを作成しました。IE9 および FF は、セグメント リストの長さ 1、1、10、10 を返します。Opera、Safari、Chrome は 1,0,10,8 を返します。

また、ブラウザの違いを何らかの方法で考慮する必要があります。最初のアイテムの前にダミー セグメントを追加するか、path1.numberOfItems() をクエリして、元のパスが変更されているかどうかを判断します。

于 2012-10-20T21:49:34.960 に答える