Related
I'm building a small UI which provides users progress of downloading or loading certain information. Here is the codes so far
http://jsfiddle.net/pge1wukj/4/
var s = Snap("svg");
var movepath = s.select("#movePath").attr({
"fill":"none"
});
var dapath = s.select("#dapath").attr({
stroke: "#cdcdcd",
"stroke-width": 5,
});
var dapoints = [242,334.5, 372,334.5, 372,390, 320.5,390.5 ,308.5,421.5 ,293.5,391.5 ,242,391]
var circle = s.select("circle");
var poly = s.select("polygon");
$("a").click(function(){
circle.animate({
opacity: 0
},100);
poly.polyAnimate(dapoints,100,mina.linear,function(){
moveAlongPath(poly,{x:308,y:421},s.halfArc(308,421,135,382,50,0),100);
});
dapath.animate({
d:"M135,382.5c0,52.159,85,79.031,170.001,79.498 C 390.3,462.466,475.598,436.344,475,382.5",
},100,function(){
dapath.animate({d:"M135,382.5c0,0,85.999-0.467,171,0c85.299,0.468,169,0,169,0"
},100,function(){
dapath.animate({
d:"M135,382.292c0,0,85.999-22.759,171-22.292c85.299,0.468,169,22.292,169,22.292"
},100,function(){
dapath.animate({
d:"M136,382.415c0,0,90.999,13.118,176,13.585c85.299,0.468,164-13.585,164-13.585"
},100,function(){
dapath.animate({
d:"M135,382.5c0,0,85.999-0.467,171,0c85.299,0.468,169,0,169,0"
},500,mina.bounce,function(){
var pathclone = dapath.clone().attr({
stroke: "blue",
strokeDashoffset: 500,
strokeDasharray: 500
});
var datext = s.text(100,330,"90").attr("style","text-align: center");
var banner = s.group(poly,datext);
moveAlongPath(banner,{x:136,y:382.415},movepath,3600);
var tick = 0;
var interval = setInterval(function(){
tick += 1;
var red = Math.random()*255;
var blue = Math.random()*255;
var green = Math.random()*255;
var hex = Snap.rgb(red,green,blue);
var dadatext = $("text").text(tick+" %")
if(tick % 10 == 0){
dadatext.attr({"font-size":"30px","fill":hex});
};
if (tick >= 100){clearTimeout(interval)};
},36);
pathclone.animate({
"stroke-dashoffset":0,
},5300);
var paths = Snap.set().push(dapath,pathclone);
paths.animate({
d:"M135,382.5c0,0,30,17,42,17c10,0.208,298-17,298-17"
},300,function(){
paths.animate({
d:"M135,382.5c0,0,287,17.208,297,17c12,0,43-17,43-17"
},2900,function(){
paths.animate({d:"M135,382.5c0,0,287,17.208,297,17c12,0,43-17,43-17"},100,function(){
paths.animate({
d:"M135,382.5c0,0,85.999-0.467,171,0c85.299,0.468,169,0,169,0"
},200,function(){
$("a").off("click");
/* End of animation */
/* Ready for next transformation*/
banner.animate({
transform: "rotate(180deg)"
},200);
})
})
});
})
});
});
})
})
});
});`
At the end of the animation, the banner should rotate 180 deg on the sharp point. However it doesn't animate as i expected. Is there any solution to this ? transforming animation is intimidating and i don't fully understand it....
I think what you are missing is that you need to provide the original transform to include, otherwise it will assume you are just replacing that transform.
So with this line...
banner.animate({ transform: 'rotate(180)' },200);
What this really means is, I'm going to overwrite any current transforms and animate to a new one of rotate(180).
What you probably want is...keep any existing transforms, and now rotate(180) as well.
So you probably want something more like this...transform() with no parameters will give us the existing transform. So we can combine.
transform -> existingtransform then apply additional transform
This would look like the following.
banner.animate({ transform: banner.transform() + " s-1,1" },200);
I'm not quite sure of the rotation effect you are after (did you mean it to go upside down or back to front?), but 's-1,1' may have been what you were thinking of.
jsfiddle example
Edit: jsfiddle with alternate rotation.
Note, for this, you need to take into account 'where' the polygon is, in relation to the group, as its offset as you have moved it (and then also moved the group).
Edit: The rotation center point is quite difficult, as we have the polygon points offset (not centred around 0) and then translated. Also the group they are in is translated, so you've kinda of got 3 things going on.
To try and help understand getting the actual points, I have rewritten the rotation animation.
banner.animate({ transform: banner.transform() + "r180," + banner.getBBox(1).cx + ',' + banner.getBBox(1).y2 },200);
We get the bounding box, which calculates the centre for us. The pivot point is mid length cx, and the lowest y point is y2.
I suspect there is an easier way to get the whole thing working to reduce the transform complexity in the overall code, but there's a bit too much to break down for a question here.
jsfiddle with getBBox
Logo and elements from ul once clicked rotates image. By default image is already rotated by certain degrees, then on each click image rotates to necessary value.
So far I was using the following:
$("#objRotates").css('opacity','.2');
var value = 0;
var prev_value = 0;
$( "li" ).click(function() {
var text=$(this).text();
if(text==="text1"){value=0;}
if(text==="text2"){value=33;}
if(text==="text3"){value=66;}
if(prev_value != value){
$("#objRotates").animate({opacity:'1'});
$("#objRotates").rotate({
animateTo:value,
easing: $.easing.easeInOutExpo,
center: ["25px", "150px"],
callback: function(){$("#objRotates").animate({opacity:'0.2'});}
});
}
prev_value = value;
});
Above code is the one that was used before, where images start position was 0 and its animation was triggered from link text.
Using jqueryRotate.js examples(here)
How do I change the code, so that images start position is certain degrees and animation starts if element with specific ID is clicked?
Give at least clue..Cause for now, looking at my old code, I am lost. Thanks in advance.
SIMPLIFIED FIDDLE
Ok, so I've created a couple of samples for you to check out. The first one is very basic and I've simplified the code a little to make it easier to understand. This one just uses completely static values and a static elementId for the event, which I'm pretty sure answers your question based on your response to my comment yesterday. http://jsfiddle.net/x9ja7/594/
$("#elementId").click(function () {
var startingAngle = 45;
var endingAngle = 90;
var elementToRotate = "img";
$(elementToRotate).rotate({
angle: startingAngle,
animateTo: endingAngle
});
});
But I wanted to give another example as well that would be dynamic and repeatable for multiple elements. With the code above, you would have to copy/paste the same code over and over again if you want to perform this animation by clicking different elements. Here's an alternative. In this example, you set all of your parameters in the data attributes in the clickable element, then the function is completely repeatable, you only have to write it once. Less code = everyone happy! Here's the example: http://jsfiddle.net/x9ja7/595/
//#region Default starting angles
$("#image1").rotate({ angle: 90 });
$("#image2").rotate({ angle: 20 });
//#endregion
$(".rotateAction").click(function () {
//#region Optional parameter - used in the optional callback function
var $self = $(this);
//#endregion
var startingAngle = Number($(this).attr("data-startingangle"));
var endingAngle = Number($(this).attr("data-endingangle"));
var elementToRotate = $(this).attr("data-elementtorotate");
//#region If the current angle is the ending angle, reverse the animation - this can be removed if you want, I thought it may be cool to show some of the things you can do with this.
var currentAngle = $(elementToRotate).getRotateAngle();
if ( currentAngle[0] === endingAngle) {
startingAngle = Number($(this).attr("data-endingangle"));
endingAngle = Number($(this).attr("data-startingangle"));
}
//#endregion
$(elementToRotate).rotate({
angle: startingAngle,
animateTo: endingAngle
//#region This is optional - uncommenting this code would make the animation single-use only
//, callback: function () { $self.off().removeClass("clickable"); }
//#endregion
});
});
Hope this helps. If you need any other assistance, please let me know.
I've created a line animation with RaphaelJS (see jsfiddle here - http://jsfiddle.net/7n040zdu/). I'm attempting to create a animation that occurs after this one takes place that is basically an erasing of the initial animation. That is, the line animated out the same way that it is animated in - along the same path, the same duration, the same direction.
I have tried just animating another path on top, but that solution is not preferable. If the initial path overlaps itself, then erasing with another path would reveal that the animation is not 'erasing' but rather being overlapped.
I am having trouble finding something in the Raphael documentation that would achieve anything similar to this.
Relevant code below:
HTML
<body>
<div class='drawings' id="draw0"></div>
</body>
CSS
body {
background-color: black;
}
JS
var animateLine = function(canvas, colorNumber, strokeWidth, pathString) {
var line = canvas.path(pathString).attr({
stroke: colorNumber
});
var length = line.getTotalLength();
$('path[fill*="none"]').animate({
'to' : 1
}, {
duration: 1000,
step: function (pos, fx) {
var offset = length * fx.pos;
var subpath = line.getSubpath(0, offset);
canvas.clear();
canvas.path(subpath).attr({
stroke: colorNumber,
"stroke-dasharray" : "",
"stroke-width" : strokeWidth
});
}
});
}
var canvas = new Raphael('draw0', 50,50);
var drawPath1 = 'M0.767,0.915 M48.538,20.228L0.767,0.915l3.896,39.312L48.538,20.228L37.663';
animateLine(canvas, '#FFF', '1.5', drawPath1);
Based on #Ian's comment on the original question, I was able to use a single path and then animate the dashoffset of the svg, but it took some further changing in order to get that actually working correctly.
Initially, the SVG path's css is set with the following parameters: 'stroke-dasharray': '9999px' and 'stroke-dashoffset': '9999px'. The stroke-dashoffset is then animated from 9999px to 9999px minus the length of the path. At the end of the initial animation, the css has to be set once again, this time: 'stroke-dasharray': '999 999' and 'stroke-dashoffset': '9999px'. At this point, the stroke-dashoffset is animated once again, this time 'stroke-dashoffset': (9999-(length of path)-100)+'px'.
A jsfiddle showing this is present here: http://jsfiddle.net/tim_m/94ze4ajj/
*Note that in the jsfiddle, I've added more paths with varying opacity and time offsets to give the illusion of a fade at the tips of the line animation.
I would like to draw(animate a line) in Raphael to the edge of the screen/browser from e.g. the x=100, y=100 pixels to the very right edge of the screen.
I know how to do the animation part, I just need to know how can I dynamically find out the rightest coordinates.
How to do such thing without creating a horizontal scroller in browser?
Is this possible in Raphael js or not at all?
My code so far:
var paper = Raphael(100, 100, ???, 1);
var lineToEdge = paper.path("M0 0");
lineToEdge.attr(fillerLine);
var anim = Raphael.animation({path: "M0 0L??? 100"}, 500);
lineToEdge.animate(anim.delay(2500));
??? - variables that will somehow give me the rightest x position.
Use Javascript's window.screen object to get this info.
See: http://www.javascriptkit.com/howto/newtech3.shtml
So your code would look like (sorry, haven't tested this myself):
var paper = Raphael(100, 100, screen.width, 1);
var lineToEdge = paper.path("M0 0");
lineToEdge.attr(fillerLine);
var anim = Raphael.animation({path: "M0 0L"+screen.width+" 100"}, 500);
lineToEdge.animate(anim.delay(2500));
Please consider the following code snippet:
jQuery(function ()
{
drawLogo();
});
function drawLogo()
{
var paper = Raphael('logo', 100, 100);//creates canvas width=height=100px
var rect = paper.rect(1,1,98,98, 10);//chessboard background
rect.attr("fill","#efd5a4");
var circle1 = paper.circle(20,20,12);
var circle2 = paper.circle(50,20,12);
var circle3 = paper.circle(80,20,12);
var circle4 = paper.circle(20,50,12);
var circle5 = paper.circle(50,50,12);
var circle6 = paper.circle(80,50,12);
var circle7 = paper.circle(20,80,12);
var circle8 = paper.circle(50,80,12);
var circle9 = paper.circle(80,80,12);
paper.path("M35,0 L35,100");
paper.path("M65,0 L65,100");
paper.path("M0,35 L100,35");
paper.path("M0,65 L100,65");
circle1.animate({scale:"0"}, 2000);
//setTimeout(circle1.animate({scale:"1"}, 2000), 2000);
}
The animation I'd like to achieve is a chain of two parts, first, a vertical scale animation from 100% to 0%, second, a vertical scale animation from 0% to 100%. The above code scales down both vertically and horizontally, so it is incorrect.
I've check Raphael's documentation but couldn't get it, particularly because I cannot see the correct syntax... Any good API reference like that of jQuery's?
Also, if I make the following change, then Firefox shows an error saying too many recursions:
transform(circle1);
function transform(item)
{
item.animate({scale:"0"}, 2000, transform(item));
}
I know this is bad, but what is the correct way to get a infinite "loop" of animation?
Edit: I modified the code to the following
transform([circle1, circle3, circle5, circle7, circle9]);
function transform(elements)
{
for(var e in elements)
{
e.animate({scale:"0"}, 2000);
}
}
in the hope that this would at least run the first part of animation for 5 circles, but unfortunately, it only gives an error saying e.animate() is not a function. Probably the reason is that when elements are retrieved back from the array, it "loses its type"? (just like in Java when you get an elements from plain old ArrayList, you must explicitly downcast or everything will be just of type object.)
2nd Edit before going to bed
At least the following works for once!
var elements = [circle1, circle3, circle5, circle7, circle9];
for(var i = 0; i < elements.length; i++)
transform(elements[i]);
function transform(e)
{
e.animate({scale: 0},2000, function(){this.animate({scale:1},
2000, transform(this));});
}
Achieved parts: chained two scaling animations one after another, for five circles;
Failed parts: Still not an infinite loop, still not only vertical scale.
It seems scaling of circle in just one direction is not possible. Instead use an ellipse. The scale attribute takes a string like "1 0" which means scale 100% for x (horizontally) and 0% for y (vertically). See attr-scale
So your animation can be achieved by
ellipse.animate({"50%": {scale: "1 0"}, "100%": {scale: "1 1"}}, 2000);
see 3rd method (keyframes) in animate
which means at 50% of animation the ellipse should be scaled 0% vertically and at 100% animation scale it back to 100%.
When you call a function, it will be evaluated immediately. Your transform calls transform(item) again before passing it to animate. Instead you should wrap it in a function and pass it.
Here's the full source
jQuery(function ()
{
drawLogo();
});
function drawLogo()
{
var paper = Raphael('logo', 100, 100);//creates canvas width=height=100px
var rect = paper.rect(1,1,98,98, 10);//chessboard background
rect.attr("fill","#efd5a4");
var ellipse1 = paper.ellipse(20,20,12, 12);
var ellipse2 = paper.ellipse(50,20,12, 12);
var ellipse3 = paper.ellipse(80,20,12, 12);
var ellipse4 = paper.ellipse(20,50,12, 12);
var ellipse5 = paper.ellipse(50,50,12, 12);
var ellipse6 = paper.ellipse(80,50,12, 12);
var ellipse7 = paper.ellipse(20,80,12, 12);
var ellipse8 = paper.ellipse(50,80,12, 12);
var ellipse9 = paper.ellipse(80,80,12, 12);
paper.path("M35,0 L35,100");
paper.path("M65,0 L65,100");
paper.path("M0,35 L100,35");
paper.path("M0,65 L100,65");
var elements = [ellipse1, ellipse3, ellipse5, ellipse7, ellipse9];
for(var i = 0; i < elements.length; i++)
transform(elements[i]);
}
function transform(e)
{
e.animate({
"50%": {scale: "1 0"},
"100%": {scale: "1 1", callback: function() {transform(e);}}
}, 2000);
}