캔버스에서는 원호 방식을 이용하면 쉽게 그릴 수 있습니다. 원래 원은 너비와 높이가 같은 타원으로 간주할 수도 있지만, 캔버스에서는 타원을 그릴 수 있는 방법이 없습니다. 그것을 시뮬레이션합니다.
타원을 그리는 데 필요한 매개변수가 무엇인지 먼저 명확히 해야 합니다. 기본 기하학적 지식에 따르면 타원에는 중심 좌표, 너비, 높이 또는 회전 각도가 필요하지만 당분간은 생략할 수 있으므로 회전이 더 쉽습니다.
1. lineTo를 사용하여 타원 그리기
읽으셨군요. 순전히 직선을 그리는 데 사용되는 메서드인 lineTo를 실제로 타원을 그리는 데 사용할 수 있습니다! ? 하지만 존재하지만 작성 방법이 정말 놀랍습니다.
function DrawEllipse(Canvas,O,OA,OB){
//타원 그리기, 예: var B=new Array(150,150); DrawEllipse(hb,B,50,30) ;
(캔버스){
var x=O[0] OA
moveTo(x,y); 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번 반복하고 각 각도에 대한 선분을 그린 다음 마지막으로 타원으로 연결합니다. 계산에는 삼각함수 사인과 코사인이 필요합니다.
이 메서드의 두 번째 매개 변수는 타원의 중심 좌표인 배열입니다.
아이디어가 매우 이상하고 타원이 비교적 매끄럽게 그려집니다. 그러나 모든 사람이 사용할 가치는 없습니다. 이 방법은 타원을 그릴 때마다 360번 순환하며 브라우저 성능 테스트인 타원을 약간만 더 그립니다.
그의 아이디어를 이해하면 됩니다
2. 호를 사용하여 원을 그린 다음 타원으로 크기를 조정합니다
이 방법의 원문은 여기에 있으며 핵심은 다음과 같습니다. 함수는 다음과 같습니다.
var context = canvas.getContext('2d');
var centerX = 0
var centerY = 0;
// 상태 저장
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인 타원이 필요합니다. 호의 반경을 28로 설정하면 고통스럽고 이해할 수 없는 숫자 171/28/2에 우울해집니다.
단, 호의 반경을 항상 100으로 설정하고, 부족하면 늘리고, 초과하면 줄이는 것이 절충안입니다. 그러나 아직은 정확하지 않습니다.
3, 베지어 곡선 사용 bezierCurveTo
위의 크기 조정 방법이 정확하지 않다고 느꼈기 때문에 타원을 그리는 정확한 방법을 찾고 싶었고 마침내 stackoverflow에서 찾았습니다.
코드 복사
oy = (h / 2) * kappa, // 제어점 수직 오프셋
xe = x w, // x 끝
ye = y h, // y 끝
xm = x w / 2, // x 중간
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.strok()
;
이 방법은 완벽하다고 할 수 있습니다. 그는 타원을 네 개의 베지어 곡선으로 나누고 이를 연결하여 타원을 형성했습니다. 마지막으로 너비와 높이가 더 정확해지고 오버헤드가 줄어듭니다.
그러나 이 방법에는 여전히 단점이 있습니다. 카파 매개변수를 보면 매우 특이한 값이 있습니다. 기하학 전문가가 왜 이 값이어야 하는지 설명하기 전까지는 많은 사람들이 왜 이 값이어야 하는지 이해하지 못한다고 생각합니다. 저는 아직도 모르겠습니다. 그리고 나는 그것을 바꾸고 그 결과가 어떻게 될지 보고 싶은 강한 충동을 가지고 있습니다.
물론 강박장애 환자와 유사한 충동이 이 방법의 단점이라고 할 수는 없습니다. 왜 4개의 베지어 곡선을 사용합니까? 나는 개인적으로 타원이 분명히 4개의 베지어 곡선이 아닌 2개의 베지어 곡선으로 구성되어 있다고 생각합니다. 이 아이디어는 결국 타원을 그리는 완벽한 방법으로 이어졌습니다.
4
두 개의 베지어 곡선을 사용하여 타원을 그린다
이전 방법을 단순화할 수 있는지 알아보기 위해 특별히 stackoverflow 계정을 등록했는데, 에 사진이 있기 때문이다. 질문, 양도할 포인트가 부족하여 포인트를 적립하기 위해 외국인의 질문에 답하기 위해 겨우 부족한 영어를 사용해야 했습니다. 그런데 마침내 행운이 찾아왔고, 질문에 답함으로써 포인트 문제가 해결되었습니다.
베지어 곡선과 타원의 관계에 대해 제가 질문한 내용은 여기에 있습니다.
솔직히 아래 외국인 답변을 대부분 이해하지 못했는데 다행히 코드 샘플 페이지를 제공해 주셔서 이해가 되었습니다. 원칙님, 다시 한 번 그분께 감사의 말씀을 전하고 싶습니다. 그의 답변에 따르면 타원을 그리는 방법은 다음과 같습니다.
//Ellipse
CanvasRenderingContext2D.prototype.oval = function (x, y, width, height) {
var k = (width/0.75)/2,
w = 너비/2,
h = 높이/2;
this.beginPath();
this.moveTo(x, y-h)
this.bezierCurveTo(x k, y-h, x k , y h, x, y h );
this.bezierCurveTo(x-k, y h, x-k, y-h, x, y-h)
this.closePath()
return this;
이 방법은 정확하고 코드가 덜 필요하며 이상한 점이 없습니다. 이것만 기억하세요, 타원을 그리는 베지어 곡선의 제어점 좌표에 대한 타원의 너비의 비율은 다음과 같습니다.
베지어 제어점 x=(타원 너비/0.75)/2 이것은 이미 반영된 코드에서.
타원을 그리려면 위의 4가지 방법을 시도해 볼 수 있습니다.
더 간단한 방법을 찾으면 공유하여 토론해 주세요.