Animate polygon points snap.svg - javascript

it's the first time I tried to animate polygon points with snap.svg and I have the felling I'm doing something wrong there.
Here is my code :
var fdr = Snap('#fdright');
var time1_stp0 = [363.617,262.895, 363.562,367.4, 273.145,315.191, 273.145,315.191];
var time1_stp1 = [363.617,262.895, 363.562,367.4, 273.145,315.191, 273.145,210.688];
var timeline1 = fdr.polygon(time1_stp0).attr({fill:'red',opacity:'0.5'});
timeline1_anim = function(){
timeline1.animate({"points":time1_stp1},3000,mina.linear);
}
timeline1_anim();
As soon as the page is loaded, my polygon disappears (I guess it's because my function is called right after the creation of the polygon). I checked the html, my polygon's still there but here is what i get :
<polygon fill="#ff0000" style="opacity: 0.5;" points="363.617"></polygon>
I don't get what might be the issue, so if someone's got an answer i'll be glad to hear it.
EDIT : I tried to add "toString()" but it's still not working :
timeline1_anim = function(){
timeline1.animate({"points":time1_stp1.toString()},3000,mina.linear);
}

I think there's a bug in Snaps polygon animation.. its listed here There is a patch submitted linked from there.
However, you can get around this easily by animating the array values though if needed.
timeline1_anim = function(){
Snap.animate(time1_stp0, time1_stp1,
function( val ){
timeline1.attr({ points: val })
},
2000);
}
jsfiddle
If you are doing a lot of them, you could write a small plugin to include it...
Snap.plugin( function( Snap, Element, Paper, global ) {
Element.prototype.polyAnimate = function( destPoints, duration, easing, callback ) {
var poly = this;
Snap.animate( this.attr('points'), destPoints,
function( val ){ poly.attr({ points: val }) }, duration, easing, callback)
};
});
timeline1.polyAnimate( time1_stp1, 2000, mina.linear, function() { alert('finished')})
jsfiddle

Related

Three.js: Uniforms value not updating

I'm using Tween.js to animate the uniforms value of a shader upon clicking a button. Here is what I have:
Shader.uniforms.threshold.needsUpdate = true;
function fadeIn() {
new TWEEN.Tween( Shader.uniforms.threshold )
.to( { value : 0.6 }, 100 )
.start();
}
function fadeOut() {
new TWEEN.Tween( Shader.uniforms.threshold )
.to( { value : 2 }, 100 )
.start();
}
document.getElementById("FadeIn").onclick = function() {
fadeIn();
}
document.getElementById("FadeOut").onclick = function() {
fadeOut();
}
The above does not work. When I try refreshing the page, the value does change but the button click does nothing. Does anyone know the mistake in my implementation? Can Tween.js be used like this or is there a better method? Thanks.
Ok here's how I got it working. It seems changing the value of the "Shader" itself is the cause. The above works when I change the uniforms value of the individual objects. So instead of Shader.uniforms.threshold, I did this:
myObject.material.uniforms.threshold, which works.

Changing All Icons Rotating Down to One

I currently have a giant table of "auditpoints", some of those points are "automated". If they are automated they receive a gear icon in their row. The gear icon is not the only icon each row receives. Each row, no matter if it's automated or not receives two other icons, a pencil and a toggle button. When an automated point "runs" the gear icon rotates until it is finished "running". I've have implemented some code to ran all of these points at once but I have a small problem. When you click my button to run all these points all three of the icons I have mentioned rotate and this is not the result I am looking for. The line commented out in my code snippet (and it's matching bracket) will prevent the code from running all of the automated points. Commenting out the line is what causes all the icons to rotate. I know this line is required to get the automated points to run properly as it used in the single execution of automated points I just don't know what to change it to. It obviously shouldn't be click because you are no longer clicking the gear icon to get a point to run I just don't know what to change it to but the classes in that click function are related to the gear icon.
Hopefully this is a very easy question to solve and doesn't waste anyone's time. Thank you!
private updateAuto() {
var self = this;
$(".auditPointRow").each(function () {
//self.el.on("click", ".update, .edit", function () {
var row = $(this).closest(".auditPointRow");
var id = row.data("id");
var automated = (<string>row.data("automated")).toLowerCase() == "true";
var running = true;
if (automated && $(this).closest(".edit").length == 0) {
var gear = $(this).find(".fa");
var maxTurns = 120;
gear.css("transition", "transform linear " + maxTurns * 2 + "s");
gear.css("transform", "rotate(" + (maxTurns * 360) + "deg)");
var request = $.ajax(self.root + "api/sites/" + self.site.ID + "/auditpoints/" + id, {
"type": "PATCH", data: JSON.stringify([
{
Op: "Replace"
, Path: "/score"
, Value: "run"
}
])
});
request.done(function () {
gear.css("transition", "").css("transform", "rotate(0deg)");
row.prev().find("td").css("background-color", "");
if (row.prev().qtip("api")) {
row.prev().qtip("api").destroy(true);
}
});
}
//}
});
}
I think I found a solution to my problem. I used .each again to go through all of the "gears" and only rotate them.
private updateAuto() {
var self = this;
//$(".auditPointRow").each(function () {
$(".update, .edit").each(function () {
//Left out the rest of the code so this answer isn't too
//long, none of it changed if that matters.
});
//});
}
For some reason the result runs very slowly (but it runs!) and I'm not sure why so if anyone has any better suggestion/optimizations please feel free to leave those here.
Edit: I realized I didn't to go through .each twice, that's what was slowing to down so I removed that first each that went over auditPoints and just did the ones with gears instead.

About image rotation once element with specific id is clicked

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.

how to build a 3d donut chart

I wonder if it's possible to build a 3d donut chart in html.
I have found a interesting link here but infortunatly i need to add links (or javascript event) when clicking to launch a ajax request.
Have you ever done such a thing ?
Thanks for your answers
See the following example I've just made:
http://jsfiddle.net/baQCD/3/embedded/result/
The key point (pun intended) is to add a url key for each row (object) in the data array, and use it in the 'click' event handler:
point: {
events: {
click: function(e) {
location.href = e.point.url;
e.preventDefault();
}
}
},
In your case instead of opening a new url, you could do your ajax request or do anything else. In my example I've shown how to manipulate the data and title.
click: function(e) {
if (this.name == "Randomize!") {
sliceK = getRandomInt(0,chart.series[0].data.length-1);
chart.options.series[0].data[sliceK].y = getRandomInt(1,30);
chart = new Highcharts.Chart(chart.options);
} else if (this.name == "Link") {
location.href = this.url;
e.preventDefault();
} else {
chart.setTitle(null,{text:this.name + " clicked"});
}
}
You can immediately see, 2 features I very like in Highcharts, the ability to print or download the chart, and the ability to disable part of the data (removing it from the chart) by clicking on the legend.
This is based on the code shown in:
http://birdchan.com/home/2012/09/07/highcharts-pie-charts-can-have-url-links/
http://www.highcharts.com/demo/3d-pie-donut/
this is a simple 3d Axonometric class i wrote for testing, its very simple it puts the canvas transformation into a plane of zy or zx or yx... it uses canvas setTransform
you first have to call the axionometric class with phi and theta the angles of view
get_bd is a function where you can enter x,y,z coordinates and the method returns an object with b and d value... b is the x of the screen and d is the y of the screen.
i have appended and example, you just have to put a canvas tag in the html with id canvasView
//3d Maths - Axonometric -- Artner Thorsten -- Austria -- Wiener Neustadt
var context=document.getElementById("canvasView").getContext("2d");
function Axonometric (phi,theta)
{
var cosPHI=Math.cos(phi);
var sinPHI=Math.sin(phi);
var cosTHETA=Math.cos(theta);
var sinTHETA=Math.sin(theta);
this.cosPHI=cosPHI;
this.sinPHI=sinPHI;
this.cosTHETA=cosTHETA;
this.sinTHETA=sinTHETA;
this.phi=phi;
this.theta=theta;
}
Axonometric.prototype.get_bd=function (x,y,z)
{
var b=y*this.cosPHI-x*this.sinPHI-500;
var d=x*this.cosPHI*this.cosTHETA+y*this.sinPHI*this.cosTHETA-z*this.sinTHETA+500;
return {b:b,d:d};
}
Axonometric.prototype.plane_zy=function (x)
{
context.setTransform (0,this.sinTHETA,-this.cosPHI,this.sinPHI*this.cosTHETA,500+x*this.sinPHI,500+x*this.cosPHI*this.cosTHETA);
}
Axonometric.prototype.plane_zx=function (y)
{
context.setTransform (this.sinPHI,this.cosPHI*this.cosTHETA,0,this.sinTHETA,500+y*-this.cosPHI,500+y*this.sinPHI*this.cosTHETA);
}
Axonometric.prototype.plane_yx=function (z)
{
context.setTransform (this.sinPHI,this.cosPHI*this.cosTHETA,-this.cosPHI,this.sinPHI*this.cosTHETA,500,500-z*this.sinTHETA);
}
Axonometric.prototype.draw_axis=function (length)
{
var O=this.get_bd (0,0,0);
var X=this.get_bd (length,0,0);
var Y=this.get_bd (0,length,0);
var Z=this.get_bd (0,0,length);
context.save;
context.beginPath ();
context.textAlign="top";
context.fillText ("X",-X.b,X.d);
context.moveTo (-O.b,O.d);
context.lineTo (-X.b,X.d);
context.strokeStyle="red";
context.stroke ();
context.beginPath ();
context.fillText ("Y",-Y.b,Y.d);
context.moveTo (-O.b,O.d);
context.lineTo (-Y.b,Y.d);
context.strokeStyle="green";
context.stroke ();
context.beginPath ();
context.fillText ("Z",-Z.b,Z.d);
context.moveTo (-O.b,O.d);
context.lineTo (-Z.b,Z.d);
context.strokeStyle="blue";
context.stroke ();
context.restore ();
}
// example
var Viewer=new Axonometric (Math.PI/4, Math.PI/8);
Viewer.draw_axis (400);
Viewer.plane_yx (0);
context.beginPath ();
context.fillStyle="red";
context.fillRect (0,0,200,200);
Viewer.plane_zx (0);
context.beginPath ();
context.fillStyle="lightgrey";
context.fillRect (0,0,200,-200);
Viewer.plane_zy (0);
context.beginPath ();
context.arc (-100,100,100,0,2*Math.PI);
context.fillStyle="black";
context.fill();
Using an existing library is an easy solution. If I'm understanding your question properly, you would like users to be able to click on a slice to open a new URL.
This can be achieved in ZingChart by setting up a "pie3d" type, and then including "url" and "target" in the series.
Here's how I did it:
{
"graphset":[
{
"type":"pie3d",
"plot":{
"slice":45
},
"plotarea":{
"margin-top":"35px"
},
"series":[
{
"text":"Apples",
"values":[5],
"url":"http://www.google.com",
"target":"_blank"
},
{
"text":"Oranges",
"values":[8]
},
{
"text":"Bananas",
"values":[22]
},
{
"text":"Grapes",
"values":[16]
},
{
"text":"Cherries",
"values":[12]
}
]
}
]
}
Expanding on Merrily's answer, you can also use ZingChart's API to track chart interaction and call any functions you like.
var ZCwindow;
function openWindow() {
ZCwindow = window.open("http://zingchart.com/docs/chart-types/pie/", "ZingChart Pie Charts");
}
zingchart.node_click = function(e){
if(e.value == 5) openWindow();
};
You can view a live demo here.
I am part of the ZingChart team. You can reach out to us for assistance via support#zingchart.com
For the past few months I have been working with Google Visualization charts, and I think it may be exactly what you're looking for. Here is the link to the documentation.
This will give you a donut chart (though I am not sure if you can make it 3-D or not, I believe you can) and you can add event handlers for when the user clicks on a slice. Here's what it looks like:
I highly recommend trying the charts, I have found them to be extraordinarily useful. Good luck!
EDIT: My apologies, after re-reading the section on donut charts it appears the new API does not yet support 3-D donut charts. Does it absolutely have to be three-dimensional? If not this is still an excellent choice.
It's not 3D, but you should have a look at chart.js

Snap SVG animate SVG on hover / reset SVG on leave

I'm using Snap.svg to create some SVGs that animate on hover.
A very simplified jsfiddle is here:
http://jsfiddle.net/62UA7/2/
var s = Snap("#svg");
var smallCircle = s.circle(100, 150, 70);
//animation
function animateSVG(){
smallCircle.animate({cy: 300}, 5000,mina.bounce);
smallCircle.animate({fill:"red"},200);
}
//reset function?
function resetSVG(){
// something here to reset SVG??
}
smallCircle.mouseover(animateSVG,resetSVG);
The hover / animation is working fine.
The intention is to stop the animation and return to original SVG state if the user moves the mouse off the SVG - and this is where I'm currently stuck.
The actual SVG files I'm using are complex, so hoping for a quick way of 'refreshing' the SVG rather than manually moving it back to original position and colour
I'm assuming there's a really easy way of doing this - just can't seem to work it out or find the answer in any documentation anywhere.
Hopefully someone can help - thanks in advance if you can!
If you are only willing to animate between 2 states I found that Codrops animated svg icons did great job with handling this type of snap.svg animations. I have started using their code as a basis for my future exploration of SNAP.SVG. But getting back to the code: the most fun part is that you configure your animation with simple JSON objects such as:
plus : {
url : 'plus',
animation : [
{
el : 'path:nth-child(1)',
animProperties : {
from : { val : '{"transform" : "r0 32 32", "opacity" : 1}' },
to : { val : '{"transform" : "r180 32 32", "opacity" : 0}' }
}
},
{
el : 'path:nth-child(2)',
animProperties : {
from : { val : '{"transform" : "r0 32 32"}' },
to : { val : '{"transform" : "r180 32 32"}' }
}
}
]
},
and you can easily attach any sort of event trigger for animation In/Out. Hope that helps.
Personally I'd probably do it something like the following, storing it in a data element. It depends what problems you are really trying to overcome though, how you are actually animating it (I suspect it could be easier than my solution with certain animations, but trying to think of something that covers most bases), and if you really need it reset, also how many attributes you are animating and if there is other stuff going on...
var smallCircle = s.circle(100, 150, 70);
var saveAttributes = ['fill', 'cy'];
Snap.plugin( function( Snap, Element, Paper, global ) {
Element.prototype.resetSVG = function() {
this.stop();
for( var a=0; a<saveAttributes.length; a++) {
if( this.data( saveAttributes[a] ) ) {
this.attr( saveAttributes[a], this.data( saveAttributes[a] ) );
};
};
};
Element.prototype.storeAttributes = function() {
for( var a=0; a<saveAttributes.length; a++) {
if( this.attr( saveAttributes[a]) ) {
this.data( saveAttributes[a], this.attr( saveAttributes[a] ) );
};
};
};
});
function animateSVG(){
smallCircle.animate({cy: 300}, 5000,mina.bounce);
smallCircle.animate({fill:"red"},200);
};
smallCircle.storeAttributes();
smallCircle.mouseover( animateSVG );
smallCircle.mouseout( smallCircle.resetSVG );
jsfiddle

Categories

Resources