回答:
@wdebeaumの素晴らしい答えを拡張して、弧状のパスを生成する方法を次に示します。
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;
}
使用する
document.getElementById("arc1").setAttribute("d", describeArc(200, 400, 100, 0, 180));
そしてあなたのhtmlで
<path id="arc1" fill="none" stroke="#446688" stroke-width="20" />
endAngle - 0.0001
。そうしないと、完全な弧はレンダリングされません。
楕円形のA
rcコマンドを使用したい。残念ながら、これには、極座標(半径、角度)ではなく、始点と終点のデカルト座標(x、y)を指定する必要があるため、いくつかの計算を行う必要があります。これは動作するはずのJavaScript関数です(私はテストしていません)。かなりわかりやすいと思います。
function polarToCartesian(centerX, centerY, radius, angleInDegrees) {
var angleInRadians = angleInDegrees * Math.PI / 180.0;
var x = centerX + radius * Math.cos(angleInRadians);
var y = centerY + radius * Math.sin(angleInRadians);
return [x,y];
}
どの角度がどの時計位置に対応するかは、座標系に依存します。必要に応じて、sin / cosの用語を入れ替えたり否定したりするだけです。
arcコマンドには、次のパラメーターがあります。
rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y
最初の例では:
rx
= ry
= 25およびx-axis-rotation
= 0、楕円ではなく円が必要なため。M
上記の関数を使用して、開始座標(移動先)と終了座標(x、y)の両方を計算し、それぞれ(200、175)と約(182.322、217.678)を生成できます。これまでのところこれらの制約を考えると、描画できるアークは実際には4つあるため、2つのフラグがいずれかを選択します。おそらくlarge-arc-flag
、角度が減少する方向(= 0を意味する)に小さな弧(= 0を意味する)を描画したいと思いますsweep-flag
。まとめると、SVGパスは次のとおりです。
M 200 175 A 25 25 0 0 0 182.322 217.678
2番目の例(同じ方向、つまり大きな円弧を想定していると仮定)の場合、SVGパスは次のとおりです。
M 200 175 A 25 25 0 1 0 217.678 217.678
繰り返しますが、私はこれらをテストしていません。
(編集2016-06-01)@clocksmithのように、なぜ彼らがこのAPIを選んだのか疑問に思っているなら、実装ノートを見てください。それらは、「エンドポイントのパラメーター化」(彼らが選択したもの)と「中央のパラメーター化」(これは質問が使用するものに似ています)の2つの可能なアークパラメーター化について説明しています。「エンドポイントのパラメーター化」の説明では、次のように述べています。
エンドポイントパラメータ化の利点の1つは、すべてのパスコマンドが新しい「現在のポイント」の座標で終了する一貫したパス構文を許可することです。
したがって、基本的には、それ自体の個別のオブジェクトではなく、より大きなパスの一部と見なされる弧の副作用です。SVGレンダラーが不完全な場合、引数の数がわかっている限り、レンダリングする方法がわからないパスコンポーネントをスキップするだけだと思います。あるいは、多くのコンポーネントを持つパスの異なるチャンクの並列レンダリングを可能にするかもしれません。あるいは、複雑なパスの長さに沿って丸め誤差が蓄積しないようにするために、そうしたのかもしれません。
実装ノートは、2つのパラメーター化の間で変換するためのより数学的な疑似コードを持っているので、元の質問にも役立ちます(最初にこの回答を書いたときに気が付きませんでした)。
large-arc-flag
0から1に切り替える必要があるという事実は、いくつかのバグを引き起こす可能性があります。
opsbの答えを少し変更し、サークルセクターのサポートフィルを作成しました。 http://codepen.io/anon/pen/AkoGx
JS
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 arcSweep = endAngle - startAngle <= 180 ? "0" : "1";
var d = [
"M", start.x, start.y,
"A", radius, radius, 0, arcSweep, 0, end.x, end.y,
"L", x,y,
"L", start.x, start.y
].join(" ");
return d;
}
document.getElementById("arc1").setAttribute("d", describeArc(200, 400, 100, 0, 220));
HTML
<svg>
<path id="arc1" fill="orange" stroke="#446688" stroke-width="0" />
</svg>
centerX
、centerY
例えば100に。
viewBox="0 0 500 500"
これは、古い質問ですが、私はコードが有用であることが判明し、私の思考の3分を保存した:)私は小さな拡張追加していだから@opsbの答えを。
この円弧をスライスに変換したい場合(塗りつぶしを可能にするため)、コードを少し変更できます。
function describeArc(x, y, radius, spread, startAngle, endAngle){
var innerStart = polarToCartesian(x, y, radius, endAngle);
var innerEnd = polarToCartesian(x, y, radius, startAngle);
var outerStart = polarToCartesian(x, y, radius + spread, endAngle);
var outerEnd = polarToCartesian(x, y, radius + spread, startAngle);
var largeArcFlag = endAngle - startAngle <= 180 ? "0" : "1";
var d = [
"M", outerStart.x, outerStart.y,
"A", radius + spread, radius + spread, 0, largeArcFlag, 0, outerEnd.x, outerEnd.y,
"L", innerEnd.x, innerEnd.y,
"A", radius, radius, 0, largeArcFlag, 1, innerStart.x, innerStart.y,
"L", outerStart.x, outerStart.y, "Z"
].join(" ");
return d;
}
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))
};
}
var path = describeArc(150, 150, 50, 30, 0, 50)
document.getElementById("p").innerHTML = path
document.getElementById("path").setAttribute('d',path)
<p id="p">
</p>
<svg width="300" height="300" style="border:1px gray solid">
<path id="path" fill="blue" stroke="cyan"></path>
</svg>
そこに行きます!
@opsbの答えはきちんとしていますが、中心点は正確ではありません。さらに、@ Jithinが指摘したように、角度が360の場合、何も描画されません。
@Jithinは360の問題を修正しましたが、360度未満を選択した場合、アークループを閉じる線が表示されますが、これは必須ではありません。
私はそれを修正し、以下のコードにいくつかのアニメーションを追加しました:
function myArc(cx, cy, radius, max){
var circle = document.getElementById("arc");
var e = circle.getAttribute("d");
var d = " M "+ (cx + radius) + " " + cy;
var angle=0;
window.timer = window.setInterval(
function() {
var radians= angle * (Math.PI / 180); // convert degree to radians
var x = cx + Math.cos(radians) * radius;
var y = cy + Math.sin(radians) * radius;
d += " L "+x + " " + y;
circle.setAttribute("d", d)
if(angle==max)window.clearInterval(window.timer);
angle++;
}
,5)
}
myArc(110, 110, 100, 360);
<svg xmlns="http://www.w3.org/2000/svg" style="width:220; height:220;">
<path d="" id="arc" fill="none" stroke="red" stroke-width="2" />
</svg>
@Ahtenusの回答、特にレイフルハのコメントで、コードペンには弧が表示されないというコメントがありましたが、私の評判は十分ではありません。
このcodepenが機能しない理由は、そのhtmlのストローク幅がゼロで欠陥があるためです。
私はそれを修正し、2番目の例をここに追加しました:http : //codepen.io/AnotherLinuxUser/pen/QEJmkN。
html:
<svg>
<path id="theSvgArc"/>
<path id="theSvgArc2"/>
</svg>
関連するCSS:
svg {
width : 500px;
height : 500px;
}
path {
stroke-width : 5;
stroke : lime;
fill : #151515;
}
JavaScript:
document.getElementById("theSvgArc").setAttribute("d", describeArc(150, 150, 100, 0, 180));
document.getElementById("theSvgArc2").setAttribute("d", describeArc(300, 150, 100, 45, 190));
より明確にし、別のソリューションを提供するだけです。 Arc
[ A
]コマンドは現在位置を開始点として使用するため、Moveto
最初に[M]コマンドを使用する必要があります。
次に、パラメータはArc
次のとおりです。
rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, xf, yf
たとえば、次のsvgファイルを定義するとします。
<svg viewBox="0 0 500 500">
<path fill="red" d="
M 250 250
A 100 100 0 0 0 450 250
Z"/>
</svg>
M
パラメータof xf
とyf
を使用して、開始点と終了点を設定しますA
。
円を探しrx
てry
いるので、基本的に同じように設定しているためrx
、始点と終点と交差するすべての半径の円を見つけようとします。
import numpy as np
def write_svgarc(xcenter,ycenter,r,startangle,endangle,output='arc.svg'):
if startangle > endangle:
raise ValueError("startangle must be smaller than endangle")
if endangle - startangle < 360:
large_arc_flag = 0
radiansconversion = np.pi/180.
xstartpoint = xcenter + r*np.cos(startangle*radiansconversion)
ystartpoint = ycenter - r*np.sin(startangle*radiansconversion)
xendpoint = xcenter + r*np.cos(endangle*radiansconversion)
yendpoint = ycenter - r*np.sin(endangle*radiansconversion)
#If we want to plot angles larger than 180 degrees we need this
if endangle - startangle > 180: large_arc_flag = 1
with open(output,'a') as f:
f.write(r"""<path d=" """)
f.write("M %s %s" %(xstartpoint,ystartpoint))
f.write("A %s %s 0 %s 0 %s %s"
%(r,r,large_arc_flag,xendpoint,yendpoint))
f.write("L %s %s" %(xcenter,ycenter))
f.write(r"""Z"/>""" )
else:
with open(output,'a') as f:
f.write(r"""<circle cx="%s" cy="%s" r="%s"/>"""
%(xcenter,ycenter,r))
この記事では、私が書いた詳細な説明を記載しています。
回答を求める人(私もそうでした)への注意- 円弧の使用が必須ではない場合、部分円を描画するためのはるかに簡単な解決策stroke-dasharray
はSVG を使用することです<circle>
。
ダッシュ配列を2つの要素に分割し、それらの範囲を目的の角度にスケーリングします。開始角度はを使用して調整できますstroke-dashoffset
。
単一の余弦ではありません。
説明付きの完全な例:https : //codepen.io/mjurczyk/pen/wvBKOvP
wdebeaumによる元のpolarToCartesian関数は正しいです。
var angleInRadians = angleInDegrees * Math.PI / 180.0;
以下を使用して開始点と終了点を逆にする:
var start = polarToCartesian(x, y, radius, endAngle);
var end = polarToCartesian(x, y, radius, startAngle);
これはスイープフラグを反転させるため、(私にとって)混乱しています。使用:
var start = polarToCartesian(x, y, radius, startAngle);
var end = polarToCartesian(x, y, radius, endAngle);
スイープフラグ= "0"の場合、 "通常の"反時計回りの円弧が描画されます。https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Pathsを参照してください
@opsbの回答を少し変更。この方法では完全な円を描くことはできません。つまり、(0、360)を指定すると、何も描画されません。したがって、これを修正するために行われたわずかな変更。100%に達するスコアを表示すると便利な場合があります。
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 endAngleOriginal = endAngle;
if(endAngleOriginal - startAngle === 360){
endAngle = 359;
}
var start = polarToCartesian(x, y, radius, endAngle);
var end = polarToCartesian(x, y, radius, startAngle);
var arcSweep = endAngle - startAngle <= 180 ? "0" : "1";
if(endAngleOriginal - startAngle === 360){
var d = [
"M", start.x, start.y,
"A", radius, radius, 0, arcSweep, 0, end.x, end.y, "z"
].join(" ");
}
else{
var d = [
"M", start.x, start.y,
"A", radius, radius, 0, arcSweep, 0, end.x, end.y
].join(" ");
}
return d;
}
document.getElementById("arc1").setAttribute("d", describeArc(120, 120, 100, 0, 359));
ES6バージョン:
const angleInRadians = angleInDegrees => (angleInDegrees - 90) * (Math.PI / 180.0);
const polarToCartesian = (centerX, centerY, radius, angleInDegrees) => {
const a = angleInRadians(angleInDegrees);
return {
x: centerX + (radius * Math.cos(a)),
y: centerY + (radius * Math.sin(a)),
};
};
const arc = (x, y, radius, startAngle, endAngle) => {
const fullCircle = endAngle - startAngle === 360;
const start = polarToCartesian(x, y, radius, endAngle - 0.01);
const end = polarToCartesian(x, y, radius, startAngle);
const arcSweep = endAngle - startAngle <= 180 ? '0' : '1';
const d = [
'M', start.x, start.y,
'A', radius, radius, 0, arcSweep, 0, end.x, end.y,
].join(' ');
if (fullCircle) d.push('z');
return d;
};
const d = `M ${start.x} ${start.y} A ${radius} ${radius} 0 ${largeArc} 0 ${end.x} ${end.y}`
選択した回答に基づくReactJSコンポーネント:
import React from 'react';
const polarToCartesian = (centerX, centerY, radius, angleInDegrees) => {
const angleInRadians = (angleInDegrees - 90) * Math.PI / 180.0;
return {
x: centerX + (radius * Math.cos(angleInRadians)),
y: centerY + (radius * Math.sin(angleInRadians))
};
};
const describeSlice = (x, y, radius, startAngle, endAngle) => {
const start = polarToCartesian(x, y, radius, endAngle);
const end = polarToCartesian(x, y, radius, startAngle);
const largeArcFlag = endAngle - startAngle <= 180 ? "0" : "1";
const d = [
"M", 0, 0, start.x, start.y,
"A", radius, radius, 0, largeArcFlag, 0, end.x, end.y
].join(" ");
return d;
};
const path = (degrees = 90, radius = 10) => {
return describeSlice(0, 0, radius, 0, degrees) + 'Z';
};
export const Arc = (props) => <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 300">
<g transform="translate(150,150)" stroke="#000" strokeWidth="2">
<path d={path(props.degrees, props.radius)} fill="#333"/>
</g>
</svg>;
export default Arc;
上記の回答のために作成したJSFiddleコードを使用できます。
https://jsfiddle.net/tyw6nfee/
あなたがする必要があるのは、最後の行のconsole.logコードを変更し、それにあなた自身のパラメータを与えることです:
console.log(describeArc(255,255,220,30,180));
console.log(describeArc(CenterX,CenterY,Radius,startAngle,EndAngle))
arcSweep
変数が実際にlarge-arc-flag
svg Aパラメーターを制御していることに注意してください。上記のコードでは、sweep-flag
パラメーターの値は常にゼロです。arcSweep
おそらくのような名前に変更する必要がありますlongArc
。