I have never used GreenSock before. The background image changes fine, it switches and scales in and out however the issues I am facing are as follows:
The first background image on the sprite to show does not scale in and out but all the others do, how can I fix this?
It seems to change the background then scale in and out. So there is a small delay between the changing of the background image and the start of scale animation. Is there anyway to tighten this up so it scales as its changed to make it a more smoother transition?
JavaScript:
// Avatar animations
var avatarInterval;
var fadePulse = true; // true: will fade avatar images and pulse in and out once changed
// false: will slide the avatars in and out
var avatarCount = 11; // set the amount of avatars in the sprite image
var avatarSpeed = 1000; // set the avatar transition speed
var avatarHeight = 250; // set the height of a single avatar image
var avatarTotalHeight = 2750; // set the total height of the avatar sprite image
function startAvatarAnimation() {
var i = 0;
$(".avatars").show();
// Loop through avatar background images on sprite
avatarInterval = setInterval(function(){
i++;
if(i > avatarCount){
i = 0;
}
// Let's change the background
$(".avatars").css({'background-position' : '0 -' + (i*avatarHeight) + 'px' });
// avatar fading / pulse effect
if (fadePulse == true) {
// Now some scaling effects!
TweenMax.to(avatars, 0.1, {
css: {
// 'background-position': '0 -' + (i*avatarHeight) + 'px',
scaleX: 1.1,
scaleY: 1.1,
transformOrigin: "center center"
},
onComplete: scaleOut,
onCompleteParams: [avatars],
delay: 0.1,
ease: Power3.easeInOut
});
// Bring the scale back to normal
function scaleOut(el) {
TweenMax.to(el, 0.1, {
css: {
scaleX: 1.0,
scaleY: 1.0,
transformOrigin: "center center",
autoAlpha: 1,
},
ease: Power2.easeOut
});
}
} else {
// avatar sliding effect
}
}, avatarSpeed);
return false;
}
Take a look at this result.
Snippet:
var avatarCount = 6;
var avatarHeight = 250;
var avatarTotalHeight = 1500;
var avatars = $(".avatars");
var animDuration = 0.1;
var i = 0;
var timeline = new TimelineMax({ paused: true, repeat: -1 });
timeline.to(avatars, animDuration, {
scaleX: 1.1,
scaleY: 1.1,
ease: Power3.easeIn,
onComplete: onCompleteScaleIn
});
timeline.to(avatars, animDuration, {
scaleX: 1.0,
scaleY: 1.0,
ease: Power3.easeOut
});
function onCompleteScaleIn() {
i++;
i = i >= avatarCount ? 0 : i;
TweenMax.set(avatars, {
backgroundPosition: '0 -' + (i * avatarHeight) + 'px'
});
}
timeline.play();
#container {} #container,
.section {
overflow: hidden;
position: relative;
}
.section {
position: absolute;
}
#container .logo_o2 {
bottom: 10px;
right: 20px;
}
.section {
position: relative;
height: 250px;
width: 300px;
display: block;
}
.section .abs {
position: absolute;
}
.section h1,
.section h2,
.section h3,
.section h4 {
font-size: 21px;
width: 100%;
text-align: center;
letter-spacing: 0;
}
.section1,
.section2,
.section3,
.section4,
.section5,
.section6 {} .avatars {
background-image: url(http://s1.postimg.org/dwt9yu9b3/test_bg_sprite.png);
background-repeat: no-repeat;
background-size: cover;
display: block;
height: 250px;
width: 300px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/gsap/latest/TweenMax.min.js"></script>
<div class="section section3">
<div class="abs clouds"></div>
<div id="avatars" class="abs avatars"></div>
</div>
Details:
First off, this result could have been achieved in a number of ways, more efficiently. Even within TweenMax there could have been a number of possible solutions. So, this attempt is in no way supposed to be the best.
Because you are already using GSAP; I have used TimelineMax, TweenMax's powerful cousin that makes sequencing of animations very easy.
So we have a timeline variable which carries an instance of TimelineMax object with default settings of: 1. initially paused and 2. indeterminate loops.
We then populate this timeline by using the method .to() which basically will start animation from wherever the object currently is. There are a plethora of methods and properties available for the GSAP platform, you should explore.
On the first line of .to() call, we have an onComplete callback pointing to a function.
This callback adjusts the backgroundPosition as per the current iteration.
Finally, there is another .to() call which does the same i.e. start the animation from whatever attributes avatars object currently possesses (in our case, scaleX & scaleY would be at 1.1 because of the first .to() call).
Note: by default, any new .to() (or .from() or .fromTo()) call is appended at the end of a timeline. Read more about the position parameter here.
Let me know if you have any questions.
Update: Here is another version using TweenMax only. Much leaner I guess.
Related
Note: I've asked this question again because I was not be able to edit my old question. (No idea if this was a SO bug or a bug with my beta safari.)
So I want to generate a joystick, as it is used in many games. The joystick stands out of a background and a movable billet. The billet may only be moved within the background.
Here you can find both images
let background = new Image()
let stick = new Image()
let enableMaxDistance = false
background.onload = function() {
$(this).css({
position: "absolute",
left: "2%",
bottom: "2%",
width: "30%"
}).appendTo(document.body)
}
stick.onload = function() {
$(this).css({
position: "absolute",
left: "2%",
bottom: "2%",
width: "30%"
}).appendTo(document.body)
let zeroPosition = $(this).offset()
$(this).draggable({
drag: function(e, ui) {
let distance = Math.sqrt(Math.pow(zeroPosition.top - $(this).offset().top, 2) + Math.pow(zeroPosition.left - $(this).offset().left, 2));
if (distance > 60 && enableMaxDistance) {
e.preventDefault();
}
},
scroll: false
})
}
background.src = "https://i.stack.imgur.com/5My6q.png"
stick.src = "https://i.stack.imgur.com/YEoJ4.png"
html, body {
overflow: hidden;
height: 100%;
}
input {
margin-top: 10%;
margin-left: 50%;
}
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<input onclick="enableMaxDistance = !enableMaxDistance " value="toggle maximum distance" type="button"/>
But while implementing this joystick some problems occurred:
My idea was to make the stick maneuverable by using jqueryUI and to calculate its distance to the origin with each drag event. If the distance is too large, the event will be stopped (not executed) using e.preventDefault();. --> If the distance in the frame, the stick is wearable.
The problem is that ...
The stick is no longer draggable after moving out the maximum distance.
The stick should be just be movable inside the bounds without canceling the event so that I have to grab the stick again and again if I'm touching the bounds (going out of the maximum distance).
How to implement a working joystick using jQuery + jQueryUI?
The issue with your logic is that as soon as the drag event is prevented the distance value will be over 60 due to the inherent delays in JS processing time. Therefore the logic in the next drag is immediately cancelled as the distance > 60 check is immediately hit. While it would be possible to fix this, a much better solution would be to not allow the value to ever be greater than the limit you set.
To achieve this I would not recommend using jQueryUI. You can do it quite easily using native methods which give you more direct control of the positioning without having to fight against any built in logic.
It's also slightly more performant, which is vital when dealing with game mechanics; especially when dealing with direct user input which needs to be as responsive as possible.
With that said, you can use modify the basic logic as laid out in Twisty's comment on this question. Then it simply becomes a question of changing the size of the relevant elements, which is a trivial task. Try this:
var $canvas = $('#background');
var $pointer = $('#stick');
var $window = $(window);
var settings = {
width: $canvas.prop('offsetWidth'),
height: $canvas.prop('offsetHeight'),
top: $canvas.prop('offsetTop'),
left: $canvas.prop('offsetLeft')
};
settings.center = [settings.left + settings.width / 2, settings.top + settings.height / 2];
settings.radius = settings.width / 2;
let mousedown = false;
$window.on('mouseup', function() { mousedown = false; });
$pointer.on('mousedown', function() { mousedown = true; });
$pointer.on('mouseup', function() { mousedown = false; });
$pointer.on('dragstart', function(e) { e.preventDefault(); });
$window.on('mousemove', function(e) {
if (!mousedown)
return;
var result = limit(e.clientX, e.clientY);
$pointer.css('left', result.x + 'px');
$pointer.css('top', result.y + 'px');
});
function limit(x, y) {
var dist = distance([x, y], settings.center);
if (dist <= settings.radius) {
return {
x: x,
y: y
};
} else {
x = x - settings.center[0];
y = y - settings.center[1];
var radians = Math.atan2(y, x)
return {
x: Math.cos(radians) * settings.radius + settings.center[0],
y: Math.sin(radians) * settings.radius + settings.center[1]
}
}
}
function distance(dot1, dot2) {
var x1 = dot1[0],
y1 = dot1[1],
x2 = dot2[0],
y2 = dot2[1];
return Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));
}
html,
body {
height: 100%;
}
#background {
background-image: url('https://i.stack.imgur.com/5My6q.png');
position: absolute;
height: 200px;
width: 200px;
top: 50%;
left: 50%;
margin: -100px 0 0 -100px;
border-radius: 200px;
border: dashed #ccc 1px;
}
#stick {
background: transparent url('https://i.stack.imgur.com/YEoJ4.png') 50% 50%;
position: absolute;
width: 100px;
height: 100px;
border-radius: 100px;
margin: -50px 0 0 -50px;
top: 50%;
left: 50%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="background"></div>
<div id="stick"></div>
This is a follow up from my previous question.
I have a progressbar.js circle that animates on scroll. If there is just one circle it works as expected.
Now I want to create many of these animated circles by looping through an object with different key-values pairs.
For example:
var divsValues = {
'total-score-circle': 0.75,
'general-score-circle': 0.80,
'speed-score-circle': 0.85,
'privacy-score-circle': 0.90,
};
For each key-value pair, the key is a div ID and the value is number that tells the animation how far to go.
Below is the code where I try to implement my loop, but the problem is that only the last circle is animated on scroll. All the circles appear in their "pre-animation" state, but only the last circle actually becomes animated when you scroll to the bottom.
I need each circle to animate once it is in the viewport.
//Loop through my divs and create animated circle for each one
function makeCircles() {
var divsValues = {
'total-score-circle': 0.75,
'general-score-circle': 0.80,
'speed-score-circle': 0.85,
'privacy-score-circle': 0.90,
};
for (var i in divsValues) {
if (divsValues.hasOwnProperty(i)) {
bgCircles(i, divsValues[i]);
}
}
}
makeCircles();
// Check if element is scrolled into view
function isScrolledIntoView(elem) {
var docViewTop = jQuery(window).scrollTop();
var docViewBottom = docViewTop + jQuery(window).height();
var elemTop = jQuery(elem).offset().top;
var elemBottom = elemTop + jQuery(elem).height();
return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
}
//Circle design and animation
function bgCircles(divid, countvalue) {
// Design the circle using progressbar.js
bar = new ProgressBar.Circle(document.getElementById(divid), {
color: '#ddd',
// This has to be the same size as the maximum width to
// prevent clipping
strokeWidth: 4,
trailWidth: 4,
easing: 'easeInOut',
duration: 1400,
text: {
autoStyleContainer: false
},
from: {
color: '#ddd',
width: 4
},
to: {
color: '#888',
width: 4
},
// Set default step function for all animate calls
step: function(state, circle) {
circle.path.setAttribute('stroke', state.color);
circle.path.setAttribute('stroke-width', state.width);
var value = Math.round(circle.value() * 100);
if (value === 0) {
circle.setText('');
} else {
circle.setText(value + '%');
}
}
});
bar.text.style.fontFamily = '"Montserrat", sans-serif';
bar.text.style.fontSize = '1.7rem';
bar.trail.setAttribute('stroke-linecap', 'round');
bar.path.setAttribute('stroke-linecap', 'round');
//Animate the circle when scrolled into view
window.onscroll = function() {
if (isScrolledIntoView(jQuery('#' + divid))) bar.animate(countvalue);
else bar.animate(0); // or bar.set(0)
}
}
#total-score-circle,
#general-score-circle,
#speed-score-circle,
#privacy-score-circle {
margin: 0.8em auto;
width: 100px;
height: 100px;
position: relative;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/progressbar.js/1.0.1/progressbar.min.js"></script>
<div id="total-score-circle"></div>
<div id="general-score-circle"></div>
<div id="speed-score-circle"></div>
<div id="privacy-score-circle"></div>
While researching this problem I learned that JavaScript will only output the last value of a loop, which I thought could be the cause of my problem.
So I tried to replace the for loop with these solutions...
Solution 1: Same problem as before, only the last loop animates on scroll.
for (var i in divsValues) {
(function(){
var ii = i;
if (divsValues.hasOwnProperty(ii)) {
bgCircles(ii, divsValues[ii]);
}
})();
}
Solution 2: Again, same problem as before, only the last loop animates on scroll.
for (var i in divsValues) {
let ii = i;
if (divsValues.hasOwnProperty(ii)) {
bgCircles(ii, divsValues[ii]);
}
}
Solution 3: Again, same problem as before, only the last loop animates on scroll.
for (var i in divsValues) {
try{throw i}
catch(ii) {
if (divsValues.hasOwnProperty(ii)) {
bgCircles(ii, divsValues[ii]);
}
}
}
So now I'm thinking maybe the problem is not the loop, but something I can't see or figure out.
You were quite close.
Here are the fixes:
In the function bgCircles(...), use var to declare the bar in that function's scope:
var bar = new ProgressBar.Circle(document.getElementById(divid), {
When you set the animate scrolled into view checker event, you assign a new function over-and-over to window.onscroll. Since you are using jQuery, consider jQuery's .scroll event handler and use it like this:
$(window).scroll(function () {
if (isScrolledIntoView(jQuery('#' + divid))) bar.animate(countvalue);
else bar.animate(0); // or bar.set(0)
});
The solution in whole:
//Loop through my divs and create animated circle for each one
function makeCircles() {
var divsValues = {
'total-score-circle': 0.75,
'general-score-circle': 0.80,
'speed-score-circle': 0.85,
'privacy-score-circle': 0.90,
};
for (var i in divsValues) {
if (divsValues.hasOwnProperty(i)) {
bgCircles(i, divsValues[i]);
}
}
}
makeCircles();
// Check if element is scrolled into view
function isScrolledIntoView(elem) {
var docViewTop = jQuery(window).scrollTop();
var docViewBottom = docViewTop + jQuery(window).height();
var elemTop = jQuery(elem).offset().top;
var elemBottom = elemTop + jQuery(elem).height();
return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
}
//Circle design and animation
function bgCircles(divid, countvalue) {
// Design the circle using progressbar.js
var bar = new ProgressBar.Circle(document.getElementById(divid), {
color: '#ddd',
// This has to be the same size as the maximum width to
// prevent clipping
strokeWidth: 4,
trailWidth: 4,
easing: 'easeInOut',
duration: 1400,
text: {
autoStyleContainer: false
},
from: {
color: '#ddd',
width: 4
},
to: {
color: '#888',
width: 4
},
// Set default step function for all animate calls
step: function(state, circle) {
circle.path.setAttribute('stroke', state.color);
circle.path.setAttribute('stroke-width', state.width);
var value = Math.round(circle.value() * 100);
if (value === 0) {
circle.setText('');
} else {
circle.setText(value + '%');
}
}
});
bar.text.style.fontFamily = '"Montserrat", sans-serif';
bar.text.style.fontSize = '1.7rem';
bar.trail.setAttribute('stroke-linecap', 'round');
bar.path.setAttribute('stroke-linecap', 'round');
//Animate the circle when scrolled into view
$(window).scroll(function () {
if (isScrolledIntoView(jQuery('#' + divid))) bar.animate(countvalue);
else bar.animate(0); // or bar.set(0)
});
}
#total-score-circle,
#general-score-circle,
#speed-score-circle,
#privacy-score-circle {
margin: 0.8em auto;
width: 100px;
height: 100px;
position: relative;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/progressbar.js/1.0.1/progressbar.min.js"></script>
<div id="total-score-circle"></div>
<div id="general-score-circle"></div>
<div id="speed-score-circle"></div>
<div id="privacy-score-circle"></div>
Note:
Since I didn't edit any of your circle animation/circle visibility checking functions, I assume you intended the current state of your animate-when-scrolled-and-in-view functionality the way, that it is right now. In this current state, your script does/has the following side-effects:
If you don't scroll the page, not at all, your circles won't start to animate, even, when they are visible. Solution: encapsulate the visibility checker lines to a separate function and run, when creating the circles.
If you scroll through a circle, its animation with the percent will going to go to its default state, which is 0%. Solution: change the visibility checker function, when the particular element is not visible because of overscroll, return that state as visible too. This way your circles will stay at 100%, even when you scroll over them.
Regarding performance and best practices:
When using jQuery, make sure to call jQuery(...) or its shorthand $(...) as few times as possible. Use variables to store elements, properties, and data.
It's better to separate longer/larger, monolithic functions into smaller functions with a more narrow, but also more clear scope of functionality.
When using event listeners, make sure to run as few of them as possible. Structure your HTML and your JavaScript code to have clear and performant ways to access and modify your crucial elements, properties, and data.
The loop you have will run so fast that the browser engine wont be able to render the changes, I would suggest either you use setInterval() method or continuous setTimeout() method which will add some delay to your code so that the browser can render the changes you are making.
For your special case I would suggest:
var i = 0;
var tobecleared = setInterval(timer,1000);
function timer(){
var p = get_ith_key_from_divsvalues(i);//implement this method
console.log(p);
bgCircles(p, divsValues[p]);
i++;
if(i == Object.keys(divsValues).length)
clearInterval(tobecleared);
}
function get_ith_key_from_divsvalues(i){
var j = -1;
for(var property in divsValues){
j++;
if(j==i)
return property;
}
}
Note : window.onscroll is being overwritten in each call that is why only the last circle responds.
There are two fixes you need to apply.
Currently bar is the global variable, so it's always the same, to fix it declare it with var.
Use window.addEventListener to attach scroll event to window, by setting handler with window.onscroll you constantly override event handler and usage of addEventListener allow you attach more than one event handler.
//Loop through my divs and create animated circle for each one
$( document ).ready(function(){
function makeCircles() {
var divsValues = {
'total-score-circle': 0.75,
'general-score-circle': 0.80,
'speed-score-circle': 0.85,
'privacy-score-circle': 0.90,
};
for (var i in divsValues) {
if (divsValues.hasOwnProperty(i)) {
bgCircles(i, divsValues[i]);
}
}
}
makeCircles();
// Check if element is scrolled into view
function isScrolledIntoView(elem) {
var docViewTop = jQuery(window).scrollTop();
var docViewBottom = docViewTop + jQuery(window).height();
var elemTop = jQuery(elem).offset().top;
var elemBottom = elemTop + jQuery(elem).height();
return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
}
//Circle design and animation
function bgCircles(divid, countvalue) {
// Design the circle using progressbar.js
var bar = new ProgressBar.Circle(document.getElementById(divid), {
color: '#ddd',
// This has to be the same size as the maximum width to
// prevent clipping
strokeWidth: 4,
trailWidth: 4,
easing: 'easeInOut',
duration: 1400,
text: {
autoStyleContainer: false
},
from: {
color: '#ddd',
width: 4
},
to: {
color: '#888',
width: 4
},
// Set default step function for all animate calls
step: function(state, circle) {
circle.path.setAttribute('stroke', state.color);
circle.path.setAttribute('stroke-width', state.width);
var value = Math.round(circle.value() * 100);
if (value === 0) {
circle.setText('');
} else {
circle.setText(value + '%');
}
}
});
bar.text.style.fontFamily = '"Montserrat", sans-serif';
bar.text.style.fontSize = '1.7rem';
bar.trail.setAttribute('stroke-linecap', 'round');
bar.path.setAttribute('stroke-linecap', 'round');
//Animate the circle when scrolled into view
window.addEventListener('scroll', function() {
if (isScrolledIntoView(jQuery('#' + divid))) bar.animate(countvalue);
else bar.animate(0); // or bar.set(0)
})
}
})
#total-score-circle,
#general-score-circle,
#speed-score-circle,
#privacy-score-circle {
margin: 0.8em auto;
width: 100px;
height: 100px;
position: relative;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/progressbar.js/1.0.1/progressbar.min.js"></script>
<div id="total-score-circle"></div>
<div id="general-score-circle"></div>
<div id="speed-score-circle"></div>
<div id="privacy-score-circle"></div>
I am looking to animate this progress bars, but I'm having a different behavior using jQuery animate() method. I want to animate the progress bars one by one with a 0.1s delay. I will need help with choosing the right animation, because now my animation is behaving downwards. I'd like to do it in the simplest way possible.
Here is what I have so far:
$('.vertical-bars .progress-fill span').each(function() {
var percent = $(this).html();
var pTop = 100 - (percent.slice(0, percent.length - 1)) + "%";
$(this).parent().css({
'height': percent,
'top': pTop
});
$(this).parent().animate({
height: "toggle"
}, {
duration: 900,
specialEasing: {
height: "swing"
}
});
});
I have prepared a JSFiddle with my progress bars HERE.
The right behavior is to fill the progress-bars upwards, like in THIS example.
You need to animate both the height and top of your bars, or you need to construct them such that they are pinned to the horizontal axis when you change the height. The second takes a little more thought, but the first, although not as elegant, is straight forward.
To animate top you can't use toggle (as it is animating to 100% and back, not to 0), so you will need to animate both the shrink and grow separately using done to trigger a second animation. Taking the same style as you used above:
$('.vertical-bars .progress-fill span').each(function () {
var percent = $(this).html();
var pTop = 100 - ( percent.slice(0, percent.length - 1) ) + "%";
$(this).parent().css({
'height': percent,
'top': pTop
});
var self=this;
$(this).parent().animate({
height: 0,
top: "100%"
}, {
duration: 900,
specialEasing: {
height: "swing",
top: "swing"
},
done:function(){
$(self).parent().animate({
height: percent,
top: pTop
}, {
duration: 900,
specialEasing: {
height: "swing",
top: "swing"
}
})
}
});
});
Of course you can also achieve the same thing using css animation. If I have time to figure it out I'll post an edit.
I don't know what height: "toggle" does but you basically want to set 0 height and 100% offset from top and then start animation that adjusts both styles.
The 100ms between animations is done simply by using setTimeout and incrementing the timeout.
https://jsfiddle.net/kss1su0b/1/
var elm = $(this).parent();
elm.css({
'top': '100%',
'height': 0
});
setTimeout(function() {
elm.animate({
'height': percent,
'top': pTop
}, {
duration: 900,
specialEasing: {
height: "swing"
},
});
}, animOffset);
animOffset += 100;
The simplest and most performing way to invert the animation direction is to align the bars at the bottom with css:
vertical-bars .progress-fill {
position: absolute;
bottom: 0;
}
Then you don't need to set the top any more with jQuery and set a delay:
$('.vertical-bars .progress-fill').each(function (index) {
var percentage = $(this).find('.percentage').html();
$(this).delay(index * 100).animate(
{
height: percentage
}, {
duration: 900,
done: function () {
$(this).find('span').show("normal");
}
}
);
});
jsfiddle
I'm kinda new to JS so this may be pretty easy to solve.
I simply want to change interactive map elements' opacity and color when mouse enters element and change it back when it leaves.
So this is what I'm doing:
var paper = Raphael('map', '100%', '100%');
// map contents
var rect = paper.rect(3.5714281, 74.505051, 151.42857, 143.57143).attr({
x: '3.5714281',
y: '74.505051',
fill: '#ffb380',
stroke: '#ff6600',
'stroke-width': '1',
'stroke-opacity': '1'
}).transform("t6.9285719,8.1378246").data('id', 'rect');
var crcl = paper.path("m 472.14285,202.00504 a 72.5,72.5 0 1 1 -145,0 72.5,72.5 0 1 1 145,0 z").attr({
fill: '#916f6f',
stroke: '#6c5353',
'stroke-width': '1',
'stroke-opacity': '1'
}).transform("t6.9285719,8.1378246 t-245,-127.14286").data('id', 'crcl');
var objs = [];
objs.push(rect, crcl);
for (var i = objs.length - 1; i >= 0; i--) {
objs[i].data('original-fill', objs[i].data('fill'));
objs[i].mouseover(function(event) {
damn = this.data('fill');
this.stop(true, false).animate({
opacity: 0.7,
fill: 'white',
},
75);
});
objs[i].mouseout(function(event) {
this.stop(true, false).animate({
opacity: 1,
fill: this.data('original-fill'),
},
200);
});
};
But every time i move mouse out it sets to 'none' like this.data('original-fill') was unset. Though I can access objs[i].data('original-fill') outside mouseover and mouseout.
I'm using Raphaƫl JS library.
I would appreciate any help.
If CSS is in your arsenal for the project, it offers a transition property and a :hover attribute to animate styles over a length of time on mouseover events. If CSS is something you're able to use, this can accomplish what you're outlining in your expected behavior (just replace div with a class on the elements you're looking to animate):
div {
opacity: 1;
background-color: #000;
transition: opacity .2s;
transition: background-color .2s;
}
div:hover {
background-color: #FFF;
opacity: .7;
}
It's not a javascript solution, but is considerably more elegant if your hover needs are strictly style-related
This is the fiddle!
The image should move up until it's bottom edge reaches the bottom of div and then move down until it's top edge reaches the top edge of parent div, to reveal it.
This has to work with different sized images.
$(document).ready(function() {
move();
});
function move() {
$(".image").animate({
bottom: "-=50%"
}, 10000, 'linear', function() {
$(".image").animate({
bottom: "+=50%"
}, 10000, 'linear', move);
});
}
.container {
position: relative;
width: 1100px;
height: 480px;
overflow: hidden;
background-color: #000;
}
.image {
position: absolute;
max-width: 100%;
min-width: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<img class="image" src="http://www.hotel-aramis.com/slider/home/notre-dame-de-paris.jpg />
</div>
Something like this seems to work:
$(document).ready(function () {
move();
});
function move() {
$img = $(".image");
var i = new Image();
i.src = $img.attr('src');
var d = i.height - $('.container').height();
$img.animate({
bottom: "+="+d+'px'
}, 10000, 'linear', function () {
$img.animate({
bottom: "-="+d+'px'
}, 10000, 'linear', move);
});
}
This is a little sneaky, it creates a new javascript image Object (non Jquery) using the same src as the selected one and uses its natural height to perform the animation. It seems that if we create a jQuery object its height isn't the same, maybe it needs to be attached to the dom or similar.
Jsfiddle: http://jsfiddle.net/VqzvR/8/
moving the setup code outside of the move() function will mean that the http get (for the img src) will only be performed once:
$(document).ready(function () {
setupMove();
});
function setupMove() {
$img = $(".image");
var i = new Image();
i.src = $img.attr('src');
var d = i.height - $('.container').height();
function move() {
$img.animate({
bottom: "+="+d+'px'
}, 10000, 'linear', function () {
$img.animate({
bottom: "-="+d+'px'
}, 10000, 'linear', move);
});
}
move();
}
Is this the effect you were looking for?