JavaScript function is only working the first time I call it? - javascript

I was wondering whether you guys could help me troubleshoot an issue I'm having. Hopefully identifying the problem won't require you look into the documentation of the graphics package I'm using, but if it does, here you go: http://raphaeljs.com/reference.html#Element.transform.
I have the following block of code
window.setInterval(function()
{
mycirc.transform("t1,1");
}, 500);
which of course should call the function mycirc.transform("t1,1") every half-second. That function is supposed to translate the x and y coordinates of mycirc each by 1 unit (look at Element.transform([tstr]) on http://raphaeljs.com/reference.html#Element.transform).
However, when I test my page, mycirc gets translated once and then the subsequent calls have no effect. I used console.log(...) to test and make sure:
window.setInterval(function()
{
var bb = mycirc.getBBox();
console.log("coords before transformation: " + bb.x + "," + bb.y);
mycirc.transform("t1,1");
var bb = mycirc.getBBox();
console.log("coords after transformation: " + bb.x + "," + bb.y);
}, 500);
yields
coords before transformation: 120.98508107696858,106 jsfunctions.js:411
coords after transformation: 121.98508107696858,107 jsfunctions.js:414
coords before transformation: 121.98508107696858,107 jsfunctions.js:411
coords after transformation: 121.98508107696858,107 jsfunctions.js:411
etcetera.
Any idea why this might be?
(I tried to look through the source code for the graphics package, but it's unreadable because of no whitespace.)

your code
mycirc.transform("t1,1");
isn't relative to current state. It just transforms from original state to t1,1 and then from t1,1 to t1,1 etc.
You should calculate transformation every time.
EDIT: So it would need a global variable, incremented every time like:
var xyPos = 1;
window.setInterval(function()
{
mycirc.transform("t"+xyPos+","+xyPos);
xyPos++;
}, 500);

In the usage section of the docs you linked, it shows how to prepend and append transformations. This implies to me that you code will just reset the transformation to the same thing every time. I have never used this graphics library, so I can't say for sure, but try something like the following and see if it works:
mycirc.transform("t1,1");
mycirc.transform("...t1,1");
mycirc.transform("...t1,1");
mycirc.transform("...t1,1");
I believe that will apply the same transform 4 times. Of course, you will then need to convert this logic into an interval for your use.

I think this is expected behavior. Quoting the docs:
Adds transformation to the element which is separate to other
attributes, i.e. translation doesn’t change x or y of the rectange.
Try:
var amount = 1;
window.setInterval(function()
{
mycirc.transform("t" + [amount, amount].join(','));
amount++;
}, 500);

Related

Compare images in node.js (using e.g. opencv)

What I want to do is to get an image diff using node.js.
Ultimately I want to have a method expecting e.g. two filepaths or image data outputting the subtraction of both. Somehow like the compare function in imagemagick.
Something like:
var comparison_result = compareModule.compare('./image1.png', './image2.png');
Also, I would like to get the position of the spots in the resulting image that mark the differences.
Like this:
comparison_result.forEach(function(difference) {
console.log("A difference occurred at " + difference.x + "|" + difference.y);
});
I installed node-opencv, however I can not find a documentation that maps basic opencv c++ functions to node.js.
The function I would like to use is cvSub.
I would like to avoid js-imagediff as it works with canvas, has a dependency to "cairo" and I am not sure whether I can access the spots because in the documentation it rather seems like it just returns the difference as an image.
I have never tried to calculate per-element difference by cv::addWeighted() but it may work in practice:
var diff = new cv.Matrix(first.width(), first.height());
diff.addWeighted(first, 1.0, second, -1.0);
In native code (C++), this function can be replaced with the expression below:
diff = first*1.0 + second*(-1.0) + 0.0;
p.s.: node-opencv's authors published a sample code for measuring similarity:
node-opencv / examples / dissimilarity.js

How to constantly move SVG paths without losing performance

I am trying to do a mobile game where I draw 6 SVG paths and I move then through the screen (from top to bottom) constantly. I am manipulating the paths with a simple javascript that updates some variables value and use them to set the attribute "d" of the paths. Like the example below:
setInterval(scrollPaths, 17); // ~ 60 fps
function scrollPaths() {
// leftYPoints is an array of points defined earlier and scrollSpeed is an integer value (e.g. 2)
for (var i = 0; i < leftYPoints.length; i++) leftYPoints[i] += scrollSpeed;
// then I change the paths attribute
var pathAttribute = "M"+ leftXPoints[0] + leftYPoints[0]
+ " L" + leftXPoints[1] + leftYPoints[1];
document.getElementById("leftpath").setAttribute("d", pathAttribute);
document.getElementById("righpath").setAttribute("d", pathAttribute);
... // continue to do that with the other paths, changing some variables only
}
The javascript itself runs very fast (scrollPaths takes about 5ms every time) and runs perfectly on the browser. But when I test the script in the mobile browser it seems that theres is a lot of lag on the paths. You can see that the paths are not scrolling smoothly. So I tried to decrease the value of scrollSpeed to a very small value but that did not solve it. So I thought the problem was related to the rendering method of the mobile browser or something like that. I tried to find some answers but nothing solved my problem. Then I found AmeliaBR`s answer here How do you move an SVG around a webpage without triggering slow redraws? where she says that it is better to use the transform attribute because the browser will understand it as it should just move some content that was already rendered instead of re-calculating the whole layout. So I tried to do that like this:
var newYPos = 1;
setInterval(scrollPaths, 17); // ~ 60 fps
function scrollPaths() {
// increased the position of the paths
newYPos += 1;
// then I did the transform of the paths with a group <g>
document.getElementById("pathsgroup").setAttribute("transform", "translate(0," + value + ")");
}
But unfortunately the result was not very effective. The javascript ran a little faster but the lag effect of the paths is still happening. So I am here, asking:
Does anyone knows what is happening?
Is there a better way to do that?
Or the problem is that mobile browsers are not ready for that yet (they still lack performance)?
Not sure if it helps but I tested it on a Nexus 5 with Chrome (supposed to have a very good performance).
Thanks.
Maybe try storing the "pathsgroup" element as a variable so you don't have to keep using getElement every iteration?
var newYPos = 1;
var pathsGroup = document.getElementById("pathsgroup");
setInterval(scrollPaths, 17); // ~ 60 fps
function scrollPaths() {
// increased the position of the paths
newYPos += 1;
// then I did the transform of the paths with a group <g>
pathsGroup.setAttribute("transform", "translate(0," + value + ")");
}

Sprite Animation using a for loop

I am trying to create an animation using a sprite sheet and a for loop to manipulate the background position until it has reached the total number or rows in the sheet. Ideally a reset back to the initial position would be practical, but I cannot even get the animation itself to trigger...
With the current function, no errors occur and the background position in my CSS does not change. I even recorded using Chrome DevTools Timeline and there was nothing either then everything related to my page loading. I have also tried using "background-position-y" as well as a simpler value rather then the math I currently have in place.
This is my function:
$(document).load(function() {
var $height= 324;
var $rows= 34;
for(var i=0; i<$rows; i++){
setTimeout(function() {
$('#selector').css("background-position", "0px ", "0" - ($height*i) + "px");
}, 10);
}
});
I hate to ask a question that is similar to previous issues, but I cannot seem to find another individual attempting sprite sheet animation with a for loop, so I suppose it is it's own problem.
p.s. I didn't include a snippet of my HTML and CSS because it is pretty standard and I don't see how that could be the problem. That being said, I am all ears to any potential thoughts!
I am completely revamping my answer
This issue is that the for() loop is not affected by the setTimeout so the function needs to be written on our own terms, not with a loop
Working Fiddle
Here it is..
var $height= 5;
var $rows= 25;
var i = 1; // Starting Point
(function animateMe(i){
if(i<=$rows){ // Test if var i is less than or equal to number of rows
var newHeight = 0-($height*i)+"px"; // Creat New Height Position
console.log(i); //Testing Purposes - You can Delete
$('#selector').css({"background-position": "0px "+ newHeight}); // Set New Position
i++; // Increment by 1 (For Loop Replacement)
setTimeout(function(){animateMe(i)}, 1000); // Wait 1 Second then Trigger Function
};
})(0);
Here is your solution
First Change
$(document).load() To $(document).ready()
And Change .css Syntex as
$('#selector').css("background-position",'0px '+(0 - ($height*i))+'px');
Here is fiddle Check it ihad implemented it on my recent project http://jsfiddle.net/krunalp1993/7HSFH/
Hope it helps you :)

How can I make Raphael.js elements "wiggle" on the canvas?

I'm working on a project that uses SVG with Raphael.js. One component is a group of circles, each of which "wiggles" around randomly - that is, slowly moves along the x and y axes a small amount, and in random directions. Think of it like putting a marble on your palm and shaking your palm around slowly.
Is anyone aware of a Raphael.js plugin or code example that already accomplishes something like this? I'm not terribly particular about the effect - it just needs to be subtle/smooth and continuous.
If I need to create something on my own, do you have any suggestions for how I might go about it? My initial idea is along these lines:
Draw a circle on the canvas.
Start a loop that:
Randomly finds x and y coordinates within some circular boundary anchored on the circle's center point.
Animates the circle from its current location to those coordinates over a random time interval, using in/out easing to smooth the effect.
My concern is that this might look too mechanical - i.e., I assume it will look more like the circle is tracing a star pattern, or having a a seizure, or something like that. Ideally it would curve smoothly through the random points that it generates, but that seems far more complex.
If you can recommend any other code (preferably JavaScript) that I could adapt, that would be great too - e.g., a jQuery plugin or the like. I found one named jquery-wiggle, but that seems to only work along one axis.
Thanks in advance for any advice!
Something like the following could do it:
var paper = Raphael('canvas', 300, 300);
var circle_count = 40;
var wbound = 10; // how far an element can wiggle.
var circleholder = paper.set();
function rdm(from, to){
return Math.floor(Math.random() * (to - from + 1) + from);
}
// add a wiggle method to elements
Raphael.el.wiggle = function() {
var newcx = this.attrs.origCx + rdm(-wbound, wbound);
var newcy = this.attrs.origCy + rdm(-wbound, wbound);
this.animate({cx: newcx, cy: newcy}, 500, '<');
}
// draw our circles
// hackish: setting circle.attrs.origCx
for (var i=0;i<circle_count;i++) {
var cx = rdm(0, 280);
var cy = rdm(0, 280);
var rad = rdm(0, 15);
var circle = paper.circle(cx, cy, rad);
circle.attrs.origCx = cx;
circle.attrs.origCy = cy;
circleholder.push(circle);
}
// loop over all circles and wiggle
function wiggleall() {
for (var i=0;i<circleholder.length;i++) {
circleholder[i].wiggle();
}
}
// call wiggleAll every second
setInterval(function() {wiggleall()}, 1000);
http://jsfiddle.net/UDWW6/1/
Changing the easing, and delays between certain things happening should at least help in making things look a little more natural. Hope that helps.
You can accomplish a similar effect by extending Raphael's default easing formulas:
Raphael.easing_formulas["wiggle"] = function(n) { return Math.random() * 5 };
[shape].animate({transform:"T1,1"}, 500, "wiggle", function(e) {
this.transform("T0,0");
});
Easing functions take a ratio of time elapsed to total time and manipulate it. The returned value is applied to the properties being animated.
This easing function ignores n and returns a random value. You can create any wiggle you like by playing with the return formula.
A callback function is necessary if you want the shape to end up back where it began, since applying a transformation that does not move the shape does not produce an animation. You'll probably have to alter the transformation values.
Hope this is useful!
There is a very good set of easing effects available in Raphael.
Here's a random set of circles that are "given" bounce easing.
Dynamically add animation to objects
The full range of easing effects can be found here. You can play around with them and reference the latest documentation at the same time.
Putting calls in a loop is not the thing to do, though. Use callbacks, which are readily available.

SVG animation along path with Raphael

I have a rather interesting issue with SVG animation.
I am animating along a circular path using Raphael
obj = canvas.circle(x, y, size);
path = canvas.circlePath(x, y, radius);
path = canvas.path(path); //generate path from path value string
obj.animateAlong(path, rate, false);
The circlePath method is one I have created myself to generate the circle path in SVG path notation:
Raphael.fn.circlePath = function(x , y, r) {
var s = "M" + x + "," + (y-r) + "A"+r+","+r+",0,1,1,"+(x-0.1)+","+(y-r)+" z";
return s;
}
So far, so good - everything works. I have my object (obj) animating along the circular path.
BUT:
The animation only works if I create the object at the same X, Y coords as the path itself.
If I start the animation from any other coordinates (say, half-way along the path) the object animates in a circle of the correct radius, however it starts the animation from the object X,Y coordinates, rather than along the path as it is displayed visually.
Ideally I would like to be able to stop/start the animation - the same problem occurs on restart. When I stop then restart the animation, it animates in a circle starting from the stopped X,Y.
UPDATE
I created a page that demonstrates the issue:
http://infinity.heroku.com/star_systems/48eff2552eeec9fe56cb9420a2e0fc9a1d3d73fb/demo
Click "start" to start the animation.
When you stop and re-start the animation, it continues from the current circle coords in a circle of the correct dimensions.
The problem is that Raphael has no way of knowing that the circle is already part-way along the path. The "start" function means just that -- start an animation. imo it would be broken if it did anything else.
That said, your use case is a valid one, and might warrant another function -- a 'pause' of some sort. Of course, getting that into trunk would take longer probably than you want to wait.
From the Raphael source code, here's what happens when you call 'stop'.
Element[proto].stop = function () {
animationElements[this.id] && animationElements[length]--;
delete animationElements[this.id];
return this;
};
This decrements the total number of animations, and removes that animation from the list. Here's what the 'pause' function might look like:
Element[proto].pause = function () {
animationElements[this.id] && animationElements[length]--;
this._paused_anim = animationElements[this.id];
delete animationElements[this.id];
return this;
};
this saves the animation to be resumed later. then
Element[proto].unpause = function () {
this._paused_anim && (animationElements[this.id]=this._paused_anim);
++animationElements[length] == 1 && animation();
return this;
};
would unpause. Given scoping conditions, these two functions might need to be injected right into the Raphael source code (it's core hacking, I know but sometimes there's no alternative). I would put it right below the "stop" function shown above.
Try that, and tell me how it goes.
====EDIT====
Ok, so it looks like you'll have to modify the "start" attribute of animationElements[this.id]... something like:
this._pause_time = (+new Date) - animationElements[this.id].start;
in the pause, and then
animationElements[this.id].start = (+new Date) - this._pause_time;
on resume.
http://github.com/DmitryBaranovskiy/raphael/blob/master/raphael.js#L3064

Categories