캔버스에서는 아크 방법을 사용하여 쉽게 원을 그릴 수 있습니다. 원래 원은 너비와 높이가 같은 타원으로 간주 될 수 있지만 캔버스에서 타원을 그릴 방법은 없습니다. 다른 방법을 사용하여 시뮬레이션해야합니다.
우선 타원을 그리는 데 필요한 매개 변수를 명확히해야합니다. 기본 기하학적 지식에 따르면 타원은 중심 좌표, 너비, 높이 또는 회전 각도가 필요하다는 것을 알려줍니다. 그러나 시간 동안 피할 수 있습니다. 회전은 비교적 쉽습니다.
1. Lineto를 사용하여 타원을 그립니다 직선을 그리는 데 순전히 사용되는 방법 인 Lineto는 실제로 타원을 그리는 데 사용될 수 있습니다! ? 그러나 그는 존재하지만 글쓰기 스타일은 정말 믿어지지 않습니다.함수 DrawEllipse (Canvas, O, OA, OB) {
// 타원을 그립니다. 예 : var b = 새 배열 (150,150); DrawEllipse (HB, B, 50,30);
(캔버스) {
var x = o [0]+OA;
var y = o [1];
moveto (x, y);
for (var i = 0; i <= 360; i ++) {
var II = i*Math.pi/180;
var x = o [0]+oa*math.cos (ii);
var y = o [1] -ob*math.sin (ii);
Lineto (x, y);
}
}
}
이 방법의 원리는 원이 360도를 가지므로 Lineto를 사용하여 360 회 루프를 사용하여 각 학위의 선 세그먼트를 그린 다음 마침내 타원에 연결합니다. 그중에서도 Trigonometric Function Sine Cosine은 계산에 사용해야합니다.
이 방법의 두 번째 매개 변수는 배열, 즉 타원의 중심 좌표입니다.
아이디어는 매우 이상하며 타원은 비교적 매끄 럽습니다. 그러나 사용할 가치가 없습니다.이 방법은 타원마다 360 사이클이 필요합니다. 타원이 그려 질 때만 브라우저의 성능에 대한 약간의 테스트입니다.
우리는 단지 그의 아이디어를 이해하면됩니다
2. Arc를 사용하여 원을 그리고 타원으로 확장하십시오. 이 방법의 원본 텍스트는 여기에 있으며 핵심 함수는 다음과 같습니다.var canvas = document.getElementById ( 'mycanvas');
var context = canvas.getContext ( '2d');
var centerx = 0;
var centery = 0;
var 반경 = 50;
// 상태 저장
context.save ();
// 컨텍스트를 번역합니다
context.translate (canvas.width / 2, canvas.height / 2);
// 컨텍스트를 가로로 스케일
Context.Scale (2, 1);
// 타원으로 뻗어있는 원을 그리는 원
context.beginpath ();
context.arc (centerx, centery, radius, 0, 2 * math.pi, false);
// 원래 상태로 복원합니다
Context.Restore ()
이 방법은 이전에 언급하지 않은 캔버스 기능, 즉 캔버스의 스케일링을 실현할 수있는 캔버스 기능을 사용합니다. 스케일링에는 수평과 수직의 두 방향이 있습니다. 코드는 캔버스의 수평 방향을 확대하는 반면 수직 방향은 변경되지 않습니다. 따라서 아크로 그려진 원은 타원으로 변합니다.
이 방법은 코드가 거의없는 언뜻보기에 매우 훌륭하며 원칙은 간단하고 이해하기 쉽습니다. 그러나 그것을 분석 한 후에는 그의 명백한 결점, 즉 부정확 한 것입니다! 예를 들어, 너비 171, 높이가 56 인 타원이 필요합니다. ARC 반경을 28로 설정하면 후속 171/28/2의 후속 수는 저하됩니다.
그러나 항상 아크 반경을 100으로 설정하는 타협 방법이 있으며, 충분하지 않으면 확대되고 초과하면 감소됩니다. 그러나 여전히 부정확합니다.
3. Bezier Curveto를 사용하십시오 위의 스케일링 방법이 부정확하다고 느꼈기 때문에 타원을 그리는 정확한 방법을 찾고자하고 마침내 StackoverFlow에서 찾았습니다.함수 DrawEllipse (ctx, x, y, w, h) {
var kappa = 0.5522848;
ox = (w / 2) * 카파, // 제어점 오프셋 가로
Oy = (H / 2) * Kappa, // 제어점 오프셋 세로
xe = x + w, // x-end
Ye = y + h, // y-end
xm = x + w / 2, // x-middle
ym = y + h / 2; // y-Middle
ctx.beginpath ();
ctx.moveto (x, ym);
ctx.beziercurveto (x, ym -oy, xm -ox, y, xm, y);
ctx.beziercurveto (xm + ox, y, xe, ym -oy, xe, ym);
ctx.beziercurveto (xe, ym + oy, xm + ox, ye, xm, ye);
ctx.beziercurveto (xm -ox, ye, x, ym + oy, x, ym);
ctx.closepath ();
ctx.stroke ();
}
이 방법은 완벽한 것으로 간주 될 수 있습니다. 그는 타원을 4 개의 베 지어 곡선으로 나누고 타원에 연결했습니다. 최종 너비와 높이도 비교적 정확하며 오버 헤드가 적습니다.
그러나이 방법에는 여전히 단점이 있습니다. 모두가 Kappa 매개 변수를보고 매우 이상한 가치가 있습니다. 나는 많은 사람들이 지오메트리 전문가가 왜이 가치를 취하고 싶은지 알려주기 전에 왜이 가치를 취해야하는지 이해하지 못한다고 생각합니다. 그리고 나는 그를 바꾸고 그 결과가 무엇인지 확인하려는 강한 충동을 가졌습니다.
물론, 강박 장애 질환 환자와 유사한 나의 충동은이 방법의 단점이라고 말할 수 없습니다. 그의 진정한 단점은 - 왜 4 개의 Bezier 곡선을 사용해야합니까? 나는 개인적으로 타원이 분명히 4 개가 아닌 두 개의 베 지어 곡선으로 구성되어 있다고 생각합니다. 이 아이디어는 결국 타원을 그리는 가장 완벽한 방법을 찾게되었습니다.
4. 두 개의 Besel 곡선을 사용하여 타원을 그립니다
이전 방법을 간소화 할 수 있는지 이해하기 위해 질문을하기 위해 stackoverflow 계정을 특별히 등록했습니다. 문제에 그림이 있으므로 포인트를 전송할 수 없습니다. 외국인의 질문에 대답하여 포인트를 얻기 위해 간신히 영어 능력을 사용해야했습니다. 그러나 결국 행운이 와서 질문에 대답하면 내 요점 문제가 해결되었습니다.
나는 Besel 곡선과 타원 사이의 관계 문제를 제기했습니다.
솔직히 말해서, 나는 아래의 대부분의 외국인의 답변을 이해하지 못했지만 다행히도 그는 코드 샘플 페이지를 제공하여 원칙을 이해하게했으며 다시 감사하고 싶습니다. 그의 대답에 따르면, 타원을 그리는 데 찾은 방법은 다음과 같습니다.
//타원형
CanvasRenderingContext2d.prototype.oval = 함수 (x, y, 너비, 높이) {
var k = (너비/0.75)/2,
w = 너비/2,
H = 높이/2;
this.beginpath ();
this.moveto (x, yh);
this.beziercurveto (x+k, yh, x+k, y+h, x, y+h);
this.beziercurveto (xk, y+h, xk, yh, x, yh);
this.closepath ();
이것을 반환하십시오;
}
이 방법은 정확하고 코드가 거의 없으며 이상하고 이해하기 어렵지 않습니다. 타원을 그리는 Besel 곡선의 제어점에 대한 타원 폭의 좌표 비율은 다음과 같습니다.
베셀 제어 지점 x = (타원 너비/0.75)/2는 이미 코드에 반영되어 있습니다.
위의 네 가지 방법을 테스트하여 타원을 그릴 수 있습니다.
더 쉬운 방법을 찾으면 공유하고 토론하십시오.