HTML offsetLeft delays to change - javascript

I have four canvas in my screen, positioned two above and two below.
Each one have a button that makes possible to maximize the canvas, hiding the others.
This button is positioned above each canvas, with absolute position based on offsetTop and offsetLeft of the canvas.
However, when I maximize or minimize a canvas, the button formula updates only the width property.
The strange thing is that if I resize the screen, which also calls resize function, everything goes to the right place.
EDIT: Additional information: I am using VueJS and, in order to hide the other canvas, I apply v-show="false" to them parent divs, which only applies display: none.
Some snippets:
Initial resize and listener:
window.onload = function () {
resizeAll();
window.addEventListener('resize', resizeAll, false);
};
The resize hub:
function resizeAll () {
vue.$refs.panelOne.resizeDefault();
// ...
vue.$refs.panelN.resizeDefault();
}
The panel's resize default and resize method. The "expandStyles" is the css styles applied to the button:
resizeDefault() {
let dimensions;
if (this.expanded) {
dimensions = getScreenDimensions();
} else {
dimensions = getHalfScreenDimensions();
}
this.resize(dimensions.width, dimensions.height);
}
resize (width, height) {
this.canvas.width = width;
this.canvas.height = height;
this.expandStyles.top = (this.canvas.offsetTop + 10) + 'px';
this.expandStyles.left = (this.canvas.offsetLeft + this.canvas.width - 40) + 'px';
drawInterface.redraw();
}
And finally, the dimension getters:
function getScreenDimensions () {
return {
width: window.innerWidth - 310,
height: window.innerHeight * 0.92
};
}
function getHalfScreenDimensions () {
return {
width: (window.innerWidth - 310) / 2,
height: (window.innerHeight * 0.92) / 2
};
}

I agree with S.P.H.I.N.X , it seems like the problem lies with propagation of reactive properties in this.expandStyles to actual DOM. Would be useful if you can share the part of the template which has your canvases and positioning application.
Meanwhile, if setTimeOut doesn't feel right to you, you may do things more "Vue-way" by using Vue: nextTick to set order of operations (styles recalculation, redraw).

Related

Alternative of position fixed using JavaScript shows weird behavior on window resize

I have CSS transform scale on the body of my page and some other elements. The position fixed CSS property doesn't work with transform property. I tried to do the same as position fixed but with JavaScript by changing the element's top/bottom value while scrolling. This requires some calculations dynamically as you load the page on different sized screens. Mine works on different screens but when I do window resize on any screen, the fixed div behaves weirdly. It disappears and reappear again. Sometimes it doesn't fixes its position on the intended scroll-y value. I have applied "scroll" and "resize" event listeners for the body/window. I had to do some initial calculations before scroll event, so some functions are under a parent function.
JAVASCRIPT
function chekon()
{
document.addEventListener('DOMContentLoaded', upme);
window.addEventListener('resize', upme);
function upme()
{
var rome = document.getElementById("out-cmnt");
var rect = rome.getBoundingClientRect();
// console.log(rect.top, rect.right, rect.bottom, rect.left);
var poss = rect.top + window.scrollY;
var koss = rect.bottom + window.scrollY; var loss = koss - poss;
var isMobile = !(navigator.userAgentData.mobile);
// event listeners
// window.addEventListener('resize', relod, false);
// function relod() { if(isMobile) { location.reload(); } }
window.addEventListener('scroll', doso, false);
window.addEventListener('resize', doso, false);
function doso()
{
lopp = document.getElementById("Web_1920__1");
hope = lopp.clientHeight;
const meme = document.body.scrollHeight;
const keke = hope/meme;
const scsc = window.scrollY;
var scmx = (document.documentElement.scrollHeight - document.documentElement.clientHeight);
console.log("meme scroll-height = ", meme); console.log("scsc scroll-y = ", scsc);
console.log("scmx max-scroll-y = ", scmx);
var innr = window.innerHeight; console.log("innr inner-height = ", innr);
var scbb = scmx - scsc; var finn = scsc * keke; var nunn = scbb * keke;
if (window.matchMedia("(min-width: 765px)").matches)
{
var finn = scsc * keke * 1.087;
var nunn = scbb * keke * 1.087;
}
var noss = poss - innr + loss;
if(scsc > noss && window.matchMedia("(min-width: 765px)").matches && isMobile)
{
var xoxo = nunn;
document.getElementById("out-cmnt").style.top = "auto";
document.getElementById("out-cmnt").style.bottom = xoxo + "px";
}
if(scsc < noss)
{
document.getElementById("out-cmnt").style.top = "7074px";
}
if(nunn < 100 && isMobile)
{
document.getElementById("last-dab").style.visibility = "hidden";
}
if(nunn > 100 && isMobile)
{
document.getElementById("last-dab").style.visibility = "visible";
}
} }
}
chekon();
Function upme() and doso() is under function chekon() there. The upme() has 2 event listeners and doso() has also 2 event listeners with resize in common. I checked that if doso() resize isn't applied, the upme() resize event listener has no effect on doso() even though doso() is under upme() function. I though, maybe there is overlapping. But seems like fine to me. Is there something messed up in my code that is responsible for the window resize action? The "Web_1920__1" is for getting the total height of the page. The "out-cmnt" is flickering and showing up at wrong place after stopping window resize action for the browser. Then when I start scrolling again the element should get back at its intended position again. But no, staying at wrong position. A reload only fixes the problem for now. Funny thing is, I can't reproduce the wrong position even when the resize is down to at the same window size that showed the problem before. So I think Chrome is showing the problem at random window resizes. Is it browser bug or mine? Help me out please.
You can ignore the variables and calculations. Just care more for the structure, functions and event-listeners like any wrong declarations. Please help me to understand the problem.

How to align an element to the bottom of the window using JS

I have created a html-5 banner using Adobe Animate and have an element, which should be aligned to the bottom of the window depending on the height of this window.
My banner should be 100% height and on the first picture you can see the right position of the bottom elements. And on the second picture there is a space between the element and the background.
And my element should remain aligned to the bottom when changing the height of the window. How can I do it using js?
Here is my code which helps me move the element but it doesn't align it to the bottom:
this.frame_0 = function() {
var _second = this.second;
this.addEventListener("tick", res.bind(this));
function res() {
_second.y = window.innerHeight/2 + 120;
}
}
This is my file
use CSS to set the positions of element.
position:fixed;
left:ValueFromLeft;
bottom:0;
It's easy
If use CreateJS then you are using a canvas.
CSS solutions don't work, only JS.
Use the Window's resize event.
this.frame_0 = function() {
var _second = this.second;
function setSecondToTheBottom() {
_second.y = window.innerHeight - (_second.nominalBounds.height / 2);
}
setSecondToTheBottom();
window.addEventListener("resize", setSecondToTheBottom);
};

Using .onresize to control text on responsive video player

I'm trying to control the size of the text used to show elapsed and total time of a video player. I am currently controlling the play/pause/sound and full screen icons, but can't access the time display. Below is the javascript used to resize the controls on window resize:
window.onload = function() {
resize();
}
window.onresize = function() {
resize();
}
function resize() {
document.getElementsByClassName('play')[0].style.width = (document.getElementsByClassName('timeline')[0].offsetHeight * .25) + 'px';
document.getElementsByClassName('fullscreen')[0].style.width = (document.getElementsByClassName('timeline')[0].offsetHeight * .25) + 'px';
document.getElementsByClassName('mute')[0].style.width = (document.getElementsByClassName('timeline')[0].offsetHeight * .25) + 'px';
document.getElementsByClassName('time-played')[0].style.width = (document.getElementsByClassName('timeline')[0].offsetHeight * .25) + 'px';
}
Also trying to figure out the best way to minimize and simplify this using jQuery(to consolidate all of the classes into one array, similar to:
$('.play .fullscreen .mute .time-played')
My current implementation: jsfiddle
If you'd like to use jQuery, then you can run the resize method on .ready() and add window .resize() bindings as well, like so:
$(document).ready(function () {
// resize on dom ready
resizePlayer();
// add window resize binding
$(window).resize(resizePlayer);
});
To combine selectors in jQuery, you can do something like this:
$('.play, .fullscreen, .mute, .time-played')
So, your resize method can now look something like this:
function resizePlayer() {
// Set your width to whatever you want...
// this is just a rough translation of your method above
var newWidth = $('.timeline').outerHeight() * 0.25;
$('.play, .fullscreen, .mute, .time-played').width(newWidth);
}

Detect vertical resize jquery

I am making a login page in which I use a little javascript and jquery to vertically align the login box.
I also have an event on resize() to put the box in the middle again.
But, with resize(), everytime the user resize the window, the function is fired and this is a kind of ugly :))
So, I would like to know if there is a way to fire the function only on vertical resize.
Thank you
It will fire every time, but you can track the width to check for only vertical resizing:
// track width, set to window width
var width = $(window).width();
// fire on window resize
$(window).resize(function() {
// do nothing if the width is the same
if ($(window).width()==width) return;
// update new width value
width = $(window).width();
// ... your code
});
Instead of comparing heights for each situation where you want to detect vertical resize, you can create reusable events for horizontal and vertical resizing like this:
// Horizontal and vertical window resize events.
(function () {
var win = jQuery(window),
prev_width = win.width(),
prev_height = win.height();
win.on('resize', function () {
var width = win.width(),
height = win.height();
if (width !== prev_width) {
win.trigger('hresize');
}
if (height !== prev_height) {
win.trigger('vresize');
}
prev_width = width;
prev_height = height;
});
})();
That way you can just drop that code in place once, and then use the events like this:
$(window).on('hresize', function () {
// handle horizontal resizing
});
$(window).on('vresize', function () {
// handle vertical resizing
});
Got better solution:
$('#element').resizable({
stop: function( event, ui ) {
$('#element').height(ui.originalSize.height);
}
});
As a complement to Doublesharp's useful answer:
In my case, window.outerWidth worked better, and was stable to vertical resizes.
Indeed, I had some troubles with $(window).width() : it (strangely!) happened to be modified also when I only resized vertically.

Catch browser's "zoom" event in JavaScript

Is it possible to detect, using JavaScript, when the user changes the zoom in a page?
I simply want to catch a "zoom" event and respond to it (similar to window.onresize event).
Thanks.
There's no way to actively detect if there's a zoom. I found a good entry here on how you can attempt to implement it.
I’ve found two ways of detecting the
zoom level. One way to detect zoom
level changes relies on the fact that
percentage values are not zoomed. A
percentage value is relative to the
viewport width, and thus unaffected by
page zoom. If you insert two elements,
one with a position in percentages,
and one with the same position in
pixels, they’ll move apart when the
page is zoomed. Find the ratio between
the positions of both elements and
you’ve got the zoom level. See test
case.
http://web.archive.org/web/20080723161031/http://novemberborn.net/javascript/page-zoom-ff3
You could also do it using the tools of the above post. The problem is you're more or less making educated guesses on whether or not the page has zoomed. This will work better in some browsers than other.
There's no way to tell if the page is zoomed if they load your page while zoomed.
Lets define px_ratio as below:
px ratio = ratio of physical pixel to css px.
if any one zoom The Page, the viewport pxes (px is different from pixel ) reduces and should be fit to The screen so the ratio (physical pixel / CSS_px ) must get bigger.
but in window Resizing, screen size reduces as well as pxes. so the ratio will maintain.
zooming: trigger windows.resize event --> and change px_ratio
but
resizing: trigger windows.resize event --> doesn’t change px_ratio
//for zoom detection
px_ratio = window.devicePixelRatio || window.screen.availWidth / document.documentElement.clientWidth;
$(window).resize(function(){isZooming();});
function isZooming(){
var newPx_ratio = window.devicePixelRatio || window.screen.availWidth / document.documentElement.clientWidth;
if(newPx_ratio != px_ratio){
px_ratio = newPx_ratio;
console.log("zooming");
return true;
}else{
console.log("just resizing");
return false;
}
}
The key point is difference between CSS PX and Physical Pixel.
https://gist.github.com/abilogos/66aba96bb0fb27ab3ed4a13245817d1e
Good news everyone some people! Newer browsers will trigger a window resize event when the zoom is changed.
I'm using this piece of JavaScript to react to Zoom "events".
It polls the window width.
(As somewhat suggested on this page (which Ian Elliott linked to): http://novemberborn.net/javascript/page-zoom-ff3 [archive])
Tested with Chrome, Firefox 3.6 and Opera, not IE.
Regards, Magnus
var zoomListeners = [];
(function(){
// Poll the pixel width of the window; invoke zoom listeners
// if the width has been changed.
var lastWidth = 0;
function pollZoomFireEvent() {
var widthNow = jQuery(window).width();
if (lastWidth == widthNow) return;
lastWidth = widthNow;
// Length changed, user must have zoomed, invoke listeners.
for (i = zoomListeners.length - 1; i >= 0; --i) {
zoomListeners[i]();
}
}
setInterval(pollZoomFireEvent, 100);
})();
This works for me:
var deviceXDPI = screen.deviceXDPI;
setInterval(function(){
if(screen.deviceXDPI != deviceXDPI){
deviceXDPI = screen.deviceXDPI;
... there was a resize ...
}
}, 500);
It's only needed on IE8. All the other browsers naturally generate a resize event.
There is a nifty plugin built from yonran that can do the detection. Here is his previously answered question on StackOverflow. It works for most of the browsers. Application is as simple as this:
window.onresize = function onresize() {
var r = DetectZoom.ratios();
zoomLevel.innerHTML =
"Zoom level: " + r.zoom +
(r.zoom !== r.devicePxPerCssPx
? "; device to CSS pixel ratio: " + r.devicePxPerCssPx
: "");
}
Demo
Although this is a 9 yr old question, the problem persists!
I have been detecting resize while excluding zoom in a project, so I edited my code to make it work to detect both resize and zoom exclusive from one another. It works most of the time, so if most is good enough for your project, then this should be helpful! It detects zooming 100% of the time in what I've tested so far. The only issue is that if the user gets crazy (ie. spastically resizing the window) or the window lags it may fire as a zoom instead of a window resize.
It works by detecting a change in window.outerWidth or window.outerHeight as window resizing while detecting a change in window.innerWidth or window.innerHeight independent from window resizing as a zoom.
//init object to store window properties
var windowSize = {
w: window.outerWidth,
h: window.outerHeight,
iw: window.innerWidth,
ih: window.innerHeight
};
window.addEventListener("resize", function() {
//if window resizes
if (window.outerWidth !== windowSize.w || window.outerHeight !== windowSize.h) {
windowSize.w = window.outerWidth; // update object with current window properties
windowSize.h = window.outerHeight;
windowSize.iw = window.innerWidth;
windowSize.ih = window.innerHeight;
console.log("you're resizing"); //output
}
//if the window doesn't resize but the content inside does by + or - 5%
else if (window.innerWidth + window.innerWidth * .05 < windowSize.iw ||
window.innerWidth - window.innerWidth * .05 > windowSize.iw) {
console.log("you're zooming")
windowSize.iw = window.innerWidth;
}
}, false);
Note: My solution is like KajMagnus's, but this has worked better for me.
⬤ The resize event works on modern browsers by attaching the event on window, and then reading values of thebody, or other element with for example (.getBoundingClientRect()).
In some earlier browsers it was possible to register resize event
handlers on any HTML element. It is still possible to set onresize
attributes or use addEventListener() to set a handler on any element.
However, resize events are only fired on the window object (i.e.
returned by document.defaultView). Only handlers registered on the
window object will receive resize events.
⚠️ Do resize your tab, or zoom, to trigger this snippet:
window.addEventListener("resize", getSizes, false)
function getSizes(){
let body = document.body
body.width = window.innerWidth
body.height = window.innerHeight
console.log(body.width +"px x "+ body.height + "px")
}
getSizes()
⬤ An other modern alternative: the ResizeObserver API
Depending your layout, you can watch for resizing on a particular element.
This works well on «responsive» layouts, because the container box get resized when zooming.
function watchBoxchange(e){
info.textContent = e[0].contentBoxSize[0].inlineSize+" x "+e[0].contentBoxSize[0].blockSize + "px"
}
new ResizeObserver(watchBoxchange).observe(fluid)
#fluid {
width: 200px;
height:100px;
overflow: auto;
resize: both;
border: 3px black solid;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-size: 8vh
}
<div id="fluid">
<info id="info"></info>
</div>
💡 Be careful to not overload javascript tasks from user gestures events. Use requestAnimationFrame whenever you needs redraws.
I'd like to suggest an improvement to previous solution with tracking changes to window width. Instead of keeping your own array of event listeners you can use existing javascript event system and trigger your own event upon width change, and bind event handlers to it.
$(window).bind('myZoomEvent', function() { ... });
function pollZoomFireEvent()
{
if ( ... width changed ... ) {
$(window).trigger('myZoomEvent');
}
}
Throttle/debounce can help with reducing the rate of calls of your handler.
According to MDN, "matchMedia" is the proper way to do this https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio#Monitoring_screen_resolution_or_zoom_level_changes
it's a bit finicky because each instance can only watch one MQ at a time, so if you're interested in any zoom level change you need to make a bunch of matchers.. but since the browser is in charge to emitting the events it's probably still more performant than polling, and you could throttle or debounce the callback or pin it to an animation frame or something - here's an implementation that seems pretty snappy, feel free to swap in _throttle or whatever if you're already depending on that.
Run the code snippet and zoom in and out in your browser, note the updated value in the markup - I only tested this in Firefox! lemme know if you see any issues.
const el = document.querySelector('#dppx')
if ('matchMedia' in window) {
function observeZoom(cb, opts) {
opts = {
// first pass for defaults - range and granularity to capture all the zoom levels in desktop firefox
ceiling: 3,
floor: 0.3,
granularity: 0.05,
...opts
}
const precision = `${opts.granularity}`.split('.')[1].length
let val = opts.floor
const vals = []
while (val <= opts.ceiling) {
vals.push(val)
val = parseFloat((val + opts.granularity).toFixed(precision))
}
// construct a number of mediamatchers and assign CB to all of them
const mqls = vals.map(v => matchMedia(`(min-resolution: ${v}dppx)`))
// poor person's throttle
const throttle = 3
let last = performance.now()
mqls.forEach(mql => mql.addListener(function() {
console.debug(this, arguments)
const now = performance.now()
if (now - last > throttle) {
cb()
last = now
}
}))
}
observeZoom(function() {
el.innerText = window.devicePixelRatio
})
} else {
el.innerText = 'unable to observe zoom level changes, matchMedia is not supported'
}
<div id='dppx'>--</div>
You can also get the text resize events, and the zoom factor by injecting a div containing at least a non-breakable space (possibly, hidden), and regularly checking its height. If the height changes, the text size has changed, (and you know how much - this also fires, incidentally, if the window gets zoomed in full-page mode, and you still will get the correct zoom factor, with the same height / height ratio).
<script>
var zoomv = function() {
if(topRightqs.style.width=='200px){
alert ("zoom");
}
};
zoomv();
</script>
On iOS 10 it is possible to add an event listener to the touchmove event and to detect, if the page is zoomed with the current event.
var prevZoomFactorX;
var prevZoomFactorY;
element.addEventListener("touchmove", (ev) => {
let zoomFactorX = document.documentElement.clientWidth / window.innerWidth;
let zoomFactorY = document.documentElement.clientHeight / window.innerHeight;
let pageHasZoom = !(zoomFactorX === 1 && zoomFactorY === 1);
if(pageHasZoom) {
// page is zoomed
if(zoomFactorX !== prevZoomFactorX || zoomFactorY !== prevZoomFactorY) {
// page is zoomed with this event
}
}
prevZoomFactorX = zoomFactorX;
prevZoomFactorY = zoomFactorY;
});
Here is a clean solution:
// polyfill window.devicePixelRatio for IE
if(!window.devicePixelRatio){
Object.defineProperty(window,'devicePixelRatio',{
enumerable: true,
configurable: true,
get:function(){
return screen.deviceXDPI/screen.logicalXDPI;
}
});
}
var oldValue=window.devicePixelRatio;
window.addEventListener('resize',function(e){
var newValue=window.devicePixelRatio;
if(newValue!==oldValue){
// TODO polyfill CustomEvent for IE
var event=new CustomEvent('devicepixelratiochange');
event.oldValue=oldValue;
event.newValue=newValue;
oldValue=newValue;
window.dispatchEvent(event);
}
});
window.addEventListener('devicepixelratiochange',function(e){
console.log('devicePixelRatio changed from '+e.oldValue+' to '+e.newValue);
});
Here is a native way (major frameworks cannot zoom in Chrome, because they dont supports passive event behaviour)
//For Google Chrome
document.addEventListener("mousewheel", event => {
console.log(`wheel`);
if(event.ctrlKey == true)
{
event.preventDefault();
if(event.deltaY > 0) {
console.log('Down');
}else {
console.log('Up');
}
}
}, { passive: false });
// For Mozilla Firefox
document.addEventListener("DOMMouseScroll", event => {
console.log(`wheel`);
if(event.ctrlKey == true)
{
event.preventDefault();
if(event.detail > 0) {
console.log('Down');
}else {
console.log('Up');
}
}
}, { passive: false });
I'am replying to a 3 year old link but I guess here's a more acceptable answer,
Create .css file as,
#media screen and (max-width: 1000px)
{
// things you want to trigger when the screen is zoomed
}
EG:-
#media screen and (max-width: 1000px)
{
.classname
{
font-size:10px;
}
}
The above code makes the size of the font '10px' when the screen is zoomed to approximately 125%. You can check for different zoom level by changing the value of '1000px'.

Categories