Why are Safari and Chrome giving different results when using document.querySelector in the same script?
What I'm trying to do is display the image next to the link when hovering over it. The image should be displayed next to the link.
In Safari, the image is displayed properly from the left corner, but in Chrome, when I scroll down and point at the link, the image is displayed from unexpected angles.
JavaScript:
let attached = false;
function showImage() {
const image = document.querySelector('img');
if (image && !attached) {
attached = true;
image.style.display = 'block';
document.addEventListener('pointermove', function(event) {
image.style.left = event.x + 'px';
image.style.top = event.y + 'px';
});
}
}
function hideImage() {
const image = document.querySelector('img');
if (image && attached) {
attached = false;
image.style.display = 'none';
document.removeEventListener('pointermove', function(event) {
image.style.left = event.x + 'px';
image.style.top = event.y + 'px';
});
}
}
CSS:
img{
position: fixed;
display: none;
pointer-events: none;
width: 640px;
height: auto;
}
I've tried changing the code to:
let attached = false;
const getElmtImage = (elmt) => {
return elmt.querySelector("img")
}
const followMouse = (elmt, event) => {
elmt.style.left = event.x + "px";
elmt.style.top = event.y + "px";
}
function showImage(elmt) {
const image = getElmtImage(elmt)
if (!attached) {
attached = true;
image.style.display = "block";
document.addEventListener("pointermove", function(event) {
followMouse(image, event)
});
}
}
function hideImage(elmt) {
const image = getElmtImage(elmt)
attached = false;
image.style.display = "none";
document.removeEventListener("pointermove", followMouse);
}```
I have conducted some testing, and it appears that Chrome and Safari handle events differently (based on my testing, although I could be mistaken). In Safari, event.x works, whereas in Chrome only event.pageY works. To work around this issue, I first check the browser type and then execute the appropriate functions. This approach may not be the cleanest, but it is effective. If you have a better idea of how to handle this situation, please share it.
let attached = false;
var ua = navigator.userAgent.toLowerCase();
if (ua.indexOf('safari') != -1) {
if (ua.indexOf('chrome') > -1) {
// chrome
function showImage() {
const image = document.querySelector('img');
if (image && !attached) {
attached = true;
image.style.display = 'block';
document.addEventListener('mousemove', function(event) {
image.style.left = event.pageX + 'px';
image.style.top = event.pageY + 'px';
});
}
}
function hideImage() {
const image = document.querySelector('img');
if (image && attached) {
attached = false;
image.style.display = 'none';
document.removeEventListener('mousemove', function(event) {
image.style.left = event.pageX + 'px';
image.style.top = event.pageY + 'px';
});
}
} } else {
// safari
function showImage() {
const image = document.querySelector('img');
if (image && !attached) {
attached = true;
image.style.display = 'block';
document.addEventListener('pointermove', function(event) {
image.style.left = event.x + 'px';
image.style.top = event.y + 'px';
});
}
}
function hideImage() {
const image = document.querySelector('img');
if (image && attached) {
attached = false;
image.style.display = 'none';
document.removeEventListener('pointermove', function(event) {
image.style.left = event.x + 'px';
image.style.top = event.y + 'px';
});
}
} }
}
Related
I have a function that adds random images to my divs that disappear over time and create a mouse trail. My issue is: there are double images.
I'd like to add something that checks if the background url is already located on the page and if that's the case, skips to the next in the array and check it again until until it comes across one that is not there. So like a loop that refreshes every time a 'trail' is being created.
Maybe I am asking for something that won't work? What if all the images are already on the page? I don't really have an answer for it and I also don't have an idea how to solve that problem yet.
For now I tried adding a counter that checks the usedImages and counts them, but it seems to have flaws and I am unsure where to look or how to fix it. Does anyone have any tips on how to do this? Is it even possible?
My fiddle
var bgImages = new Array(
"https://www.studiourbanestrategien.com/wordpress/wp-content/uploads/2019/05/schraegluftbild-1024x725.jpg",
"https://www.studiourbanestrategien.com/wordpress/wp-content/uploads/2019/05/pikto-608x1024.jpg",
"https://www.studiourbanestrategien.com/wordpress/wp-content/uploads/2019/05/Jettenhausen-EG-Grundriss-913x1024.jpg",
"https://www.studiourbanestrategien.com/wordpress/wp-content/uploads/2019/05/lageplan-945x1024.jpg",
"https://www.studiourbanestrategien.com/wordpress/wp-content/uploads/2019/05/Jettenhausen-EG-Grundriss-913x1024.jpg",
"https://www.studiourbanestrategien.com/wordpress/wp-content/uploads/2019/05/Jettenhauser-Esch-Modell-2-1024x768.jpg",
"https://www.studiourbanestrategien.com/wordpress/wp-content/uploads/2019/07/DSCN3481-1024x768.jpg",
"https://www.studiourbanestrategien.com/wordpress/wp-content/uploads/2019/07/zoom-in-3_ASTOC-1024x683.jpg",
"https://www.studiourbanestrategien.com/wordpress/wp-content/uploads/2016/07/IMG_1345-1024x768.jpg"
);
const numberOfImages = 10;
const timesPerSecond = .1;
var usedImages = {};
var usedImagesCount = 0;
function preloadImages(images) {
for (i = 0; i < images.length; i++) {
let l = document.createElement('link')
l.rel = 'preload'
l.as = 'image'
l.href = images[i]
document.head.appendChild(l);
}
}
function animate(e) {
var image = document.createElement('div');
image.classList.add('trail');
var sizew = 200;
var sizeh = 200;
image.style.transition = '3s ease';
image.style.position = 'fixed';
image.style.top = e.pageY - sizeh / 2 + 'px';
image.style.left = e.pageX - sizew / 2 + 'px';
image.style.width = sizew + 'px';
image.style.height = sizeh + 'px';
var random = Math.floor(Math.random() * (bgImages.length));
if (!usedImages[random]) {
image.style.backgroundImage = "url(" + bgImages[random] + ")";
usedImages[random] = true;
usedImagesCount++;
if (usedImagesCount === bgImages.length) {
usedImagesCount = 0;
usedImages = {};
}
} else {
animate(e);
}
console.log(usedImages);
console.log(usedImagesCount);
image.style.backgroundSize = 'cover';
image.style.pointerEvents = 'none';
image.style.zIndex = 1;
document.body.appendChild(image);
//opacity and blur animations
window.setTimeout(function() {
image.style.opacity = 0;
image.style.filter = 'blur(20px)';
}, 40);
window.setTimeout(function() {
document.body.removeChild(image);
}, 2100);
};
window.onload = function() {
preloadImages(bgImages);
var wait = false;
window.addEventListener('mousemove', function(e) {
if (!wait) {
wait = true;
setTimeout(() => {
wait = false
}, timesPerSecond * 800);
animate(e);
}
});
};
I have developed a page where I dynamically import images and display them inside a div tag. Now i wanted to draw an rectangle over the image, and it should start from any point on the image.
I referred many sources and tried to implement the idea from it.
<style>
#rubberBand {
position: absolute;
visibility: hidden;
width: 0px; height: 0px;
border: 2px solid red;
}
</style>
<div class="imageside" id="picture"> </div>
<div ID="rubberBand"></div>
In the above code, the image is display at the div id "picture". Till this part of the code works fine.
var pic, rubber, pt = { x: 0, y: 0 };
picture= getpicture();
function getpicture(){
pic= document.getElementById('picture')
pic.innerHTML= getgImage(event.target.dataset.number);
}
function startRubber (evt) {
var ev = evt || window.event,
rs = rubber.style,
bb = pic.innerHTML.getBoundingClientRect();
console.dir(ev);
rs.left = bb.left + 'px';
rs.top = bb.top + 'px';
rs.width = bb.width + 'px';
rs.height = bb.height + 'px';
rs.display = 'block';
pt = { x: ev.clientX - bb.left, y: ev.clientY - bb.top };
return false;
}
function stopRubber () {
rubber.style.display = 'none';
}
function moveRubber (evt) {
var ev = evt || window.event;
rubber.style.left = (evt.clientX - pt.x) + 'px';
rubber.style.top = (evt.clientY - pt.y) + 'px';
}
rubber = document.getElementById('rubberBand');
pic = document.getElementById('picture').innerHTML;
pic.onmousedown = startRubber;
document.onmouseup = stopRubber;
document.onmousemove = moveRubber;
In the above code, the function getpicture() is responsible to display the images dynamically. When i execute the above code, the image displays on the page, but I am not able to draw the rectangle over the image. In console, no errors. Can someone help me out with problem and help me to draw the rectangle over the image.
check this out.
https://jsfiddle.net/2at9n7ye/3/
your issue is that you are accessing the pic variable before you load it.
var pic, rubber, pt = {
x: 0,
y: 0
};
picture = getpicture();
function getpicture() {
pic = document.getElementById('picture');
pic.innerHTML = "<img src='https://i.imgur.com/mvMlmMb.jpg' id='img' width='100px' height='100px'/>";
}
function startRubber(evt) {
var ev = evt || window.event,
rs = rubber.style,
bb = pic.getBoundingClientRect
rs.left = bb.left + 'px';
rs.top = bb.top + 'px';
rs.width = bb.width + 'px';
rs.height = bb.height + 'px';
rs.display = 'block';
pt = {
x: ev.clientX - bb.left,
y: ev.clientY - bb.top
};
return false;
}
function stopRubber() {
rubber.style.display = 'none';
}
function moveRubber(evt) {
var ev = evt || window.event;
rubber.style.left = (evt.clientX - pt.x) + 'px';
rubber.style.top = (evt.clientY - pt.y) + 'px';
}
(function() {
rubber = document.getElementById('rubberBand');
pic = document.getElementById('picture');
pic.addEventListener("mousedown", startRubber);
document.addEventListener("mouseup", stopRubber);
document.addEventListener("mousemove", moveRubber);
})();
So basically, I'm loading and inserting html to a div element on my homepage. It all works well except that I've realised my regular href link just won't work. When I hover the URL appears on the bottom of Chrome as usual, but when I click, nothing happens.
For what I've seen, it seems like click events might not work properly on dynamically added elements?
The issue is, I've only seen jQuery solutions for this, and, frankly, I'm not even sure if this is the issue at all.
Any ideas?
PS: http://jsfiddle.net/8hz1Lubr/
// -------------------------- get the elements ----------------------- //
const deskbar = document.querySelector('#deskbar');
const screen = document.querySelector('#desktop');
const menuLink = document.querySelector('#primaryNav');
const tabsList = document.querySelector('#tabsList');
const clock = document.getElementById('theTime');
const desktop = document.querySelector('#contentarea');
// -------------------------- create events -------------------------- //
screen.addEventListener('click', toggleMenu);
tabsList.addEventListener('click', activateTab);
menuLink.addEventListener('click', openWindow);
menuLink.addEventListener('click', generateTab);
// -------------------------- open windows --------------------------- //
function openWindow(e) {
let windows = document.querySelectorAll('.window');
let openWindows = [];
windows.forEach(function(theWindow){
openWindows.push(theWindow.getAttribute('data-window'));
});
if(e.target.classList.contains('menuLink') && !openWindows.includes(e.target.getAttribute('data-link'))) {
let newWindow =`<div class="window" id="${e.target.getAttribute('data-link')}" data-window="${e.target.getAttribute('data-link')}">
<header class="header"></header>
<span class="close"></span>
<div class="headerContent">
${e.target.innerText}
<span class="minimize"></span>
</div>
<article>
<div class="content"></div>
</article>
</div>`;
desktop.insertAdjacentHTML('afterbegin', newWindow);
fetchPage(e.target.href, e.target.getAttribute('data-link'));
}
windows = document.querySelectorAll('.window');
// create add event listener for each new window
windows.forEach(function(theWindow){
theWindow.addEventListener('click', closeWindow);
theWindow.addEventListener('click', closeTab);
if(window.matchMedia("(min-width: 960px)").matches) {
theWindow.getElementsByClassName('headerContent')[0].onmousedown = function(event) {
let shiftX = event.clientX - theWindow.getBoundingClientRect().left;
let shiftY = event.clientY - theWindow.getBoundingClientRect().top;
deactivateAllWindows();
theWindow.classList.add('activeWindow');
theWindow.style.position = 'absolute';
theWindow.style.zIndex = 15;
desktop.append(theWindow);
moveAt(event.pageX, event.pageY);
// centers the ball at (pageX, pageY) coordinates
function moveAt(pageX, pageY) {
theWindow.style.left = pageX - shiftX + 'px';
theWindow.style.top = pageY - shiftY + 'px';
}
function onMouseMove(event) {
moveAt(event.pageX, event.pageY);
}
// move the window on mousemove
document.addEventListener('mousemove', onMouseMove);
// drop the window, remove unneeded handlers
theWindow.onmouseup = function() {
document.removeEventListener('mousemove', onMouseMove);
theWindow.onmouseup = null;
};
};
theWindow.ondragstart = function() {
return false;
};
}
});
e.preventDefault();
}
// -------------------------- fetch html content --------------------- //
function fetchPage(url, attribute) {
let windows = document.querySelectorAll('.window');
fetch(url)
.then(function(response) {
return response.text();
})
.then(function(body) {
windows.forEach(function(theWindow) {
theWindow.style.zIndex = 14;
theWindow.classList.remove('activeWindow');
});
windows.forEach(function(theWindow) {
if(theWindow.getAttribute('data-window') == attribute) {
if(window.matchMedia("(min-width: 960px)").matches) {
let randomHeight = Math.floor(Math.random() * (40 - 20 + 1)) + 20;
let randomWidth = Math.floor(Math.random() * (40 - 20 + 1)) + 20;
theWindow.style.zIndex = 15;
theWindow.style.top = randomHeight + '%';
theWindow.style.left = randomWidth + '%';
setTimeout(function(){
theWindow.style.opacity = 1;
}, 125);
}
theWindow.classList.add('activeWindow');
let content = theWindow.querySelector('.content');
content.innerHTML = body;
}
});
});
}
Trying to create a popup that will show when hovering over an element. However it flickers and moves around when I move my mouse inside the element. It should also stay open if the mouse moves over the popup.
Trying to do this without library cheats like jQuery. You don't learn if you use them.
If you hover your mouse over one of the tags below, that's exactly what I'm trying to create.
Think the error is somewhere in this code:
function showPopup(e) {
var popup = document.getElementById('popup');
if (popup.style.display == 'none') {
popup.style.display = 'block';
var bodyRect = document.body.getBoundingClientRect(),
elemRect = e.target.getBoundingClientRect(),
offsetX = elemRect.left - bodyRect.left,
offsetY = elemRect.bottom - bodyRect.top;
popup.style.left = offsetX + 'px';
popup.style.top = offsetY + 'px';
//console.log(e);
}
}
function hidePopup(/*e*/) {
setTimeout(function() {
var popup = document.getElementById('popup');
if (popup.style.display == 'block' && !window.inside_popup) {
popup.style.display = 'none';
window.inside_popup = false;
console.log('hide');
} else {
setTimeout(hidePopup, 50); // try a little later
}
}, 50); // Give the events ability to catch up and tell us the mouse is inside the popup
}
var targ = document.querySelector('ul li')
targ.addEventListener('mouseover', showPopup);
targ.addEventListener('mouseout', hidePopup);
Full javascript code with a real test element:
https://jsfiddle.net/g8wvae8o/
As #epascarello said, mouseleave and mouseenter are what you're looking for. There's no need for setTimeout here either. In addition, you're targeting every li on the page (is that intentional?) I recommend targeting a specific class of element to reduce flickering.
This is close, but you'll need to massage the positioning.
function createPopup() {
var container = document.createElement('div');
container.id = 'popup';
container.style.width = '500px';
container.style.height = '700px';
container.style.display = 'none';
container.style.position = 'absolute';
container.style.borderRadius = '2px';
container.style.border = '1px solid #242729';
container.style.backgroundColor = '#535a60';
container.style.color = '#e4e6e8';
container.style.zIndex = '9999999';
container.addEventListener('xmouseenter', function() {
window.inside_popup = true;
//console.log('window.inside_popup = true;');
});
container.addEventListener('xmouseleave', function() {
window.inside_popup = false;
//console.log('window.inside_popup = false;');
});
container.appendChild(document.createTextNode('This is a test'));
(document.body || document.documentElement).appendChild(container);
}
window.inside_popup = false;
createPopup();
function showPopup(e) {
var popup = document.getElementById('popup');
if (popup.style.display == 'none') {
popup.style.display = 'block';
}
}
function hidePopup(/*e*/) {
console.log('hiding')
popup.style.display = 'none';
window.inside_popup = false;
}
var bodyRect = document.body.getBoundingClientRect()
function updatePopup(e) {
var elemRect = e.target.getBoundingClientRect(),
offsetY = elemRect.bottom - bodyRect.top,
offsetX = elemRect.left - bodyRect.left;
popup.style.left = (e.clientX + offsetX) + 'px';
popup.style.top = offsetY + 'px';
}
var targ = document.querySelector('ul li')
targ.addEventListener('mouseenter', showPopup);
targ.addEventListener('mouseleave', hidePopup);
targ.addEventListener('mousemove', updatePopup)
Fiddle
Here's a pure CSS solution (I only use JS to create the popup elements)
window.addEventListener("load", function () {
var els = document.querySelectorAll("li");
els.forEach(el => {
var popup = document.createElement("div");
popup.innerHTML = el.getAttribute("popup");
popup.className = "popup";
el.appendChild(popup);
});
});
*[popup]:hover > .popup {
border: 1px solid #fff;
padding: 0.5em;
width: 400px;
height: auto
}
.popup {
overflow: hidden;
box-sizing: border-box;
background-color: black;
color: #ccc;
border-radius: 3px;
position: absolute;
height: 0px;
}
li {
margin: 2em 0
}
<ul>
<li popup="Some more info about this product">Move the mouse here</li>
<li popup="Some more info about the 2nd product">Some other product</li>
</ul>
The key to this is that the popup is a child of the element that is hovered, thus moving the mouse over the popup still counts as hovering the element.
I need to resize image from its natural size to fit the screen the same way as Chrome does with opened images in it, I wrote a rescale() function for this purpose (below).
It works mostly fine but for big landscape-oriented images (example where both width and height both exceed screen after resizing with my function http://imageontime.com/upload/big/2013/07/20/51ea60b522bba.jpg ) fullscreened image still exceeds screen by few lines at height (and rarely at width), so i wanted to ask if there is a better rescale javascript function out there or if here are any chromium source adepts who could look into chromiums source code to get the image resizing function from it so I could port it into javascript?
Here's the code:
function setautow() {
img.style.width = 'auto';
img.style.removeProperty("height");
if (document.documentElement.clientHeight == 0) // Firefox again...
{
img.height = window.innerHeight;
}
else {
img.height = document.documentElement.clientHeight;
}
}
function setautoh() {
img.style.height = 'auto';
img.style.removeProperty("width");
if (document.documentElement.clientWidth == 0) // FF
{
img.width = window.innerWidth;
}
else {
img.width = document.documentElement.clientWidth;
}
}
function shrink(a) {
if (a) {
if (img.width != document.documentElement.clientWidth) {
setautoh();
}
}
else {
if (img.height != document.documentElement.clientHeight) {
setautow();
}
}
}
var rescaled = false;
function rescale() {
if (rescaled) {
rescaled = false;
img.height = img.naturalHeight;
img.width = img.naturalWidth;
img.style.removeProperty("height");
img.style.removeProperty("width");
}
else {
rescaled = true;
if (img.naturalWidth > img.naturalHeight) {
setautoh();
setTimeout(function () {
shrink(true);
}, 0);
}
else {
setautow();
setTimeout(function () {
shrink(false);
}, 0);
}
}
}
The following seems to do the job nicely, as long as image width/height is not specified in CSS.
#Javascript
window.onresize = window.onload = function()
{
resize();
}
function resize()
{
var img = document.getElementsByTagName('img')[0];
winDim = getWinDim();
img.style.height = winDim.y + "px";
if (img.offsetWidth > winDim.x)
{
img.style.height = null;
img.style.width = winDim.x + "px";
}
}
function getWinDim()
{
var body = document.documentElement || document.body;
return {
x: window.innerWidth || body.clientWidth,
y: window.innerHeight || body.clientHeight
}
}
#CSS
body{
margin:0;
padding:0;
text-align:center;
background:rgb(51, 51, 51);
}
#HTML
<img src="http://placehold.it/4000x3000" />
Finally made what I was looking for, works great for FireFox + Chrome
edit: well, perfect for images larger than screen, gonna work on it so it could work on smaller images
function fit_to_screen()
{
img.removeAttribute("style");
var winX = window.innerWidth + "px";
var winY = window.innerHeight + "px";
var vbar = false;
if (document.body.scrollHeight > document.body.clientHeight) // vertical scrollbar
{
img.style.height = winY;
vbar = true;
}
if (document.body.scrollWidth > document.body.clientWidth) // horizontal scrollbar
{
if (vbar) // both scrollbars
{
if ((document.body.scrollHeight - document.body.clientHeight) > (document.body.scrollWidth - document.body.clientWidth)) // let's see which one is bigger
{
img.removeAttribute("style");
img.style.height = winY;
}
else
{
img.removeAttribute("style");
img.style.width = winX;
}
}
else
{
img.removeAttribute("style");
img.style.width = winX;
}
}
}
// bonus, switch between original size and fullscreen
var rescaled = false;
function rescale()
{
if (rescaled)
{
rescaled = false;
img.removeAttribute("style");
}
else
{
rescaled = true;
fit_to_screen();
}
}