トランスフォームマトリックス
簡単な答えが一番下です。あなたはどのようにして残りの部分を読むのか知りたければ。あなたはこの問題を解決するためにctx.setTransform(a, b, c, d, e, f);
を使用することができます
トランスフォームセットと狂気のABCの
。 ctx.transform
、ctx.rotate
、ctx.scale
、またはctx.translate
ではなく、既存のトランスフォームを掛け合わせるのではなく、既存のトランスフォームを置き換えるので、以前のトランスフォームを心配する必要はありません。
マジック引数は、x軸とy軸の方向とスケール、および原点のスクリーン座標として最もよく理解できます。
すべての値はピクセルの座標に関連しています。軸は、1つのピクセルの方向とサイズ、ピクセルの上部のaとb、左側のc、dを表します。 e、fは変換された座標0,0が現れる、原点と呼ばれるスクリーン上の座標です。
デフォルトでは、ピクセルはa = 1
に1ピクセルあり、ゼロピクセルはb = 0
になります。このピクセルは、c = 0
のゼロピクセルと、d = 1
の1ピクセルです。原点は左上にありますe = 0
、f = 0
;したがってさんは、より意味のある何かの変数を呼ぶことにしましょう。デフォルトはctx.setTransform(1,0,0,1,0,0);
を変換設定する
。彼らはベクトルであり、その軸xに対してxおよびy成分a = xAX
(X XIS Y成分)とb = xAY
(X XIS Y成分)を有しています。 y軸も同じです。c = yAX
とd = yAY
です。全部少し明確に(のような少ない泥を)作るctx.setTransform(xAx, xAy, yAx, yAy, ox, oy)
したがって、原点ox
ため、oy
(私はxAx
、xAy
、yAx
、yAy
大会からわずかな休憩を好みます)。
2軸は独立しており、任意の方向を指すことができ、任意の長さにすることができるため、等長投影などを作成できます。スケールは軸の長さによって決まります。 xスケールはx軸の長さで、yスケールはy軸の長さです。
軸のベクトルを作成するには、角度のxとy成分を返すときにcosとsinを使用します。私たちは45度(ラジアンにMath.PI/4)であることをx軸をしたい場合、我々は135度(にMath.PI *(3でy軸を望むのであれば、私たちは
var direction = Math.PI/4; // 45 deg down and right
var xAx = Math.cos(direction);
var xAy = Math.sin(direction);
を経由してベクトルを得ることができます/ 4)ラジアン)
var direction = Math.PI * (3/4); // 135 deg down and left
var yAx = Math.cos(direction);
var yAy = Math.sin(direction);
COSおよび罪なかれ単位ベクトル(ベクトルの規模が1であることを意味する1つの単位の長さであるベクトル)を作成する(効果なしスケールなし)
は変更しますベクトルのスケールは、xとyの両方の成分を乗算します。したがって、上記に加えて両方の軸をスケールしましょう。
var scale = 2; // zoom by 2
direction = Math.PI/4; // 45 deg down and right
xAx = Math.cos(direction) * scale;
xAy = Math.sin(direction) * scale;
direction = Math.PI * (3/4); // 135 deg down and left
yAx = Math.cos(direction) * scale;
yAy = Math.sin(direction) * scale;
今、私たちは、うまくいけば、あなたはこれがどのようにシンプル見ることができます変換
ctx.setTransform(xAx, xAy, yAx, yAy, ox, oy); // set the transform
ctx.strokeRect(0,0,20,10); // draws a rectangle 40 pixels (scale 2) at 45 deg
// and 20 pixels at 135 deg centered on the canvas
を作成するためにそれを使用するので、キャンバスの中央
var ox = ctx.canvas.width/2;
var oy = ctx.canvas.height/2;
に起源を設定することができます。
回答
あなたは私達がスケールを見つける必要がある側面は、必要なサイズのものであるようにスケーリングされる必要があるイメージを持っている場合。画像の幅が100ピクセルで、300ピクセルで表示する必要があるとします。スケールを取得するには、画面サイズを画像サイズで割ります。300/100 = 3
スケールは3です。
スケールは軸方向に依存しません。
x軸とy軸の角度、画像の幅と高さのサイズ、表示の幅と高さ、原点の位置をとる関数として、これらをすべてまとめることができます。その後、我々は、規模を計算軸を作成し、変換
function createTransform(angX, angY, imgWidth, imgHeight, displayWidth, displayHeight, originX, originY){
var scaleX = displayWidth/imgWidth; // get x scale
var scaleY = displayHeight/imgHeight; // get y scale
// create the x axis
var xAx = Math.cos(angX) * scaleX;
var xAy = Math.sin(angX) * scaleX;
// create the y axis
var yAx = Math.cos(angY) * scaleY;
var yAy = Math.sin(angY) * scaleY;
// set the transform
ctx.setTransform(xAx, xAy, yAx, yAy, originX, originY);
}
そして今、あなたが一致していない上記画像
// assume image is a loaded image
// axis at 45 and 135 deg make the display width and height 200,300 at the canvas center
createTransform(Math.PI/4, Math.PI * (3/4), image.width, image.height, 200, 300, ctx.canvas.width/2, ctx.canvas.height/2)
ctx.drawImage(image,0,0); // drawn to fit requirements.
コピーを描き、簡単な答えに
を貼り付けることができますを設定しますパターンと角度を使用しているときに必要なものは少し異なりますが、私があなたのためにソリューションをやっただけでは、問題の即時切り取りと貼り付けのソリューションを除いて、それほど多くは得られません。
function draw(widthIso, heightIso, imgObj) {
// rather than the messing around with the and rotations hand code the axis
// x axis
var xAx = 1;
var xAy = 0.5;
// y axis
var yAx = -1;
var yAy = 0.5;
// need the length of the axis so we can calculate a scale adjustment
var scaleX = Math.sqrt(xAx * xAx + xAy * xAy); // pythagoras to get the length of x axis
var scaleY = Math.sqrt(yAx * yAx + yAy * yAy); // pythagoras to get the length of y axis
// now we know how big a pixel is in isometric projection
// assuming you don't want to change the image pixel size from what you have in the fiddle
// I will workout the draw size
var drawWidth = widthIso/scaleX;
var drawHeight = heightIso/scaleY;
// get the width as sum of the product of axis x & y, x components
var canvasWidth = xAx * widthIso + yAx * heightIso;
// get the width as sum of the product of axis x & y, y components
var canvasHeight = xAy * widthIso + yAy * heightIso;
// create the canvas rounding up for size so we don't lose any pixels
var ca = document.createElement('canvas');
ca.width = Math.ceil(canvasWidth);
ca.height = Math.ceil(canvasHeight);
var ctx = ca.getContext('2d');
// now get the origin
var originY = 0; // always at the top
var originX = yAx * heightIso; // in by x component of height
// now just set the transform
ctx.setTransform(xAx, xAy, yAx, yAy, originX, originY);
// create pattern
var pattern = ctx.createPattern(imgObj.img, 'repeat');
ctx.fillStyle = pattern;
// draw with the corrected width and height
ctx.fillRect(0, 0, drawWidth, drawHeight);
// return the canvas image
return {canvas: ca, ctx: ctx, toLeft: originX};
}
これが行われます。キャンバス画像を作成するときにピクセルを丸めることを忘れないでください。エッジのピクセルが失われる可能性があります。
これは私がテストしたコードです。あなたの赤と青の線を中央に移動し、正確に200と300ピクセルの長さにしました。
// to visualise with red and blue lines.
var x = Math.cos(Math.atan2(0.5,-1))*150 + 230;
var y = Math.sin(Math.atan2(0.5,-1))*150 + 50;
ctx.strokeStyle = 'red';
ctx.beginPath();
ctx.moveTo(x, y); // no guessing
ctx.lineTo(x + Math.cos(Math.atan2(0.5,1))*200, y + Math.sin(Math.atan2(0.5,1))*200); //
ctx.stroke();
var x = Math.cos(Math.atan2(0.5,1))*100 + 230;
var y = Math.sin(Math.atan2(0.5,1))*100 + 50;
ctx.strokeStyle = 'blue';
ctx.beginPath();
ctx.moveTo(x, y); //
ctx.lineTo(x + Math.cos(Math.atan2(0.5,-1))*300, y + Math.sin(Math.atan2(0.5,-1))*300); //
ctx.stroke();