I have to move an image using jQuery / Javascript exactly like this url
I have done similar to this using my own logic. But it gets cut for smaller / bigger image either at the top or at the bottom. Or It moves completely at the bottom and doesn't move completely at the top or vice-versa.
http://jsfiddle.net/N2k6M/
(Please move the horizontal scrollbar to view full image.)
Can anyone please suggest me / Fix my code here, so that my mousemove functionality works perfectly fine and upper / lower part of image moves properly.
I need a seamless movement of image just like in the original url.
HTML PART
<div id="oheight" style="z-index:1000;position:absolute;">123</div> , <div id="yheight" style="z-index:1000;position:absolute;">123</div>
<img id="avatar" src="http://chaikenclothing.com/wp-content/uploads/2012/05/11.jpg![enter image description here][2]" style="position:absolute;overflow:hidden;" />
JAVASCRIPT PART
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script lang="javascript">
var doc_height = $(document).height();
function updateAvatarPosition( e )
{
var avatar = document.getElementById("avatar");
var yheight = parseInt(e.y);
var ywidth = e.x;
//avatar.style.left = e.x + "px";
if((yheight)<(doc_height)){
yheight*=2;
avatar.style.top = '-'+(yheight) + "px";
}
console.log(yheight);
$("#oheight").html(doc_height);
$("#yheight").html(yheight);
/*if((ywidth)<(doc_height/6)){
avatar.style.top = '-'+e.x + "px";
}*/
}
document.getElementById("avatar").onmousemove = updateAvatarPosition;
</script>
see http://jsfiddle.net/N2k6M/7/
function updateAvatarPosition( e )
{
var img_height = $('#avatar').height();
var window_height = $(window).height();
var factor = (img_height - window_height) / window_height;
if(factor > 1) {
var avatar = document.getElementById("avatar");
var yheight = parseInt(e.clientY);
avatar.style.top = '-'+(yheight * factor) + "px";
}
}
#Felix's answer is great and works well, however it's doing more work than necessary. There are a few constants that do not need to be reassigned with every call. By setting these outside of the updateAvatarPosition function you can improve performance some.
var avatar = $('#avatar');
img_height = avatar.height(),
window_height = $(window).height();
function updateAvatarPosition( e )
{
var factor = (img_height - window_height) / window_height,
yheight = parseInt(e.clientY);
if (factor < 1) {
factor = 1;
}
avatar.css('top', -(yheight * factor));
}
avatar.on('mousemove', updateAvatarPosition);
Updated Fiddle
Avatar is referenced more than once so no need to traverse the DOM multiple times, especially multiple times within a constantly cycling event like mousemove. Make a variable reference to avatar outside of the function. The image_height and window_height are also constants and do not change, so there is no need to recalculate them every time as well. If there is the chance that they would change, reassignment should be handled by a resize event.
Would have replied/commented directly under #Felix's answer but apparently don't have enough influence yet. :-/
i think this is something you want
http://jsfiddle.net/N2k6M/6/
var doc_height = $(document).height();
function updateAvatarPosition( e )
{
var avatar = document.getElementById("avatar");
var yheight = parseInt(e.clientY);
var ywidth = e.clientX;
if((yheight)<(doc_height)){
yheight*=2;
avatar.style.top = '-'+(yheight) + "px";
}
/*if((ywidth)<(doc_height/6)){
avatar.style.top = '-'+e.x + "px";
}*/
}
document.getElementById("avatar").onmousemove = updateAvatarPosition;
Related
What I want to achieve is a javascript animation with variable speed based on cursor position.
For that porpouse I'm using jquery's animate function and mousever event and javascript's setInterval function, but those aren't required, so if there is a better way to achieve it I would be more than happy to hear it (the only requeriment would be javascript).
The problem I'm facing is that I can't change speed dinamicly, for some reason the speed keeps adding to the one it already had instead of set what I wanted and even if it would change as spected it just doesn't happen in a smoothly way because of an unknown reason for me.
Here is the javascript that I have so far:
//settings for container_slider. Are used in startSlider() which handles the animation
var steps_animation_speed = 1000;
var steps_interval = 1500;
var steps_speed_factor = 1; // 100%
var amount_sliders = 3;
//cache DOM elements
var $container_slider = $('#container_slider');
var $shown_slides = $('.shown_slides', $container_slider);
var $slide = $(".slide");
// Just making sure sizing (widths) fits as they should.
var slides_width = $container_slider.width()/amount_sliders;
var slides_margin = parseInt($slide.css('marginLeft').replace('px', '')) + parseInt($slide.css('marginRight').replace('px', ''));
var steps_width = slides_width + slides_margin;
$shown_slides.css('width', steps_width*(amount_sliders+1) + 'px');
$slide.css('width', slides_width);
var interval;
// This function is responsible of the animation
function startSlider() {
$shown_slides.stop(false);
interval = setInterval(function() {
$shown_slides.animate({'margin-left': '-='+steps_width}, steps_animation_speed*steps_speed_factor, function() {
$('.shown_slides > li:last').after($('.shown_slides > li:first'));
$('.shown_slides').css('margin-left', '0');
});
}, steps_interval);
}
function pauseSlider() {
clearInterval(interval);
}
$container_slider.mouseleave(function(){
steps_interval = 3000;
$shown_slides.stop(true);
pauseSlider();
startSlider();
});
// $container_slider.mouseenter(function(){
// pauseSlider();
// });
$container_slider.mousemove(function(event){
pauseSlider();
var cursor_location = '';
if(event.pageX > 0 && event.pageX < 165){
cursor_location = "Cursor is on the left side";
// This is where i'm doing the tests that should work of changing animation's speed based on cursor position
if(steps_speed_factor !== (event.pageX / 165)){
steps_speed_factor = event.pageX / 165;
steps_speed_factor = (steps_speed_factor < 0.15 ? 0.15 : steps_speed_factor);
steps_interval = 0;
startSlider();
}
} else if(event.pageX > 165 && event.pageX < ($container_slider.width()-165)){
cursor_location = "Cursor is in the center (paused)";
// This stops animation, it could be achieved way better but i'm focusing on above's block of code.
steps_speed_factor = 1;
steps_interval = 3000;
$shown_slides.stop(true);
pauseSlider();
} else if(event.pageX > ($container_slider.width()-165) && event.pageX < $container_slider.width()) {
cursor_location = "Cursor is on the right side";
// This would be an exact copy (almost) of the left side, but since it doesn't work yet, this is pretty much a "blank" block of code
steps_interval = 0;
steps_speed_factor = ( event.pageX - ($container_slider.width() - 165) ) / 165;
}
$(".coordinates").html("X: " + event.pageX + " Y: " + event.pageY );
$(".cursor_location").html(cursor_location);
$(".speed_factor").html("Speed Factor is: "+steps_speed_factor);
});
startSlider();
Here is a codepen showing this javascript code "working".
--- EDIT
I forgot to explain propperly what happens in the codepen , since it is just an example didnt give it to much importance. Mainly what should happen is that the furthier the cursor is from the center, the tinier/faster the invervals of the animation should be without losing fluidness.
In this case i'm using a "speed factor" which I calculate by taking cursor's X position and then comparing it with a predefined area, converting it in a percentage (decimal) from 15% to 99%. But it isn't actually the important part. I'm clueless about how to achieve this and the more I try the messier my code gets, so as long as you can give me an example of changing animation's speed (in "real" time, i mean, smoothly/fluid) based on cursor's position as an example it would be perfect.
I have a fullscreen slideshow page, but the slides don't take up 100% of the background. Instead, they base size off of the browser. I want the slides to take 100% of the background. I THINK I narrowed it down to one function, but I'm not sure and not good with JavaScript yet. Here's the function:
// calculate image size, top and left position
jQuery.fn.superbgCalcSize = function(imgw, imgh) {
var options = $.extend($.fn.superbgimage.defaults, $.fn.superbgimage.options);
// get browser dimensions
var browserwidth = $(window).width();
var browserheight = $(window).height();
// use container dimensions when inlinemode is on
if (options.inlineMode === 1) {
browserwidth = $('#' + options.id).width();
browserheight = $('#' + options.id).height();
}
// calculate ratio
var ratio = imgh / imgw;
// calculate new size
var newheight = 0; var newwidth = 0;
if ((browserheight / browserwidth) > ratio) {
newheight = browserheight;
newwidth = Math.round(browserheight / ratio);
} else {
newheight = Math.round(browserwidth * ratio);
newwidth = browserwidth;
}
// calculate new left and top position
var newleft = Math.round((browserwidth - newwidth) / 2);
var newtop = Math.round((browserheight - newheight) / 2);
var rcarr = [newwidth, newheight, newleft, newtop];
return rcarr;
};
Let me know if there needs to be more code or even to link to the entire document, as I said I'm not at all experienced with JS and don't know where the problem resides.
*I've tried doing it with CSS, but I get a bug where as it's transitioning to the next image it bleeps the first image's actual size just before displaying the next and it's rather unsleek. Fixing this would also solve my question.
I made a carousel using 2 divs named "left" and "right" putting mousemove events on them. I wanted to make it go up and down as well so I created a "top" and "bottom" and noticed that I couldn't make them combine to go the way the cursor goes.
I thus thought of targeting a specific area in the container (i.e top half of my container div) instead of creating divs inside triggering a specific direction, this way (I think) I can trigger all these event altogether. However after now hours of research I couldn't find a way to do so.
How should I proceed ? here is the code : http://jsfiddle.net/pool4/vL5g3/3/
var x=0,
y=0,
rateX=0,
rateY=0,
maxspeed=10;
var backdrop = $('.backdrop');
$('.directionx', backdrop).mousemove(function(e){
var $this = $(this);
var left = $this.is('.left');
var right = $this.is('.right');
if (left){
var w = $this.width();
rateX = (w - e.pageX - $this.offset().left + 1)/w;
}
else if (right){
var w = $this.width();
rateX = -(e.pageX - $this.offset().left + 1)/w;
}
});
$('.directiony', backdrop).mousemove(function(e){
var $this = $(this);
var top = $this.is('.top');
var bottom = $this.is('.bottom');
if (top){
var h = $this.height();
rateY = (h - e.pageY - $this.offset().top + 1)/h;
}
else if (bottom) {
var h = $this.height();
rateY = -(e.pageY - $this.offset().top + 1)/h;
}
});
backdrop.hover(
function(){
var scroller = setInterval( moveBackdrop, 30 );
$(this).data('scroller', scroller);
},
function(){
var scroller = $(this).data('scroller');
clearInterval( scroller );
}
);
function moveBackdrop(){
x += maxspeed * rateX;
y += maxspeed * rateY;
var newpos = x+'px '+y+'px';
backdrop.css('background-position',newpos);
}
Your problem is that the divs that control movement up and down are placed over the ones that control left and right, so the latter do not receive the mousemove event ever. Mouse events do not propagate through layers, even if they're transparent. I changed your code and CSS, so each div is in one of the corners. To make things easier, I've used data-* attributes so the direction controlled by each div is set in a declarative way, without the need to change the code. You'll see that the code is much simpler (and it could be simplified even more).
By the way, you could achieve this witout extra divs, just controlling where the cursor is (to the top, right, left or bottom of the center of the div).
backdrop.on('mousemove', '.dir', function(e){
var $this = $(this);
var direction = $(e.target).attr('data-direction');
var left = direction.indexOf('left') > - 1;
var right = direction.indexOf('right') > - 1;
var top = direction.indexOf('up') > - 1;
var bottom = direction.indexOf('down') > - 1;
if (left){
var w = $this.width();
rateX = (w - e.pageX - $this.offset().left + 1)/w;
}
else if (right){
var w = $this.width();
rateX = -(e.pageX - $this.offset().left + 1)/w;
}
if (top){
var h = $this.height();
rateY = (h - e.pageY - $this.offset().top + 1)/h;
}
else if (bottom) {
var h = $this.height();
rateY = -(e.pageY - $this.offset().top + 1)/h;
}
});
I've updated your fiddle.
EDIT In this new fiddle I do it without extra divs:
var w = backdrop.width() / 2;
var h = backdrop.height() / 2;
var center = {
x: backdrop.offset().left + backdrop.width() / 2,
y: backdrop.offset().top + backdrop.height() / 2
};
backdrop.on('mousemove', function(e){
var offsetX = e.pageX - center.x;
var offsetY = e.pageY - center.y;
rateX = -offsetX / w;
rateY = -offsetY / h;
});
backdrop.hover(
function(){
var scroller = $(this).data('scroller');
if (!scroller) {
scroller = setInterval( moveBackdrop, 30 );
$(this).data('scroller', scroller);
}
},
function(){
var scroller = $(this).data('scroller');
if (scroller) {
clearInterval( scroller );
$(this).data('scroller', null);
}
}
);
As you see, the mousmove handler is considerably simpler.
To avoid issue of children losing event could use just the one.
First HTML from 4 child divs to just one
<div class="backdrop">
<div class="direction"></div>
</div>
<div id="pos"></div>
Next Inside the mousemove find your relative position
//Get Relative Position
var relX = e.pageX - $this.offset().left;
var relY = e.pageY - $this.offset().top;
Get Relative Position as a percentage of width and put 50% of it in negative for direction
var w = $this.width();
rateX = ((relX / w) - 0.5) * -1;
var h = $this.height();
rateY = ((relY / h) - 0.5) * -1;
Fiddle
Here I tried to make simple zoom in and out functions on button click.
HTML
<input type="button" value ="-" onClick="zoom(0.9)"/>
<input type="button" value ="+" onClick="zoom(1.1)"/>
<div id="thediv">
<img id="pic" src="http://cdn1.iconfinder.com/data/icons/VistaICO_Toolbar-Icons/256/Zoom-in.png"/>
</div>
SCRIPT
var zoomLevel = 100;
var maxZoomLevel = 105;
var minZoomLevel = 95;
function zoom(zm) {
var img=document.getElementById("pic");
if(zm > 1){
if(zoomLevel < maxZoomLevel){
zoomLevel++;
}else{
return;
}
}else if(zm < 1){
if(zoomLevel > minZoomLevel){
zoomLevel--;
}else{
return;
}
}
wid = img.width;
ht = img.height;
img.style.width = (wid*zm)+"px";
img.style.height = (ht*zm)+"px";
img.style.marginLeft = -(img.width/2) + "px";
img.style.marginTop = -(img.height/2) + "px";
}
But the problem is, whenever I click the zoom-in function the image moves to the top corner of the page. I tried to solve this but no solution was effective.
Here is the BIN I am working on which may be useful to find my mistake.
And also another question: Is there a way to apply mousewheel to this function?
UPDATE
The problem of zoom has been changed. But now the mousewheel also done here but the problem is we can't give the maximum value for the mousewheel.
UPDATED BIN
img.style.marginLeft = -(img.width/2) + "px"; // you have negation sign here
img.style.marginTop = -(img.height/2) + "px"; // you have negation sign here
Change it TO :
img.style.marginLeft = (img.width/2) + "px";
img.style.marginTop = (img.height/2) + "px";
JS BIN LINK
Judging by your marginLeft and marginTop calculation, I guess that you want to zoom in and out of the image while preserving the center point.
So try this:
http://jsbin.com/itekek/4
Preserved an initial width and height value, and slightly modified the zoom limit value.
Edit:
http://jsbin.com/itekek/46
Added mouse wheel support.
See this : http://jsbin.com/itekek/14/edit
You have unstripped zoom plus Mousewheel here..
Update: To get elements by class name use function below:
function findElementByClass(matchClass) {
var elems = document.getElementsByTagName('*'),i;
for (i in elems) {
if ((" " + elems[i].className + " ").indexOf(" " + matchClass + " ") > -1) {
return elems[i];
}
}
return null;
}
See sample
I have written a function that positions a tooltip just above a textbox.
The function takes two arguments:
textBoxId - The ID of the textbox above which the tooltip will appear.
Example: "#textBoxA"
toolTipId - The ID of the tooltip which will appear above the textbox.
Example: "#toolTipA"
function positionTooltip(textBoxId, toolTipId){
var hoverElementOffsetLeft = $(textBoxId).offset().left;
var hoverElementOffsetWidth = $(textBoxId)[0].offsetWidth;
var toolTipElementOffsetLeft = $(toolTipId).offset().left;
var toolTipElementOffsetWidth = $(toolTipId)[0].offsetWidth;
// calcluate the x coordinate of the center of the hover element.
var hoverElementCenterX =
hoverElementOffsetLeft + (hoverElementOffsetWidth / 2);
// calculate half the width of the toolTipElement
var toolTipElementHalfWidth = toolTipElementOffsetWidth / 2;
var toolTipElementLeft = hoverElementCenterX - toolTipElementHalfWidth;
$(toolTipId)[0].style.left = toolTipElementLeft + "px";
var toolTipElementHeight = $(toolTipId)[0].offsetHeight;
var hoverElementOffsetTop = $(textBoxId).offset().top;
var toolTipYCoord = hoverElementOffsetTop - toolTipElementHeight;
toolTipYCoord = toolTipYCoord - 10;
$(toolTipId)[0].style.top = toolTipYCoord + "px";
$(toolTipId).hide();
$(textBoxId).hover(
function(){ $(toolTipId + ':hidden').fadeIn(); },
function(){ $(toolTipId + ':visible').fadeOut(); }
);
$(textBoxId).focus (
function(){ $(toolTipId + ':hidden').fadeIn(); }
);
$(textBoxId).blur (
function(){ $(toolTipId+ ':visible').fadeOut(); }
);
}
The function works fine upon initial page load:
However, after the user resizes the window the tooltips move to locations that no longer display above their associated textbox.
I've tried writing some code to fix the problem by calling the positionTooltip() function when the window is resized but for some reason the tooltips do not get repositioned as they did when the page loaded:
var _resize_timer = null;
$(window).resize(function() {
if (_resize_timer) {clearTimeout(_resize_timer);}
_resize_timer = setTimeout(function(){
positionTooltip('#textBoxA', ('#toolTipA'));
}, 1000);
});
I'm really at a loss here as to why it doesn't reposition the tooltip correctly as it did when the page was initially loaded after a resize.
Your logic for calculating the position of the tooltip only fires initially when you call positionTooltip. You want to call it to recalculate position before the fadeIn call.
i don't understand why you use a setTimeout() to launch your function. Try
$(function(){
// all your code onDocumentReady
...
...
$(window).resize(function() {
positionTooltip('#textBoxA', ('#toolTipA'));
});
});
That worked like a charm for me, the only drawback is that sometimes it dosen't get the proper X,Y position, apparently not it's compensating with object's padding/margin values, i did a dirty fix by adding those values manually before they are set like:
toolTipElementLeft = toolTipElementLeft + 40;
$(toolTipId)[0].style.left = toolTipElementLeft + "px";
and
toolTipYCoord = toolTipYCoord + 25;
$(toolTipId)[0].style.top = toolTipYCoord + "px";