JavaScript: On Firefox mousemove is triggered when resizing window - javascript

When I'm on Firefox, canvas calls requestPointerLock and I'm pressing F11 for fullscreen - I see that event mousemove is being triggered. This makes some things to move which must be static because mouse is not moving.
I tried to create a demo, but I get error Blocked pointer lock on an element because the element's frame is sandboxed and the 'allow-pointer-lock' permission is not set.
So here is a code example which you can read at least.
HTML part:
<canvas id="canvas" width="800" height="600"></canvas>
JavaScript part:
canvas = document.getElementById('canvas');
document.addEventListener("click", function(e) {
canvas.requestPointerLock = canvas.requestPointerLock ||
canvas.mozRequestPointerLock ||
canvas.webkitRequestPointerLock;
if (canvas.requestPointerLock)
canvas.requestPointerLock();
}, false);
document.addEventListener("pointerlockchange", plChange, false);
document.addEventListener("mozpointerlockchange", plChange, false);
function plChange(e) {
var controlEnabled = (document.mozPointerLockElement === canvas ||
document.webkitPointerLockElement === canvas ||
document.pointerLockElement === canvas);
if (!controlEnabled) {
window.removeEventListener("mousemove", mouseMove);
} else {
window.addEventListener("mousemove", mouseMove, false);
}
}
function mouseMove(e) {
// This is being executed on window resize
console.log(e.movementY);
}
As a result, when window is going fullscreen (and Firefox does it slooowly) - I get e.movementY printed in a console and value is not 0 always.
The question is how can I prevent this Firefox "feature" so that mouse move event is not being triggered?

Found a solution to mitigate the problem. Unfortunately there's no viable solution that could actually fix the problem, because whenever Firefox resizes its window, the mouse is somehow dragged along so that the pointer's position relative to the top left corner remains unchanged. However, since it moves across the screen, a spurious mousemove event is triggered.
A way to mitigate this is adding a resize handler to the window object to check whether a window resize is taking place - and if so, set a flag and use it to have the mouse move handler bail out. Unfortunately you cannot just reset this flag when the mouse move fires, because you would still get occasional spurious mousemove events. Instead you have to set off a timeout that eventually resets the flag when you can be relatively certain that the browser window has been completely resized.
I managed to get that done with my test case which looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xml:lang="en">
<head>
<title>canvas Test Case</title>
<style type="text/css">
body {
background-color: silver;
}
canvas {
background-color: white;
}
</style>
<script type="application/javascript">
/* <![CDATA[ */
'use strict';
var canvas;
var this_timeout = null;
document.addEventListener('DOMContentLoaded', function (p_event) {
canvas = document.getElementById('canvas');
document.addEventListener("click", function (p_event) {
canvas.requestPointerLock = canvas.requestPointerLock ||
canvas.mozRequestPointerLock ||
canvas.webkitRequestPointerLock;
if (canvas.requestPointerLock)
canvas.requestPointerLock();
}, false);
document.addEventListener("pointerlockchange", plChange, false);
document.addEventListener("mozpointerlockchange", plChange, false);
window.addEventListener('resize', function (p_event) {
// Use this handler to set a flag that a resize event is taking place.
// Using the timeout ID actually hits two birds with one stone: It serves as a
// flag that a resize is actually taking place, plus it allows us to reset the
// timeout if it hasn't expired when another one fires.
if(this_timeout)
clearTimeout(this_timeout);
this_timeout = setTimeout(function () { this_timeout = null; }, 250);
console.log('Resizing...'); }, true);
}, false);
function stoppedResize() {
// If the timeout expires, reset the timeout id to show that we are done resizing.
this_timeout = null;
}
function plChange(p_event) {
var controlEnabled = (document.mozPointerLockElement === canvas ||
document.webkitPointerLockElement === canvas ||
document.pointerLockElement === canvas);
if (!controlEnabled) {
console.log('Disabling mouse tracker...');
window.removeEventListener("mousemove", mouseMove);
} else {
console.log('Enabling mouse tracker...');
window.addEventListener("mousemove", mouseMove, false);
}
}
function mouseMove(p_event) {
// Check whether there's a timeout running. If yes, just bail out...
if(this_timeout)
{
console.log('Skipping...');
return;
}
console.log('Mouse movement detected!');
}
/* ]]> */
</script>
</head>
<body>
<header><h1>canvas Test Case</h1></header>
<main>
<canvas id="canvas" width="800" height="600" />
</main>
</body>
</html>
By doing this you can easily mitigate this problem. Unfortunately it's not the clean solution that I would have preferred, but given the cirumstances, this is the best way to deal with the problem that I could come up with.
As for your other question, I guess you wanted to post an example here on SO? If yes, I think that you have run into some restrictions imposed on the code. Since everything seems to take place in an iframe, I guess that certain actions have been disallowed. Attaching certain event handlers is obviously affected.

Related

Javascript / HTML adding an image to center position on the mouse click

I want to print out a picture whenever the mouse is clicked on the screen.
This is my current Javascript and HTML code. It only prints the h1, I don't know what I am doing wrong.
var image = document.getElementById("im"); // idenfitifes span eleme nt
var roll = false; // to know the image is moving or not , intitally it is not moving state hence value is false
image.addEventListener("mousedown", start, false); // at starting image is in rest
function mouse_move(x) // funciton to move image with mouse
{
var newX = x.clientX; // copies mouse x position
var newY = x.clientY; // copies mouse y position
image.style.left = newY + "px"; // assigns latest mouse position to span (image)
image.style.top = newX + "px";
}
function start(x) // span (image) starting no rolling mode
{
if(roll){ // when the mouse is moving
document.removeEventListener("mousemove", mouse_move); // initiages image span move
roll = !roll;
return;
}
roll = !roll; // when the mouse is not moving
document.addEventListener("mousemove", mouse_move, false);
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title> Picture of Me! </title>
</head>
<body>
<h1> HTML File to move image along with mouse movement. </h1>
<script type="text/javascript" src="h5j.js">
<span id="im">
<img src="https://static01.nyt.com/images/2020/04/27/us/politics/00-trump-cand-page/00-trump-cand-page-mediumSquareAt3X.jpg" height="120" width="120"></img>
</span>
</body>
</html>
You Use The AddEventListener Function Like This
document.addEventListener("mousedown", mouse_move, false);
the syntax for addEventListener is:
addEventListener("Event Name", "Your Function name, the function you want to run after event happening")
when you need to run in the click event, you simply need to change Event name from "mousedown" to "click" , example:
document.addEventListener("click", mouse_move, false);
you have to use "click" event instead of "mousedown"
like:
document.addEventListener("click", mouse_move, false);
<code>
var image = document.getElementById("im");
var roll = false;
image.addEventListener("click", start, false);
function mouse_move(x)
{
var newX = x.clientX; // copies mouse x position
var newY = x.clientY; // copies mouse y position
image.style.left = newX + "px";
image.style.top = newY+ "px";
}
function start(x) // span (image) starting no rolling mode
{
if (roll) { // when the mouse is moving
document.removeEventListener("click", mouse_move); // initiages image span move
roll = !roll;
return;
}
roll = !roll; // when the mouse is not moving
}
document.addEventListener("click", mouse_move, false);
</code>
It looks like your trying to get the image element by id, before the DOM has finished loading.
I would suggest one of the following:
Move the <script> tag to the bottom of the page between </body> and </html>
Add defer to the <script> tag, which will cause the script to be loaded after the DOM.
Move the first block of your JavaScript into a DOMContentLoaded event listener as shown below.
var roll = false;
var image;
document.addEventListener('DOMContentLoaded', function(){
image = document.getElementById("im");
image.addEventListener("mousedown", start, false);
});

Zimjs pressmove event doesn't work outer the elements

I'm using zimjs library for my canvas project. I'm trying to do continued pressing around the circles. When pressing and moving over the circles, circles must be change color. But pressmove event don't start outer the circles. You need to start to press over the circle. if I start pressing over the circle, the other circle is not affected.
Here is zimjs events:
https://zimjs.com/tips.html (See Events)
What do I want approximately?
https://zimjs.com/intro/index.html (See drag to eraser example. I want like this but without eraser. Only single pressing)
Note: I can't use mouse events. They didn't work on phone touchs.
See snippet:
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>ZIM Frame - Outside Template</title>
<script src="https://zimjs.org/cdn/1.3.0/createjs.js"></script>
<script src="https://zimjs.org/cdn/10.9.0/zim.js"></script>
<!-- use zimjs.com/distill for minified individual functions! -->
<script>
var scaling = "fit"; // this will resize to fit inside the screen dimensions
var width = 600;
var height = 400;
var color = white; // or any HTML color such as "violet" or "#333333"
var outerColor = light;
var frame = new Frame(scaling, width, height, color, outerColor);
frame.on("ready", function() {
var stage = frame.stage;
var circle1 = new Circle(20, "red").pos(100,40, stage)
var circle2 = new Circle(20, "blue").pos(200,40, stage)
circle1.on("pressmove", () => {
circle1.color = "green"
stage.update()
console.log("Circle - 1 || Circles pressmove doesn't work when pressing start the outside")
})
circle2.on("pressmove", () => {
circle2.color = "green"
stage.update()
console.log("Circle - 2 || Circles pressmove doesn't work when pressing start the outside")
})
var button = new Button(140, 100, "reset", grey, dark).center(stage).tap(() => {
circle1.color = "red"
circle2.color = "blue"
stage.update()
})
new Label("Pressmove can be start anywhere", 16).pos(0, 300)
new Label("When pressing and moving over the circles,", 16).pos(0, 320)
new Label("circles must be select and change color,", 16).pos(0, 340)
stage.on("pressmove", () => console.log("Stage !!. Stage pressmove doesn't work when pressing outside the circles"))
stage.update();
}); // end of ready
</script>
<meta name="viewport" content="width=device-width, user-scalable=no" />
</head>
<body>
</body>
</html>
It is true that the pressmove event only works as you press on an object and move. If you want to start the press off the object or indeed anywhere then you use stage.on("stagemousedown", function); Mouse events DO work on mobile they are triggered by a touch so you do not even have to think of it. There is also "stagemousemove" and "stagemouseup". Objects on the stage get "mousedown", "presssmove", "pressup", "mouseover", "mouseout", etc. Usually we would change color on "mouseover" and change back on "mouseout" - ZIM has hov() that will do that. Or a Button() and Label() have built in backgroundColor and rollBackgroundColor.
If you really need to press anywhere before activating a change of color you could do something like this to remember the mousedown stage in general:
let mousedown = false;
stage.on("stagemousedown", ()=>{mousedown=true});
stage.on("stagemouseup", ()=>{mousedown=false});
const circle = new Circle().center();
circle.on("mouseover", ()=>{
if (mousedown) {
circle.color = red;
stage.update();
}
});
Or you could specifically add a stagemousemove event inside a stagemousedown event and remove it in a stagemouseup event to get the equivalent to a stage pressmove event. The pressmove event was created to help with dragging objects and usually, we do not drag the stage.
Hope this helps and apologies for the delay - you are welcome to join us at https://zimjs.com/slack for discussion! Cheers.

How to Avoid continuous triggering of HTML5 DeviceOrientationEvent

I am trying to tilt an image based on HTML5 DeviceOrientation event. However, I am seeing that the event is getting continuously fired even when the device is stable i.e non rotating/non moving. In the following code snippet, the console log is printed continuously. What is the possible reason, how can I stop it.
I tried both capturing and bubbling,
if (window.DeviceOrientationEvent) {
window.addEventListener('deviceorientation', function(eventData) {
var tiltLR = eventData.gamma;
console.log("tiltLR..........",tiltLR);
}, false);
}
I havent needed to use this type of event listener before so I am not familiar with the output.
However, I believe you would need to compare the old tilt with the new tilt. If the new tilt is substantially greater or less then... execute code.
if (window.DeviceOrientationEvent) {
var originalTilt = undefined,
tolerance = 5;
window.addEventListener('deviceorientation', function(eventData) {
if (eventData.gamma > originalTilt + tolerance ||
eventData.gamma < originalTilt - tolerance){
var tiltLR = eventData.gamma;
console.log("tiltLR..........",tiltLR);
originalTilt = tiltLR;
}
}, false);
}

Play HTML5 Canvas animation onClick or onTouchEnd on iPhone

I have a test site that uses HTML5 Canvas to load an array of stills from a video, then draws them to the Canvas at 24 frames per second. It works great and is currently set up to autoplay once the array has been pre-loaded.The reason for this was to autoplay on iOS.
What I'm trying to do now is instead of autoplaying the image sequence, I want to trigger the animate() function by use of document.getElementById('anim').onclick=animate; The element ID is a CSS3 ID that has two background elements: the background image (which is the first frame of the image sequence, and a play button). This is shown to the user until all the images have preloaded.
I want the user to simply press the Anim element (anywhere, but there is a play button for the user) and then play the image sequence. After the sequence, hide the canvas element so the background image and play button shows again that way it can be triggered again.
This needs to work on iPhone.
You can view the full source here to see it in action.
CSS:
#anim {
background-image:url('images/play_button.png'),url('images/t5.png');
background-position: center, left top;
background-repeat: no-repeat;
height:500px;
width:660px;
}
JS:
function draw() {
var ctx = document.getElementById('anim').getContext("2d");
var start = 1, stop = 121,cur=start,imgArr=[];
var loadLoop = function() {
var img = document.createElement("img");
img.onload = function() {
imgArr.push(this);
cur++;
if(cur > stop) {
// all images preloaded
// This is where the animate function is called for auto-play
animate();
}
else {
loadLoop();
}
}
img.src = "jpg_80/t5_"+(cur)+".jpg";
}
loadLoop();
function animate() {
var timer = setInterval(function() {
ctx.drawImage(imgArr.shift(), 0, 0 );
if(imgArr.length == 0) {
// no more frames
clearInterval(timer);
}
},1000/24);
}
}
HTML:
<body>
<!-- HTML5 Canvas Animation-->
<div>
<canvas id="anim" width="660" height="500"></canvas>
</div>
<script>
//call after page loaded
window.onload = function() {
draw();
// This is where I want the animate function called for manual play
//document.getElementById('anim').onclick=animate;
}
</script>
</body>
Animate is limited to within the scope of the draw function. You can only call the animate function within draw function the way it's currently defined. You probably want Option 2.
Option 1)
If you do the following you'll be able to get the animation to fire on the click.
document.getElementById('anim').onclick = draw;
Option 2)
If you want to call just the animate function you'll need to declare the animate variable outside of the draw function.
var animate;
function draw(){
//...other draw stuff here
animate = function(){
//animate stuff here
}
}
You'll then have access to the animate function on global scope.

Trying to drag ship on canvas from left to right in Space Invaders clone

I have a "ship" that I have drawn on my canvas and I want to be able to drag it left and right on the bottom of the canvas when it is clicked. I have done some research but I'm having no luck.
I'm assuming I use onMouseDown to do this so I have this when the page loads...
canGame.onMouseDown = canCanvas.onMouseDown(e);
and here is the code that creates my ship
gShip = spriteNew("MediumSpringGreen", 230, 950, 150, 20);
From there I am not really sure what to do. I have a gameUpdate function which moves the invaders down the screen. A gameInit function that will draw the invaders and ship on the screen. Also I have a gameDraw function which draws everything on the screen. I have a few others which are not really important for my issue.
Here is the jsfiddle with the full source code. For some reason though it will run on my browser when I run the HTM file but not in jsfiddle.
http://jsfiddle.net/f66bk/2/
Like I said in comment, the best way of doing this kind of behaviour is by using the events mouseup, mousedown and mousemove.
I defined a var named isMouseDown to know that the ship is dragged that I set to true on mousedown and false on mouseup:
canGame.onMouseDown = function() { isMouseDown = true }
canGame.onMouseUp = function() { isMouseDown = false }
You will also need the event onmousemove to get your mouse position to redraw your ship properly:
canGame.onMouseUp = function(event) { moveShip(event, this) }
In the function moveShip, you can get your mouse position and set the position of your ship properly:
function moveShip(evt, obj) {
if(!isMouseDown)
return;
var target = evt.target || evt.srcElement,
rect = target.getBoundingClientRect(),
offsetX = evt.clientX - rect.left;
gShip.Rect.X = offsetX - gShip.Rect.Width/2;
}
Here is your jsfiddle :)

Categories

Resources