Can I prevent browsers from buffering CSS changes? - javascript

I have figured out a nice effect from application that needs several UI elements but also requires as much screen space as possible.
Idea of the effect is, that the UI buttons almost dissapear as soon as you move the mouse too away from them.
I have made a jsFiddle in case you'd like to see it.
It's quite simple:
window.addEventListener("mousemove", function(e) {
var rect = element.getBoundingClientRect();
//Measuring distance from top-left corner of the div
var top = rect.top+(rect.bottom-rect.top)/2;
var left = rect.left+(rect.right-rect.left)/2;
//Mouse position
var x = e.clientX;
var y = e.clientY;
//Thank pythagoras for this
var distance = Math.sqrt(Math.pow(x-left, 2)+Math.pow(y-top, 2));
//Brightness in interval <1, 0.1>
var brightness = Math.min(1, Math.max(0.1, 100/distance));
element.style.opacity = brightness+"";
});
This jsFiddle was also supposed to demonstrate problem I have - but it runs unexpectedly smoothly.
The problem is, that the browsers seem to buffer the CSS changes if they are too frequent. This is a very smart performance strategy but in my case it quite breaks the effect.
I have also uploaded test script here. In Google Chrome, buffering appeared to be so strong (and unsynchronized), that the buttons sometimes flickered.
Should I implement some frame-skip so that the browser buffer is not initiated by the animation effect?
My buttons have their bottom border cut off. If you'd know why this happens, please let me know in comments

Related

svg.js / svg-pan-zoom - doubleclick interactions

I am using Ariutta's svg-pan-zoom with svg.js. I have disabled the native Arriuta doubleclick functionality and have tried adding my own, which ultimately consists of a pan adjustment and an animation.
Usually this works fine, but sometimes when I load my page the doubleclick function acts strangely. According to my debugging, it looks like sometimes when my app loads, the doubleclick function I wrote is called twice for each doubleclick. This causes the animation to behave strangely, and there seems to be no consistent basis for when this issue arises. Restarting my server sometimes works, and sometimes doesn't. I pretty much just have to continue reloading my page until the issue goes away.
My initial thoughts are that maybe there is something off in the load order of my files, and sometimes things load out of order. Currently investigating this. My other thought was that maybe this has something to do with the svg.js animation library or my trying to replace the native double-click function in arriuta's plugin. Thoughts?
myApp.service('AnimatorService', function(){
this.dblClickBehavior = function(svgCanvas, zoom){
$('.node').dblclick(function(){
// get pan
pan = zoom.getPan();
// get screen width and height
var sizes = zoom.getSizes();
var centerX = (sizes.width)/2;
var centerY = (sizes.height)/2;
// get center position of svg object double clicked
var x0 = this.instance.first().attr('cx');
var y0 = this.instance.first().attr('cy');
//determine the correct pan value necessary to center the svg
panAdjustX = centerX - x0*sizes.realZoom;
panAdjustY = centerY - y0*sizes.realZoom;
//center the svg object by adjust pan
zoom.pan({'x' :centerX - x0*sizes.realZoom, 'y' : centerY - y0*sizes.realZoom});
//simple animation on the object
this.instance.first().animate().radius(centerX);
});
}
});
When it behaves correctly, the svg image centers and then grows. When it behaves incorrectly, it centers and then shrinks into nothingness.
You tagged svg.js so I will give an svg.js answer. There is a plugin svg.panZoom.js now which can be used to easily implement the functionality you want:
var canvas = SVG('container').viewbox(0,0,1000,1000)
canvas.image('https://www.zooroyal.de/magazin/wp-content/uploads/2017/05/cat-2783601_1920.jpg', 1000, 1000)
.attr('preserveAspectRatio', 'none')
canvas.on('dblclick', function(e) {
var p = this.point(e.pageX, e.pageY)
var zoomLvl = 3
// zoom into point p to zoomLvl
canvas.animate().zoom(zoomLvl, p)
})
Here is a fiddle: https://jsfiddle.net/Fuzzy/95t6oL8y/5/
When you want to be able to panZoom your svg, too. Just add a call to canvas.panZoom()

No cursor movement when under Pointer Lock

I use Pointer Lock for capturing the cursor in a game I'm developing in JavaScript with three.js. I've done my basic Googling, but I can't seem to find why, on Chrome OS, the cursor doesn't seem to move. If you look at http://scheib.github.io/HTMLMisc/PointerLockAndFullscreen.html Pointer Locking is working just fine and there's even a nice "cursor" to go along with the movement!
JavaScript Console output (The logging is me):
I "fabricate" the movementX/Y with
if (evt.movementX === undefined) {
evt.movementX = evt.screenX - lastx;
evt.movementY = evt.screenY - lasty;
lastx = evt.screenX;
lasty = evt.screenY;
}
In case you're wondering, I'm just setting up basic graphics.
The cursor is not moving because you have "lock" it. But evt.movementX and evt.movementY gives you the direction of the movement.
You have to update the position or direction of your camera and render the result to make it feel like it moves.
Under pointer lock, only the movementX and movementY properties are available. All other "ordinary" position co-ordinates are deliberately set to zero.
In pointer lock mode, it is perceived that there is no cursor, only mouse movement, so there's no (screenX,screenY) for a cursor which does not exist, nor is there an (offsetX,offsetY) for the same reason.
Only (movementX,movementY) by design.

Is there a way to improve the performance of this draggable world map?

I implemented a simple draggable world map for a game but the performance differs when using different browsers - which is kinda obvious. I used 256x256 pixle tiles and the script dynamically renders the number to fill the whole window plus borders.
Prototype: http://mt111102.students.fhstp.ac.at/draggable/game.html
Currently I'm doing it simply by setting the top and left style attributes on mousemove. Heres a snippet:
mouseDown : function(e) {
Map.myPreventDefault(e);
dx = map.offsetLeft - e.clientX;
dy = map.offsetTop - e.clientY;
map.addEventListener('mousemove', Map.divMove, false);
},
divMove : function(e) {
Map.myPreventDefault(e);
map.style.position = "absolute";
map.style.cursor = "move";
map.style.left = e.clientX + dx + "px";
map.style.top = e.clientY + dy + "px";
}
Later when dragging to the borders I'm gonna load new tiles with XHR and delete old ones on the other end to retain performance so that the wrapper doesn't get to big.
My question is: Would it be more performant by using CSS translate instead of just setting the top and left attributes? And do you guys have any tips how to make it smoother?
In Firefox the prototype works almost perfectly smooth but in Webkit browsers like Chrome it doesn't look very good - it lags a bit. I just wonder how Google Maps managed it to work in every modern browser with the same smoothness.
A CSS transform, especially with a Z value (which will load the transform into the GPU), will almost always be faster and smoother - especially on devices like iPads, but elsewhere as well.
For more details you can check out this tutorial on GPU acceleration:
http://creativejs.com/2011/12/day-2-gpu-accelerate-your-dom-elements/

What is causing my canvas drawing to break and skip at certain values (2^15, for one)?

I'm working on a 2d canvas-based app using EaselJS where the user can move indefinitely on the xy-plane by dragging the background. Think google maps, except the background is a repeating tile.
The code for the movement is very simple and looks something like this:
// container - the createjs.Container being panned
// background - a createjs.Shape child of container, on which the
// background is drawn
background.onPress = function(evt) {
var x = evt.stageX, y = evt.stageY;
evt.onMouseMove = function(evt) {
// the canvas is positioned in the center of the window, so the apparent
// movement works by changing the registration point of the container in
// the opposite direction.
container.regX -= evt.stageX - x;
container.regY -= evt.stageY - y;
x = evt.stageX;
y = evt.stageY;
stage.update();
};
evt.onMouseUp = function(evt) {
// Here the background would be redrawn based on the new container coords.
// However the issue occurs even before the mouse is released.
background.redraw();
stage.update();
};
};
All works as expected until reaching 32678px (2^15) on either axis. What occurs is different in different browsers, but the point where it first happens is the same.
In Firefox, it will suddenly shift a large chunk of pixels (~100) rather than 1. It will then happen again at 65538 (2^16+2), perhaps more after that, but I haven't witnessed it. After the trouble points, the drag will continue smoothly, as expected, but remaining shifted.
In Chrome, the effect is more dramatic. The drawing breaks and results in repeated ~100px wide "stripes" of the background across the page at 32768, and does not correct itself on redraw.
Oddly, the numbers in EaselJS don't reflect the issue. The only change in the container's transform matrix is the tx or ty incrementing by 1. No other matrices change. It seems as though EaselJS is getting all the numbers right.
Can anyone shed any light this issue?
Edit:
I worked around this problem by redrawing parts of the container using a calculated regX/regY, rather than attempting to translate very large regX/regY coords on the canvas.
This question may be related
What is the maximum size for an HTML canvas?
From what I gather browsers use short int to store canvas sizes with 32,767 being the maximum possible value.
Links possibly related to your issue,
Mozilla - HTML5 Canvas slow/out of memory
https://stackoverflow.com/a/12535564/149636

Canvas: pointer based viewport / contain mouse pointer

There doesn't seem to be a good way to base the <canvas> viewport on the location of the mouse pointer and being able to move around freely. Basically, like every other first-person game on the market.
There is no way to capture the mouse
inside a <canvas> element.
There is no way to set the position
of the mouse pointer.
It is not possible to go full screen
with <canvas>, and even if, once the edge has been reached, functionality will be broken.
For good reasons, too. Imagine what possible scenarios could (and definitely would) be employed by malicious persons.
Perhaps it's too early to be thinking of something that is almost only of any use in a 3D environment, something that there isn't yet a spec for.
What's your take or solution?
You can get the mouse position inside of a canvas.
function getCursorPosition(e) {
var x;
var y;
if (e.pageX != undefined && e.pageY != undefined) {
x = e.pageX;
y = e.pageY;
}
else {
x = e.clientX + document.body.scrollLeft +
document.documentElement.scrollLeft;
y = e.clientY + document.body.scrollTop +
document.documentElement.scrollTop;
}
x -= gCanvasElement.offsetLeft;
y -= gCanvasElement.offsetTop;
var cell = new Cell(Math.floor(y/kPieceHeight),
Math.floor(x/kPieceWidth));
return cell;
}
From Dive Into HTML5: Let's Call it a Draw(ing Surface)
I don't think there is a good solution for this -- at least, not until we get mouse locking. No matter how elegant your solution, if you make a twitchy mouselook driven game, the user is going to twitch outside the canvas area at some point. Even if they don't accidentally click a link, their immersion will be broken when the view stops responding to their mouse.
For slower paced games, you could:
Use click and drag to turn. Once user starts dragging within the canvas, you use the mouse delta from the point where they started dragging to determine how far to turn. Because the user is holding down the button, they won't accidentally click things.
Hover cursor near the edges of the canvas to turn, similar to an RTS. This would turn more slowly, but is probably the most intuitive, and easiest for a user to accidentally discover.
Use the keyboard to look, like pre-mouse FPS games (such as Doom).
It's worth noting that there is an open feature request in Firefox for mouse locking. But, unfortunately, neither this, nor mouse hiding or fullscreen are part of the WebGL spec.
All of these features are supported by Unity, so that may be a path to look at if you really need FPS controls.

Categories

Resources