ARCTO SVG specification與我們在Canvas中的ARCTO很不相同。我有一個用例,我將按照SVG規範獲取數據,但我需要在Canvas上繪製該數據。將SVG ARCTO映射到HTML畫布ARCTO
我試過這個,但我猜我的幾何體很弱。你能幫忙嗎?
ARCTO SVG specification與我們在Canvas中的ARCTO很不相同。我有一個用例,我將按照SVG規範獲取數據,但我需要在Canvas上繪製該數據。將SVG ARCTO映射到HTML畫布ARCTO
我試過這個,但我猜我的幾何體很弱。你能幫忙嗎?
svg橢圓和畫布弧的區別在於,在svg中有兩個半徑,而在arcTo中只有一個半徑。然後,您還需要在畫布上以特定角度旋轉弧線。要模擬2個半徑,需要用給定的半徑最小的座標製作一個弧。然後,您需要以係數(rx/ry)在特定方向上縮放此弧線。現在你只需要旋轉。但是在這種方法中,真的很難弄清楚你想要顯示的橢圓的哪一部分,因爲它取決於svg規範中的大弧標記和掃描標記。另一個問題是通過結束座標(來自svg規範)來限制弧線。所以通過arcTo,我可以建立一個橢圓的最大值的一半。如果您的橢圓上有3個控制點的座標,您還可以使用bezierCurveTo(x0,y0,x1,y1,x2,y2)繪製橢圓的一部分。通過這種方法,您可以構建橢圓的任何部分。當然,對於比PI更多的段,您至少需要兩條曲線。您可以從SVG規範(rx ry 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();
});
標記無非是:
<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>
曲線是不相似的,因爲我沒有旋轉控制點到-30度。但我相信這是你唯一需要做的事情。因爲如果你會把角度= 0.他們會類似 你可以使用this文章來獲得旋轉的數學。
PS:我把代碼的某些部分從this答案
當試圖映射 「M100,100 a25,50 -30 0,1 50,-25」 到畫布上用我的功能。 當然,我在腦海中寫了這個圓弧。
橢圓(100,100,50,-25,50,假);
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的包的整個九碼。與以前的解決方案不同,它不是一個近似值,而是我非常感謝Gabe的SVG弧路徑元素的精確等價物。
還有一點是,如果您在繪製路徑之前已經在畫布上應用了一些縮放比例和/或平移,則需要將這個參數分成兩個對Context.translate調用的參數,還有進入調用的半徑參數Context.arc
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);
};
您是否有權發佈Gabe的代碼?即許可證是否允許這樣做? –
我找不到任何對我的情況的參考。 – AppleGrew
我編輯了我的答案 –
謝謝。方法二更好。方法一需要縮放,這會產生一個不希望的副作用。這將導致縮小的行程部分擴大,使曲線不均勻地變厚。 – AppleGrew