jQuery to get background image height and change parent based on ratio - javascript

I have a background image for each item; in this case the image size is 580x374.
This is being set inline on the li a item for each as a background image but I need to set the elements height so it shows correctly. The image height returned I need to half as it's two images in one that I need to move position on hover but I can do that.
What I am having a problem with is getting the elements width, getting the background size, working out the ratio of the background image size and setting the height of the container to display it.
I need it to be responsive as well, so it sets right on page load whichever viewport size it is and resize.
Here is where I have got to so far, but I'm new to JS.
HTML EXAMPLE:
<ul>
<li class="collection-list-item grid-item first collection-hover">
<a href="/collections/butterfly-sofa" data-image="//cdn.shopify.com/s/files/1/1839/7697/collections/category-panel-butterfly.jpg?v=1490985733" style="background-image: url("//cdn.shopify.com/s/files/1/1839/7697/collections/category-panel-butterfly.jpg?v=1490985733");">
<div class="collection-list-hover-desc right">
<p>Dein eigener Ruhepol in einer hektischen Welt. Der durch eine Struktur im Inneren formstabile Sitzsack vereint Komfort und Ästhetik.</p>
</div>
<div class="collection-list-hover-button left">
<span class="button">Entdecken</span>
</div>
</a>
</li>
<li class="collection-list-item grid-item first collection-hover">
<a href="/collections/butterfly-sofa" data-image="//cdn.shopify.com/s/files/1/1839/7697/collections/category-panel-butterfly.jpg?v=1490985733" style="background-image: url("//cdn.shopify.com/s/files/1/1839/7697/collections/category-panel-butterfly.jpg?v=1490985733");">
<div class="collection-list-hover-desc right">
<p>Dein eigener Ruhepol in einer hektischen Welt. Der durch eine Struktur im Inneren formstabile Sitzsack vereint Komfort und Ästhetik.</p>
</div>
<div class="collection-list-hover-button left">
<span class="button">Entdecken</span>
</div>
</a>
</li>
<li class="collection-list-item grid-item first collection-hover">
<a href="/collections/butterfly-sofa" data-image="//cdn.shopify.com/s/files/1/1839/7697/collections/category-panel-butterfly.jpg?v=1490985733" style="background-image: url("//cdn.shopify.com/s/files/1/1839/7697/collections/category-panel-butterfly.jpg?v=1490985733");">
<div class="collection-list-hover-desc right">
<p>Dein eigener Ruhepol in einer hektischen Welt. Der durch eine Struktur im Inneren formstabile Sitzsack vereint Komfort und Ästhetik.</p>
</div>
<div class="collection-list-hover-button left">
<span class="button">Entdecken</span>
</div>
</a>
</li>
</ul>
JS:
$('.collection-hover a').each(function (index, value){
var collection_bg_img = new Image;
collection_bg_img.src = $(this).data('image');
var bgImgWidth = collection_bg_img.width;
var bgImgHeight = collection_bg_img.height;
var divWidth = $(this).width();
var realImgHeight = ( bgImgHeight / bgImgWidth) * divWidth;
var halfImage = (realImgHeight / 2);
$(this).height(halfImage);
//console.log(halfImage);
});
I guess could set a max width and height and change it width whatever width is set by viewport and adjust height based on ratio?
UPDATE
I tried something like this, not got it working yet though... but maybe a good approach as would be a max width:
$('.collection-hover a').each(function() {
var maxWidth = 580; // Max width for the image
var maxHeight = 374; // Max height for the image
var ratio = 0; // Used for aspect ratio
var width = $(this).width(); // Current image width
var height = $(this).height(); // Current image height
// Check if the current width is larger than the max
if(width > maxWidth){
ratio = maxWidth / width; // get ratio for scaling image
$(this).css("width", maxWidth); // Set new width
$(this).css("height", height * ratio); // Scale height based on ratio
height = height * ratio; // Reset height to match scaled image
}
var width = $(this).width(); // Current image width
var height = $(this).height(); // Current image height
// Check if current height is larger than max
if(height > maxHeight){
ratio = maxHeight / height; // get ratio for scaling image
$(this).css("height", maxHeight); // Set new height
$(this).css("width", width * ratio); // Scale width based on ratio
width = width * ratio; // Reset width to match scaled image
}
});

You can only :
address DOM elements after the document is ready
measure an image's width after it has successfully loaded.
Therefore :
jQuery(function($) {
function resizeBgImgContainers() {
$('.collection-hover a').each(function() {
var $a = $(this);
var img = new Image();
img.onload = function() {
$a.height(img.height * $a.width() / img.width / 2);
};
img.src = $a.data('image');
});
}
$(window).on('resize', resizeBgImgContainers).trigger('resize');
});

If I understand this question correctly, you're trying to:
Add a div to a webpage, the width of which is unknowable.
Add a background to that div and have the background stretch to the width of the div
Resize the div to 1/2 the height of the stretched background
This can actually be accomplished with a combination of img tags and pure CSS.
Here's a JsFiddle demonstating that: https://jsfiddle.net/x11n48yz/1/
<div id='my-page'>
<div class='image-holder'>
<img src='http://cflrs.in/wp-content/uploads/2017/01/example.jpg'/>
</div>
</div>
#my-page {
background-color: green;
width: 200px;
height: 800px;
}
.image-holder {
position:relative;
width: 100%;
height: 0;
padding-bottom: 50%;
margin-bottom: -10%;
overflow: hidden;
}
.image-holder img {
width: 100%;
height: 200%;
position: absolute;
left: 0;
}
.image-holder img:hover {
bottom: 0;
}

Related

JavaScript: Enlarge and decrease image on scroll

I am trying to resize an image on scroll in javascript with the following conditions:
The image is close to an upper and lower image that should not resize
The image has a minimum height of 0, and a max height of almost all screen height
The image should have height 0 until the lower image is fully seen on screen
The image should be resized, letting the lower image's position fixed at the bottom, until the upper image reaches the top.
The image will then start shrinking, and the upper image should be kept at top until the middle image reaches it's minimum size again.
My approach is as follows:
var upperImg = document.getElementById("scroll-sup");
var middleImg = document.getElementById("scroll-int");
var lowerImg = document.getElementById("scroll-inf");
const minHeight = 0;
const maxHeight = document.documentElement.clientHeight - 50;
document.addEventListener("wheel", function(e) {
var upperRect = upperImg.getBoundingClientRect();
var lowerRect = lowerImg.getBoundingClientRect();
var upperDistanceToTop = window.pageYOffset + upperRect.top - 100;
var delta = Math.floor(e.deltaY);
if (lowerRect.y > maxHeight + 500 || middleImg.height < minHeight) {
middleImg.height = minHeight;
} else if (middleImg.height > maxHeight) {
middleImg.height = maxHeight;
} else if (upperRect.top < 60 && middleImg.height > minHeight) {
middleImg.height -= delta;
window.scrollBy(0, -delta);
} else {
middleImg.height += delta;
}
e.preventDefault();
});
.flex-container {
display: flex;
flex-direction: column;
align-items: flex-start;
}
.scroll-img {
border-radius: 0px;
width: 100%;
}
<div style="height: 1000px">some HTML</div>
<div class="flex-container">
<img
src="https://raw.githubusercontent.com/sandraparraga/surveillancepower/main/assets/marco_teorico/scroll-sup.png"
id="scroll-sup"
class="scroll-img"
/>
<img
src="https://raw.githubusercontent.com/sandraparraga/surveillancepower/main/assets/marco_teorico/scroll-int.png"
id="scroll-int"
class="scroll-img"
style="position: sticky; object-fit: fill"
/>
<img
src="https://raw.githubusercontent.com/sandraparraga/surveillancepower/main/assets/marco_teorico/scroll-inf.png"
id="scroll-inf"
class="scroll-img"
/>
</div>
<div style="height: 1000px">some more HTML</div>
I fail to see how my code is wrong, but it is not decreasing the image and keeping the upper one in a fixed position.
Any help is appreciated, thanks in advance.

Trying to keep the random placement of my folders within the window. At the moment it seems to overflow on the x and y axis

I am trying to keep the random placement of my folders within the window. At the moment it seems to overflow on the x-axis and y-axis. Are you able to help? I'm sure this is a simple fix.
The goal is to have the set of folders randomly placed on the screen, but never be placed outside of the screen height and width.
<style>
/* Background Color */
body {
background-color: lightcoral;
}
/* Div position and placement */
div {
position: absolute;
top: 100px;
left: 100px;
}
</style>
<body>
<div class="container">
<div><img src="/images/folder.png" width="100px" /></div>
<div><img src="/images/folder.png" width="100px" /></div>
<div><img src="/images/folder.png" width="100px" /></div>
<div><img src="/images/folder.png" width="100px" /></div>
<div><img src="/images/folder.png" width="100px" /></div>
<div><img src="/images/folder.png" width="100px" /></div>
<div><img src="/images/folder.png" width="100px" /></div>
</div>
</body>
<script>
// collect all the div folders
var folderDivs = document.getElementsByTagName("div");
// get window width and height
var winWidth = window.innerWidth;
var winHeight = window.innerHeight;
// i stands for "index". you could also call this banana or haircut. it's a variable
for (var i = 0; i < folderDivs.length; i++) {
// shortcut! the current div in the list
var thisDiv = folderDivs[i];
// get random numbers for each element
randomTop = getRandomNumber(0, winHeight);
randomLeft = getRandomNumber(0, winWidth);
// update top and left position
thisDiv.style.top = randomTop + "px";
thisDiv.style.left = randomLeft + "px";
}
// function that return a random number between a min and max
function getRandomNumber(min, max) {
return Math.random() * (max - min) + min;
}
</script>
Do not use getElementsByTagName("div") because this applies also to
div class="container"
Instead use
var folderDivs = document.querySelectorAll(".container div");
Subtract image size from allowed place
In your style part you have set top and left position to each div. This rule applies to container div too.
Notice: Your images are in div with class "container" but this div is positioned 100px left and 100px top.
So all your images have 100px left and top offset.
200 = 100 (for image size) + 100 (for container offset)
var imgSizeWithOffset = 200;
// get random numbers for each element
randomTop = getRandomNumber(0, winHeight-imgSizeWithOffset);
randomLeft = getRandomNumber(0, winWidth-imgSizeWithOffset);
If you decide you don't need this container offset you can set your style like this and use 100
<style>
/* Background Color */
body {
background-color: lightcoral;
}
/* Div position and placement */
.container div {
position: absolute;
}
</style>

How to get width and height of text not the span with display table-cell

How to find width and height of a text not the span's having display:table-cell. In side of a div with display:table.
<div style="display: table; width: 50px; height: 343.559px;"><span class="nodeText" style="display: table-cell;vertical-align: middle;text-overflow: ellipsis;font-family: Arial;font-size: 10px;font-style: normal;font-weight: normal;color: black;opacity: 1;">Desktop 1.43k (53.34%)</span></div>
Text width and height is
width is approx 45px
height is approx 35px
If you don't want the height of the span to be the height of the div (you want the space that the actual text takes up) you can extra wrap the text:
const span = document.querySelector("span>span");
console.log(
span.getBoundingClientRect()
)
<div style="display: table; width: 50px; height: 343.559px;">
<span class="nodeText" style="display: table-cell;vertical-align: middle;text-overflow: ellipsis;font-family: Arial;font-size: 10px;font-style: normal;font-weight: normal;color: black;opacity: 1;">
<span>Desktop 1.43k (53.34%)</span>
</span>
</div>
You can have a check for the div if it has a display:table then you can iterate through it and find the span with display:table-cell property.
let divs = document.querySelectorAll('div');
divs.forEach(div => {
if(div.style.display === 'table'){
let spans = document.querySelectorAll('span');
spans.forEach(spn => {
if(spn.style.display === 'table-cell'){
let theSpan = spn.getBoundingClientRect();
console.log(theSpan.width, theSpan.height);
}
});
}
})
Strange nobody recommended getBoundingClientRect:
fiddle
var span = document.getElementsByTagName("span")[0],
rect = span.getBoundingClientRect();
span.parentNode.nextElementSibling.textContent = "width: " + (rect.width|0)
+ "\nheight: " + (rect.height|0);
PS: I see that you meant the client area without the padding. And that was not clear in your question. Use 2 spans so that you end up with client areas.
HERE - width: 40 height: 32
https://developer.mozilla.org/en-US/docs/Web/API/Element/clientWidth
https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetWidth
https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect
https://developer.mozilla.org/en-US/docs/Web/API/Window/getComputedStyle
var $e = document.getElementById("e");
var $a = document.getElementById("a");
// Thses are for the span itself...
// Only inner width and padding
console.log($e.clientWidth,$e.clientHeight);
// also scrollbar if presented and ...
console.log($e.offsetWidth,$e.offsetHeight);
// get the width after any computing necessary
console.log( $e.getBoundingClientRect() );
var style = window.getComputedStyle( $e );
console.log( style.font );
// Now combine them to measure string in pixels
var $canvas= document.createElement("canvas");
var ctx = $canvas.getContext("2d");
ctx.font = style.font;
var txt = $e.innerText;
var measures = ctx.measureText(txt);
console.log( ctx.font );
console.log( measures );
$a.style.height = Math.ceil(measures.width / $e.clientWidth)
* parseInt(style.lineHeight) + 'px';
div, #e { position:relative; }
#a { display:block;width:3px;background:red; }
<!-- changed the size to fit in preview -->
<div style="display: table; width: 50px; height: 47px;"><span id="e" class="nodeText" style="display: table-cell;vertical-align: middle;text-overflow: ellipsis;font-family: Arial;font-size: 10px;font-style: normal;font-weight: normal;color: black;opacity: 1;">Desktop 1.43k (53.34%)</span>
<span style="display: table-cell;vertical-align: middle;">
<span id="a"></span>
</span>
</div>

Javascript countdown and redirect - Part 2

I have a webpage that runs a JavaScript modal popup box with a message in it informing the visitor that they will be redirected to our new site in XX seconds. It also has two links saying "Agree" (then they are redirected) and "Disagree" (to stay on the old/current website).
This all seems to work fine but what I want it to do is stop the redirect when the user either clicks the Disagree link and/or when they click the darkened area outside the popup box (called #mask).
How can I get this to work? - the JS code is below.
Here is the popup box JS code:
$(document).ready(function() {
var id = '#dialog';
//Get the screen height and width
var maskHeight = $(document).height();
var maskWidth = $(window).width();
//Set heigth and width to mask to fill up the whole screen
$('#mask').css({'width':maskWidth,'height':maskHeight});
//transition effect
$('#mask').fadeIn(500);
$('#mask').fadeTo("slow",0.9);
//Get the window height and width
var winH = $(window).height();
var winW = $(window).width();
//Set the popup window to center
$(id).css('top', winH/2-$(id).height()/2);
$(id).css('left', winW/2-$(id).width()/2);
//transition effect
$(id).fadeIn(2000);
//if Disagree word is clicked
$('#disagree').click(function () {
$(this).hide();
$('.window').hide();
$('#mask').hide();
});
//if mask is clicked
$('#mask').click(function () {
$(this).hide();
$('.window').hide();
});
});
And here is the countdown timer code (which is not external like the above popup.js but in the page itself):
<script src="popup.js"></script>
var time_left = 12;
var cinterval;
function time_dec(){
time_left--;
document.getElementById('countdown').innerHTML = time_left;
if(time_left == 1){
var originalstring = document.getElementById('countdown2').innerHTML;
var newstring = originalstring.replace('seconds','second');
document.getElementById('countdown2').innerHTML = newstring;
window.location.replace("http://cadfemukandireland.com/");
clearInterval(cinterval);
}
}
cinterval = setInterval('time_dec()', 1000);
The HTML code is:
<div id="boxes">
<div id="dialog" class="window">
<p>We are currently in the process of upgrading our current website to a new and improved version.</p>
<p>You will automatically be directed to the new website <span id="countdown2">in <span id="countdown">12</span> seconds</span>.</p>
<div id="popupfoot"> I disagree </div>
</div>
<div id="mask"></div>
</div>
Try the code below - It basically zeros the time left when disagree is clicked
I've also assigned the time_dec function to a variable for easier scoping
$(document).ready(function() {
var id = '#dialog';
//Get the screen height and width
var maskHeight = $(document).height();
var maskWidth = $(window).width();
//Set heigth and width to mask to fill up the whole screen
$('#mask').css({'width':maskWidth,'height':maskHeight});
//transition effect
$('#mask').fadeIn(500);
$('#mask').fadeTo("slow",0.9);
//Get the window height and width
var winH = $(window).height();
var winW = $(window).width();
//Set the popup window to center
$(id).css('top', winH/2-$(id).height()/2);
$(id).css('left', winW/2-$(id).width()/2);
//transition effect
$(id).fadeIn(2000);
//if Disagree word is clicked
$('#disagree').click(function () {
$(this).hide();
$('.window').hide();
$('#mask').hide();
time_left = 0;
});
//if mask is clicked
$('#mask').click(function () {
$(this).hide();
$('.window').hide();
});
});
var time_left = 3;
var cinterval;
document.getElementById('countdown').innerHTML = time_left;
var time_dec = function(){
time_left--;
document.getElementById('countdown').innerHTML = time_left;
if(time_left == 1){
var originalstring = document.getElementById('countdown2').innerHTML;
var newstring = originalstring.replace('seconds','second');
document.getElementById('countdown2').innerHTML = newstring;
window.location.replace("http://cadfemukandireland.com/");
clearInterval(cinterval);
}
}
cinterval = setInterval(time_dec, 1000);
#dialog {
position: absolute;
width: 300px;
height: 220px;
border: 1px solid #ccc;
padding: 16px;
top: 100px;
left: 100px;
z-index: 999;
background: #fff;
}
#mask {
z-index: 9;
background: rgba(0,0,0,0.6)
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="boxes">
<div id="dialog" class="window">
<p>We are currently in the process of upgrading our current website to a new and improved version.</p>
<p>You will automatically be directed to the new website <span id="countdown2">in <span id="countdown">12</span> seconds</span>.</p>
<div id="popupfoot"> I agree | <a id="disagree" style="color:red;">I disagree</a>
</div>
</div>
<div id="mask"></div>
</div>

How to get width and height of canvas after resizing the browser

I want to get width and height of canvas which is responsive. I have 5 canvas elements on a single page.
Using Javascript before drawing I want to know the height and width of canvas to be able to draw images at the right size.
HTML Code:
<div id='container'>
<div class='all'>
<canvas id='clock1' style="border:solid">
</div>
<div class='all'>
<canvas id='clock2' style="border:solid">
</div>
<div class='all'>
<canvas id='clock3' style="border:solid">
</div>
<div class='all'>
<canvas id='clock4' style="border:solid">
</div>
<div class='all'>
<canvas id='clock5' style="border:solid">
</div>
</div>
CSS:
#container
{
width:100%;
height:100%;
position:relative;
}
.all
{
width:30%;
height:45%;
float:left;
}
canvas
{
width:100%;
height:100%;
}
Usually you don't set size of canvas using CSS but calculating the w/h and use the width and height properties.
But if you use CSS you can get the calculated size of the canvas element set by CSS using getComputedStyle():
Online demo
var cs = getComputedStyle(canvas);
var width = parseInt( cs.getPropertyValue('width'), 10);
var height = parseInt( cs.getPropertyValue('height'), 10);
the size is here returned by getPropertyValue() as a string and in pixel size (ie. "400px"), so we use parseInt() to chop of the "px" part.
Then simply set the width and height on canvas and update its content.
Full example (adjust as needed):
window.onresize = updateCanvas;
updateCanvas();
function updateCanvas() {
var cs = getComputedStyle(canvas);
var width = parseInt(cs.getPropertyValue('width'), 10);
var height = parseInt(cs.getPropertyValue('height'), 10);
canvas.width = width;
canvas.height = height;
var ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(width, height);
ctx.moveTo(0, height);
ctx.lineTo(width, 0);
ctx.stroke();
}

Categories