I have this simple animation that moves from side to side, Im trying to create a reset button so that the animation stops and gets back to default, but I cant seem to get i right.
The library I am using is Raphael, but I'm almost sure that with a simple javascript I can reset the values inside the function.
Body onload init function
function init() {
paper = Raphael("loadSVG");
var bg = paper.rect( 0, 0, "240px", "90px", 0 );
bg.attr( {fill: "#f3f3ff"} );
rect1 = paper.rect(150, 20, 50, 50);
rect1.attr( {fill: "#ffaaaa", "stroke-width": 3} );
}
The animation function
function moveRect1() {
if( xEnd == 150 )
xEnd = 50;
else
xEnd = 150;
rect1.animate( {x: xEnd}, 1000, "Sine", function (){
moveRect1();
});
}
and the stop button that don't work :)
function stopsvgRect1() {
rect1.stop();
}
You need to bind the stop button to the function you've created.
For example like this:
document.querySelector('#stop').onclick = function() {
stopsvgRect1();
};
Open this fiddle to see it in action.
edit:
As the position should also be resetted, you can choose Raphael.transform() for this action.
Open my updated fiddle to see how it works.
Related
I am trying to control a GSAP animation using a forward & backward button. The expected behaviour I am aiming for is:
When the user hovers over the forward button the animation moves forward (increments in px).
When the user mouseleaves the button then the animation pauses.
When the user hovers over the backwards button the animation moves the other way.
The issue I have encountered is that I have tried to add a dynamic positioning variable in place which increments when the user hovers over the 'forward' button. This is not working as expected - instead it just moves once instead of waiting until the user's mouse leaves to stop.
I tried to add a setInterval to the button event listener to increment the positioning so that when the user hovered over the button it would move px at a time, which did work, but it would not stop causing the browser to crash. I also added a mouseleave to clear the setInterval but I don't think it was good practise.
var masterTimeline = new TimelineMax();
var mousedown = false;
var forwardBTN = document.getElementById("forward");
var backwardBTN = document.getElementById("backward");
var pauseBTN = document.getElementById("pause");
var blueboxElement = document.getElementById("blueBox");
var direction = '+';
var counter = 0;
var distance = 0;
var value1 = direction + '=' + distance;
var tween;
forwardBTN.addEventListener("mouseenter", function(){
// setInterval(function() {
directionMove('moveForward');
// }, 500);
});
backwardBTN.addEventListener("mouseenter", function(){
directionMove('moveBackward')
});
pauseBTN.addEventListener("click", function(){
directionMove('pause');
});
function directionMove(playk) {
if (playk == 'moveBackward') {
var direction = '-';
value1 = direction + '=' + distance; // how to update value
masterTimeline.to(blueboxElement, 0.1, {css: {x: value1}, ease: Linear.easeNone}); // no need move by default
}
else if (playk == 'moveForward') {
var direction = '+';
value1 = direction + '=' + distance; //how to update value
masterTimeline.to(blueboxElement, 0.1, {css: {x: value1}, ease: Linear.easeNone}); // no need move by default
}
else if (playk == 'pause') {
masterTimeline.kill();
console.log("killed");
//
}
}```
The expected behaviour is to move forward incrementally without stopping until the user moves off the forward button but at present it is just moving a single amount one time.
Here is a CodePen link if this helps:
https://codepen.io/nolimit966/pen/pXBeZv?editors=1111
I think you're overcomplicating this a bit (at least in the demo). The entire point of GSAP is moving things along a timeline. What you're trying to do is essentially forcibly use a timeline to work in a non-timeline way, which is why I think you're having trouble.
If you step back and just think about your three requirements, I think it becomes a lot more simple. It's always good to think about it in words like you did because it can help you simplify it and understand it better.
The key steps are to:
Create a timeline for the movement of the box.
Play the timeline forward when the forward button is hovered.
2b. Pause it when it's no longer hovered.
Play the timeline backward when the reverse button is hovered.
3b. Pause it when it's no longer hovered.
In code that looks like this:
var tl = new TimelineMax({paused: true});
var forwardBTN = document.getElementById("forward");
var backwardBTN = document.getElementById("backward");
var pauseBTN = document.getElementById("pause");
var blueboxElement = document.getElementById("blueBox");
tl.to(blueboxElement, 10, {x: window.innerWidth - blueboxElement.clientWidth, ease: Linear.easeNone});
function pause() {
tl.pause();
}
forwardBTN.addEventListener("mouseenter", function() {
tl.play();
});
forwardBTN.addEventListener("mouseleave", pause);
backwardBTN.addEventListener("mouseenter", function() {
tl.reverse();
});
backwardBTN.addEventListener("mouseleave", pause);
Demo
By the way, you're much more likely to get a faster response over on the official GreenSock forums :)
Do you mean something like this?
var tl = new TimelineMax({paused: true});
tl.to('.element', 3, {
x: 800,
});
$(document).on({
mouseenter: function () {
if($(this).hasClass('forward')){
tl.play();
}
else if($(this).hasClass('backwards')){
tl.reverse();
}
},
mouseleave: function () {
tl.pause();
}
}, ".btn");
.wrapper{
width: 100%;
padding: 40px;
}
.element{
width: 100px;
height: 100px;
background: red;
}
.btn{
display: inline-block;
padding: 15px;
background: #bbb;
margin-top: 20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.3/TweenMax.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="wrapper">
<div class="element_wrapper">
<div class="element"></div>
</div>
<div class="forward btn">Forward</div>
<div class="backwards btn">Backwards</div>
</div>
I’m quite new with the GreenSock and I got myself in trouble...
I would like to modify GreenSock TimelineLite timing offset for reverse so that some delays get deleted (I think that they are called staggers).
Here is an example: http://jsfiddle.net/4bvnv1d5/
var red = $('.red');
var green = $('.green');
var blue = $('.blue');
var black = $('.black');
var tl = new TimelineLite({onReverseComplete:reverseCompleted});
$('#start').click(function(){
tl.to(red, 0.3, {ease: Power1.easeInOut, 'margin-left':'100px'});
tl.to(green, 0.3, {ease: Power1.easeInOut, 'margin-left':'100px'});
tl.to(blue, 0.3, {ease: Power1.easeInOut, 'margin-left':'100px'});
tl.to(black, 0.3, {ease: Power1.easeInOut, 'margin-left':'100px', onComplete:lastCompleted, onCompleteParams:[black]}, "+=4");
});
$('#reverse').click(function(){
tl.reverse();
});
function lastCompleted(target) {
console.log('lastCompleted');
}
function reverseCompleted(){
console.log('reverseCompleted');
tl.clear();
tl.restart();
}
On play there is a four second delay with the last box, but on the reverse I’d like to animations to play right after each other with no delays. There is function lastCompleted() which is triggered after the last tween gets run. How can I use that function to remove the delay between the black and blue box animations?
Thanks!
Take a look at this fiddle.
JavaScript:
var red = $('.red');
var green = $('.green');
var blue = $('.blue');
var black = $('.black');
var tl = new TimelineLite({
paused: true,
callbackScope: this,
onReverseComplete: onTlReverseComplete
});
tl.staggerTo([red, green, blue], 0.3, { marginLeft: 100, ease: Power1.easeInOut }, 0.3);
tl.addLabel('MyLabel');
tl.to(black, 0.3, { marginLeft: 100, ease: Power1.easeInOut, onReverseComplete: onBlackBoxReverseComplete, callbackScope: this }, '+=4');
$('#start').click(function () {
tl.play();
});
$('#reverse').click(function () {
tl.reverse();
});
function onBlackBoxReverseComplete() {
tl.reverse('MyLabel');
}
function onTlReverseComplete() {
tl.stop();
}
Quite a few things have changed from your code. Here is the list:
The tweens are added into the tl instance outside the scope of click handler of #start button. The click handler only .play()s the timeline forward.
.staggerTo() method is used instead of adding adding the 3 tweens one by one before the one for .black element.
Also, margin-left has been replaced by its JS equivalent marginLeft and since it accepts numbers and defaults to pixels, no need to pass the values as strings.
The tween for .black element has now a onReverseComplete callback.
Hope this helps. Let me know if you have any questions.
I'm developing some page when I use Raphael liblary to draw some items.
my App
So my problem is in that when I'm moving to some rect it growing up but when my mouse is on text which is positioning on my rect, it loss his hover. You can see it on my app example.
var paper = new Raphael(document.getElementById('holder'), 500, object.length * 100);
drawLine(paper, aType.length, bType.length, cType.length, cellSize, padding);
process = function(i,label)
{
txt = paper.text(390,((i+1)* cellSize) - 10,label.devRepo)
.attr({ stroke: "none", opacity: 0, "font-size": 20});
var a = paper.rect(200, ((i+1)* cellSize) - 25, rectWidth, rectHeight)
.hover(function()
{
this.animate({ transform : "s2"}, 1000, "elastic");
this.prev.animate({opacity: 1}, 500, "elastic");
this.next.attr({"font-size" : 30});
},
function()
{
this.animate({ transform : "s1" }, 1000, "elastic");
this.prev.animate({opacity: 0}, 500);
this.next.attr({"font-size" : 15});
});
}
I have tried e.preventDefault(); on hover of this.next and some other solutions but it's doesn't work.
Any help would be appreciated.
Most people will suggest you place a transparent rectangle over the box and the labels and attach the hover functions to that instead. (If memory serves, you have to make the opacity 0.01 instead of 0 to prevent the object from losing its attached events.) This works fine, but I don't love this solution; it feels hacky and clutters the page with unnecessary objects.
Instead, I recommend this: Remove the second function from the hover, making it functionally a mouseover function only. Before you draw any of the rectangles and labels, make a rectangular "mat" the size of the paper. Then, attach the function that minimizes the label as a mouseover on the mat. In other words, you're changing the trigger from mousing out of the box to mousing over the area outside of it.
I left a tiny bit of opacity and color on the mat to be sure it's working. You can just change the color to your background color.
var mat = paper.rect(0, 0, paper.width, paper.height).attr({fill: "#F00", opacity: 0.1});
Now, you want to make a container for all the rectangles so you can loop through them to see which need to be minimized. I made an object called "rectangles" that contains the objects we're concerned with. Then:
mat.mouseover(function () {
for (var c = 0; c < rectangles.length; c += 1) {
//some measure to tell if rectangle is presently expanded
if (rectangles[c].next.attr("font-size")) {
rectangles[c].animate({
transform : "s1"
}, 1000, "elastic");
rectangles[c].prev.animate({opacity: 0}, 500);
rectangles[c].next.attr({"font-size" : 15});
}
}
});
Then I just removed the mouseout function from the individual rectangles.
jsBin
To be clear, this will have some downsides: If people run the mouse around really fast, they can expand several rectangles at the same time. This is remedied as soon as the mouse touches the mat. I think the functionality looks pretty nice. But the invisible mats is always an option.
I wrote a small extension to Raphael - called hoverInBounds - that resolves this limitation.
Demo: http://jsfiddle.net/amustill/Bh276/1
Raphael.el.hoverInBounds = function(inFunc, outFunc) {
var inBounds = false;
// Mouseover function. Only execute if `inBounds` is false.
this.mouseover(function() {
if (!inBounds) {
inBounds = true;
inFunc.call(this);
}
});
// Mouseout function
this.mouseout(function(e) {
var x = e.offsetX || e.clientX,
y = e.offsetY || e.clientY;
// Return `false` if we're still inside the element's bounds
if (this.isPointInside(x, y)) return false;
inBounds = false;
outFunc.call(this);
});
return this;
}
To keep it small and simple, when clicking a button, all the the divs should slide away in random directions and another set of new divs should be displayed.
Basic demo of what the jQuery code is like:
$(document).ready(function() {
$("#toggle_value").click(function(){
$("#div1").show("fast");
$("#div2").show("fast");
$("#div3").show("fast");
});
});
But its all about randomizing the effects. Any solutions?
I would do something like this:
http://jsfiddle.net/8uKt3/13/
$(document).ready(function() {
var $div = $('div'),
pos = [0, 0, 0, 500, 250, 100, 50, -500, -750, -1000, -1500], // Define your numbers
mypos1,
mypos2,
$me;
$("#toggle_value").click(function(){
$div.each(function(){
$me = $(this);
// Choose a value from each array randomly
mypos1 = pos[Math.floor(Math.random() * pos.length)];
mypos2 = pos[Math.floor(Math.random() * pos.length)];
// animate in a random direction in a random quantitya
$me.animate({
'top' : mypos1,
'left': mypos2
});
});
});
});
You can do something like this, lets say you have 3 possible cases for how the divs might slide away:
var rand = Math.random();
if (rand < .33) {
// Some animation
} else if (rand < .66) {
// Some other possible animation
} else {
// Final animation possibility
}
Algorithm:
create an array of 'n' ints
shuffle the array
in the click function:
for each value 'v' in the shuffled array:
$('#div' + v).show('fast')
My guess is that you're going to have introduce a delay in the animation using the completion all back on 'effect' for this to look good, but that should be trivial to do
I apologize for asking this question but I am just looking for a little guidance on this morning. I simply want to create a function so that way I can make a Raphael element glow by just passing in that element. Below is the code I have. Why does this not work?
var paper = Raphael("playarea", 500, 500);
var rectangle = paper.rect(100, 100, 200, 200, 4);
function elemHover(var el)
{
el.hover(
// When the mouse comes over the object //
// Stock the created "glow" object in myCircle.g
function() {
this.g = this.glow({
color: "#0000EE",
width: 10,
opacity: 0.8
});
},
// When the mouse goes away //
// this.g was already created. Destroy it!
function() {
this.g.remove();
});
}
elemHover(rectangle);
here is the fiddle http://jsfiddle.net/aZG6C/15/
You should fill the element( rectangle in our case) to trigger the hover.
rectangle.attr("fill", "red");
Try this fiddle http://jsfiddle.net/aZG6C/17/
The full code will look like
<div id="playarea"></div>
<script type="text/javascript">
var paper = Raphael("playarea", 500, 500);
var rectangle = paper.rect(100, 100, 200, 200, 4);
function elemHover(el)
{
el.hover(
// When the mouse comes over the object //
// Stock the created "glow" object in myCircle.g
function() {
this.g = this.glow({
color: "#0000EE",
width: 10,
opacity: 0.8
});
},
// When the mouse goes away //
// this.g was already created. Destroy it!
function() {
this.g.remove();
});
}
rectangle.attr("fill", "red");
elemHover(rectangle);
</script>
Update
Hover event is triggered only if the element is filled with something. If you want to have a transparent element you can try
rectangle.attr("fill", "transparent");
Check the fiddle here http://jsfiddle.net/aZG6C/20/