Pretty much since my first day at Motorola I have been working with HTML 5 canvases. I have been mostly working on creating a charting framework from scratch because the existing frameworks don't perform well enough.
Without going into too much detail, one of the newer pieces of functionality that I added was the ability to zoom into a section of the chart by dragging your mouse over a given area. JS Fiddle Link.
The first challenge was to figure out where on the canvas the mouse event is happening. All of the mouse events (move, down, etc) use the same event object so I created a helper function that would get the current coordinates from the current event object.
function getCursorPosition(e) {The crux here is to make sure to keep getting the offset of the each element because the parent might not be the window. Another thing I ran into with the mouse events was since I was handling the mousedown and mouseup events I had to add a flag on mousemove to indicate whether or not if the mouse action was a click event or not.
var totalOffsetX = 0;
var totalOffsetY = 0;
var canvasX = 0;
var canvasY = 0;
var currentElement = e.target;
do {
totalOffsetX += currentElement.offsetLeft - currentElement.scrollLeft;
totalOffsetY += currentElement.offsetTop - currentElement.scrollTop;
}
while (currentElement = currentElement.offsetParent)
canvasX = e.pageX - totalOffsetX;
canvasY = e.pageY - totalOffsetY;
return {
x: canvasX,
y: canvasY
}
}
The next piece of logic is the actual zoom function.
function zoom(point1, point2) {
var canvas = document.getElementById('myCanvas');
var translation = {
x: point2.x,
y: point2.y
};
var canvasMax = {
x: point1.x,
y: point1.y
};
if (point1.x < point2.x) {
translation.x = point1.x;
canvasMax.x = point2.x;
}
if (point1.y < point2.y) {
translation.y = point1.y;
canvasMax.y = point2.y;
}
currentTranslation.x += 1 / canvasScale.width * translation.x;
currentTranslation.y += 1 / canvasScale.height * translation.y;
canvasScale.width = canvasScale.width * canvas.width / (canvasMax.x - translation.x);
canvasScale.height = canvasScale.height * canvas.height / (canvasMax.y - translation.y);
drawPicture();
}
In he function I choose the upper left hand point of the rectangle as the points of the translation. I then figure out what the position should be based on the current zoom. Next we have to figure out the new scale based on the current scale, and the size of the rectangle that we selected. Once we have generated the scale and translation we can just plug them in our paint function.
While this code gave me a good start on what I needed, the actual implementation for the charting functionality is a bit more complicated due to having to scale the numbers on the graph without actually scaling the axis canvas.
No comments:
Post a Comment