ARCTO를 SVG specification에 입력하면 Canvas과 매우 다릅니다. SVG 스펙에 따라 데이터를 가져올 유스 케이스가 있지만 Canvas에 그 데이터를 그려야합니다.SVG ARCTO를 HTML 캔버스에 매핑하는 중 ARCTO
나는 이것을 시도했지만 나의 기하학은 약하다. 좀 도와 줄 수있어?
ARCTO를 SVG specification에 입력하면 Canvas과 매우 다릅니다. SVG 스펙에 따라 데이터를 가져올 유스 케이스가 있지만 Canvas에 그 데이터를 그려야합니다.SVG ARCTO를 HTML 캔버스에 매핑하는 중 ARCTO
나는 이것을 시도했지만 나의 기하학은 약하다. 좀 도와 줄 수있어?
svg 타원과 캔버스 호의 차이점은 svg에 2 개의 반경이 있고 arcTo에 하나의 반경이 있다는 것입니다. 그런 다음 캔버스에서 특정 각도로 호를 회전해야합니다. 2 개의 반경을 에뮬레이션하려면 가장 작은 반경을 가진 주어진 좌표로 호를 만들어야합니다. 그런 다음이 호를 계수 (rx/ry)를 사용하여 특정 방향으로 스케일해야합니다. 이제는 회전 만하면됩니다. 그러나이 접근 방식에서는 타원형의 어떤 부분을 표시할지 결정하기가 정말 어렵습니다. 왜냐하면 타원형의 크기가 큰 아크 플래그와 스윕 플래그에 달려 있기 때문입니다. 또 다른 문제는 끝 좌표 (svg spec에서)로 아크를 제한하는 것입니다. 따라서 arcTo를 사용하면 타원의 최대 반을 만들 수 있습니다.
타원에 3 개의 제어점 좌표가있는 경우 bezierCurveTo (x0, y0, x1, y1, x2, y2)를 사용하여 타원의 일부를 그릴 수도 있습니다. 이 접근 방식을 사용하면 타원의 모든 세그먼트를 만들 수 있습니다. 물론 PI 이외의 세그먼트의 경우 최소 두 개의 곡선이 필요합니다.
SVG 사양에서 (x 축 회전 큰 아크 플래그 스윕 플래그 x y)가 있습니다. 그래서 샘플 경로는 그렇게 될 것입니다 : 당신이 그려 방법을 베 지어 곡선을 찾을 수 있습니다
M100,100 a25,50 -30 0,1 50,-25
Here.
이제 (100,100 임) 컨텍스트 점 있고, (100 + 50,100-25입니다)를 끝 지점는 당신은 -30도까지 회전하기 전에 제어 지점을 계산해야합니다. 다음나를 위해 작동 예
는 :$(document).ready(function(){
var startX = 100;
var startY = 100;
var dX = 50;
var dY = -25;
var angle = -30;
var rx = 25;
var ry = 50;
var svg = Raphael($('#svg')[0], 200, 200);
var path = "M" +startX + "," + startY + " a" + rx + "," + ry + " " + angle + " 0,1" + " " + dX + "," +dY;
svg.path(path).attr({"stroke-width" : 2, "stroke" : "#FFFFFF"});
var kappa = .5522848,
ox = rx*kappa,
oy = ry*kappa,
xm = startX + rx, // x-middle
ym = startY + ry; // y-middle
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.moveTo(startX,startY);
ctx.bezierCurveTo(startX, startY - oy, startX + ox, startY - ry, startX + rx, startY - ry);
ctx.bezierCurveTo(startX + rx + ox, startY - ry, startX + 2*rx, startY - oy, startX + dX, startY + dY);
ctx.stroke();
});
마크 업 단순히 : 나는이 -30도까지 조절 점을 회전 didnt가 있기 때문에
<div id="svg" style="border: 1px solid black;position : absolute;top : 50px;left : 50px;"></div>
<canvas id="canvas" width="200px" height="200px" style="border: 1px solid black;position : absolute;top : 300px;left : 50px;"></canvas>
곡선이 유사하지 않다. 그러나 나는 그것이 당신이해야 할 유일한 일이라고 믿습니다. 왜냐하면 당신이 각도 = 0을 넣을 것이기 때문입니다. 그들은 비슷할 것입니다. this 기사를 사용하여 회전을위한 수학을 얻을 수 있습니다.
PS : 나는 "M100,100 a25,50 -30 0.1 50 -25"지도하려고 할 때 캔버스에 this 대답
에서 코드의 일부를했다 내 함수를 사용합니다. 허락 된 원호를 사용하여 이것을 작성했습니다.
ellipse (100,100,50, -25,50, false);
function ellipse(x1, y1, x2, y2, radius, clockwise) {
var cBx = (x1 + x2)/2; //get point between xy1 and xy2
var cBy = (y1 + y2)/2;
var aB = Math.atan2(y1 - y2, x1 - x2); //get angle to bulge point in radians
if (clockwise) { aB += (90 * (Math.PI/180)); }
else { aB -= (90 * (Math.PI/180)); }
var op_side = Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2))/2;
var adj_side = Math.sqrt(Math.pow(radius, 2) - Math.pow(op_side, 2));
if (isNaN(adj_side)) {
adj_side = Math.sqrt(Math.pow(op_side, 2) - Math.pow(radius, 2));
}
var Cx = cBx + (adj_side * Math.cos(aB));
var Cy = cBy + (adj_side * Math.sin(aB));
var startA = Math.atan2(y1 - Cy, x1 - Cx); //get start/end angles in radians
var endA = Math.atan2(y2 - Cy, x2 - Cx);
var mid = (startA + endA)/2;
var Mx = Cx + (radius * Math.cos(mid));
var My = Cy + (radius * Math.sin(mid));
context.arc(Cx, Cy, radius, startA, endA, clockwise);
}
다음 코드 세그먼트가 날 좋아 거기에 당신의위한 게이브 러너의 광범위한 CANVG 패키지의 관련 섹션 (https://github.com/canvg/canvg 참조)에서 추출, 게이브의 패키지의 돈벼락을하지 않을 수 있습니다. 이전 솔루션과는 달리 근사치는 아니며 Gabe에게 엄청난 감사의 말을 전하는 SVG 아크 경로 요소와 정확히 동일합니다.
경로를 그리기 전에 이미 캔버스에 일부 크기 조절 및/또는 변환을 적용한 경우이를 Context.translate에 대한 두 번 호출의 매개 변수로 고려해야하며 Context.arc에 대한 호출의 radius 매개 변수에
function drawSVGarcOnCanvas (Context,lastX,lastY,rx,ry,xAxisRotation,largeArcFlag,sweepFlag,x,y)
{
//--------------------
// rx, ry, xAxisRotation, largeArcFlag, sweepFlag, x, y
// are the 6 data items in the SVG path declaration following the A
//
// lastX and lastY are the previous point on the path before the arc
//--------------------
// useful functions
var m = function ( v) {return Math.sqrt (Math.pow (v[0],2) + Math.pow (v[1],2))};
var r = function (u, v) {return (u[0]*v[0] + u[1]*v[1])/(m(u) * m(v))};
var ang = function (u, v) {return ((u[0]*v[1] < u[1]*v[0])? -1 : 1) * Math.acos (r (u,v))};
//--------------------
var currpX = Math.cos (xAxisRotation) * (lastX - x)/2.0 + Math.sin (xAxisRotation) * (lastY - y)/2.0 ;
var currpY = -Math.sin (xAxisRotation) * (lastX - x)/2.0 + Math.cos (xAxisRotation) * (lastY - y)/2.0 ;
var l = Math.pow (currpX,2)/Math.pow (rx,2) + Math.pow (currpY,2)/Math.pow (ry,2);
if (l > 1) {rx *= Math.sqrt (l); ry *= Math.sqrt (l)};
var s = ((largeArcFlag == sweepFlag)? -1 : 1) * Math.sqrt
(((Math.pow (rx,2) * Math.pow (ry ,2)) - (Math.pow (rx,2) * Math.pow (currpY,2)) - (Math.pow (ry,2) * Math.pow (currpX,2)))
/(Math.pow (rx,2) * Math.pow (currpY,2) + Math.pow (ry,2) * Math.pow (currpX,2)));
if (isNaN (s)) s = 0 ;
var cppX = s * rx * currpY/ry ;
var cppY = s * -ry * currpX/rx ;
var centpX = (lastX + x)/2.0 + Math.cos (xAxisRotation) * cppX - Math.sin (xAxisRotation) * cppY ;
var centpY = (lastY + y)/2.0 + Math.sin (xAxisRotation) * cppX + Math.cos (xAxisRotation) * cppY ;
var ang1 = ang ([1,0], [(currpX-cppX)/rx,(currpY-cppY)/ry]);
var a = [( currpX-cppX)/rx,(currpY-cppY)/ry];
var b = [(-currpX-cppX)/rx,(-currpY-cppY)/ry];
var angd = ang (a,b);
if (r (a,b) <= -1) angd = Math.PI;
if (r (a,b) >= 1) angd = 0;
var rad = (rx > ry)? rx : ry;
var sx = (rx > ry)? 1 : rx/ry;
var sy = (rx > ry)? ry/rx : 1;
Context.translate (centpX,centpY);
Context.rotate (xAxisRotation);
Context.scale (sx, sy);
Context.arc (0, 0, rad, ang1, ang1 + angd, 1 - sweepFlag);
Context.scale (1/sx, 1/sy);
Context.rotate (-xAxisRotation);
Context.translate (-centpX, -centpY);
};
게이브 코드를 게시 할 수있는 권한이 있습니까? 나는. 면허가 이것을 허락합니까? –
내 사례에 대한 참조를 찾을 수 없습니다. – AppleGrew
나는 나의 대답을 편집했다 –
고마워. 접근법 2가 더 좋습니다. 접근법 1에는 스케일링이 필요하며, 이것은 바람직하지 않은 부작용을 일으 킵니다. 이렇게하면 확장 된 스 토크 부분이 확장되어 곡선이 고르지 않게 두꺼워집니다. – AppleGrew