I'm trying to implement a feature where you can drag on your screen to change the Position of an Object.
Right now the object is moving similarly to the change of the mouseX.
What I want is the further down on the screen you drag your mouse, the slower the object moves.
I'm pretty bad at maths so i dont really now how to achieve that in a good way.
Right now I'm doing it like that
factor = Math.abs(e.deltaY)/4;
this.newX = this.currentX + (e.deltaX / factor);
currentX is the start X value of the object.
No idea if it is clear what i want to achieve or if i provided all information, but any help is appreciated!
Your arithmetics always makes step equal to 4.
Consider using some function like exponent. For example,
factor = Exp(- k * Abs(deltaX))
If you want to provide factor 1 at close distances and factor halves per every 100 pixels (I've got arbitrary reasonable values), then
0.5 = exp( - k * 100)
ln(0.5) = -k * 100
k = - ln(0.5) / 100 ~= 0.007
note that I mean multiplicative factor:
factor = Exp(- 0.007 * Abs(deltaX))
this.newX = this.currentX + (e.deltaX * factor);
Now speed will be 1 for small distances, 0.5 for 100, 0.25 for 200, 0.125 for 300 and so on.
If you want another dependence, it is possible to find appropriate function.
Related
I've been trying to implement projectile motion in Javascript and I'm stuck at figuring out the angle (from which to derive the x and y velocity)
var v = 1;
var d = 10;
var g = -1;
var angle = 0.5 * Math.asin((g*d)/(v*v));
I would've expected someting like this to work, since it's coming from here Here.
The values I seem to get are either NaN or a very small number.
To give a bit more context; The projectile has to go from point A to point B (the distance is d in my code) where A and B are at the same height. Later on I would like to randomize the distance and angle a bit, but I assume that's not going to be an issue once this angle problem is solved.
EDIT:
As for a better example:
var v = 100;
var d = 100;
var g = 1; // I've made this positive now
var angle = 0.5 * Math.asin((g*d)/(v*v));
This says that angle is now 0.005
Im not really good at this physics problrm but i'll try
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/asin
the arg for Math.asin() should be between -1 and 1. Otherwise it returns NaN
from your example you run Math.asin(-10/1) maybe the velocity has max distance that it could cover. No matter the angle, 1m/s wont reach 500m distance for example
in your link there is a formula to count the max distance from given velocity and angle. Use that to confirm your variables are relevant.
angles are represented in values between -1 to 1 in cos, sin, tan. It makes sense that NaN (or values outside the range) means no angle can cover the distance
Hope it helps a bit
Note from the same wikipedia page you linked d_max = v*v/g. Given your inputs this evaluates to 1. Therefore a distance of 10 is impossible.
Another way to notice this is the range of sin is (-1,1). Therefore asin of any number outside of this range is undefined. (g*d)/(v*v) is 10, so Math.asin returns NaN
I'm attempting to get an object to move along a circular path in a fixed time period.
The application of this is a 'smooth motion' clock.
So, instead of moving the position to a fixed co-ordinate everytime .getSeconds() updates, I want to use a combination of ( .getSeconds() + ( .getMilliseconds()/1000 ) in order to accurately represent the motion of the second hand at all times.
For doing circular motion in the past I have used the following pair of functions:
var OrbitCalculationX = function(velocityPartial, orbitalRadius) {
return (Math.sin(Date.now() / 16000 * velocityPartial) * orbitalRadius);
};
var OrbitCalculationZ = function(velocityPartial, orbitalRadius) {
return (Math.cos(Date.now() / 16000 * velocityPartial) * orbitalRadius);
};`
The 16000 in that calculation controlled the orbital time. However, this is not accurate. Is there a way to control a x-axis sin vs z-axis cos equation set that has accurate time constraints?
If not, is there a way to set an animation path to complete in an exact time period in THREEjs?
I hope that I understood you correctly here...
Take one minute which has 60 secs and 60,000 msecs. So, the first step we want is to have numbers in that range.
var millisInMinute = Date.now() % 60000;
next thing we want is to normalize the value, so that it goes from 0 to 1:
var millisInMinuteNormalized = millisInMinute / 60000;
Now, to make a whole circular movement with sin and cos where we know that our variable will be between 0 and 1, we need to multiply it by 2*PI see plot here
The rest with the radius is like you did it, resulting in
var orbitCalculation = function(radius) {
return {x: (Math.sin((Date.now()%60000)/60000 * Math.PI * 2) * radius),
z: (Math.cos((Date.now()%60000)/60000 * Math.PI * 2) * radius)};
}
The actual seconds are now displayed correctly, you can compare it with your system time. Here is a working JSFiddle
All right people, I've got a slight performance bottle neck.
Basically I have a graph that consists of a screen div ("screen") and a chart div ("chart"), when this graph finishes rendering it checks to see what scale it needs to set on the chart in order to have the chart fit inside the screen. The problem is that whatever scale I come up with needs to be an exponent of 1.2. In other words you need to be able to get to the number of the new scale by taking 1.2 to the power of some number.
This function is what calculates the scale I need.
fitScale = function (width, height)
{
var scale = 1,
gWidth = graph.element.offsetWidth,
gHeight = graph.element.offsetHeight;
while (gWidth > width * scale && gHeight > height * scale)
scale *= 1.2;
while (gWidth < width * scale || gHeight < height * scale)
scale /= 1.2;
return 900 / scale;
}
The problem is that this sucks...
What it's doing is getting the chart size (width, height) and the screen size (gWidth, gHeight) and looping through a new scale until it hits the right number.
First it makes the scale bigger until at least one dimension of the chart times the scale is bigger than one dimension of the screen.
Than it loops back to make sure that both the dimensions of chart * scale are at least a little bit smaller than the screen.
I'de like to perform this action with just one math calculation. Maybe by calculating a snug fit and then by rounding down, but I can't figure out how to round down to an exponent of 1.2
-fix-
Here's the resulting working version...
fitScale = function (width, height)
{
var wScale = graph.element.offsetWidth / width,
hScale = graph.element.offsetHeight / height,
snugg = wScale < hScale ? wScale : hScale,
exp = Math.log(snugg) / Math.log(1 / 1.2),
scale = Math.pow(1 / 1.2, Math.ceil(exp));
return 900 / scale;
}
My math skills are rusty, so go easy if I wander off the Path of Truth here.
Basically you want to know what power y of 1.2 is equal to some given number x. While the log function would appear not to be helpful since it tells you what power of e will equal your number x, with some mad logarithm skillz you can in fact use that to get to where you want to go:
var y = Math.log(x) / Math.log(1.2);
Odds are pretty good that y won't be a whole number which is I think what you want, so if you just go ahead and Math.floor(y), you should be all set.
This is in part an EaselJS problem and in part a Physics/animation programming question.
I'm trying to learn EaselJS by studying the examples included in the EaselJS zip file. Right now, I'm looking at the SimpleTransform example,(http://bit.ly/LebvtV) where the robot rotates and fades into the background and expands towards the foreground. I find this effect really cool, and would like to learn how to achieve it. However, when I came to this set of code, I'm lost:
function tick() {
angle += 0.025;
var value = (Math.sin(angle) * 360);
bmp.setTransform (bmp.x , bmp.y , bmp.scaleX , bmp.scaleY , value/2 , bmp.skewX, bmp.skewY , bmp.regX , bmp.regY );
bmp.scaleX = bmp.scaleY = ((value)/360) + 0.25;
stage.update();
}
(For those unfamiliar with EaselJS, tick() is a function that dictates the actions on each tick, whose interval is set with setFPS. So if I've set FPS to be 20, then tick() will execute its statements 20 times in a second. I believe. And bmp here is a Bitmap object that points to the robot image.)
I've never been a wizard in Math, but I do understand the basics. I can see that angle += 0.025; is used to increased the angle variable so that the value passed into setTransform can change with time. However, I can't understand why a) 0.025 is used. b) what (Math.sin(angle) * 360) and ((value)/360) + 0.25 means, and c) why value is not just passed into setTransform, but divided by 2 (value/2).
I know it might be a challenge to explain this here, but any help is appreciated. In fact, if anyone thinks I'm a noob and needs to go study some Physics first, I'll most appreciate if someone can point me to a resource (book/url) for me to turn to.
Thanks in advance.
I can understand why you are confused. The code isn't efficient and that makes it harder to figure out what is going on. But here is the gist of it:
a) 0.025 is used because it is approximately π/125. With a Ticker speed of 25FPS, this means that the angle value will start at 0 and get to π at just about 5 seconds. π is used because Math.sin uses radians, not degrees (π radians == 180 degrees)
b) Math.sin(angle) will essentially start at 0, increase until it hits 1, decrease until it hits -1, then increase back to 0 -- all over a period of 10 seconds with sinusoidal rhythm.
(Math.sin(angle) * 360) has the same behavior as Math.sin(angle), just with a range of -360 to 360.
((value)/360) + 0.25) has the same behavior as Math.sin(angle), just with a range of -0.75 to 1.25.
c) value/2 is there so the robot only rotates 180 degrees instead of 360 degrees. I know what you are thinking -- why multiply by 360 only to divide by 2 one line later? Well, there is no reason for it really.
Here's a slightly clearer version of tick:
function tick() {
angle += Math.PI/125;
var sineValue = Math.sin(angle);
bmp.rotation = sineValue * 180;
bmp.scaleX = bmp.scaleY = sineValue + 0.25;
stage.update();
}
b) The Math.sin(angle)*360 seems like a conversion between degrees and radians.
Math.sin( x ) always evaluates to -1>=x>=1,
and therefore
Math.sin( angle ) is also always -1>=angle>=1
(we just substituted x), and
var value = Math.sin( angle ) * 360 is always -360>=value>=360.
(In the context of degrees rotated that is thus 1 whole rotation left or one whole rotation right).
We can see that the setTransform function exists as follows:
p.setTransform = function(x, y, scaleX, scaleY, rotation, skewX, skewY, regX, regY) {}
Obviously, we can see that there is a direct connection between value & angle. What we further see is that both the transform & scaleX are again depending on value. We can pull the conclusion that each tick there will be -after some calculations- a changing transform and scaleX.
So as the variable 'value' is passed as a parameter, this means that we wish to rotate 'this' much, as much as value tells us (-360>=x>=360). That means, /2 and 0.025 is just configured like this.
Hope this is helpful :-)
I'm using Raphael.js to animate an SVG circle's radius on hover. I like the stock elastic effect that the library offers, but I'd like to increase the amplitude - i.e., make the circle grow and shrink with a lot more gusto when it's hovered - not with extra speed, but to grow larger and shrink smaller when the effect runs.
I copied the elastic function and renamed it super_elastic, and have been tinkering with it here:
http://jsfiddle.net/ryWH3/
I have no idea how the function works, so I've just been tinkering with its numerical values to see what happens. So far I haven't found anything that appears to do what I want. Can anyone recommend any modifications to the function (or a different function altogether) that might do what I'm looking for?
Thanks!
UPDATE:
Thanks for the replies! Sorry, I may not have explained this very well. I'm guessing that the statement "grow larger and shrink smaller" was especially misleading.
I'm aware that the r property affects the final radius of the circle after the animation runs; what I'm trying to do, though, is make the elastic animation "bounce" with greater amplitude. That is, while the animation will still start and end at the same r values that I've set for the circle, I'd like the elastic transition to be a lot more dramatic - expand and contract the circle much more aggressively during the transition before arriving at the final r values. To do this, I'm assuming that I need to modify the equation used in the elastic function to make the effect more dramatic.
Hopefully that makes sense - it's kind of hard to explain without showing an example, but if I had an example, I wouldn't have needed to post this question. ;-)
OK, based on your clarification, here's a new answer. To expand the effect of the easing (amplification), you need to multiply the easing result with a multiplier like this.
return 6 * Math.pow(2, -10 * n) * Math.sin((n - .075) * (2 * Math.PI) / .3) + 1;
But, when you do that, you find that the large part of the amplification goes too fast. The small part goes slow and the large part goes fast. So, the pace when it's larger needs to be changed. My guess (which seems to work) was to change Math.sin() to Math.cos() because that shifts the phase and it seems to work as you can see here: http://jsfiddle.net/jfriend00/fuaNp/39/.
return 6 * Math.pow(2, -10 * n) * Math.cos((n - .075) * (2 * Math.PI) / .3) + 1;
Other things to understand about this easing function. This part:
(2 * Math.PI) / .3
determines how many bounce cycles there are. The larger that multipler is, the more bounces it will have (but the faster the bounces will go). The smaller that multipler is, the fewer bounces it will have (and the slower those bounces will go).
This part:
Math.pow(2, -10 * n)
determines how fast the bounce decays since this value gets smaller the larger n gets which negates the other multipliers as n gets large. So:
Math.pow(2, -5 * n)
makes it decay slower (you see more of the larger swings at the beginning and less of the smaller swings at the end.
To make the circle go larger when you hover over it, you change the hovered radius which I've upped to r: 100 here. To make the circle smaller, you change the initial size and the unhovered size from 25 to something smaller like this:
var paper = Raphael(0, 0, 300, 300),
circle = paper.circle(150, 150, 10); // <== change initial radius here to make it smaller
circle.attr({
'stroke': '#f00',
'stroke-width': 4,
'fill': '#fff'
});
circle.hover(function() {
this.animate({ r: 100 }, 1000, 'super_elastic'); // <== change enlarged size here
}, function() {
this.animate({ r: 10 }, 1000, 'super_elastic'); // <== change small size here
});
// no changes made to the easing function
Raphael.easing_formulas.super_elastic = function(n) {
if (n == !!n) {
return n;
}
return Math.pow(2, -10 * n) * Math.sin((n - .075) * (2 * Math.PI) / .3) + 1;
};
You can see it here: http://jsfiddle.net/jfriend00/fuaNp/.
The super_elastic() function is the easing function which controls what pace the animation moves at different parts of the cycle. Easing doesn't control the overall amplitude. That's done with the parameters to the animate() method.
If you wanted to slow down the animation, you would increase the time of the animation (make the two 1000 arguments to animate() be larger numbers. If you wanted to speed up the animation, you make those two numbers smaller. These are milliseconds for the animation. Smaller numbers means the animation runs in fewer milliseconds (which means faster).