jQuery calculate image background-position top position? - javascript

I set my images centred in CSS:
background-position: center center;
But I want to know its top-position now after it is set to centre, how can I calculate that with jQuery or just plain javaScript?
.parallax3 {
position: relative;
background-position: center center;
background-repeat: no-repeat;
background-size: cover;
background-image: url('https://picsum.photos/g/200/600');
height: 100%;
}
.tagline {
font-size: 2.5vw;
letter-spacing:0.05em;
padding: 25% 25%;
}
.grid-x {
border:1px solid red;
}
.cell {
border: 1px solid blue;
}
<div class="row widescreen">
<div class="grid-container full">
<div class="grid-x grid-padding-x align-stretch small-padding-collapse">
<div class="medium-6 cell">
<div class="tagline text-center">
<p>Lorem ipsum dolor sit amet</p>
</div>
</div>
<div class="medium-6 cell parallax-viewport">
<div class="parallax3">
</div>
</div>
</div>
</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/foundicons/3.0.0/foundation-icons.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/foundation/6.4.1/css/foundation.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/foundation/6.4.1/js/foundation.min.js"></script>
Any ideas?

As I commented above we need to find the formula, so the idea is to rely on the logic of background-position:center and background-size:cover. So since the image will always be stretched, we have two possibilities :
The top of the image will be the same as the top of div and thus top=0
The height of the image will be longer than the div and the top will be hidden and thus top<0
As you may notice I considered the top position relatively to the top of the div which is the origin for me
Now we need to consider all the different cases on how the image will cover the div and calculate the new height of the image depending on each situation.
Here is a code example:
//am using fixed values because they are known in this case, so this need to also be calculated
var him = 600;
var wim = 200;
var ratio = him / wim;
/*--*/
function get_top() {
var h = $('.parallax3').height();
var w = $('.parallax3').width();
var diffh = h - him;
var diffw = w - wim;
if (diffw > 0 && diffh > 0) {
//the image is smaller than the div so it should get bigger by at least the max difference
if (diffh > diffw*ratio) {
//both height will be equal here so top position = 0
console.log(0);
} else {
//height of image will be bigger so top position < 0
var newH = (wim + diffw) * ratio;
console.log((h - newH) / 2)
}
} else if (diffw > 0) {
//only the width if div is bigger so the image width will stretch and the height will be bigger and top < 0;
var newH = (wim + diffw) * ratio;
console.log((h - newH) / 2)
} else if (diffh > 0) {
//only the height is bigger so the image height will stretch and both heights will be equal to div and top = 0
console.log(0);
} else {
// the image is bigger in this case so we do same logic as the start with abs value but we will reduce size so we consider the lowest value
if (Math.abs(diffh) < Math.abs(diffw)*ratio) {
//both height will be equal here so top position = 0
console.log(0);
} else {
//height of image will remain bigger so top position < 0
var newH = (wim + diffw) * ratio;
console.log((h - newH) / 2)
}
}
}
get_top();
$(window).resize(function() {
get_top()
})
body {
height: 100vh;
}
.parallax3 {
position: relative;
background-position: center center;
background-repeat: no-repeat;
background-size: cover;
background-image:url('https://picsum.photos/g/200/600');
height: 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="parallax3">
</div>
If we consider contain as value in background-size the image will always be contained inside the div so the two possibilities are:
The top of the image will be the same as the top of the div and thus top=0
The image will be smaller in height and the top of image will be visible and thus top>0
Same thing as the above, we need to consider the different situations and calculate the new height of the image.
Here is a code example:
//am using fixed values because they are known in this case, so this need to also be calculated
var him = 600;
var wim = 200;
var ratio = him / wim;
/*--*/
function get_top() {
var h = $('.parallax3').height();
var w = $('.parallax3').width();
var diffh = h - him;
var diffw = w - wim;
if (diffw > 0 && diffh > 0) {
//the image is smaller than the div so it should get bigger by at least the min difference
if (diffh < diffw*ratio) {
//both height will be equal here so top position = 0
console.log(0);
} else {
//height of image will be bigger so top position < 0
var newH = (wim + diffw) * ratio;
console.log((h - newH) / 2)
}
} else if (diffw > 0) {
//only the width if div is bigger so the image height need to be reduced and both height will be equal
console.log(0);
} else if (diffh > 0) {
//only the height is bigger so the image width will be reduced
var newH = (wim + diffw) * ratio;
console.log((h - newH) / 2);
} else {
// the image is bigger in this case so we do same logic as the start with abs value but we will reduce size so we consider the biggest value
if (Math.abs(diffh) > Math.abs(diffw)*ratio) {
//both height will be equal here so top position = 0
console.log(0);
} else {
//height of image will be bigger so top position < 0
var newH = (wim + diffw) * ratio;
console.log((h - newH) / 2)
}
}
}
get_top();
$(window).resize(function() {
get_top()
})
body {
height: 100vh;
}
.parallax3 {
position: relative;
background-position: center center;
background-repeat: no-repeat;
background-size: contain;
background-image: url('https://picsum.photos/g/200/600');
height: 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="parallax3">
</div>
Both snippet can be optimized to reduce redundancy but I kept them like this to better explain different situations.

Related

How to align elements around the perimeter of a circle?

I'm trying to align elements around a circle like this:
this is my code, I've added a drag function to rotate the wrapper box, I'm not very Math savy so I don't know where to go from here.
https://codepen.io/pedro_coelho/pen/GRQKWPW
const box = wrapper.getBoundingClientRect()
const xCenter = (box.left + box.right) / 2;
const yCenter = (box.top + box.bottom) / 2;
console.log(xCenter, yCenter);
wrapper.style.transformOrigin = `${xCenter}, ${yCenter}`;
//wrapper.style.transform = 'rotate(30deg)';
document.onmousedown = dragMouseDown;
let mouseX, mouseY, offsetX,offsetY;
function dragMouseDown(e) {
e = e || window.event;
e.preventDefault();
// get the mouse cursor position at startup:
mouseX = e.clientX;
mouseY = e.clientY;
document.onmouseup = closeDragElement;
// call a function whenever the cursor moves:
document.onmousemove = elementDrag;
}
function elementDrag(e) {
e = e || window.event;
e.preventDefault();
// calculate the new cursor position:
offsetX = mouseX - e.clientX;
offsetY = mouseY - e.clientX;
// rotate:
wrapper.style.transform = `rotate(${offsetX/5}deg)`;
}
function closeDragElement() {
// stop moving when mouse button is released:
document.onmouseup = null;
document.onmousemove = null;
}
Instead of doing the math yourself, CSS can help as it will rotate an element a given number of degrees.
If we create elements which have height the radius of the circle and some width (which you decide) and place them all top center of the container (.circle) element we can rotate the nth one about its bottom central point a number of degrees depending on its child position.
This could give us something like this for 10 elements with angle 36 degrees between them:
Within each of those elements (or however many you actually want to show) you can place your divs which have the image, and anything else you want, at the top of the element.
We then have to rotate the whole circle back an amount to get an equal number of elements either side of the vertical.
This snippet uses CSS variables to do the calculation and you can set the number of elements to be shown and the angle between them, CSS does the rest.
.circle {
position: relative;
--w: 50vmin;
width: var(--w);
height: var(--w);
rdisplay: flex;
--show: 5;
/* put to the number you want to have */
--angle: 36;
/* put to the angle between them */
--num: calc(360 / var(--angle));
transform: rotate(calc(((var(--show) + 1) / 2 * var(--angle)) * -1deg));
}
.element {
width: calc(var(--w) / 6);
/* set to whatever width you want */
height: 50%;
top: 0;
left: calc(50% - 1vw);
transform-origin: center bottom;
transform: rotate(calc(360deg * var(--n) / var(--num)));
position: absolute;
}
.element>* {
background-position: center center;
background-size: contain;
background-repeat: no-repeat;
position: absolute;
top: 0;
left: 0;
width: 100%;
aspect-ratio: 1 / 1.5;
/* put this to what you want */
}
.element:nth-child(1) {
--n: 1;
}
.element:nth-child(2) {
--n: 2;
}
.element:nth-child(3) {
--n: 3;
}
.element:nth-child(4) {
--n: 4;
}
.element:nth-child(5) {
--n: 5;
}
.element:nth-child(1)>* {
background-image: url(https://picsum.photos/id/1015/200/200);
}
.element:nth-child(2)>* {
background-image: url(https://picsum.photos/id/1015/200/200);
}
.element:nth-child(3)>* {
background-image: url(https://picsum.photos/id/1015/200/200);
}
.element:nth-child(4)>* {
background-image: url(https://picsum.photos/id/1015/200/200);
}
.element:nth-child(5)>* {
background-image: url(https://picsum.photos/id/1015/200/200);
}
<meta name="viewport" content="width=device-width, initial-scale=1">
<div class="circle">
<div class="element">
<div></div>
</div>
<div class="element">
<div></div>
</div>
<div class="element">
<div></div>
</div>
<div class="element">
<div></div>
</div>
<div class="element">
<div></div>
</div>
</div>

How to simulate rays emerging from an image/div to another image/div using HTML and CSS

I want to build a page to show a blown-up version of an image.
I have the smaller image and the bigger image built out. I am not sure how to build the in between portion that looks like rays coming out of the smaller image.
HTML
<div class="flex">
<div class="exp" tabindex="0">
<img class="image" src="http://via.placeholder.com/50x50">
</div>
<div class="big-image">
<img class="image" src="http://via.placeholder.com/350x550">
</div>
</div>
CSS
.exp {
margin: 5px;
width: 100px;
height: 100px;
background-color: #ded3c0;
border-radius: 100%;
line-height: 80px;
align-items: center;
display: flex;
justify-content: center;
}
.exp .image {
width: 50px;
height: 50px;
}
.big-image {
border: 1px solid #000;
padding: 20px;
border-radius: 19px;
}
.flex {
display: flex;
align-items: center;
justify-content: space-around;
}
Any pointers on how to do this is helpful.
Here is jsfiddle https://jsfiddle.net/npkeq7ut/
If you need only lines you can achieve this with JS and skew transform:
let topLine = document.getElementById('top-line');
let bottomLine = document.getElementById('bottom-line');
function updateLines()
{
let b = document.getElementById('b').getBoundingClientRect();
let a = document.getElementById('a').getBoundingClientRect();
let left = a.right;
let width = b.left - a.right;
let tHeight = a.top - b.top;
let tTop = tHeight / 2 + b.top;
let tAngle = Math.atan(tHeight / width) * 180 / Math.PI;
let bHeight = b.bottom - a.bottom;
let bTop = bHeight / 2 + a.bottom - bottomLine.offsetHeight;
let bAngle = Math.atan(bHeight / width) * 180 / Math.PI;
topLine.style.top = tTop + "px";
topLine.style.left = left + "px";
topLine.style.width = width + "px";
topLine.style.transform = "skewY("+(-tAngle)+"deg)";
bottomLine.style.top = bTop + "px";
bottomLine.style.left = left + "px";
bottomLine.style.width = width + "px";
bottomLine.style.transform = "skewY("+(bAngle)+"deg)";
}
updateLines();
Fiddle: https://jsfiddle.net/JacobDesight/f40yeuqe/2/
#EDIT
If you want trapeze with background then here is example using canvas: https://jsfiddle.net/JacobDesight/f40yeuqe/3/
This could be a starting point for you.
Code by thecodeplayer.
http://thecodeplayer.com/walkthrough/magnifying-glass-for-images-using-jquery-and-css3
$(document).ready(function() {
var native_width = 0;
var native_height = 0;
//Now the mousemove function
$(".magnify").mousemove(function(e) {
//When the user hovers on the image, the script will first calculate
//the native dimensions if they don't exist. Only after the native dimensions
//are available, the script will show the zoomed version.
if (!native_width && !native_height) {
//This will create a new image object with the same image as that in .small
//We cannot directly get the dimensions from .small because of the
//width specified to 200px in the html. To get the actual dimensions we have
//created this image object.
var image_object = new Image();
image_object.src = $(".small").attr("src");
//This code is wrapped in the .load function which is important.
//width and height of the object would return 0 if accessed before
//the image gets loaded.
native_width = image_object.width;
native_height = image_object.height;
} else {
//x/y coordinates of the mouse
//This is the position of .magnify with respect to the document.
var magnify_offset = $(this).offset();
//We will deduct the positions of .magnify from the mouse positions with
//respect to the document to get the mouse positions with respect to the
//container(.magnify)
var mx = e.pageX - magnify_offset.left;
var my = e.pageY - magnify_offset.top;
//Finally the code to fade out the glass if the mouse is outside the container
if (mx < $(this).width() && my < $(this).height() && mx > 0 && my > 0) {
$(".large").fadeIn(100);
} else {
$(".large").fadeOut(100);
}
if ($(".large").is(":visible")) {
//The background position of .large will be changed according to the position
//of the mouse over the .small image. So we will get the ratio of the pixel
//under the mouse pointer with respect to the image and use that to position the
//large image inside the magnifying glass
var rx = Math.round(mx / $(".small").width() * native_width - $(".large").width() / 2) * -1;
var ry = Math.round(my / $(".small").height() * native_height - $(".large").height() / 2) * -1;
var bgp = rx + "px " + ry + "px";
//Time to move the magnifying glass with the mouse
var px = mx - $(".large").width() / 2;
var py = my - $(".large").height() / 2;
//Now the glass moves with the mouse
//The logic is to deduct half of the glass's width and height from the
//mouse coordinates to place it with its center at the mouse coordinates
//If you hover on the image now, you should see the magnifying glass in action
$(".large").css({
left: px,
top: py,
backgroundPosition: bgp
});
}
}
})
})
/*Some CSS*/
* {
margin: 0;
padding: 0;
}
.magnify {
width: 200px;
margin: 50px auto;
position: relative;
}
/*Lets create the magnifying glass*/
.large {
width: 175px;
height: 175px;
position: absolute;
border-radius: 100%;
/*Multiple box shadows to achieve the glass effect*/
box-shadow: 0 0 0 7px rgba(255, 255, 255, 0.85), 0 0 7px 7px rgba(0, 0, 0, 0.25), inset 0 0 40px 2px rgba(0, 0, 0, 0.25);
/*Lets load up the large image first*/
background: url('http://thecodeplayer.com/uploads/media/iphone.jpg') no-repeat;
/*hide the glass by default*/
display: none;
}
/*To solve overlap bug at the edges during magnification*/
.small {
display: block;
}
<!-- Lets make a simple image magnifier -->
<div class="magnify">
<!-- This is the magnifying glass which will contain the original/large version -->
<div class="large"></div>
<!-- This is the small image -->
<img class="small" src="http://thecodeplayer.com/uploads/media/iphone.jpg" width="200"/>
</div>
<!-- Lets load up prefixfree to handle CSS3 vendor prefixes -->
<script src="http://thecodeplayer.com/uploads/js/prefixfree.js" type="text/javascript"></script>
<!-- You can download it from http://leaverou.github.com/prefixfree/ -->
<!-- Time for jquery action -->
<script src="http://thecodeplayer.com/uploads/js/jquery-1.7.1.min.js" type="text/javascript"></script>

Why does the container lose 10px height?

I have the following code which is basically a container that has a width and is then filled up with squares so there is an equal number of squares accorss and down:
var container = $('.container'),
numberOfSquares = 25,
squareSize = container.width() / numberOfSquares;
for (var squares = 0; squares < numberOfSquares * numberOfSquares; squares++) {
$('<div class="gridSquare"></div>').appendTo(container);
}
$('.gridSquare').css({
"height": squareSize + "px",
"width": squareSize + "px"
});
.container {
width: 960px;
}
.gridSquare {
background-color: black;
display: inline-block;
vertical-align: top;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container"></div>
My question is why does the .container lose 10px in height (if you inspect element it is only 950px high), even though the squares inside are square, there is an equal number vertically and horizontally and the row fills up the full 960px?
I've just checked and this only seems to occur in chrome
Because you can only draw at full pixels. The height of each square is rounded from 38.4px down to 38px. 25 * 38px = 950px.

Stretched background stopped working

I am working on an experimental art site that involves a grid of images each scaled to the size of the viewport. The background for the page body should be one stretched image and it was working at one point but has stopped functioning. The background color shows and the image simply doesn't. However if the background-size CSS is turned off in Chrome inspector it shows up at it's own size positioned top and left...
I am guessing that having body contain a box which amounts to 5 viewports wide and 5 viewports tall is messing with what the body element's size is? Though allowing bg image to repeat didn't make it show up...
I resolved this by grabbing the screen width and height in the JavaScript and then setting background-size to those values like so:
$('body,html').css('background-size',the_width + 'px ' + the_height+'px');
But my question remains- why did the background-size:100% 100% stop working?
The page HTML looks like this only with 25 total divs and images.
<body>
<div id="box">
<div class="full" id="full_10">
<img src="home_tiles/10.jpg" width="800" height="600" title="10">
</div>
<div class="full" id="full_11">
<img src="home_tiles/11.jpg" width="800" height="600" title="11">
</div>
</div>
</body>
The CSS looks like this
* { padding: 0; margin: 0; }
html, body {
overflow:hidden;
background-color: #FF0000;
background-size: 100% 100%;
background-image:url(home_tiles/edge.jpg);
background-repeat:no-repeat;
}
img { display: block; }
#box {
position:absolute;
}
.full {
float:left;
}
The JavaScript sizing the images is
$(function() {
$('.full').hide();
var win = $(window),
fullscreen = $('.full'),
image = fullscreen.find('img'),
imageWidth = image.width(),
imageHeight = image.height(),
imageRatio = imageWidth / imageHeight;
var the_width;
var the_height;
var left_limit;
var right_limit;
function resizeImage() {
var winWidth = win.width(),
winHeight = win.height(),
winRatio = winWidth / winHeight;
if(winRatio > imageRatio) {
the_width = winWidth;
the_height = Math.round(winWidth / imageRatio);
} else {
the_width = Math.round(winHeight * imageRatio);
the_height = winHeight;
}
left_limit = the_width * -2;
right_limit = the_width * 2;
image.css({
width: the_width,
height: the_height
});
$('#box').css({
width: the_width * 5,
height: the_height * 5,
top: the_height * -2,
left: the_width * -2
});
}
win.bind({
load: function() {
resizeImage();
$('.full').show('slow');
},
resize: function() {
resizeImage();
}
});

Scrolling Parallax Issues — posY Jumping

I'm working on a site based on this: http://inner.geek.nz/javascript/parallax/
All's well except I'm getting a jump down (by whatever px is set in calcParallax(xx, x, posY))
on scroll. This number should be where the image ends not where it begins — it should begin scrollTop or 0. Not sure what I'm doing wrong, I've pretty much taken the structure verbatim from the above link without the #cloud object or relevant script.
Here's what I have:
<script type="text/javascript">
function calcParallax(tileheight, speedratio, scrollposition) {
return ((tileheight) - (Math.floor(scrollposition / speedratio) % (tileheight+1)));
}
window.onload = function() {
window.onscroll = function() {
var posX = (document.documentElement.scrollLeft) ? document.documentElement.scrollLeft : window.pageXOffset;
var posY = (document.documentElement.scrollTop) ? document.documentElement.scrollTop : window.pageYOffset;
var ground = document.getElementById('ground');
var groundparallax = calcParallax(53, 8, posY);
ground.style.backgroundPosition = "0 " + groundparallax + "px ";
document.getElementById('javascriptcode').onscroll = function() {
var posX = (this.scrollLeft) ? this.scrollLeft : this.pageXOffset;
var j = calcParallax(53, 16, posX);
console.log('scroll js: '+ j);
document.getElementById('javascriptcode').style.backgroundPosition = j + "px 0";
}
}
</script>
Any help would be much appreciated
Use this example instead. It uses a different jQuery that seems more stable and does not jump around like the script from inner geek.
http://www.stevefenton.co.uk/cmsfiles/assets/File/backgroundparallax.html
I put together a demo on something similar while trying to minimize scripting in the scroll event... I've found that it's jumpy in Firefox and Chrome, and oddly smooth as silk in IE.
Even this game website that uses a combination of Mootools and CSS transitions is a bit jumpy.
CSS
/* Tiled background image */
body {
margin: 0;
padding: 0;
/* Use height of header image for top position */
background: #000 url(http://i201.photobucket.com/albums/aa236/Mottie1/testsite/forums/bgtile.jpg) left 1080px repeat-y;
}
/* Top background image (1920x1080) */
#wrapper {
position: relative;
top: 0;
left: 0;
height: 100%;
width: 100%;
background: url(http://i201.photobucket.com/albums/aa236/Mottie1/testsite/forums/bg1.jpg) center top repeat-x;
z-index: 100;
}
/* Page Title image */
#header {
height: 350px;
background: url(http://i201.photobucket.com/albums/aa236/Mottie1/testsite/forums/title.png) center 40px no-repeat;
}
/* Content Block with 55% opacity background image */
.block {
width: 600px;
height: 500px;
margin: 20px auto;
border: #333 1px solid;
padding: 20px;
background: url(http://i201.photobucket.com/albums/aa236/Mottie1/testsite/forums/bg-black-55.png);
}
.block h3 {
font-family: 'Arial Black', Gadget, sans-serif;
font-size: 130%;
}
HTML
<body> <!-- contains repeated background image -->
<div id="wrapper"> <!-- contains top image -->
<div id="header"></div> <!-- contains the page title image -->
<div class="block"> <!-- contains 55% opacity background image -->
<h3>Block 1</h3>
<div class="content">Content 1.</div>
</div>
<div class="block">
<h3>Block 2</h3>
<div class="content">Content 2.</div>
</div>
<div class="block">
<h3>Block 3</h3>
<div class="content">Content 3.</div>
</div>
<div class="block">
<h3>Block 4</h3>
<div class="content">Content 4.</div>
</div>
<div class="block">
<h3>Block 5</h3>
<div class="content">Content 5.</div>
</div>
</div>
</body>
Script
$(document).ready(function(){
// defaults
var st, win = $(window)[0],
body = $('body')[0],
doc = (jQuery.support.boxModel) ? document.documentElement : document.body,
wrap = $('#wrapper')[0],
// Set top background image height here
imgH = 1080; // top image height
// vertical parallax scroll
$(win).scroll(function(){
st = (win.pageYOffset || doc.scrollTop );
if (st < imgH) { wrap.style.backgroundPosition = 'center ' + (st/4) + 'px'; } // limit moving top image only when in view
body.style.backgroundPosition = 'left ' + ( imgH + st/4) + 'px';
});
});
Change your 53 to the exact height of each element.
The only thing I can't figure out about this script is it jumps slightly vertically when I change it to a scroll left function.
var element = document.getElementById('element');
var elementparallax = calcParallax(7000, .5, posX);
element.style.backgroundPosition = " 0" + elementparallax + "px";
};
P.S. You can change the vertical scroll to horizontal by changing posY to posX and in = "0_" + elementparalax to = "_0"

Categories