Zooming in/out with animate on hover with snap.svg - javascript

I'm building an SVG and animating it in snap.svg because of a lack of IE support for animations (thanks IE). What I have in it's most basic form is a pentagon I'd like to rotate on hover, on mouse out it then resets itself. Code is located in the fiddle below (obviously this is a cut down version of the real thing but it shows the bug clearly still)
The JS is as follows:
// Set up snap on the svg element
var svgElement = Snap("#svg");
// Create the hover on and off events
var hoverover = function() {
svgElement.select('#pentagram-one').stop().animate({transform: 's1r72,500,515'}, 1000);
};
var hoverout = function() {
svgElement.select('#pentagram-one').stop().transform('s1R0,500,515');
};
// Set up the functions for hover in and out
svgElement.select('#pentagram-one').hover(hoverover, hoverout);
Fiddle demo of this behaviour here: http://jsfiddle.net/kfs8o9mw/
The pentagon rotates as expected on the first hover in then out. However when doing it a second time the pentagon zooms in and out a bit which is completely unexpected (it's ends up at the right size but during the animation isn't). And I've been able to replicate this in IE(10), Chrome and Firefox.
Is this a bug in snap.svg or is there something wrong in the code?
Thanks in advance

You simply can remove the s1 you have defined for the scale as show in the following:
Also note that you're using a capital R in the transform event for hoverout, when it should be a lowercase r
http://jsfiddle.net/3phpbef7/2/
I would also define you pentagram element as a variable as you're using it multiple times. I've also included this in the Fiddle above.
Hope this helps

Related

Parent css transform affecting d3.mouse points

I'm using a third library that is adding 'transform: translate3d(200,0,0);' to a parent element. So the elements within the svg tend to move to the right. For drag&drop events, setting the origin is enough, but I'm having troubles to get corrected the d3.mouse(this).
I have created a jsfiddle of this example: http://bl.ocks.org/hlucasfranca/f133da4493553963e710
jsFiddle: https://jsfiddle.net/rahpuser/5jp6123u/
So, when clicking without applying the transform to the parent, everything is ok, but when the parent has the transform, d3.mouse returns a wrong number
var coords = d3.mouse(this);
coords[0] === 100; //true without transform..
coords[0] === 300; // true when the transform to the parent is applied.
// the values are not precise but you can verify the behavior in the jsfiddle
Why d3.mouse(this) is not able to get the correct value ?
my understanding is that d3.mouse should get the coords based on the container this ( svg ).
What should I do to fix the behavior keeping the parent with the new transform?
Thanks.
UPDATE:
Not working in Firefox 46 for ubuntu
Working well in chrome and opera
As you've discovered, this is a known FireFox bug. Even if you did fix FireFox, it's going to take some time to propagate, and it'll never be backwards-fixed. So you still need a workaround.
One thing you can do — as long as the SVG's top-left is always at the 0,0 coordinate of its containing div (as is the case with your jsFiddle) — is replace the call to d3.mouse(this) with:
d3.mouse(this.parentNode)
That'll get the mouse coordinate from the parent of the SVG, which is a normal div, so apparently it's not affected by this bug and will get you the value you want on all platforms.
This does not address the root problem (for example getClientBoundingRect would still return the wrong values), but it works around your specific problem.

Masked element in Snap SVG doesn't come into view when translated

I have a group of elements that are masked by a rect in SnapSVG and I want to translate the elements, bringing new ones into view (and hiding ones that are currently in view). The code is really simple - here's a codepen: http://codepen.io/austinclemens/pen/ZbpVmX
As you can see from the pen, box1, which starts outside the mask element (clip) should cross through it when animated, but it never appears. Moreover, box2, which should move out of the clipping area, remains visible.
This example seems to do a similar thing and has no problems: http://svg.dabbles.info/snaptut-masks2
Here's the code from codepen:
var t = Snap('#target')
var clip=t.rect(200,200,200,200).attr({fill:'#fff'})
var box1=t.rect(300,100,50,50).attr({fill:'#000'})
var box2=t.rect(300,300,50,50).attr({fill:'#000'})
var boxgroup=t.group(box1,box2)
boxgroup.attr({mask:clip})
boxgroup.animate({transform:'t100,300'},2000)
I notice that the svg.dabbles examples translates the clip region by 0,0 at one point, but adding something like that doesn't seem to get me anywhere.
Ok, I figured this out thanks in part to this really great article about SVG transforms: http://sarasoueidan.com/blog/svg-transformations/
The upshot is that when I translate the box group, it takes the mask with it. This is a little confusing to me still - I guess the mask attribute is causing this somehow? Anyways, the solution is to apply an opposite translation to the mask to keep it in place. Check the pen to see it in action but basically I just had to add:
clip.animate({transform:'t-100,-300'},2000)
The tricky part of this is that you now need to synchronize the movement of the mask and the movement of the box group.
edit - I now demonstrate how synchronization can be achieved using snap's set.animate method on the codepen.

HTML5 Canvas choppy graphics when animating

When animating one layer in canvas the graphics become choppy if there are other layers present, see fiddle (click RUN to see animation): http://jsfiddle.net/Q97Wn/
If i change this line:
opts.percentageIndicator.clearRect(0, 0, opts.percentageIndicator.width, opts.percentageIndicator.height);
To:
opts.percentageIndicator.clearRect(0, 0, opts.canvas.width, opts.canvas.height);
Then everything goes smoothly, except that this will remove the other layer completely.
I could solve this issue by having both in one canvas each, but i was hoping for structure-purposes that i could avoid that. Any suggestions?
First of all, canvas.getContext() not generating new context, it returning already existing instance, so the lines:
opts.centerCircle = opts.canvas.getContext('2d');
// ...
opts.percentageIndicator = opts.canvas.getContext('2d');
Would mean the same thing.
So I advice you to do like this:
http://jsfiddle.net/Volter9/Q97Wn/2/
What I did I just changed both contexts to one property and after rendering base added:
opts.ctx.strokeStyle = opts.indicatorColor;
Good luck!

Combining EaselJS and TweenJS for Fade Over Time

I have a working animation that uses only EaselJS to load and display images. The whole animation works quite well, but images appear and disappear immediately. I would like them to fade in and out over time. Here's a small jsfiddle that might illustrate the problem better: http://jsfiddle.net/tNLyx/
var stage = new createjs.Stage("canvas");
var shape = new createjs.Shape(new createjs.Graphics().f("#f00").dc(0,0,100)).set({x:100,y:100});
stage.addChild(shape);
stage.update();
shape.addEventListener("click", function(){
//Shape will now disappear quickly. I would like it to fade out, by tweening its alpha or opacity or something. Any help would be greatly appreciated!
stage.removeChild(shape);
stage.update();
});
When you click the red circle, it simply disappears, immediately. I would like it to fade out slowly. I have done some research but am having trouble finding good documentation - it appears that what I need is the TweenJS "sister" library, and at least some of the following code:
createjs.Ticker.setFPS(30); //Sets frames-per-second for TweenJS
createjs.Tween.get(shape).to({alpha: 0},1000);
I believe the last line is supposed to get the "shape" object which I made previously, then set up an animation which animates its alpha property (which I assume is 1 by default when added to the stage, but I'm not sure), and reduces it to this 0 over 1000 milliseconds. The code doesn't actually do anything - any help would be much appreciated!
You need to ensure you update the stage during a tween, or whenever a property changes.
Here is a quick fiddle using your code. I added a tick listener to the stage, which will redraw the stage constantly. http://jsfiddle.net/lannymcnie/FVw7E
createjs.Ticker.addEventListener("tick", stage);
Note that you may want to control when the tick is added and removed, so it isn't unnecessarily redrawing the stage when nothing is changing. A quick way would be to add a call to the end of the tween.
createjs.Tween.get(shape).to({alpha: 0},1000).call(doneAnimating);
function doneAnimating() {
createjs.Ticker.removeEventListener("tick", stage);
}
Cheers.

Tracking mouse position of a jqplot vertical line chart

I want to create a jqPlot line chart which has the ability to change orientation between vertical and horizontal orientation. I was able to achieve this using CSS rules, by rotating the div element containing the chart.
My work up to now: http://jsfiddle.net/GayashanNA/A4V4y/14/
But the problem is I also want to track the mouse-pointer and mouse clicks on points on chart after the orientation is flipped because i want to annotate those points. I am unable to do this when the chart is in vertical orientation. Can anyone suggest a method to do this? Or am i approaching the problem in a wrong way?
(Note: I am able to do this in horizontal orientation, you can observe it if you try to click on a point on the above chart.)
Thanks and help is much appreciated.
I've never used jqPlot, but I guess your problem is trying to use css rotate(), since the cursor plugin is using the mouse position to determine where to draw the lines, and element's size doesn't change when transformed by rotate(), it still have the same width and height values.
If you take a look at the code, you will see:
if (c.showVerticalLine) {
c.shapeRenderer.draw(ctx, [[gridpos.x, 0], [gridpos.x, ctx.canvas.height]]);
}
if (c.showHorizontalLine) {
c.shapeRenderer.draw(ctx, [[0, gridpos.y], [ctx.canvas.width, gridpos.y]]);
}
So it seems like the library is always drawing the lines based on mouse position over the original element, which of course, won't match the position after being transformed by rotate(), and XY coordinates are going to be transformed to YX after rotate().
I would try to change the size of your original element, though I don't know if the library lets you specify in which sides are the labels going to be drawn.
I finally found a solution for the problem. But i had to change jqPlot library to achieve this. To help anyone else who run in to the same problem, i'll put my solution here.
First i had to insert the following code in to the jqPlot class of the jquery.jqplot.js file, which is the core library.
function jqPlot() {
//add the following code segment
var verticallyOriented = false;
this.setVertical = function(state){
verticallyOriented = state;
}
//don't change other code that isn't mentioned here
//now you have to change the logic in the getEventPosition function
//to make sure the new orientation is detected
function getEventPosition(ev) {
//change the line starting with var gridPos = ...
//to the following code segment
//depending on the orientation the event position calculating algorithm is changed
if(verticallyOriented){
var gridPos = {x:ev.pageY - go.top , y:plot.eventCanvas._elem.height() - ev.pageX + go.left};
} else {
var gridPos = {x:ev.pageX - go.left, y:ev.pageY - go.top};
}
//no change to other code is needed
}
}
You can view a working example here: http://jsfiddle.net/GayashanNA/yZwxu/
Gist for the changed library file: https://gist.github.com/3755694
Please correct me if i have done something wrong.
Thanks.

Categories

Resources