我對JavaScript和畫布很陌生,我有一個程序,它應該檢測在橢圓路徑上動畫的元素。它後來去形成一棵樹..但這是我連接到jsfiddle的基本結構。 它工作正常,沒有縮放或平移,但只要我嘗試縮放或平移,鼠標座標就會失靈。 我嘗試了以下markE的建議HTML5 canvas get coordinates after zoom and translate 但是我肯定是做錯了事,我很清楚不瞭解畫布和變換矩陣發生了什麼。我花了大約3天試圖改變這一切我能想到的組合,但我似乎無法推測出來:■縮放和平移畫布後鼠標座標不匹配
解決: 這裏是我的代碼以縮放和平移鼠標和動畫和在橢圓檢測元件: http://jsfiddle.net/metalloyd/A8hgz/
theCanvas = document.getElementById("canvasOne");
context = theCanvas.getContext("2d");
var status = document.getElementById('status');
var $canvas = $("#canvasOne");
var canvasOffset = $canvas.offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var scrollX = $canvas.scrollLeft();
var scrollY = $canvas.scrollTop();
var cw = theCanvas.width;
var ch = theCanvas.height;
var scaleFactor = 1.00;
var panX = 0;
var panY = 0;
var mainX = 250;
// setting the middle point position X value
var mainY = 100;
// setting the middle point position Y value
var mainR = 125;
// main ellipse radius R
var no = 5;
// number of nodes to display
var div_angle = 360/no;
var circle = {
centerX: mainX,
centerY: mainY + 100,
radius: mainR,
angle: .9
};
var ball = {
x: 0,
y: 0,
speed: .1
};
var a = 1.8;
//Ellipse width
var b = .5;
//Ellipse height
//Scale and Pan variables
var translatePos = {
x: 1,
y: 1
};
var startDragOffset = {};
var mouseDown = false;
var elements = [{}];
// Animate
var animateInterval = setInterval(drawScreen, 1);
//Animation
function drawScreen() {
context.clearRect(0, 0, cw, ch);
// Background box
context.beginPath();
context.fillStyle = '#EEEEEE';
context.fillRect(0, 0, theCanvas.width, theCanvas.height);
context.strokeRect(1, 1, theCanvas.width - 2, theCanvas.height - 2);
context.closePath();
context.save();
context.translate(panX, panY);
context.scale(scaleFactor, scaleFactor);
ball.speed = ball.speed + 0.001;
for (var i = 1; i <= no; i++) {
// male
new_angle = div_angle * i;
//Starting positions for ball 1 at different points on the ellipse
circle.angle = (new_angle * (0.0174532925)) + ball.speed;
//elliptical x position and y position for animation for the first ball
//xx and yy records the first balls coordinates
xx = ball.x = circle.centerX - (a * Math.cos(circle.angle)) * (circle.radius);
yy = ball.y = circle.centerY + (b * Math.sin(circle.angle)) * (circle.radius);
//Draw the first ball with position x and y
context.fillStyle = "#000000";
context.beginPath();
context.arc(ball.x, ball.y, 10, 0, Math.PI * 2, true);
context.fill();
context.closePath();
//alert("male Positions "+"X: "+ball.x+ " Y: "+ball.y);
// female
new_angle = div_angle * i + 4;
//Starting positions for ball 2 at different points on the ellipse
circle.angle = (new_angle * (0.0174532925)) + ball.speed;
//elliptical x position and y position for animation for the second ball
//ball.x and ball.y record the second balls positions
ball.x = circle.centerX - (a * Math.cos(circle.angle)) * (circle.radius);
ball.y = circle.centerY + (b * Math.sin(circle.angle)) * (circle.radius);
context.fillStyle = "#000000";
context.beginPath();
context.arc(ball.x, ball.y, 10, 0, Math.PI * 2, true);
context.fill();
context.closePath();
//alert("female Positions "+"X: "+ball.x+ " Y: "+ball.y);
//Record the ball positions in elements array for locating positions with mouse coordinates.
elements[i] = {
id: i,
femaleX: ball.x,
femaleY: ball.y,
maleX: xx,
maleY: yy,
w: 10 //radius of the ball to draw while locating the positions
};
//Text Numbering
context.beginPath();
context.fillStyle = "blue";
context.font = "bold 16px Arial";
context.fillText(elements[i].id, ball.x - 20, ball.y + 20);
context.closePath();
// line drawing--Connecting lines to the balls from the center.
context.moveTo(mainX, mainY);
context.lineTo((ball.x + xx)/2, (ball.y + yy)/2);
//Draw line till the middle point between ball1 and ball2
context.stroke();
context.fill();
context.closePath();
}
// center point
context.fillStyle = "#000000";
context.beginPath();
context.arc(mainX, mainY, 15, 0, Math.PI * 2, true);
context.fill();
context.closePath();
context.restore();
}
// Event Listeners
// Mouse move event to alert the position of the ball on screen
document.getElementById("plus").addEventListener("click", function() {
scaleFactor *= 1.1;
drawScreen();
}, false);
document.getElementById("minus").addEventListener("click", function() {
scaleFactor /= 1.1;
drawScreen();
}, false);
// Event listeners to handle screen panning
context.canvas.addEventListener("mousedown", function (evt) {
mouseDown = true;
startDragOffset.x = evt.clientX - translatePos.x;
startDragOffset.y = evt.clientY - translatePos.y;
});
context.canvas.addEventListener("mouseup", function (evt) {
mouseDown = false;
});
context.canvas.addEventListener("mouseover", function (evt) {
mouseDown = false;
});
context.canvas.addEventListener("mouseout", function (evt) {
mouseDown = false;
});
context.canvas.addEventListener("mousemove", function (evt) {
if (mouseDown) {
translatePos.x = evt.clientX - startDragOffset.x;
translatePos.y = evt.clientY - startDragOffset.y;
panX = translatePos.x;
panY = translatePos.y;
drawScreen();
}
evt.preventDefault();
evt.stopPropagation();
var mouseX = parseInt(evt.clientX - offsetX);
var mouseY = parseInt(evt.clientY - offsetY);
var mouseXT = parseInt((mouseX - panX)/scaleFactor);
var mouseYT = parseInt((mouseY - panY)/scaleFactor);
status.innerHTML = mouseXT + " | " + mouseYT;
for (var i = 1; i < elements.length; i++) {
var b = elements[i];
context.closePath();
context.beginPath();
context.arc(b.femaleX, b.femaleY, 10, 0, Math.PI * 2);
context.arc(b.maleX, b.maleY, 10, 0, Math.PI * 2);
if (context.isPointInPath(mouseXT, mouseYT)) {
theCanvas.style.cursor = 'pointer';
alert(b.id + " female.x: " + b.femaleX + " female.y: " + b.femaleY + " ball.x: " + ball.x + " ball.y: " + ball.y);
return;
} else theCanvas.style.cursor = 'default';
context.closePath();
}
});`
你代碼變得太大了。首先要把它分解成小部分,你可以簡單地進行單元測試。例如,有一個矩陣處理的單獨部分,並檢查它工作正常。編寫一些小的繪圖函數來簡化(drawBackground,drawBall,...),並將你的事件處理從你的代碼中解除關聯(你的mousemove就像60行!!)。用小測試的積木,你很快就會看到捕獲物的位置。 – GameAlchemist
哈哈!試圖讓它作爲一個整體工作,我陷入了一段迷霧。但我確實將其分解爲基礎知識。它確實得到解決。謝謝你的建議:) 我真的不知道爲什麼我以前沒有這麼想過。 – MetalloyD
這是一個常見的錯誤,不會看到複雜性已經達到「關鍵」的門檻,不用擔心。當我得到一個錯誤時,我總是懷疑它是否只是一個錯誤或我需要重構我的代碼的標誌。順便說一下,我沒有看到你發佈的編輯有太多的變化,給一個重構的例子,我做了drawScreen()的這個小提琴的重構(http://jsfiddle.net/gamealchemist/A8hgz/2/ – GameAlchemist