Javascript - Controlling image movement at different speeds with scroll - javascript

I have a container and and image inside that container. When the container is not in view - the image must be at translate y 0%. When the container is halfway into the viewport and past halfway - the image must be translate y 50%. The % value must be bound to the position of the container into the viewport (controlled by scrolling). The position of the container also determines the speed the image is being translated at. The problem I'm getting is that when the speed value changes, the image jerks up or down instead of changing the speed from that point onward.
Here is my script:
if (wScroll > $(".largeWindow").offset().top - ($(window).height())) {
var cont = $(".largeWindow");
var img = $(".coffee2");
var top = cont.offset().top - cont.height();
var speed;
// translate the image within the container
var moveImage = function() {
setSpeed();
var scroll = Math.floor((wScroll - top)) * speed;
return img.css("transform", "translate(-50%, " + scroll + "%)");
}
// get the position of the image within the container
var getImagePos = function() {
return img.position().top - img.height()/2;
}
var getContainerPos = function() {
var windowHeight = $(window).height();
var contPos = Math.floor(cont.offset().top + cont.height()/2) - wScroll;
return Math.floor(contPos/windowHeight * 100);
}
// set the speed the image will be translated at
var setSpeed = function() {
if (getContainerPos() < 50) {
speed = 0;
}
else if (getContainerPos() < 60 ) {
speed = 0.5
}
else if (getContainerPos() < 70 ) {
speed = 0.5
}
else {
speed = 0.8
}
}
getContainerPos();
moveImage();
getImagePos();
}
Here is the sass for the container and image:
.largeWindow
position: relative
margin: 0 auto
height: 400px
width: 400px
border-radius: 50%
overflow: hidden
background:
image: url(../images/bgTable.jpg)
size: cover
repeat: no-repeat
position: center
attachment: fixed
.coffee2
position: absolute
height: 200px
width: 200px
left: 50%
transform: translateX(-50%)
top: - 200px
background:
image: url(../images/bgCup.png)
size: contain
repeat: no-repeat
position: center

Related

I have a map that can be zoomed in and out, how can I easily place markers with javascript?

Its basicly an image, but I want to add some points with dropdowns, and its like 15 points, ajusting it with px would be very time consuming, I wonder if there is any other way around it. Thanks
<div id="map">
<div id="slide">
<img id="mapimg" src="https://i.imgur.com/NLS1KX0.jpg">
<div id="point">
<i id="pointIcon" class="fa-solid fa-location-dot"></i>
</div>
</div>
</div>
$(document).ready(function (){
var scroll_zoom = new ScrollZoom($('#map'),5,0.5)
})
//The parameters are:
//
//container: The wrapper of the element to be zoomed. The script will look for the first child of the container and apply the transforms to it.
//max_scale: The maximum scale (4 = 400% zoom)
//factor: The zoom-speed (1 = +100% zoom per mouse wheel tick)
function ScrollZoom(container,max_scale,factor){
var target = container.children().first()
var size = {w:target.width(),h:target.height()}
var pos = {x:0,y:0}
var scale = 1
var zoom_target = {x:0,y:0}
var zoom_point = {x:0,y:0}
var curr_tranform = target.css('transition')
var last_mouse_position = { x:0, y:0 }
var drag_started = 0
target.css('transform-origin','0 0')
target.on("mousewheel DOMMouseScroll",scrolled)
target.on('mousemove', moved)
target.on('mousedown', function() {
drag_started = 1;
target.css({'cursor':'move', 'transition': 'transform 0s'});
/* Save mouse position */
last_mouse_position = { x: event.pageX, y: event.pageY};
});
target.on('mouseup mouseout', function() {
drag_started = 0;
target.css({'cursor':'default', 'transition': curr_tranform});
});
function scrolled(e){
var offset = container.offset()
zoom_point.x = e.pageX - offset.left
zoom_point.y = e.pageY - offset.top
e.preventDefault();
var delta = e.delta || e.originalEvent.wheelDelta;
if (delta === undefined) {
//we are on firefox
delta = e.originalEvent.detail;
}
delta = Math.max(-1,Math.min(1,delta)) // cap the delta to [-1,1] for cross browser consistency
// determine the point on where the slide is zoomed in
zoom_target.x = (zoom_point.x - pos.x)/scale
zoom_target.y = (zoom_point.y - pos.y)/scale
// apply zoom
scale += delta * factor * scale
scale = Math.max(1,Math.min(max_scale,scale))
// calculate x and y based on zoom
pos.x = -zoom_target.x * scale + zoom_point.x
pos.y = -zoom_target.y * scale + zoom_point.y
update()
}
function moved(event){
if(drag_started == 1) {
var current_mouse_position = { x: event.pageX, y: event.pageY};
var change_x = current_mouse_position.x - last_mouse_position.x;
var change_y = current_mouse_position.y - last_mouse_position.y;
/* Save mouse position */
last_mouse_position = current_mouse_position;
//Add the position change
pos.x += change_x;
pos.y += change_y;
update()
}
}
function update(){
// Make sure the slide stays in its container area when zooming out
if(pos.x>0)
pos.x = 0
if(pos.x+size.w*scale<size.w)
pos.x = -size.w*(scale-1)
if(pos.y>0)
pos.y = 0
if(pos.y+size.h*scale<size.h)
pos.y = -size.h*(scale-1)
target.css('transform','translate('+(pos.x)+'px,'+(pos.y)+'px) scale('+scale+','+scale+')')
}
}
I tried using this, but the image is very long, and it would take to much time, I wonder if there is any easy way to do it.
#point {
position: relative;
overflow: hidden;
margin-left: 338px;
margin-top: -243px;
width: 25px;
height: 25px;
}
I tried using this, but the image is very long, and it would take to much time, I wonder if there is any easy way to do it.
#point {
position: relative;
overflow: hidden;
margin-left: 338px;
margin-top: -243px;
width: 25px;
height: 25px;
}

How to recalculate position of marker inside div with vh html,css,js

I trying to create a map framework for some games and i have a problem with recalc position of marker. Look url to test, with wheel you can resize div with image but the dot red not come back to own position. Sorry but im new on this y trying to learn more about js and css. Thanks
$('.map-live').css('width', "928px");
$('.map-live').css('height', "928px");
$('.map-live').css('background-size', "100%");
$('.map-live').bind('mousewheel DOMMouseScroll', function(event) {
var divSize = $('.map-live').css('width');
console.log(divSize);
divSize = divSize.replace('px', '')
divSize = parseInt(divSize);
console.log("oldSize: " + divSize);
var delta_px = event.originalEvent.wheelDelta > 0 ? (divSize + (divSize * 0.15)) : (divSize - (divSize * 0.15));
console.log("NewSize: " + delta_px);
$(this).css('width', delta_px + "px");
$(this).css('height', delta_px + "px");
$(this).css('background-size', "100%");
UpdatePoints();
});
$(function() {
$("#map-live").draggable();
});
document.getElementById('map-live').addEventListener('click', printPosition)
function getPosition(e) {
var rect = e.target.getBoundingClientRect();
var x = e.clientX - rect.left;
var y = e.clientY - rect.top;
return {
x,
y
}
}
function printPosition(e) {
var position = getPosition(e);
console.log('X: ' + position.x + ' Y: ' + position.y);
var divX = parseInt($('.map-live').css('width').replace('px', ''));
var divY = parseInt($('.map-live').css('height').replace('px', ''));
var vhX = (position.x / divX) * 100;
var vhY = (position.y / divY) * 100;
console.log('vhX: ' + vhX + ' vhY: ' + vhY);
}
function UpdatePoints() {
$('.point').css('top', '2.477565353101834vh');
$('.point').css('left', '2.477565353101834vh');
$('.point').css('position', 'absolute');
}
body {
margin: 0;
overflow: hidden;
}
.map-live {
position: absolute;
left: 10px;
z-index: 9;
background-image: url(https://i.ibb.co/d2y5G1y/map.jpg);
width: 222px;
height: 222px;
transition: all 0.2s linear;
}
.point {
position: absolute;
left: 2.477565353101834vh;
top: 2.477565353101834vh;
width: 10px;
height: 10px;
background-color: red;
border-radius: 50%;
}
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<div class="map-live ui-widget-content" id="map-live">
<div class="point"></div>
</div>
jsfiddle.net/f84mto52
Someone can correct me, but I believe your use of position: absolute is what is making the <div class="point"></div> stay in place.
Your UpdatePoints is setting always the same position in the div. With 'vh' you are calculating and absolute position proportional to viewport, no to parent container.
So, you are zooming the background image but the position (x, y) will be always be (x, y), positions are not zoomed. You need to recalculate which is the new position.
So you need to calculate new position.
function UpdatePoints(){
var divW = parseInt($('.map-live').css('width').replace('px',''));
var divH = parseInt($('.map-live').css('height').replace('px',''));
var topPosition = (2.477565353101834 / 928) * divH;
var leftPosition = (2.477565353101834 / 928) * divW;
$('.point').css('top', topPosition+'vh');
$('.point').css('left', leftPosition+'vh');
$('.point').css('position', 'absolute');
}
Also, instead using 'vh' I recommend to calculate the px position instead. I have added the already calculated delta_px parameter to UpdatePoints function:
<style>
.point {
position: absolute;
left: 22.99180647678502px;
top: 22.99180647678502px;
width: 10px;
height: 10px;
background-color: red;
border-radius: 50%;
}
</style>
<script>
function UpdatePoints(delta_px){
var position = (delta_px/100)*2.477565353101834;
$('.point').css('top', position+'px');
$('.point').css('left', position+'px');
$('.point').css('position', 'absolute');
}
</script>
Also, here we are calculating the top-left position of the .point element, not the position for the center. As it is a circle, it work fine, but if you use any other shape the position translation should be calculated from its center.
I recommend to do some research about how to translate elements. You can start here:
Calculating relative position of points when zoomed in and enlarged by a rectangle!
Zoom in on a point (using scale and translate)!
How do I effectively calculate zoom scale?!

change background position with skrollr.js

i want to change the background position on scroll with skrollr.js library , my background image has lots of images ( about 500 images ) and i want to change theme on scrolling , how can i do it ?
i want to do something like this code but with skrollr.js library :
$(function() {
var rotator = $('#rotator');
var container = $(document);
var viewport = $(window);
var images = 72;
var imageHeight = 30000 / images;
var scrollHeight = container.height() - viewport.height() + imageHeight;
var step = images / scrollHeight;
viewport.scroll(function(event) {
var x = -Math.floor(step * viewport.scrollTop()) * imageHeight;
rotator.css('background-position', x + 'px 0');
});
});
body {
height: 2000px;
}
#rotator {
font-size: 416px;
width: 1em;
height: 1em;
position: fixed;
top: 0;
right: 0;
z-index: -1;
background: transparent url(http://www.3sessanta.it/images/polaroid/sprite_polaroid_total.jpg) no-repeat 0 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="rotator"></div>
Example Demo

Keep div overlay relative to background image regardless of window size

I want to overlay some text over a background image with background-size: cover.
Problem here is how do I keep the overlay div at the same position, relative to the background image, regardless of the window's size?
Here's a fiddle to play around: http://jsfiddle.net/resting/2yr0b6v7/
So I want to position the word eye over the eye of the cat, regardless of window size.
CSS or JS solutions are both welcomed.
EDIT: Added js alternative
I was convinced that this could be done with css and almost gave up, but then I remembered the new(ish) css units vh and vw....
jsfiddle
CSS
html, body{
height: 100%;
width: 100%;
}
.cat {
height: 100%;
width: 100%;
position: relative;
background:url(http://placekitten.com/g/800/400) no-repeat center center / cover;
}
.place-on-eye {
position: absolute;
color: #fff;
margin:0;
}
#media (min-aspect-ratio: 2/1) {
.place-on-eye {
bottom: 50%;
left: 46.875%;
margin-bottom: 1.25vw;
}
}
#media (max-aspect-ratio: 2/1) {
.place-on-eye {
bottom: 52.5%;
left: 50%;
margin-left: -6.25vh;
}
}
Explanation
So the left eye is at approx 375, 190, and since the image is centered, we will also want to know how far off the center it is, so 25, 10. Since the image is covering, the size of the image will change based on whether the aspect ratio of the viewport is greater or less than the aspect ratio of the background image. Knowing this, we can use media queries to position the text.
The image is 2:1, so when the viewport aspect ratio is > 2:1, we know that the width of the image is the width of the viewport, so the left position of the <p> should always be 46.867% (375/800). The bottom position is going to be more difficult because the image extends beyond the viewport top and bottom. We know that the image is centered, so first move the <p> to the middle, then push it up by 2.5% (10/400) of the height of the image. We don't know the height of the image, but we do know the image aspect ratio and that the width of the image is equal to the width of the viewport, so 2.5% of the height = 1.25% width. So we have to move the bottom up by 1.25% width, which we can do by setting margin-bottom:1.25vw. Incidentally, we can do this without vw in this case because padding is always calculated relative to the width, so we could have set padding-bottom:1.25%, however this won't work in the next case where you have to position the left relative to the height.
The case when the aspect ratio is < 2:1 is analogous. The height of the image is the height of the viewport, so the bottom position should always be 52.5% (210/400) and the left is calculated similar to above. Move it over to center, then back it up by 3.125% (25/800) the width of the image, which is equal to 6.25% the height of the image, which is equal to the viewport height, so margin-left:-6.25vh.
Hopefully this is correct and helps you out!
JS Alternative
jsfiddle
Here's an alternative that uses js. It uses some features like forEach and bind that might cause problems depending on how old a browser you need it to work on, but they are easily replaceable. With js you can directly calculate the scaled dimensions of the bg image which makes the positioning easier. Not the most elegant code, but here goes:
//elem: element that has the bg image
//features: array of features to mark on the image
//bgWidth: intrinsic width of background image
//bgHeight: intrinsic height of background image
function FeatureImage(elem, features, bgWidth, bgHeight) {
this.ratio = bgWidth / bgHeight; //aspect ratio of bg image
this.element = elem;
this.features = features;
var feature, p;
for (var i = 0; i < features.length; i++) {
feature = features[i];
feature.left = feature.x / bgWidth; //percent from the left edge of bg image the feature resides
feature.bottom = (bgHeight - feature.y) / bgHeight; //percent from bottom edge of bg image that feature resides
feature.p = this.createMarker(feature.name);
}
window.addEventListener("resize", this.setFeaturePositions.bind(this));
this.setFeaturePositions(); //initialize the <p> positions
}
FeatureImage.prototype.createMarker = function(name) {
var p = document.createElement("p"); //the <p> that acts as the feature marker
p.className = "featureTag";
p.innerHTML = name;
this.element.appendChild(p);
return p
}
FeatureImage.prototype.setFeaturePositions = function () {
var eratio = this.element.clientWidth / this.element.clientHeight; //calc the current container aspect ratio
if (eratio > this.ratio) { // width of scaled bg image is equal to width of container
this.scaledHeight = this.element.clientWidth / this.ratio; // pre calc the scaled height of bg image
this.scaledDY = (this.scaledHeight - this.element.clientHeight) / 2; // pre calc the amount of the image that is outside the bottom of the container
this.features.forEach(this.setWide, this); // set the position of each feature marker
}
else { // height of scaled bg image is equal to height of container
this.scaledWidth = this.element.clientHeight * this.ratio; // pre calc the scaled width of bg image
this.scaledDX = (this.scaledWidth - this.element.clientWidth) / 2; // pre calc the amount of the image that is outside the left of the container
this.features.forEach(this.setTall, this); // set the position of each feature marker
}
}
FeatureImage.prototype.setWide = function (feature) {
feature.p.style.left = feature.left * this.element.clientWidth + "px";
feature.p.style.bottom = this.scaledHeight * feature.bottom - this.scaledDY + "px"; // calc the pixels above the bottom edge of the image - the amount below the container
}
FeatureImage.prototype.setTall = function (feature) {
feature.p.style.bottom = feature.bottom * this.element.clientHeight + "px";
feature.p.style.left = this.scaledWidth * feature.left - this.scaledDX + "px"; // calc the pixels to the right of the left edge of image - the amount left of the container
}
var features = [
{
x: 375,
y: 190,
name: "right eye"
},
{
x: 495,
y: 175,
name: "left eye"
},
{
x: 445,
y: 255,
name: "nose"
},
{
x: 260,
y: 45,
name: "right ear"
},
{
x: 540,
y: 20,
name: "left ear"
}
];
var x = new FeatureImage(document.getElementsByClassName("cat")[0], features, 800, 400);
I have done a fiddle borrowing the principles from the 2 answers. Black dot should overlay at the end of the line. But this solution drifts from actual spot a little in certain ratios.
Maybe someone can improve it?
JS:
$(function() {
function position_spot() {
w = $(window).width();
h = $(window).height();
wR = w/h;
// Point to place overlay based on 1397x1300 size
mT = 293;
mL = -195;
imgW = 1397;
imgH = 1300;
imgR = imgW/imgH;
tR = mT / imgH; // Top ratio
lR = mL / imgW; // Left ratio
wWr = w / imgW; // window width ratio to image
wHr = h / imgH; // window height ratio to image
if (wR > imgR) {
// backgroundimage size
h = imgH * wWr;
w = imgW * wWr;
} else {
h = imgH * wHr;
w = imgW * wHr;
}
$('.overlay-spot').css({
'margin-top': h * tR,
'margin-left': w * lR
});
}
$(window).resize(function() {
position_spot();
});
position_spot();
});
According to how you set your background image position and size:
background-position:center center;
background-size:cover;
the center of background image should still be in the center of your screen - that comes in handy as a constant, so just try to do the same with your p.place-on-eye
.place-on-eye {
...
top: 50%;
left: 50%;
}
Right now paragraph's left top corner is in the center of your screen, if you also add width and height properties you can actually pint elements center into the screen's center. So it's like:
.place-on-eye {
...
width:50px;
height:50px;
text-align:center /* to make sure the text is center according to elements width */
top: 50%;
left: 50%;
margin:-25px 0 0 -25px;
}
So now the center of p.place-on-eye is in the exact center of your screen, just like the center of your background image. To get it over the cat's eye just offset the left and top margin as needed.
so something like margin:-27px 0 0 -60px; should do it.
fiddle

y position issue for background images via css and javascript

I have implemented a parallax scrolling effect based on a tutorial I found. The effect works great. However, when I specify the background images, I am unable to control the y (vertical) axis. This is causing problems because I'm trying to set locations on multiple layered images.
Any thoughts on what's causing the problem?
Here is one external script:
$(document).ready(function(){
$('#nav').localScroll(800);
//.parallax(xPosition, speedFactor, outerHeight) options:
//xPosition - Horizontal position of the element
//inertia - speed to move relative to vertical scroll. Example: 0.1 is one tenth the speed of scrolling, 2 is twice the speed of scrolling
//outerHeight (true/false) - Whether or not jQuery should use it's outerHeight option to determine when a section is in the viewport
$('#mainimagewrapper').parallax("50%", 1.3);
$('#secondaryimagewrapper').parallax("50%", 0.5);
$('.image2').parallax("50%", -0.1);
$('#aboutwrapper').parallax("50%", 1.7);
$('.image4').parallax("50%", 1.5);
})
This is another external script:
(function( $ ){
var $window = $(window);
var windowHeight = $window.height();
$window.resize(function () {
windowHeight = $window.height();
});
$.fn.parallax = function(xpos, speedFactor, outerHeight) {
var $this = $(this);
var getHeight;
var firstTop;
var paddingTop = 0;
//get the starting position of each element to have parallax applied to it
$this.each(function(){
firstTop = $this.offset().top;
});
if (outerHeight) {
getHeight = function(jqo) {
return jqo.outerHeight(true);
};
} else {
getHeight = function(jqo) {
return jqo.height();
};
}
// setup defaults if arguments aren't specified
if (arguments.length < 1 || xpos === null) xpos = "50%";
if (arguments.length < 2 || speedFactor === null) speedFactor = 0.1;
if (arguments.length < 3 || outerHeight === null) outerHeight = true;
// function to be called whenever the window is scrolled or resized
function update(){
var pos = $window.scrollTop();
$this.each(function(){
var $element = $(this);
var top = $element.offset().top;
var height = getHeight($element);
// Check if totally above or totally below viewport
if (top + height < pos || top > pos + windowHeight) {
return;
}
$this.css('backgroundPosition', xpos + " " + Math.round((firstTop - pos) * speedFactor) + "px");
});
}
$window.bind('scroll', update).resize(update);
update();
};
})(jQuery);
Here is the CSS for one section:
#aboutwrapper {
background-image: url(../images/polaroid.png);
background-position: 50% 0;
background-repeat: no-repeat;
background-attachment: fixed;
color: white;
height: 500px;
width: 100%;
margin: 0 auto;
padding: 0;
}
#aboutwrapper .image4 {
background: url(../images/polaroid2.png) 50% 0 no-repeat fixed;
height: 500px;
width: 100%;
margin: 0 auto;
padding: 0;
}
.image3{
margin: 0 auto;
min-width: 970px;
overflow: auto;
width: 970px;
}
Both of these are being called to achieve the parallax scrolling. I really just want to more specifically control the background image locations. I've tried messing with the CSS background position and I've messed with the first javascript snippet as well. No luck.
just a quick shot, have you tried actually placing the images, either in a div or just using the img src tag to actually move the element rather than manipulating the y axis of a background image?

Categories

Resources