Javascript mouseout event not working - javascript

I am trying to stop the flagwave on mouseout but its not working. Once i mouseover it works but once i mouseout the mouseover action is looping its not stopping. Can i know whats the mistake i have done.
This is my js code:
elem.addEventListener("mouseout", mouseOut , false);
function mouseOut(event) {
var mouseX,
mouseY;
event.preventDefault(); // stops browser to do what it normally does
// determine where mouse is
mouseX = event.pageX;
mouseY = event.pageY;
// do something useful, e.g. change the flag to waving when mouse is over flag
clearBangladesh();
}
function clearBangladesh(){
canvas.clearRect(0,0,300, 150);
drawBangladesh();
}
THis is the code for the animation:
function waveFlag( canvas, wavelength, amplitude, period, shading, squeeze ){
if (!squeeze) squeeze = 0;
if (!shading) shading = 100;
if (!period) period = 200;
if (!amplitude) amplitude = 10;
if (!wavelength) wavelength = canvas.width/10;
var fps = 30;
var ctx = canvas.getContext('2d');
var w = canvas.width, h = canvas.height;
var od = ctx.getImageData(0,0,w,h).data;
// var ct = 0, st=new Date;
return setInterval(function(){
var id = ctx.getImageData(0,0,w,h);
var d = id.data;
var now = (new Date)/period;
for (var y=0;y<h;++y){
var lastO=0,shade=0;
var sq = (y-h/2)*squeeze;
for (var x=0;x<w;++x){
var px = (y*w + x)*4;
var pct = x/w;
var o = Math.sin(x/wavelength-now)*amplitude*pct;
var y2 = y + (o+sq*pct)<<0;
var opx = (y2*w + x)*4;
shade = (o-lastO)*shading;
d[px ] = od[opx ]+shade;
d[px+1] = od[opx+1]+shade;
d[px+2] = od[opx+2]+shade;
d[px+3] = od[opx+3];
lastO = o;
}
}
ctx.putImageData(id,0,0);
},1000/fps);
}
This is the mouseover function:
function mouseMove(event) {
var elem = document.getElementById('bangladesh-canvas');
var mouseX,
mouseY;
event.preventDefault(); // stops browser to do what it normally does
// determine where mouse is
mouseX = event.pageX;
mouseY = event.pageY;
// do something useful, e.g. change the flag to waving when mouse is over flag
waveFlag( elem, 50, 5, 200, 250, -0.1 );
}
Is this the rightway to stop an event on mouse out? Thanks in advance

Your waveFlag() animation function works by calling setInterval(), which queues up some code to be run at regular intervals forever - unless you cancel it or navigate away from the page. So how to cancel it? It returns an id. You need to call clearInterval() and pass that id, which means you need to actually store the id value in a variable as shown below.
Also, both your mouseover and mouseout handlers have a lot of unnecessary code that doesn't do anything: you create variables and assign values but never use those variables. And there is no need to call preventDefault() because neither event has default behaviour that needs cancelling. So, try something like this:
var intervalId;
function mouseMove(event) {
var elem = document.getElementById('bangladesh-canvas');
intervalId = waveFlag( elem, 50, 5, 200, 250, -0.1 );
}
function mouseOut(event) {
clearInterval(intervalId);
clearBangladesh();
}
Keep your existing calls to elem.addEventListener() as they are.

event.preventDefault() is the common way to stop an event's default behavior from occurring. Also, try e.stopPropagation(), in case your event is bubbling up anywhere else in your code. The final thing to attempt is returning false from the function.
However, you might need to show code related to drawBangladesh(), as that may be the cause of your continuous looping, and without it I can't say for certain that your issue is the event handler.
If you're not too keen on event handling, this MDN page may help: https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Tutorial/More_Event_Handlers#Prevent_Default_Action

Related

Javascript Mouse tracking variable not switching from false to true

I am making a pretty simple game demo as part of my senior project, in which I'm trying to make a basic matching game that can help teach some basic mathematical skills. I would like to have the player be able to flip over cards to check if they have the right answer, however, the variable I am using to track whether or not the mouse is being clicked doesn't seem to ever register as true.
var isMouseDown = false;
c.onmousedown =
function(evt) { isMouseDown = true; };
c.onmouseup =
function(evt) { isMouseDown = false; };
// Keep track of where the mouse is
var mouse = {x: 0, y: 0};
c.onmousemove =
function(evt) {
mouse.x = evt.clientX;
mouse.y = evt.clientY;
};
This is where I use the variable:
this.clicked = function() {
c.strokeRect(500, 500, 20, 20);
if (isMouseDown) {
c.strokeRect(400, 400, 20, 20);
var diffX = mouse.x - this.x;
var diffY = mouse.y - this.y;
if (0 <= diffX <= 40) {
var xInRange = true;
} else {
xInRange = false;
}
if (0<= diffY <= 60) {
var yInRange = true;
c.strokeRect(this.x + 10, this.y + 25, 20, 20);
} else {
yInRange = false;
}
if (xInRange && yInRange) {
this.flip();
}
}
};
I have thrown in a few instructions for the canvas to build a box to see if it is compiling that part of the code, and it looks like the first one is being drawn when I run the program, but the second one (the one in the if statement) isn't, so I figured that would be where I'm running into a problem.
EDIT: Here is where I call on the function (this isn't finished, so there's a few pieces of code lying around unused):
var cmTID;
var timeStep = 50; //milliseconds
var numCards = 10;
function update() {
var card = new Card(10, 10, 60, 40, 5);
card.draw();
card.clicked();//nothing after this compiles atm
c.strokeRect(200, 200, 30, 30);
clearTimeout(cmTID);
cmTID = setTimeout(update, timeStep);
}
I don't have a ton of experience in Javascript, though I have done a fair amount of work in Java for AP Computer Science, which I took my sophomore year. And if you are wondering, yes, I bit off a little more than I could chew here :P
Can anyone give me pointers on what might be going wrong here? Thanks!
It seems that you are trying to add mouse events to the context c. Instead add it to the actual canvas element.

Changing canvas drawn image on mouseover

I'm really struggling with the changing of my canvas drawn image so I thought I would see if anyone could assist me on here or offer advice.
I've drawn a static flag in canvas, and I've also drawn a waving flag. I'm trying to get this flag to wave on mouseover.
I initially thought that I was going to have to create two separate files, one for the static and one for the waving aspect. Then save each of them as a jpg/gif image using window.location = canvas.toDataURL("image/");.
But I've just discovered that you can apparently do this all in the same file via jquery/hover. Which seems a lot simpler and a more efficient way of doing it.
Here is the code for the waving flag:
window.onload = function(){
var flag = document.getElementById('banglaFlag');
banglaStatic( flag, 320 );
var timer = banglaWave( flag, 30, 15, 200, 200 );
};
function banglaStatic( canvas, width ){
//Drawing the Bangladesh flag.
//Declaring variables that regard width and height of the canvas.
//Variables C to L are needed for the waving function.
var a = width / 1.9;
var b = 200;
var c = 7*a/13;
var l = a / 13;
canvas.width = b;
canvas.height = a;
var ctx = canvas.getContext('2d');
var radius = 45;
};
function banglaWave( canvas, wavelength, amplitude, period, shading ){
var fps = 30;
var ctx = canvas.getContext('2d');
var w = canvas.width, h = canvas.height;
var od = ctx.getImageData(0,0,w,h).data;
// var ct = 0, st=new Date;
return setInterval(function(){
var id = ctx.getImageData(0,0,w,h);
var d = id.data;
var now = (new Date)/period;
for (var y=0;y<h;++y){
var lastO=0,shade=0;
for (var x=0;x<w;++x){
var px = (y*w + x)*4;
var o = Math.sin(x/wavelength-now)*amplitude*x/w;
var opx = ((y+o<<0)*w + x)*4;
shade = (o-lastO)*shading;
d[px ] = od[opx ]+shade;
d[px+1] = od[opx+1]+shade;
d[px+2] = od[opx+2]+shade;
d[px+3] = od[opx+3];
lastO = o;
}
}
ctx.putImageData(id,0,0);
// if ((++ct)%100 == 0) console.log( 1000 * ct / (new Date - st));
},1000/fps);
}
Thanks in advance for any advice/assistance.
I am not sure where your problem is. I did not see any event handling code, so I assume that's your question:
Define a function to "handle the mouse event". For example, if you want to move the flag when the user moves the mouse over it, define something like:
function mouseMove(event) {
var mouseX,
mouseY;
event.preventDefault(); // stops browser to do what it normally does
// determine where mouse is
mouseX = event.pageX;
mouseY = event.pageY;
// do something useful, e.g. change the flag to waving when mouse is over flag
}
Then, register this function to be called when the mouse moves:
canvas.addEventListener("mousemove", mouseMove, false);
canvas is the canvas you paint the flag on, "mousemove" is the name of the event (many more exist, such as "mousedown", "mouseup", "mouseout" (leaving canvas), "mousewheel", etc.), mouseMove is the name of your function (the event handler, as it's called).
Events are a little different from browser to browser (and even browser version), so you might need to implement different event handler if you need it across browsers.
Hoping this helped...
canvas is like a sheet. there is no any object on which you can hover.
for doing what you wanted to do is just,bound an area on the flag,
follow the 'virtualnobi' answer and calculate if mouse co-ordinate falls on that region,
if true do what ever you want.
like
if (mouseX<100 && mouseX>0 && mouseY>0 && mouseY<100){
//animate the flag
}
use mouseX=event.clientX;
mouseY=event.clientY;
bounded area is x=(0,100) , y=(0,100) here.

Move Box with the mouse cursor

Im trying to move a box on canvas as the player moves but can't figure out the correct maths to do so im trying to do something simular to the draggable of the jquery function exept on canvas.
Here my code so far:
var _proto = {left:0,top:0,left2:0,top2:0};
var _isClicked = false;
$("canvas").on("mousedown", function(e) {
var offset = $(this).offset();
_proto.left = e.pageX-offset.left; //left of screen works fine,mouse
_proto.top = e.pageY-offset.top; //top of screen works fine,mouse
_isClicked = true;
$(this).on("mousemove", function(e) {
_proto.left2 = (e.pageX-offset.left); //get new pos mouse, works fine
_proto.top2 = (e.pageY-offset.top); //get new pos mouse, works fine
//Obj is an array of proto's objects,
// It moves the box to quick and incorrect
_objects[0].left = _proto.left2-(_proto.left-_objects[0].left);
_objects[0].top = _proto.top2-(_proto.top-_objects[0].top);
if(_isClicked == false) $(this).off("mousemove");
});
}).on("mouseup", function(e) {
_isClicked = false;
});
DEMO: http://jsfiddle.net/CezarisLT/tUXM3/
I like to use event streams to solve problems like these. What is an event stream? It is a stream of events. So let's create our own EventStream constructor:
function EventStream() {
var listeners = this.listeners = [];
return [this, function (event) {
return listeners.map(function (listener) {
return listener(event);
});
}];
}
We won't be using the EventStream constructor directly. Instead we'll write a function which creates an event stream, subscribes it to a stream of events and returns the stream:
function getEventStream(event, target) {
var pair = new EventStream;
target.addEventListener(event, pair[1]);
return pair[0];
}
Now we can create event streams as follows:
var move = getEventStream("mousemove", window);
Now we have a stream of mousemove events stored in the variable move. So how do we use it? The beauty of event streams is that you can map over, filter, scan and merge them. This makes life much easier.
First let's see the map method:
EventStream.prototype.map = function (f) {
var pair = new EventStream;
var dispatch = pair[1];
this.listeners.push(function (x) {
return dispatch(f(x));
});
return pair[0];
};
The map method does two things:
It allows you to subscribe to an event.
It allows you to process an event stream, creating an entirely new event stream.
Now let's look at the filter method:
EventStream.prototype.filter = function (f) {
var pair = new EventStream;
var dispatch = pair[1];
this.listeners.push(function (x) {
if (f(x)) return dispatch(x);
});
return pair[0];
};
The filter method, as the name implies, filters the events in an event stream. It returns an entirely new event stream with the filtered events.
Next up, the scan method:
EventStream.prototype.scan = function (a, f) {
var pair = new EventStream;
var dispatch = pair[1];
dispatch(a);
this.listeners.push(function (x) {
return dispatch(a = f(a, x));
});
return pair[0];
};
The scan method allows us to create "properties" which change from event to event, creating a new "property event stream". It's a very useful function which I'll demonstrate how to use below.
Finally we have the merge method:
EventStream.prototype.merge = function (stream) {
var pair = new EventStream;
var dispatch = pair[1];
this.listeners.push(function (x) {
return dispatch({left: x});
});
stream.listeners.push(function (x) {
return dispatch({right: x});
});
return pair[0];
};
The merge method takes two events streams and merges them into a single event stream. To distinguish which event stream originated which event we tag each event as either left or right.
Now that we learned about event streams let's use them to create a draggable box on a canvas and see how they make life so simple.
The first thing we do is set up the canvas:
var canvas = document.querySelector("canvas");
var context = canvas.getContext("2d");
var width = canvas.width;
var height = canvas.height;
var position = getPosition(canvas);
var left = position.left;
var top = position.top;
The getPosition function is defined as follows:
function getPosition(element) {
if (element) {
var position = getPosition(element.offsetParent);
return {
left: position.left + element.offsetLeft,
top: position.top + element.offsetTop
};
} else {
return {
left: 0,
top: 0
};
}
}
Next we create a constructor for a Box:
function Box(x, y, w, h) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
Box.prototype.bind = function (context) {
context.beginPath();
context.rect(this.x, this.y, this.w, this.h);
return context;
};
Then we create a box and draw it to the screen:
var box = new Box(100, 100, 150, 150);
box.bind(context).fill();
Now we need to make it draggable. We start dragging by holding down the mouse button. So the first thing we do is create a mousedown event stream:
var down = getEventStream("mousedown", canvas);
We want the coordinates of the mousedown events relative to the canvas. In addition we only want those mousedown events which occur on top the box. This can easily be handled using event streams as follows:
var dragStart = down
.map(function (event) {
return {
x: event.clientX - left,
y: event.clientY - top
};
})
.filter(function (cursor) {
return box.bind(context).isPointInPath(cursor.x, cursor.y);
});
Now you have a stream of mousedown events on top of your box.
Next we get a stream of mouseup events because dragging stops once you pick up your finger from the mouse button:
var up = getEventStream("mouseup", window);
We get mouseup events for the entire window because the user should be able to mouse the mouse outside the canvas and release it.
Next we merge the dragStart and up event streams to create a single dragStartStop event stream:
var dragStartStop = dragStart.merge(up).map(function (x) {
return x.left;
});
Events from the up event stream don't have any useful information. They only serve to mark that the user has stopped dragging. Hence we only care about events from the left event stream.
Coming back, to actually drag the box we need mousemove events. So let's get a mousemove event stream:
var move = getEventStream("mousemove", canvas).map(function (event) {
return {
x: event.clientX - left,
y: event.clientY - top
};
});
Like with the dragStart stream we only want the coordinates of mousemove events relative to the canvas.
Now we can merge the dragStartStop and the move streams to create the final drag stream:
var drag = dragStartStop.merge(move)
.scan(null, function (prev, event) {
if (event.hasOwnProperty("left")) {
var left = event.left;
return left && [left, left];
} else if (prev) return [prev[1], event.right];
})
.filter(function (x) {
return x;
})
.map(function (position) {
var prev = position[0];
var current = position[1];
return {
dx: current.x - prev.x,
dy: current.y - prev.y
};
});
Here we scan the events of the merged streams to create a "property event stream" of previous and current mouse positions when the user is dragging the box. We filter those mousemove events when the user is dragging the box and we get the difference in positions between the previous and current mousemove events.
Now we can draw the box being dragged:
drag.map(function (position) {
box.x += position.dx;
box.y += position.dy;
context.clearRect(0, 0, width, height);
box.bind(context).fill();
});
That's it. Simple right? See the demo: http://jsfiddle.net/PC3m8/
So what do we conclude from this? Event streams are awesome and you should use streams instead of creating big monolithic event listeners. They make your code more readable, understandable and maintainable and they make everybody's life simpler.

How do I capture the onclick event called in HTML?

So, I have an <img> tag that has an onclick attribute. The onclick calls a function called analyze(this), with this being the image.
The analyze function does some things to the image that aren't entirely relevant, except for the fact that it draws it onto the <canvas> element (using the drawImage function).
But now, I want to also pick the color I just clicked on in the image. I am currently using the method answered here (the answer with 70+ votes, not the chosen one): How do I get the coordinates of a mouse click on a canvas element?
But, I think I might be doing this wrong. I have the image drawn and my functions called (and those all work), but the color picking part isn't being called. I think that this is because I didn't actually capture the event. This is generally how my code looks:
<img onclick="javascript:analyze(this);" />
function analyze(img_elem) {
// This is getting the canvas from the page and the image in it
var canvaselement = document.getElementById('canvas').getContext('2d'),
img = new Image();
img.onload = function () {
canvaselement.drawImage(img, 0, 0, 250, 250);
...
canvaselement.onClick = function () {
var coords = canvaselement.relMouseCoords(event);
pick(img, canvaselement, coords); // pass in coordinates
}
}
img.src = img_elem.src;
}
function relMouseCoords(event) {
var totalOffsetX = 0;
var totalOffsetY = 0;
var canvasX = 0;
var canvasY = 0;
var currentElement = this;
do {
totalOffsetX += currentElement.offsetLeft - currentElement.scrollLeft;
totalOffsetY += currentElement.offsetTop - currentElement.scrollTop;
}
while (currentElement = currentElement.offsetParent)
canvasX = event.pageX - totalOffsetX;
canvasY = event.pageY - totalOffsetY;
return {
x: canvasX,
y: canvasY
}
}
function pick(img, canvaselement, coords) {
var pickedColor = "";
canvaselement.drawImage(img, 0, 0, 250, 250);
xx = coords.x;
yy = coords.y;
var imgData = canvas.getImageData(xx, yy, 1, 1).data;
pickedColor = rgbToHex(imgData);
//alert(pickedColor);
return pickedColor;
}
So, the code never gets to the pick function. I have a feeling that it's because I didn't actually capture the onclick event. I'm also not even sure if this is the right way to get the coordinates on the canvas, I'm just sort of hoping that I even get to that part of the debugging process at this point.
Thanks for your help!
The problem is probably that you're assigning canvaselement to the results of getContext('2d') and not to the element itself, which you will need for the click event binding. Create two variables, one for the DOM element itself and one for the context, something like:
var canvaselement = document.getElementById('canvas'),
canvaselementctx = canvaselement.getContext('2d');
...
canvaselement.onClick = function() {
var coords = canvaselementctx.relMouseCoords(event);
...
}
You have a couple of errors in the code but the reason the code you got from the linked post is that you forgot to include the prototype definition it uses:
HTMLCanvasElement.prototype.relMouseCoords = relMouseCoords;
Now you can call relMouseCoords on the canvas element:
/// event name in lower case
canvaselement.onclick = function () {
var coords = canvaselement.relMouseCoords(event);
//...
However, you will still get problems as you don't use a canvas context for the drawing calls.
function analyze(img_elem) {
// This is getting the canvas from the page and the image in it
var canvaselement = document.getElementById('canvas').getContext('2d'),
/// get context like this
ctx = canvaselement.getContext('2d'),
img = new Image();
img.onload = function () {
/// use context to draw
ctx.drawImage(img, 0, 0, 250, 250);
//...

Resizing Canvas Elements with Mouse Events with EaselJS

I'm trying to draw elements to a canvas and then allow the user to resize them by clicking and dragging them. I've implemented this with Kinetic JS library, but my development team is moving over to Easel JS.
Here is the code with the Kinetic library.
This works well enough.
I get about this far in Easel JS, but this code doesn't do anything. The canvas is totally blank. I realize that I'm not sure how to:
call mouse events -- here I'm trying to attach them to the DOM element, as in this tutorial
where to set the resize function -- separate function? called within the tick() function?
grab the mouse coordinates
var canvas;
var stage;
var rect;
var mousePos = new Point();
var update = true;
var rectX = 10;
var rectY = 10;
var rectW = 100;
var rectH = 50;
var rectXOffset = 50;
var rectYOffset = 50;
var newWidth;
var newHeight;
function init() {
// create stage and point it to the canvas:
canvas = document.getElementById("testCanvas");
stage = new Stage(canvas);
// overlay canvas used to draw target and line
canvasWrapper = $("#testCanvas");
// listen for a mouse down event
canvasWrapper.mousedown(onMouseDown);
// listen for mouse up event
canvasWrapper.mouseup(onMouseUp);
// enable touch interactions if supported on the current device:
if (Touch.isSupported()) { Touch.enable(stage); }
// enabled mouse over / out events
stage.enableMouseOver(10);
// start drawing instructions
var rect = new Shape();
rect.graphics
.setStrokeStyle(1)
.beginStroke(Graphics.getRGB(25,25,112,.7))
.drawRect(rectX,rectY,rectW,rectH);
// add rectangle to stage
stage.addChild(rect);
// render stage
stage.update();
// set the tick interval to 24 fps
Tick.setInterval(1000/24);
// listen for tick event
Tick.addListener(window, true);
// pause
Tick.setPaused(false);
}
//called when user clicks on canvas
function onMouseDown(e) {
mousePos.x = e.stageX;
mousePos.y = e.stageY
// check to see if mouse is within offset of rectangle
if(mousePos.x <= (rectW + rectXOffset) || mousePos.y <= (rectH + rectYOffset)) {
// set update to true
update = true;
// unpause tick
Tick.setPaused(false);
}
}
function onMouseUp(e) {
update = false;
Tick.setPaused(true);
}
function tick() {
// this set makes it so the stage only re-renders when an event handler indicates a change has happened.
if (update) {
if(mousePos.x - rectX < 50)
{
newWidth = 50;
} else {
newWidth = mousePos.x - rectX;
}
if(mousePos.y - rectY < 50)
{
newHeight = 50;
} else {
newHeight = mousePos.y -rectY;
}
rectW = newWidth;
rectH = newHeight;
rect.clear();
rect.graphics
.setStrokeStyle(1)
.beginStroke(Graphics.getRGB(65,65,65,.7))
.drawRect(0,0,rectW,rectH);
// add rectangle to stage
stage.addChild(rect);
update = false; // only update once
stage.update();
}
}
I know it shouldn't be this difficult and would appreciate any help.

Categories