Inertia for dragging in D3 version 2 - javascript

I'm trying to implement inertia for drag using D3 version 2.
The latest version of d3 (3.3.10) from the download page does not have it, while pjanik has modified a version of d3 which does that - http://bl.ocks.org/pjanik/raw/5872514/
In any case, how can I implement this in D3 version 2?
A very primitive function to achieve the feel, but would really prefer an elegant formula if anyone has any suggestions, much appreciated:
function inertia(value) {
var remainder = value,
output,
drag = 0.3,
stepTime = 60
//var x = 0
var interval = setInterval(function() {
output = remainder * drag
//x += output
//console.log(x)
//jQuery('.logo').css('margin-left', x)
console.log(output)
remainder = remainder - output
/*a hack to clear when value is small*/
if (output < value * .005)
clearInterval(interval)
}, stepTime)
}
//Any integer to be split for steps, can be distance, time, any value!
inertia(100)

Related

How do you do large number math in QtQuick Qml using JavaScript

I want to calculate the circumstance of the Sun around the Galaxy; the Math Formula is ((241828072282107.5071453596951 * 666) * 2) * 3.14159265359, using QML JavaScript I get the answer 1011954093357316100, when the correct answer is 1011954093357316200, a 100 miles off.
galaxyRadius="241828072282107.5071453596951";
currentTrackNumber=666; // Track Number like on a Record
pIe="3.14159265359"; // not the same as Math.PI
I had to use strings because converting these sized numbers to floats truncate the precision, I am converting an old bash script, and it worked fine with bc, not so much Math.
I have tried this:
orbitDist = ((( Number.parseFloat(galaxyRadius).toPrecision(20) * currentTrackNumber) * 2) * Number.parseFloat(pIe).toPrecision(12) );
I get the same results as:
orbitDist = ((( galaxyRadius * currentTrackNumber) * 2) * pIe );
from bash:
echo "$(bc <<< "scale=13;((241828072282107.5071453596951 * 666) * 2) * 3.14159265359")"
Bash is right and JavaScript is wrong by almost a 100 miles, that is crazy, it is freaking me out, how can JavaScript Floating Point Math be so far off, and this is just one example, I have a whole app full of numbers that are close, but not even close enough, a 100 miles off is not acceptable.
I do not want to deal with exponents, I want the value as an Integer, Strings are fine, it is stored in a database as string, I just need the Math to be right.
This is a QtQuick, QML, Felgo App, using Qml and JavaScript, so it will need to run on different platforms. My next thought is C++, or a Math Library that works for this type of project, JavaScript or a QML wrapper Library for C++ would be great, figuring out how make JavaScript not so bad at Floating Point would be better, I found a few JavaScript Libraries for the Web, they do not work without a lot of work under Qml, so I am only interested in what works, and I did a lot of research and did not find what I was looking for.
Because of JavaScript for now just support bignum for integer(BigInt) only. Then I convert it to BigInt before calculate. And tracking the decimal part to re-convert to float.
const galaxyRadius="241828072282107.5071453596951";
const currentTrackNumber=666; // Track Number like on a Record
const pIe="3.14159265359"; // not the same as Math.PI
const orbitDist = ((( galaxyRadius * currentTrackNumber) * 2) * pIe );
console.log(orbitDist)
//// My approad
//Put all number into an array
var arrToMul = [galaxyRadius,currentTrackNumber, 2, pIe]
// Function multiple all item in array with BigInt format
function mulBigInt(arr) {
return arr.reduce(function (acc, e) {
return BigInt(e) * acc;
}, BigInt(1));
};
// Function get length of decimal part
function decLength(str) {
var dec = str.toString().split('.')[1];
return dec ? dec.length : 0;
};
// Function remove point in string to convert float to int
function rmPoint(strNum) {
return strNum.toString().replace('.', "");
};
// Main function
function cal(arr) {
// Get total decimal part length of all number
var pointSize = arr.reduce(function (acc, e) {
return acc + decLength(e);
}, 0);
// convert the all item to int (type string)
var newArr = arr.map(function (e) {
return rmPoint(e);
});
// Add point to reconvert BigInt to float(string actually)
var tmp = mulBigInt(newArr).toString().split('');
tmp.splice(tmp.length - pointSize, 0, '.');
// Return float result with string format
return tmp.join('');
};
const rs = cal(arrToMul)
console.log(rs, 'converted to BigInt:')

How do I find the intersection of two lines in JavaScript, given their functions?

I realize this is more of a math question, but I don't have a math brain. I'm specifically interested in solving this problem in JavaScript, just for this specific case. If someone can do this for me with a simple function, I can generalize the solution myself as needed.
I have two lines on a graph. One is linear, just going straight from (0,0) to (x,x):
// Line 1
var f1 = function(x) {
return x;
};
The other line is curved, and can be drawn like this:
// Line 2
var f2 = function(x) {
var alpha = 0.3;
return (1 - alpha) *
(1.4 *
1.6 ** alpha) *
(x ** -alpha);
};
Given only these functions, can I write a function that gives me the co-ordinates of the point(s) at which these two lines intersect?
I've looked at things like algebra.js, but haven't been able to come up with the solution myself.
Derivating process:
So, for alpha= a= 0.3 we have:
k= (1-alpha) * 1.4 * 1.6**alpha = 1.12839738
x= k ** (1/(1 + alpha)) = 1.09737595
The desired intersection is {x, f(x)} = {1.0974, 1.0974}

when generating normally-distributed random values, what is the most efficient way to define the range?

FYI: random == pseudo-random
A. when generating uniformly-random numbers, I can specify a range, i.e.:
(Math.random()-Math.random())*10+5
//generates numbers between -5 and 15
B. generating a set of random values with a version of Gaussian-esque normal randomness:
//pass in the mean and standard deviation
function randomNorm(mean, stdev) {
return Math.round((Math.random()*2-1)+(Math.random()*2-1)+(Math.random()*2-1))*stdev+mean);
}
//using the following values:
{
mean:400,
standard_deviation:1
//results in a range of 397-403, or +-range of 3
},
{
mean:400,
standard_deviation:10
//results in a range of 372-429, or +-range of 30
},
{
mean:400,
standard_deviation:25
//results in a range of 326-471, or +-range of 75
}
each one gives me a range of approximately standard_deviation*(+-3) (assuming I left the program running longer).
C. I can calculate this range as follows:
assuming I want a range from 300-500, so var total_range = 200;
my mean is 400, my +-range is total_range/2 (var r = 100)
so standard_deviation would be r/3 or in this case 33.333.
This seems to be working, but I have no idea what I'm doing with math so I feel like an idiot, this solution feels kludgy and not totally accurate.
My question:
is there some formula that I'm dancing around that can help me here? my requirements are as follows:
must be able to define a range of numbers accurately.
must be done in JavaScript, as efficiently as possible.
I think maybe I'm close but it's not quite there.
Subtracting two random numbers doesn't give you a normal distribution, it will give you numbers that decline linearly on both sides of zero. See the red diagram in this fiddle:
http://jsfiddle.net/Guffa/tvt5K/
To get a good approximation of normal distribution, add six random numbers together. See the green diagram in the fiddle.
So, to get normally distributed random numbers, use:
((Math.random() + Math.random() + Math.random() + Math.random() + Math.random() + Math.random()) - 3) / 3
This method is based on the central limit theorem, outlined as the second method here: http://en.wikipedia.org/wiki/Normal_distribution#Generating_values_from_normal_distribution
I wanted to have gaussian random numbers between 0 and 1, and after many tests (thanks to #Guffa answer too) I found this to be the best:
function gaussianRand() {
var rand = 0;
for (var i = 0; i < 6; i += 1) {
rand += Math.random();
}
return rand / 6;
}
And as a bonus:
function gaussianRandom(start, end) {
return Math.floor(start + gaussianRand() * (end - start + 1));
}

Gaps in Data on Google Charts Continuous Axis

I have a Google Chart with a continuous date-time X axis. My data comes in short bursts, with long delays between the bursts. I'd like to make the Chart have a non-continuous X axis, but still have the auto-generated timestamps during the samples. Is that possible?
Basically, say I have 3 samples, each which have 300 datapoints, recorded across 10 second intervals, but with hour gaps between them. I'd like to have my chart show the 30 seconds of data at a zoom level where it can be distinguished. Am I stuck?
Edit: Per #jmac's suggestion, here is an example of what the data looks like:
1360096658270, 10.228335
1360096658274, 10.308437
1360096658277, 10.294770
[...]
1360096673968, 9.014943
1360096673969, 8.971434
1360096673970, 9.041739
1360096673971, 9.097484
^^-- 15 seconds
<--- (~10 days)
1360989176509, 9.856928
1360989176513, 9.852907
1360989176517, 9.861740
1360989176523, 9.820416
1360989176527, 9.871401
Method 1: Multiple Charts
This is probably the simplest in concept (though still a hassle).
Summary:
Split data in to groups (eliminate the gaps)
Create a separate chart for each group
Eliminate the vAxis labels for every chart past the first
Create a consistent vAxis min/max value
Use CSS to line the charts up side to side
Details:
If you have a static data set, you can just split it by hand. If it isn't static, then you have to write some javascript to split up your data. I can't really help you here since I don't know how your data works.
As far as setting up the charts, I'll leave that up to you. I don't know how you want them formatted, so again I can't really help you with the current info.
To create a consistent axis value for all charts, you need to use some basic math in a javascript function to assign the same numbers to each vAxis max/min value. Here is a sample:
// Take the Max/Min of all data values in all graphs
var totalMax = 345;
var totalMin = -123;
// Figure out the largest number (positive or negative)
var biggestNumber = Math.max(Math.abs(totalMax),Math.abs(totalMin));
// Round to an exponent of 10 appropriate for the biggest number
var roundingExp = Math.floor(Math.log(biggestNumber) / Math.LN10);
var roundingDec = Math.pow(10,roundingExp);
// Round your max and min to the nearest exponent of 10
var newMax = Math.ceil(totalMax/roundingDec)*roundingDec;
var newMin = Math.floor(totalMin/roundingDec)*roundingDec;
// Determine the range of your values
var range = newMax - newMin;
// Define the number of gridlines (default 5)
var gridlines = 5;
// Determine an appropriate gap between gridlines
var interval = range / (gridlines - 1);
// Round that interval up to the exponent of 10
var newInterval = Math.ceil(interval/roundingDec)*roundingDec;
// Re-round your max and min to the new interval
var finalMax = Math.ceil(totalMax/newInterval)*newInterval;
var finalMin = Math.floor(totalMin/newInterval)*newInterval;
Method 2: Multiple Series
As long as the people viewing your data understand they are different sets, then there's no reason the axis needs to say the exact date/time as long as they can easily figure that out elsewhere.
Summary:
Separate your data in to different series for each 'sequence'
Artificially shorten the gaps between sequences (if they are 15 seconds each, then have a 5 second gap between series, or just start every 15 seconds)
Format each different series with a name labeling when the run started/ended
Details:
Again, you will have to split your data manually or create javascript to do it, but what you want to do is to move each set of numbers in to its own column, like so:
1360096658270, 10.228335, null
1360096658274, 10.308437, null
1360096658277, 10.294770, null
[...]
1360096673968, 9.014943, null
1360096673969, 8.971434, null
1360096673970, 9.041739, null
1360096673971, 9.097484, null
^^-- 15 seconds
<--- (~10 days)
1360989176509, null, 9.856928
1360989176513, null, 9.852907
1360989176517, null, 9.861740
1360989176523, null, 9.820416
1360989176527, null, 9.871401
This will make each series be a different color (and have a different label in the legend/on mouseover), so you can see the difference between runs, but also get a nice tooltip saying "This data was gathered from X to Y" so that if the time the data was taken is important, it's still in there (albeit not on the X axis).
These are the easiest ways.
Method 3: Manually Editing the X-Axis Labels
The third way is the most flexible but also takes the most work. You can create a custom javascript function to manipulate the X-axis labels in SVG. More details on this here by #jeffery_the_wind:
/*
*
* The following 2 functions are a little hacky, they have to be done after calling the "draw" function
* The bubble chart originally displays only numbers along the x and y axes instead of customer or product names
* These 2 functions replace those numbers with the words for the customers and products
*
*/
for ( var i = -2; i < products.length + 1; i ++ ){
$('#customer_product_grid svg text[text-anchor="start"]:contains("'+i+'")').text(function(j,t){
if (t == i){
if (i >= products.length || i < 0){
return " ";
}
return products[i];
}
});
}
for ( var i = -2; i <= customers.length + 3; i ++ ){
$('#customer_product_grid svg text[text-anchor="end"]:contains("'+i+'")').text(function(j,t){
if (i >= customers.length + 1 || i <= 0){
return " ";
}else if (t == i){
return customers[i-1];
}
});
}
Google's documentation on customizing axes describes how to do what you're asking. You can change the type of your column to a string and populate with formatted Date strings.

Math.random() returns value greater than one?

While playing around with random numbers in JavaScript I discovered a surprising bug, presumably in the V8 JavaScript engine in Google Chrome. Consider:
// Generate a random number [1,5].
var rand5 = function() {
return parseInt(Math.random() * 5) + 1;
};
// Return a sample distribution over MAX times.
var testRand5 = function(dist, max) {
if (!dist) { dist = {}; }
if (!max) { max = 5000000; }
for (var i=0; i<max; i++) {
var r = rand5();
dist[r] = (dist[r] || 0) + 1;
}
return dist;
};
Now when I run testRand5() I get the following results (of course, differing slightly with each run, you might need to set "max" to a higher value to reveal the bug):
var d = testRand5();
d = {
1: 1002797,
2: 998803,
3: 999541,
4: 1000851,
5: 998007,
10: 1 // XXX: Math.random() returned 4.5?!
}
Interestingly, I see comparable results in node.js, leading me to believe it's not specific to Chrome. Sometimes there are different or multiple mystery values (7, 9, etc).
Can anyone explain why I might be getting the results I see? I'm guessing it has something to do with using parseInt (instead of Math.floor()) but I'm still not sure why it could happen.
The edge case occurs when you happen to generate a very small number, expressed with an exponent, like this for example 9.546056389808655e-8.
Combined with parseInt, which interprets the argument as a string, hell breaks loose. And as suggested before me, it can be solved using Math.floor.
Try it yourself with this piece of code:
var test = 9.546056389808655e-8;
console.log(test); // prints 9.546056389808655e-8
console.log(parseInt(test)); // prints 9 - oh noes!
console.log(Math.floor(test)) // prints 0 - this is better
Of course, it's a parseInt() gotcha. It converts its argument to a string first, and that can force scientific notation which will cause parseInt to do something like this:
var x = 0.000000004;
(x).toString(); // => "4e-9"
parseInt(x); // => 4
Silly me...
I would suggest changing your random number function to this:
var rand5 = function() {
return(Math.floor(Math.random() * 5) + 1);
};
This will reliably generate an integer value between 1 and 5 inclusive.
You can see your test function in action here: http://jsfiddle.net/jfriend00/FCzjF/.
In this case, parseInt isn't the best choice because it's going to convert your float to a string which can be a number of different formats (including scientific notation) and then try to parse an integer out of it. Much better to just operate on the float directly with Math.floor().

Categories