답변:
@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 Arc 명령 을 사용하려고합니다 . 불행히도, 이것은 당신이 가지고있는 극좌표 (반지름, 각도) 대신 시작점과 끝점의 데카르트 좌표 (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-flag0에서 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-flagSVG A를 매개 변수를. 위 코드에서sweep-flag매개 변수 의 값 은 항상 0입니다.arcSweep아마도 같은 이름으로 바뀌어야longArc합니다.