SVGの円弧パスによる円の描画


146

簡単な質問:SVGパスを使用すると、99.99%の円を描画して表示できますが、99.99999999%の円の場合、円は表示されません。どうすれば修正できますか?

次のSVGパスは99.99%の円を描くことができます:(http://jsfiddle.net/DFhUF/1381/で試して、4つのアークまたは2つのアークしか表示されないか確認してください。ただし、IEの場合は、 SVGではなくVMLでレンダリングされますが、同様の問題があります)

M 100 100 a 50 50 0 1 0 0.00001 0

しかし、それが円の99.99999999%の場合、何も表示されません。

M 100 100 a 50 50 0 1 0 0.00000001 0    

そして、それは円の100%と同じです(それはまだ弧です、そうではありません、非常に完全な弧です)

M 100 100 a 50 50 0 1 0 0 0 

どうすれば修正できますか?その理由は、関数を使用して円弧のパーセンテージを描画することです。円関数を使用するために99.9999%または100%の円弧を「特殊なケース」で使用する必要がある場合、それはちょっとばかげているでしょう。

ここでも、RaphaelJSを使用したjsfiddleのテストケースはhttp://jsfiddle.net/DFhUF/1381/にあります
(IE 8のVMLの場合、2番目のサークルも表示されません...に変更する必要があります) 0.01)


更新:

これは、システムでスコアの弧を描画しているため、3.3ポイントで円の1/3が得られるためです。0.5は円の半分を取得し、9.9ポイントは円の99%を取得します。しかし、システムに9.99のスコアがある場合はどうなりますか?円の99.999%に近いかどうかを確認しarccircleそれに応じて関数または関数を使用する必要がありますか?では、9.9987のスコアはどうでしょうか。どちらを使用しますか?どのようなスコアが「完全すぎる円」にマッピングされ、円関数に切り替わるかを知る必要があるのはばかげています。円の「特定の99.9%」または9.9987のスコアの場合は、円弧関数を使用します。 。


@minitechもちろん動作します...円の99%になります(大まかに言えば)。場合によっては、円の98%、99%、99.99%を描画できますが、99.9999999%や100%は描画できません
非極性

1
これらのリンクはどちらも同じものにリンクしており、Safariでは正常に機能します。
マークベッシー2011

右、同じリンク、私は人々にテストケースをもっと早く見たいので、質問の最初にリンクを追加します。正しいSafariはそれを実行しますが、どれほど素晴らしい... ChromeとFirefoxはそうではありません...奇妙なcoz SafariとChromeはどちらもWebkitですが、SVGエンジンはWebkitに依存していますか?
非極性

@Marcinはどのように元気に見えますか?4つの弧または2つの弧が表示されますか?あなたもコードを見ましたか?
非極性

2
Raphael.jsをロードするクロスオリジンエラーを回避するために、Raphaelがライブラリとして含まれている更新されたjsfiddle:jsfiddle.net/DFhUF/1381
ericsoco

回答:


35

XAMLの弧についても同じです。99.99%の弧をaで閉じるだけでZ、円ができます!


jsfiddleサンプルの3番目のケースを閉じて機能させることができますか?
非極性

はい、値を0.0001に下げます。この問題は、SVG自体ではなく、WebKitのさまざまなブラウザーの実装に関連して聞こえます。しかし、これがSVG / XAMLs Arcコンポーネントで円を作る方法です。
トッドメイン

ああ、不正行為、常に最良の解決策。それでも100%のケースを処理する必要がありますが、個別のコードブランチ全体ではなく、99.999%に「切り捨て」するだけです。
SimonR 2016

デモはありますか?この答えは実現しません
Medet Tleukabiluly

@MedetTleukabilulyあなたは質問で上記の弧を持っていますz、最後にa を追加して完了しました。ゼロを削除する必要があるかもしれません。たとえば、最新のChromeでは0.0001、それを機能させるために書かなければなりませんでした。パス文字列を配置する場所を探している場合は、MDNのパスを参照してください。
TWiStErRob 2016年

415

私はそれがゲームの少し遅いことを知っています、しかし私はそれが新しく、私が同様のディレンマを持っていたときからこの質問を思い出しました、そして誰かがまだそれを探しているなら、私は誤って「正しい」解決策を見つけました:

<path 
    d="
    M cx cy
    m -r, 0
    a r,r 0 1,0 (r * 2),0
    a r,r 0 1,0 -(r * 2),0
    "
/>

つまり、これは:

<circle cx="100" cy="100" r="75" />

これでパスとして達成できます:

  <path 
        d="
        M 100, 100
        m -75, 0
        a 75,75 0 1,0 150,0
        a 75,75 0 1,0 -150,0
        "
  />

秘訣は、2つの弧を作成することです。2番目の弧は、最初の弧が中断したところから始まり、負の直径を使用して元の弧の始点に戻ります。

1つの円弧で完全な円として実行できないのは(そして私は推測しているだけです)、それ自体から(150,150としましょう)からそれ自体(150,150)に円弧を描くように指示しているためです。 「ああ、私はすでにそこにいます、アークは必要ありません!」。

私が提供するソリューションの利点は次のとおりです。

  1. 円からパスに直接変換するのは簡単です。
  2. 2つの円弧線に重複はありません(マーカーやパターンを使用している場合に問題が発生する可能性があります)。2つの部分で描かれていますが、きれいな連続線です。

textpathsが図形を受け入れることだけを許可する場合、これは問題になりません。しかし、私は彼らがその解決策を回避していると思います。なぜなら、円のような形状要素には技術的に「開始」点がないからです。

jsfiddleデモ:http ://jsfiddle.net/crazytonyi/mNt2g/

更新:

textPath参照にパスを使用していて、テキストを円弧の外縁にレンダリングしたい場合は、まったく同じ方法を使用しますが、スイープフラグを0から1に変更して、内側ではなく表面としてのパス(1,0誰かが中心に座って自分の周りに円を描くように、1,1誰かが中心を半径距離で歩き回り、チョークをそれらのそばにドラッグすると、それが助けになれば)上記のコードですが、変更が加えられています。

<path 
    d="
    M cx cy
    m -r, 0
    a r,r 0 1,1 (r * 2),0
    a r,r 0 1,1 -(r * 2),0
    "
/>

1
+1、数式をありがとう。もちろん、最初の2つのコマンドは統合できます。
John Gietzen 2013年

+1は、一般的に解の明快さと実用性のためですが、特に「円のような形状要素には、技術的には「開始」点がありません」という問題を明確に表す方法です。
David John Welsh

11
ここでの問題は「ああ、私はすでにそこにいる、アークは必要ありません」ということではないと思います。1を大きなアークフラグとして指定することで、エンジンにさらに進んでほしいことを明示的に伝えます。本当の問題は、あなたの点を通過するという制約を完全に満たす円が無限に存在することです。これは、360 *アークが必要なときにエンジンが何をすべきかわからない理由を説明しています。359.999で機能しない理由は、これは数値的に不安定な計算であり、技術的には要求に一致する円が厳密に1つあるにもかかわらず、おそらく望んだ円ではないためです
qbolec

@qbolec-そうです、私は大きな弧とスイープがオフで、弧が行き先がないという点で考えていました。または、少なくとも、大きな弧とスイープによって、2つの点の間の曲線として弧を定義するいくつかの基本的な設計が可能になった(そのため、1つの点を2回使用すると、1つの点が折りたたまれた単一の点として見えた)。中心が定義されている場合、円弧は1つの円に折りたたまれますが、中心が存在する場合、単一の円弧が完全な円になる可能性があるという疑問が生じます。
アンソニー

1
「円のような形状要素には、厳密には「開始」点がありません。これは実際には当てはまりません。SVG仕様は、すべての形状の開始点がどこにあるかを絶対的に指定しています。ダッシュ配列がシェイプで機能するためには、そうする必要があります。
Paul LeBeau 2017年

17

Anthonyのソリューションを参照して、パスを取得する関数を次に示します。

function circlePath(cx, cy, r){
    return 'M '+cx+' '+cy+' m -'+r+', 0 a '+r+','+r+' 0 1,0 '+(r*2)+',0 a '+r+','+r+' 0 1,0 -'+(r*2)+',0';
}

10

まったく異なるアプローチ:

パスをいじってsvgで弧を指定する代わりに、circle要素を使用して、疑似コードでストロークダッシュ配列を指定することもできます。

with $score between 0..1, and pi = 3.141592653589793238

$length = $score * 2 * pi * $r
$max = 7 * $r  (i.e. well above 2*pi*r)

<circle r="$r" stroke-dasharray="$length $max" />

その単純さは、複数の弧のパスを使用する方法よりも優れています(たとえば、スクリプトを作成すると、1つの値をプラグインするだけで、任意の弧の長さで完了します)。

弧は右端の点から始まり、回転変換を使用して移動できます。

注:Firefoxには、90度以上の回転が無視されるという奇妙なバグがあります。したがって、上からアークを開始するには、次を使用します。

<circle r="$r" transform="rotate(-89.9)" stroke-dasharray="$length $max" />

このソリューションは、どのタイプの塗りつぶしも使用せず、偏差のない円弧セグメントのみが必要な場合にのみ適用できることに注意してください。セクターを描画したい瞬間には、新しいsvgパスノードも必要になります。そうでなければ、単一のパスタグで処理できます。
mxfh

@mxfhは実際にはそうではありません。rokeの値の2倍のストローク幅を取ると、完璧なセクターが得られます。
mvds '25

stroke-dasharray="0 10cm 5cm 1000cm"、変換を回避することが可能である
stenci

@stenciはい、しかし欠点は、0%から100%の塗りつぶしにダッシュ配列の1つのパラメーターを使用できないことです(これは私の目的の1つでした)
mvds

5

Adobe IllustratorはSVGのようなベジェカーブを使用し、円の場合は4つのポイントを作成します。2つの楕円弧コマンドで円を作成できますが、SVGの円の場合は<circle />:) を使用します。


「2つの楕円弧コマンドで円を作成できます」?どういう意味ですか?1つだけ使用することはできませんか?少なくとも(0,0)から(0.01、0)に移動して、何かをレンダリングすることによって。を使用するcircle場合は、代わりに質問の更新を参照してください。
非極性

いいえ、1つだけでは使用できないと思います。できないことを示しましたが、HTML5 Canvasアークで同様の問題があります。
Phrogz

arcつまり、左の円弧と右の円弧を使用して完全な円を作成するために使用しますか?したがって、アークは完全な円を描くことができません...そのためには、2つのarcパスが必要です
非極性極性2011

2
@動静的能量正解です。2つのアークパスが必要です(または、1つのアークの醜いハックを最後まで行ってから、closepathコマンドで最後まで直線的に移動します)。
Phrogz

1
イラストレーターはひどい。ベジェ曲線で円を作成することはできません。円に近いものだけで、まだ円ではありません。
adius 2014年

4

2つの円弧コマンドを使用して完全な円を描くことをお勧めします。

通常、私は楕円または円要素を使用して完全な円を描きます。


5
svgの主な制限は、シェイプ要素をテキストパスに使用できないことです。これはおそらく、この質問にアクセスするすべての人にとって主な動機です。
アンソニー

1
@Anthony彼らは今できる。Firefoxはあらゆる形状に対してtextPathをサポートしています。Chromeもそうだと思います。
Robert Longson

@RobertLongson-例または例へのリンクを提供できますか?従来の開始点なしで描画されたときに、テキストパスがどこから始まるのか、それが外側にあるのか内側にあるのかなど、どのように決定するのか興味があります。
アンソニー

SVG 2仕様などを参照してください@Anthony w3.org/TR/SVG2/shapes.html#CircleElement、また新しいtextPathの側の属性
ロバートLongson

4

アンソニーとアントンの答えに基づいて、外観全体に影響を与えずに生成された円を回転させる機能を組み込みました。これは、アニメーションのパスを使用していて、アニメーションの開始位置を制御する必要がある場合に役立ちます。

function(cx, cy, r, deg){
    var theta = deg*Math.PI/180,
        dx = r*Math.cos(theta),
        dy = -r*Math.sin(theta);
    return "M "+cx+" "+cy+"m "+dx+","+dy+"a "+r+","+r+" 0 1,0 "+-2*dx+","+-2*dy+"a "+r+","+r+" 0 1,0 "+2*dx+","+2*dy;
}

これはまさに私が必要としたものです。私はgreensockモーフプラグインを使用して、円のパスを長方形のパスにモーフィングしました。
RoboKozo

3

パス変換の楕円属性を探していた私のような人たちのために:

const ellipseAttrsToPath = (rx,cx,ry,cy) =>
`M${cx-rx},${cy}a${rx},${ry} 0 1,0 ${rx*2},0a${rx},${ry} 0 1,0 -${rx*2},0`

2

関数として書くと、次のようになります。

function getPath(cx,cy,r){
  return "M" + cx + "," + cy + "m" + (-r) + ",0a" + r + "," + r + " 0 1,0 " + (r * 2) + ",0a" + r + "," + r + " 0 1,0 " + (-r * 2) + ",0";
}

2
これは素晴らしい答えです!ほんの少し追加:このパスは、東、北、西、南に描かれています。あなたは円が正確のように動作する場合<circle>、あなたは、東、南、西、北に向きを変更する必要があります。 "M" + cx + "," + cy + "m" + (r) + ",0" + "a" + r + "," + r + " 0 1,1 " + (-r * 2) + ",0" + "a" + r + "," + r + " 0 1,1 " + (r * 2) + ",0" 利点はということですstroke-dashoffsetし、startOffset今と同じように動作します。
loominade

2

これらの答えは非常に複雑です。

2つの円弧を作成したり、異なる座標系に変換したりせずにこれを行うためのより簡単な方法。

これは、キャンバス領域に幅wと高さがあることを前提としていますh

`M${w*0.5 + radius},${h*0.5}
 A${radius} ${radius} 0 1 0 ${w*0.5 + radius} ${h*0.5001}`

「長い弧」フラグを使用するだけで、完全なフラグが設定されます。次に、円弧を99.9999%完全な円にします。視覚的には同じです。円の右端の点(中心から直接水平に1つの半径)から円を開始するだけで、スイープフラグを回避します。


1

別の方法は、2つの3次ベジェ曲線を使用することです。これは、svgのarcパラメータを認識しないpocketSVGを使用しているiOS ユーザー向けです。

C x1 y1、x2 y2、xy(またはc dx1 dy1、dx2 dy2、dx dy)

3次ベジエ曲線

ここで最後の座標セット(x、y)は、線を終了する場所です。他の2つはコントロールポイントです。(x1、y1)は曲線の始点の制御点、(x2、y2)は曲線の終点の制御点です。

<path d="M25,0 C60,0, 60,50, 25,50 C-10,50, -10,0, 25,0" />

1

私はここでそれを行うためにjsfiddleを作りました:

function polarToCartesian(centerX, centerY, radius, angleInDegrees) {
var angleInRadians = (angleInDegrees-90) * Math.PI / 180.0;

return {
x: centerX + (radius * Math.cos(angleInRadians)),
y: centerY + (radius * Math.sin(angleInRadians))
};
}

function describeArc(x, y, radius, startAngle, endAngle){

var start = polarToCartesian(x, y, radius, endAngle);
var end = polarToCartesian(x, y, radius, startAngle);

var largeArcFlag = endAngle - startAngle <= 180 ? "0" : "1";

var d = [
    "M", start.x, start.y, 
    "A", radius, radius, 0, largeArcFlag, 0, end.x, end.y
].join(" ");

return d;       
}
console.log(describeArc(255,255,220,134,136))

リンク

必要なのは、console.logの入力を変更して、コンソールで結果を取得することだけです。


これはまさに私が探していたものでした。ここでベストアンサー!この男upvote
マンDahlström
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.