DragonFireGamesLvl 11
- Edited
p5.js offers transformation functions like rotate()
, translate()
, and scale()
which, when combined, allow for very complicated drawing. However, trying to detect whether or not someone is currently hovering their mouse over a transformed drawing is a nightmare. One usually has to track the translated amount in a variable and use that for mouse hovers, however, tracking rotation & scale is incredibly difficult.
Using transformation matrices, I have fixed that issue once and for all.
// You can put the below in a library if u want
window._boundGraphicsMethods = {};
window._bindGraphicsMethod = function(name,funct) {
window[name] = funct.bind(window);
window._boundGraphicsMethods[name] = funct;
}
window._createGraphics = window.createGraphics;
window.createGraphics = function(w,h,gl) {
var buf = window._createGraphics(w,h,gl);
buf.width *= buf._pixelDensity;
buf.height *= buf._pixelDensity;
for (var i in window._boundGraphicsMethods) {
buf[i] = window._boundGraphicsMethods[i].bind(buf);
}
return buf;
};
// Transforms
_bindGraphicsMethod("transformWorldToCanvas",function(x,y) {
// from world to canvas space
if (typeof x == "object") {
y = x.y;
x = x.x;
}
var s = this._pixelDensity; // Get pixel density
var matrix = this._renderer.drawingContext.getTransform(); // This is a DOMMatrix
matrix = matrix.invertSelf(); // Invert the matrix
var p = matrix.transformPoint({x:x*s,y:y*s,z:0,w:1}); // Transform the point
return {x:p.x,y:p.y};
});
_bindGraphicsMethod("transformCanvasToWorld",function(x,y) {
// from canvas to world space
if (typeof x == "object") {
y = x.y;
x = x.x;
}
var s = this._pixelDensity; // Get pixel density
var matrix = this._renderer.drawingContext.getTransform(); // This is a DOMMatrix
var p = matrix.transformPoint({x:x,y:y,z:0,w:1}); // Transform the point
return {x:p.x/s,y:p.y/s};
});
// Mouse Hovering
_bindGraphicsMethod("mouseRect",function(x,y,width,height) {
var p = this.transformWorldToCanvas(mouseX,mouseY);
return (
p.x > x &&
p.x < x+width &&
p.y > y &&
p.y < y+height
);
});
_bindGraphicsMethod("mouseEllipse",function(cx,cy,width,height) {
var p = this.transformWorldToCanvas(mouseX,mouseY);
var dx = (p.x - cx) / width;
var dy = (p.y - cy) / (height||width);
var dist = dx*dx + dy*dy;
return dist < 0.25;
});
// END
function draw() {
background(255);
translate(200,200);
var t = frameCount/100;
push();
translate(noise(t,0)*50,noise(t,1)*50);
scale(cos(t+45)*2,cos(t)*2);
rotate(t*90);
translate(50,0);
var h = mouseRect(20,5,20,10);
fill(h?100:200);
rect(20,5,20,10);
var p = transformCanvasToWorld(20,5);
pop();
push();
translate(noise(t,3)*50,noise(t,4)*50);
scale(cos(t-45)*2,cos(t)*2);
rotate(t*-45);
translate(50,0);
var h2 = mouseEllipse(-30,-5,20,15);
fill(h2?100:200);
ellipse(-30,-5,20,15);
pop();
translate(-200,-200);
rect(p.x,p.y,10,10);
}
By transforming the mouseX, and mouseY to "canvas space" from "world space" you can detect mouse hover regardless of transformation. This also works in p5!
(Graphics binding fixes pixelDensity problems)
Please note that the graphics will not be accurate unless drawn like image(buf,0,0)