답변:
@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
그렇지 않으면 전체 호가 렌더링되지 않습니다.
elliptical 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 개의 호가 있으므로 두 플래그가 그 중 하나를 선택합니다. large-arc-flag
각도가 감소하는 방향 ( = 0) 으로 작은 호 ( = 0) 를 그리려고 할 것입니다 sweep-flag
. 모두 함께 SVG 경로는 다음과 같습니다.
M 200 175 A 25 25 0 0 0 182.322 217.678
두 번째 예의 경우 (같은 방향으로 가고 큰 원호로 이동한다고 가정하면) SVG 경로는 다음과 같습니다.
M 200 175 A 25 25 0 1 0 217.678 217.678
다시, 나는 이것을 테스트하지 않았습니다.
@clocksmith와 같이 왜 그들이이 API를 선택했는지 궁금하다면 구현 노트를 살펴보십시오 . 여기에는 두 가지 가능한 아크 매개 변수화, "종료점 매개 변수화"(선택한 것) 및 "중심 매개 변수화"(질문이 사용하는 것과 유사 함)가 설명되어 있습니다. "엔드 포인트 매개 변수화"에 대한 설명에서 다음과 같이 말합니다.
엔드 포인트 매개 변수화의 장점 중 하나는 모든 경로 명령이 새로운 "현재 점"의 좌표로 끝나는 일관된 경로 구문을 허용한다는 것입니다.
따라서 기본적으로 아크는 별도의 객체가 아닌 더 큰 경로의 일부로 간주되는 아크의 부작용입니다. SVG 렌더러가 불완전하면 경로 구성 요소를 건너 뛸 수 있다고 가정합니다. 어떤 인수가 필요한지 알고있는 한 렌더링 방법을 모릅니다. 또는 많은 구성 요소가있는 경로의 다른 청크를 병렬 렌더링 할 수 있습니다. 또는 복잡한 경로의 길이에 따라 반올림 오류가 발생하지 않도록하기 위해 수행했을 수도 있습니다.
구현 노트는 두 개의 매개 변수화 사이에서 변환하기 위해 더 수학적 의사 코드가 있기 때문에 원래 질문에 유용합니다 (처음 에이 답변을 작성할 때 알지 못했습니다).
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의 답변, 특히 Ray Hulha의 의견에 대해 언급하고 싶었습니다.
이 코드 펜이 작동하지 않는 이유는 HTML에 획 너비가 0이므로 결함이 있기 때문입니다.
나는 그것을 고치고 여기에 두 번째 예를 추가했다 : 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;
}
자바 스크립트 :
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
매개 변수 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))
내가 쓴 이 게시물 에서 더 자세한 설명을 할 수 있습니다 .
답을 찾는 사람들을위한 참고 사항 (나도했던 사람) -arc를 사용해야 할 필요가 없다면 부분 원을 그리는 훨씬 간단한 해결책 stroke-dasharray
은 SVG 를 사용하는 것 입니다 <circle>
.
대시 배열을 두 요소로 나누고 원하는 각도로 범위를 조정하십시오. 를 사용하여 시작 각도를 조정할 수 있습니다 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);
sweep-flag = "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
매개 변수 의 값 은 항상 0입니다.arcSweep
아마도 같은 이름으로 바뀌어야longArc
합니다.