I'm having trouble resizing this canvas that is displaying a video. After resizing, it continually jerks all around into different sizes between the "before" and "after" window sizes.
I tried this posts' idea, and that seemed to calm down Chrome a little, but had no affect on Firefox.
This other post gave me some ideas, but still didn't fix it. It seems like I'm either calling resize multiple times in a loop (which I don't see), or the canvas's context doesn't know how to settle on the final size. Any ideas?
<!DOCTYPE html>
<html>
<head>
<title>overflow</title>
<style>
#c {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
width: 100%;
height: 100%;
z-index: 1;
}
#hold {
position: fixed;
}
#v {
position: absolute;
height: auto;
width: 100%;
z-index: 0;
}
#see {
position: relative;
top: 0;
bottom: 0;
left: 0;
right: 0;
z-index: 2;
}
</style>
</head>
<body>
<canvas id=c></canvas>
<div id=hold>
<video id=v>
</video>
</div>
<canvas id=see></canvas>
<script>
window.onload = start;
function start() {
var v = document.getElementById('v');
var house = document.getElementById('hold');
var base = document.getElementById('c');
var canvas = base.getContext('2d');
var cover = document.getElementById('see');
var canvastwo = cover.getContext('2d');
v.src=("keyed.ogv")
v.load();
v.play();
resize();
function resize() {
var wth = (window.innerWidth * 0.65);
house.width = wth;
house.height = (wth * 9/16);
house.style.marginTop=((window.innerHeight/2) - (house.height/2) + "px");
house.style.marginLeft=((window.innerWidth/2) - (house.width/2) + "px");
cover.width = (wth/2);
cover.height = (house.height/2);
cover.style.marginTop=((window.innerHeight/2) - (cover.height/2) + "px");
cover.style.marginLeft=((window.innerWidth/2) - (cover.width/2) + "px");
var rw = cover.width;
var rh = cover.height;
canvastwo.clearRect(0, 0, rw, rh);
draw(v, canvastwo, rw, rh);
}
window.onresize = resize;
function draw(o,j,w,h) {
if(v.paused || v.ended) return false;
j.drawImage(o,0,0,w,h);
setTimeout(draw,20,o,j,w,h);
}
}
</script>
</body>
</html>
You seem to lock in the old values you use for the setTimeout function the way you are using it here, as the context changes. So when you re-size the loop still uses the old values which no longer corresponds with the new sizes and results in the video toggle between these sizes.
Try to more "globalize" the values so that the loop call is clean when it comes to arguments. This way you are sure the variables contains the correct values for each round.
Also change setTimeout with requestAnimationFrame to make the loop more low-level (efficient) and fluid as this syncs to the monitor's vblank gap. This is particular important with video as you otherwise will get skipped frames as setTimeout is not able to sync with monitor.
Here is the essential code you need to change:
/// put these into you start block to keep them "global"
/// for the functions within it.
var w, h;
Change this part in the resize function:
/// ...
w = cover.width;
h = cover.height;
canvastwo.clearRect(0, 0, w, h);
/// argument free call to draw:
draw();
And finally the loop:
function draw() {
if(v.paused || v.ended) return false;
canvastwo.drawImage(v,0,0,w,h);
requestAnimationFrame(draw);
}
This will remove the jerking video and also make the update in sync to the monitor like the video element itself does.
ONLINE DEMO
Related
I'm experiencing something weird, but I'm not sure if it's intended or what's causing it.
I'm experimenting with some JavaScript that loops through a set of images when the user moves the mouse across the screen. I'm using jQuery mousemove for this. Here's a fiddle: https://jsfiddle.net/sy35dzeh/1/
The behaviour I'm experiencing is some kind of throttle with the mouse movement. I want every pixel moved to increment the pixelCount variable. But when moving the mouse in longer sweeps, it seems like the iteration reaches a limit. This causes the counter to increment faster when moving the mouse slowly as there are more "pixels" per movement added. I get that this might be how mousemove works, but on top of that it behaves differently when opening the developer tools.
When I open the developer tools in Chrome as try to move the mouse again, the iteration is a lot more rapid. This is the behaviour I want, when the iteration becomes slower on slower mouse movement and faster when moving the mouse faster.
Here's a video of the difference:
https://streamable.com/okqql3
Any idea why it's different when I open the console and any idea how to make the mouse movement affect the iteration in the way I want it to behave (like when I have the developer tools open)?
I fixed it by using event.getCoalescedEvents() which get the missing "in between" movements.
Note that you need to listen for "pointermove", which I was doing in my case.
this.canvas.addEventListener('pointermove', this.onMouseMove.bind(this), { passive: true });
onMouseMove(event) {
const events = event.getCoalescedEvents();
for (let i = 0; i < events.length; i++) this.onMovement(events[i]);
}
onMovement(event) {
// standard processing
}
Mousemove event is not called for every pixel, but it works like this - the browser periodically checks the cursor position and, noticing changes, generates mousemove events.
Accordingly, in your case, it is better not to count pixels from the number of event triggers, but the difference in coordinate changes is needed.
Also, when calling mousemove, I do not recommend using slow and heavy synchronous functions and it is worth adding them separately to the Event Loop (at least through setTimeout).
Below I have slightly modified the example you specified:
let imageIndex = 1
let pixelCount = 0
let $targetElement = $(".mouse-image");
let divisions = 50
let pixelThreshold = Math.floor($(window).width() / divisions)
$(document).ready(function() {
$targetElement.eq(0).addClass("is-active");
})
$(window).on("resize", function() {
pixelThreshold = Math.floor($(window).width() / divisions)
})
let prevX = null;
let prevY = null;
let timeout = null;
$(document).on("mouseenter", function(ev) {
prevX = ev.clientX;
prevY = ev.clientY;
})
$(document).on("mouseleave", function(ev) {
prevX = null;
prevY = null;
})
$(document).on("mousemove", function(ev) {
const posX = ev.clientX;
const posY = ev.clientY;
const deltaX = (!prevX) ? 1 : Math.abs(posX - prevX);
const deltaY = (!prevY) ? 1 : Math.abs(posY - prevY);
prevX = posX;
prevY = posY;
pixelCount += (deltaX + deltaY);
if (pixelCount > pixelThreshold) {
pixelCount = 0;
changeImage();
clearTimeout(timeout);
timeout = setTimeout(changeImage, 20);
}
$(".debug").text(`${pixelCount}, ${pixelThreshold}`)
})
function changeImage() {
imageIndex++
if (imageIndex >= $targetElement.length) {
imageIndex = 0;
}
$targetElement.removeClass("is-active");
$targetElement.eq(imageIndex).addClass("is-active");
}
html {
font-size: 100%
}
body {
width: 100%;
height: 100%;
}
*,
:after,
:before {
padding: 0;
margin: 0;
-webkit-box-sizing: border-box;
box-sizing: border-box
}
.image-container {
width: 100vw;
height: 100vh
}
.mouse-image {
display: none;
-o-object-fit: cover;
object-fit: cover;
width: 100%;
height: 100%
}
.mouse-image.is-active {
display: block
}
.debug {
position: fixed;
top: 0;
right: 0;
background-color: #fff;
z-index: 999999999;
font-size: 4rem
}
.wrapper {
position: fixed;
top: 0;
left: 0;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
width: 100vw;
height: 100vh;
z-index: 9999
}
.wrapper .trigger {
width: 100%
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="debug"></div>
<div class="image-container">
<img class="mouse-image" src="https://www.airtasker.com/blog/wp-content/uploads/2018/01/Puppy-toilet-training-1200x675.jpg" alt="">
<img class="mouse-image" src="https://awl.org.au/sites/default/files/styles/page_hero/public/hero/puppy-1221791_1920.jpg?itok=SLa7BGdj" alt="">
<img class="mouse-image" src="https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcT69ZsF7GXUMrNLc1AOvNjXXoZWmNyA61fAqg&usqp=CAU" alt="">
<img class="mouse-image" src="https://www.bil-jac.com/media/ww5kq5u4/puppy.jpg?anchor=center&mode=crop&width=1024&height=512" alt="">
<img class="mouse-image" src="https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcRWeA5-zFa86-P6aDd5NUERS6ay9isKpgkDiQ&usqp=CAU" alt="">
</div>
I'm currently learning canvas touch event function,I 'm able to draw line on the canvas, now I want to get the x and y coordinates when I draw any lines and show on the screen.please help and teach me how to get the x and y values, thank You!
here is the coding
<!DOCTYPE html>
<html><head>
<style>
#contain {
width: 500px;
height: 120px;
top : 15px;
margin: 0 auto;
position: relative;
}
</style>
<script>
var canvas;
var ctx;
var lastPt=null;
var letsdraw = false;
var offX = 10, offY = 20;
function init() {
var touchzone = document.getElementById("layer1");
touchzone.addEventListener("touchmove", draw, false);
touchzone.addEventListener("touchend", end, false);
ctx = touchzone.getContext("2d");
}
function draw(e) {
e.preventDefault();
if (lastPt != null) {
ctx.beginPath();
ctx.moveTo(lastPt.x, lastPt.y);
ctx.lineTo(e.touches[0].pageX - offX,
e.touches[0].pageY - offY);
ctx.stroke();
}
lastPt = {
x: e.touches[0].pageX - offX,
y: e.touches[0].pageY - offY
};
}
function end(e) {
var touchzone = document.getElementById("layer1");
e.preventDefault();
// Terminate touch path
lastPt = null;
}
function clear_canvas_width ()
{
var s = document.getElementById ("layer1");
var w = s.width;
s.width = 10;
s.width = w;
}
</script>
</head>
<body onload="init()">
<div id="contain">
<canvas id="layer1" width="450" height="440"
style="position: absolute; left: 0; top: 0;z-index:0; border: 1px solid #ccc;"></canvas>
</div>
</body>
</html>
Still not entirely confident I understand your question.
In the code you posted, you are already obtaining coordinates using e.touches[0].pageX/Y. The main problem with that is that the pageX/Y values are relative to the page origin. You are then subtracting fixed offX/Y in your code to try and convert these to canvas-relative coordinates. Right idea, wrong values. You need to subtract off the position of the canvas element which can be obtained by summing the offsetX/Y values as you traverse the tree upward using the offsetParent reference.
Something like:
offX=0;offY=0;
node = document.getElementById ("layer1");
do {
offX += node.offsetX;
offY += node.offsetY;
node = node.offsetParent;
} while(node);
should give you a better value for offX and offY.
If you just want to locate the actual drawing at the end, it would be easiest just to track a bounding box while the user draws.
I went through the initial tutorial for making a user radar on Zigfu's website. I am having trouble getting this radar to work in the canvas element.
I want to using the drawing methods in canvas, so I don't want it in the container.
Here is my code so far taken directly from the tutorial. Thanks so much for reading!
function loaded() {
var radardiv = document.getElementById('container');
var radar = {
onuserfound: function (user) {
var userdiv = document.createElement('div');
userdiv.className = 'user';
user.radarelement = userdiv;
radardiv.appendChild(user.radarelement);
},
onuserlost: function (user) {
radardiv.removeChild(user.radarelement);
},
ondataupdate: function (zigdata){
for (var userid in zigdata.users){
var user = zigdata.users[userid];
var pos = user.position;
//console.log(pos);
var el = user.radarelement;
var parentElement = el.parentNode;
var zrange = 2000;
var xrange = 700;
var pixelwidth = parentElement.offsetWidth;
var pixelheight = parentElement.offsetHeight;
var heightscale = pixelheight / zrange;
var widthscale = pixelwidth / xrange;
el.style.left = (((pos[0] / xrange) + 0.5) * pixelwidth - (el.offsetWidth / 2)) + "px";
el.style.top = ((pos[2] / zrange) * pixelheight - (el.offsetHeight / 2)) - 150 + "px";
}
}
};
zig.addListener(radar);
}
document.addEventListener('DOMContentLoaded', loaded, false);
<body>
<div id = 'container'></div>
</body>
</html>
<style>
div#container {
width: 800px;
height: 600px;
border: 1px solid black;
overflow: hidden;
}
div.user {
position: relative;
width: 10px;
height: 10px;
background-color: red;
}
It seems you are missing tags around the javascript, as well as some css for the users radar. Also - your 'container' div is missing a >
Try copying the code from the bottom of http://zigfu.com/en/zdk/tutorials/, or - check out http://zigfu.com/en/zdk/recipes/#omercy16 for a cleaner implementation of the users radar.
The radar used in the tutorial makes use of DOM div placement and positioning.
Unfortunately this can't be used inside the canvas element.
There are ways to overlay over the canvas and other workarounds. See: Placing a <div> within a <canvas>
You can also take the data directly from the plugin and draw to the canvas yourself.
Here is a demo using three.js and zigfu to draw the skeleton onto a canvas:
http://blog.kinect.tonkworks.com/post/30569123887/kinect-online-app-javascript-dev-tutorial-1
Is it possible to have divs located around a central point and then on hover for them to whisk off screen and return when the mouse is gone?
This what the layout:
http://pena-alcantara.com/aramael/wp-content/uploads/2010/04/Paper-Browser.8.5x11.Horizontal3.jpg
is looking like, the idea is for the green "leaves" to whisk off to show the branches and the menus. Would this be possible with JavaScript and PHP?
Any chance I could convince you to not design a site this way?
I suppose not, so the answer is to use jQuery. Here is the jQuery reference for animation, which you'll need to study carefully.
You are going to need to combine a few jQuery features.
The animation feature at: http://api.jquery.com/animate/
The mouse over feature: http://api.jquery.com/mouseover/
The mouse out feature: http://api.jquery.com/mouseout/
Have "dummy divs" where the mouse over is detected that move their ID's real div out of view using animate it, and bring it back with mouseout
I found this interesting so coded it for myself... I did it as below:
<style type="text/css">
body {
overflow:hidden;
}
.leaf {
position:relative;
background-color:#0F0;
height: 100px;
width: 100px;
}
.branch {
display:inline-block;
background-color:#F00;
height: 100px;
width: 100px;
}
</style>
<script type="text/javascript">
$(function(){
var w = $(document).width();
var h = $(document).height();
var r = 250;
$(".branch").hover(function() {
var rand = Math.random();
var x,y;
if(rand<0.25) {
x = w;
y = h*Math.random();
} else if(rand<0.5) {
x = -w;
y = h*Math.random();
} else if(rand<0.75) {
x = w*Math.random();
y = h;
} else {
x = w*Math.random();
y = -h;
}
$(this).children().animate({left: x, top: y});
}, function () {
$(this).children().animate({left: '0', top: '0'});
})
});
</script>
<div class="wrap">
<div class="branch"><div class="leaf"></div></div><!-- etc -->
</div>
I'm (still) porting an old Macintosh game to HTML5 and JavaScript. The game is a Tempest clone. (Wikipedia article on Tempest) (Shameless pimp of my project)
While it's certainly possible to implement controls using the keyboard, I'm also wondering if it's possible to make relative mouse movement work in HTML5.
The typical ways that I've seen this implemented (outside of HTML5) is to repeatedly warp the mouse to the screen's center and look for deviations, or to somehow capture raw mouse movement events. As far as I know, but I could be wrong, neither of these methods are possible in HTML5.
The odds are slim, but I figure I shouldn't completely write it off without asking the clever minds of StackOverflow. :)
I'm pretty sure that the only way to get relative mouse coords in JavaScript (HTML5 specs have no changes to this) is to calculate it from the current mouse position and the previous mouse position - or using onmousemove. As you probably are aware of, this won't work when the cursor can't physically move (eg. is touching window borders)
In the off chance that I'm wrong, you could take a search for WebGL demos. Since there's bound to be a 3D shooter demo, perhaps they have a mouse based control solution you can apply.
I don't think you need HTML5 really, but if you have an element and your game board is in the center, you could do something like this:
<html>
<head>
<title>Cursor Position Radius</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" type="text/javascript"></script>
<style type="text/css" media="screen">
#square {
height: 400px;
width: 400px;
background-color: #000;
margin: auto;
position: absolute;
overflow: hidden;
top: 10px;
left: 300px;
}
#log {
height: 100%;
width: 200px;
position: absolute;
top: 0;
left: 0;
background-color: #ccc;
color: #000;
font-size: small;
overflow: auto;
}
</style>
<!-- here's the real code, the JavaScript -->
<script type="text/javascript">
$(document).ready(function() {
var centerTop = a = $('#square').height() / 2;
var centerLeft = $('#square').width() / 2;
var squareTop = $('#square').offset().top;
var squareLeft = $('#square').offset().left;
// draw a center point
$('<div />').css({
width: '1px', height: '1px',
backgroundColor: '#fff',overflow:'hidden',
position:'absolute',
top: centerTop,left: centerLeft
}).attr('id', 'center').appendTo('#square');
$('#square').bind('mousemove', function(event) {
var mouseLeft = (event.pageX - squareLeft);
var mouseTop = (event.pageY - squareTop);
var correctTop = (centerTop - mouseTop);
var correctLeft = (mouseLeft - centerLeft);
var rawAngle = (180/Math.PI) * Math.atan2(correctTop,correctLeft);
var intAngle = parseInt(rawAngle, 10);
var msg = '';
msg += (mouseTop >= centerTop) ? ' lower ' : ' upper ';
msg += (mouseLeft >= centerLeft) ? ' right ' : ' left ';
msg += intAngle;
$('#log').prepend('<div>' + msg + '</div>');
});
/* create a dot along a radius for every degree
(not necessary for the mousemove) */
var sensitivity = (2 * Math.PI) / 360;
var radius = ($('#square').height() / 2) - 10;
var degrees = 0;
for (var t = 0; t<= (2 * Math.PI); t+=sensitivity) {
var x = radius * Math.cos(t) + a;
var y = radius * Math.sin(t) + a;
$('<div />').css({
width: '1px', height: '1px',
backgroundColor: '#ccc',overflow:'hidden',
position:'absolute',top: x,left: y
}).attr('id', 'cursor-' + t).appendTo('#square');
}
});
</script>
<!-- and the body -->
</head>
<body>
<div id="square"></div>
<div id="log"></div>
</body>
</html>
So the idea here is that you would do something with that angle around the center of the game board. If you know that the angle is 90 degrees you know that the game piece is at the far right.
I'm really interested in JavaScript for games, I'll check out your git project. Feel free to contact me and I'll do what I can. I wish I could promise real help, but I'm a newbie myself. There's probably more efficient ways to do the math I do in my sample, I did it mostly as an exercise for myself anyway. Best of luck!
Here's another tack at it, showing an avatar (really just a a bunch of points) that follow the mouse: http://gist.github.com/464974