How/when is this anonymous function invoked? - javascript

I'm new to javascript and I am looking through some Raphael demo code. I'm confused by how this is working...
if (R) {
(function (dx, dy, R, value) {
var color = "hsb(" + [(1 - R / max) * .5, 1, .75] + ")";
...
From what I can see this is declaring an anonymous function which takes 4 arguments. How is this function invoked when this function doesn't have a name??
Demo page.. http://raphaeljs.com/github/dots.html
JS file.. http://raphaeljs.com/github/dots.js

To briefly answer your question it is invoked immediately upon decleration.
You left out an important part, the end of the function definition:
})(leftgutter + X * (j + .5) - 60 - R, Y * (i + .5) - 10, R, data[o]);
What this says is }, which ends the function, then ), which ends the parenthesis that opened with (function. If what remains looks like an argument list, that's because it is.
An illustrative example:
(function(arg){ alert(arg); })("Hi!");

you didn't include enough of the code to tell. looking at the source, this method is executed immediately. ignoring the contents of the function, it looks like this
(function (dx, dy, R, value) {
// ... stuff
dot[0].onmouseover = function () {
if (bg) {
bg.show();
} else {
var clr = Raphael.rgb2hsb(color);
clr.b = .5;
dt.attr("fill", Raphael.hsb2rgb(clr).hex);
}
lbl.show();
};
// more stuff
})(leftgutter + X * (j + .5) - 60 - R, Y * (i + .5) - 10, R, data[o]);
this all happens within a loop, and the variables are referenced in an event handler method. the anonymous method creates a new scope so the values at the time the loop runs are preserved, rather than having every event handler point to the very last value the variable holds.

An anonymous function is created and called on the fly. A simplified version would be
function(a){<some method code>}(x);
In this the value x is passed as a in the function. In your example the function is later being invoked:
(function (dx, dy, R, value) {
var color = "hsb(" + [(1 - R / max) * .5, 1, .75] + ")";
...
})(leftgutter + X * (j + .5) - 60 - R, Y * (i + .5) - 10, R, data[o]);

It’s called 28 lines later:
...
})(leftgutter + X * (j + .5) - 60 - R, Y * (i + .5) - 10, R, data[o]);
so those are the four arguments.
If you don’t give a function a name, the only thing you can do with it is call it right there or pass it to someone else. This is pretty standard if you’re familiar with event listeners:
window.addEventListener("load", function(event) {
document.body.innerHTML = "hello";
}, false);
In this case, it’s used to control the scope of variables, to guarantee that their values are not reused after an iteration of the loop completes. Many libraries wrap the entire script in a function block, solely to create a new scope. (Unlike in other curly brace languages, a { } block alone does not create a new scope.)
(function() {
var foo; // guaranteed to not leak or interfere with someone else's foo
// 6000 lines ...
})();
Read about JavaScript Scope and Closures.

Related

Extracting values for tooltip

This is a continuation from my previous posts on the bubble chart I have been struggling to make. I have achieved my desired effect by adapting Chris Tufts's code:
https://blockbuilder.org/lydiawawa/347e2b0aeed51d7dc56fde40b08e5fcd
However, when I attempt to add tooltip, I'm unable to extract the original value of BMI and Race(In the code, BMI = size and Race = group) This is because .data is calling nodes instead of the original data. Does anyone know how to point the tooltip to grab the right values?
I know that I should define group and size in create_node function such as the following, but I received an unexpected var token error.
function create_nodes(data,node_counter) {
var i = cs.indexOf(data[node_counter].group),
var z = cs.data[node_counter].group,
var s = cs.data[node_counter].size,
r = Math.sqrt((i + 1) / m * -Math.log(Math.random())) * maxRadius,
d = {
cluster: i,
z,
s,
radius: radiusScale(data[node_counter].size)*1.5,
text: data[node_counter].text,
x: Math.cos(i / m * 2 * Math.PI) * 200 + width / 2 + Math.random(),
y: Math.sin(i / m * 2 * Math.PI) * 200 + height / 2 + Math.random()
}
if (!clusters[i] || (r > clusters[i].radius)) clusters[i] = d;
console.log(d);
return d;
};
You can easily create the size property the same way you created the group one:
size: data[node_counter].size,
By the way, you have a syntax error (you're missing the colon) in the group one, which should be:
group: data[node_counter].group,
Here is your updated bl.ocks: https://bl.ocks.org/GerardoFurtado/5802f23a0bd1c4a3f94f95eded56bc97/dc36321d0d4bb7db2a44246f9330f22099276524
PS: as a friendly advice, you don't need that cumbersome function. Just change the data array and pass it directly to the layout.

mystery "rnorm" function terrain generation javascript - what is this doing?

Question: What in the world is this piece of code doing?
Also: Is the way 'w' is being used some sort of existing algorithm? I'm trying to figure out the intent of the function, or at least describe what sorts of numbers it produces.
Context: I'm looking at Martin O'Leary's "Fantasy Map Generation" code - full source here, which in short summary generates fantasy maps on the canvas. There is some insightful explanations of how the higher level process works in a blog post, but this is too low level to get any coverage there. There is a particular function called 'rnorm' that gets used in a couple of places, and I'm lost at how it works. I've included it below, followed by a couple of instances where it comes up for some context. Any help on what this thing is doing would be great!
var rnorm = (function() {
var z2 = null;
function rnorm() {
if (z2 != null) {
var tmp = z2;
z2 = null;
return tmp;
}
var x1 = 0;
var x2 = 0;
var w = 2.0;
while (w >= 1) {
x1 = runif(-1, 1);
x2 = runif(-1, 1);
w = x1 * x1 + x2 * x2;
}
w = Math.sqrt(-2 * Math.log(w) / w);
z2 = x2 * w;
return x1 * w;
}
return rnorm;
})();
runif(), which is called in the code above, is a short function that generates a random number between two given values
function runif(lo, hi) {
return lo + Math.random() * (hi - lo);
}
This code is used to produce random vectors (actually the only place it's used during the generation process) -
function randomVector(scale) {
return [scale * rnorm(), scale * rnorm()];
}
But I think it's doing more than that because the following, when provided a direction of 'randomVector(4),' produces a gradual slope over the entire mesh heightmap: EDIT: no, it actually is having no effect on the gradual slope. That comes from some sneakyness using the fact that one side of the map is 0,0, and the other side of the map is width,height, which creates numbers that gradually increase.
function slope(mesh, direction) {
return mesh.map(function (x) {
return x[0] * direction[0] + x[1] * direction[1];
});
}
Let me know if there's anything else I should be providing. This is my first question here, so I may be a little soft on conventions.
I think it's horrible code. It appears to create a pair of values, z1 and z2, but instead of putting them in a tuple and returning that it returns z1 and on every second call the corresponding z2 value. I have no idea why they'd do such a thing, my only guess would be to avoid allocation of objects and make usage syntactically more convenient.
It should be simplified to
function rnorm() {
var x1 = 0;
var x2 = 0;
var w = 2.0;
while (w >= 1) {
x1 = runif(-1, 1);
x2 = runif(-1, 1);
w = x1 * x1 + x2 * x2;
}
w = Math.sqrt(-2 * Math.log(w) / w);
return [x1 * w, x2 * w];
}
function randomVector(scale) {
var [z1, z2] = rnorm();
return [scale * z1, scale * z2];
}
A modern compiler should be able to avoid array allocation for the returned literal and subsequent destructuring. If it's not, you can do it manually by inlining rnorm in randomVector, especially if this is the only place where it's called anyway.

Class method is not a function?

I'm getting "Uncaught TypeError: this.time_to_x is not a function" when incorporating some open source ES5 code into my ES6 Class. Here is the class (I've removed some of the bulk, but most of the essential stuff is there). Assume Diamond() is called. It's this line that gets the error: x = this.time_to_x(frame.time);
Why is time_to_x() not being considered a function?
export default class TimelinePanel {
constructor(ctx) {
this.ctx = ctx;
this.ctx_wrap = ctx;
}
create (ctx) {
this.rect({ctx, x: 20, y: 15, width: 130, height: 10}); // ***
this.drawLayerContents();
}
Diamond(frame, y) {
var x, y2;
x = this.time_to_x(frame.time);
y2 = y + LINE_HEIGHT * 0.5 - DIAMOND_SIZE / 2;
var self = this;
var isOver = false;
this.path = function() {
this.ctx_wrap
.beginPath()
.moveTo(x, y2)
.lineTo(x + DIAMOND_SIZE / 2, y2 + DIAMOND_SIZE / 2)
.lineTo(x, y2 + DIAMOND_SIZE)
.lineTo(x - DIAMOND_SIZE / 2, y2 + DIAMOND_SIZE / 2)
.closePath();
};
}
drawLayerContents() {
// ...
for (i = 0; i < il; i++) {
// ...
for (j = 0; j < values.length; j++) {
// Dimonds
frame = values[j];
renderItems.push(new this.Diamond(frame, y));
}
}
}
y_to_track(y) {
if (y - MARKER_TRACK_HEIGHT < 0) return -1;
return (y - MARKER_TRACK_HEIGHT + scrollTop) / LINE_HEIGHT | 0;
}
x_to_time(x) {
var units = time_scale / tickMark3;
return frame_start + ((x - LEFT_GUTTER) / units | 0) / tickMark3;
}
time_to_x(s) {
var ds = s - frame_start;
ds *= time_scale;
ds += LEFT_GUTTER;
return ds;
}
}
You are creating an instance of this.Diamond class when you do new this.Diamond(frame, y). As a result, inside the function, this is this new instance, not the instance of TimelinePanel where it has originally been created from. Hence, this does not have the members of TimelinePanel.
Because it seems y_to_track and x_to_time does not make use of this, you could make them static (add the keyword static before them) and call them as follow: TimelinePanel.y_to_track.
If you need to access methods bound to a particular instance of TimelinePanel, then I don't see any other solution than passing this instance to the Diamond constructor or refactoring TimelinePanel and use closure around the Diamond constructor.
In any case it seems you are trying to replicate the behavior of Java-like internal classes (e.g. where you can access the container class instance with ClassName.this or just access the container class members), there is no such things in JS (at least with class).
EDIT: I just noticed that you are accessing TimelinePanel's ctx_wrap member that you will not be able to put as class member. The easiest seem to pass the TimelinePanel to the Diamond constructor: Diamond(frame, y, panel) and new this.Diamond(frame, y, this). It puts into question the usefulness of adding Diamond as a member of TimelinePanel.
Because the way you have it it's supposed time_to_x from closure, not from this. In this there is no such function, so this.time_to_x name returns undefined which is not a function indeed.
I suggest smth like this:
put var self = this; inside the class but outside of the Diamond method.
Then call self.time_to_x() inside Diamond.

How to lerp back and forth between two values X,Y in a loop?

Using setInterval or RequestAnimationFrame, I'd like to get the progression value from lerping between X and Y. Assuming that X is 0 and Y is 1, I want to have 0 when it starts, 0.5 in the half, and 1 when finished.
I'd like this to happen in a given timeframe, let's say 5 seconds. Meaning that the half value 0.5 would happen when the setInterval/RequestAnimationFrame reaches 2.5seconds.
Finally, I'd like it to pingPong, so when it reaches the 5 seconds the values are decreasing and not increasing, such as 0.9, 0.8, 0.7, etc and then start again from 0, 0.1, 0.2...
Here is my code so far:
/*
function lerp(start, end, time) {
return start * (1.0 - time) + end * time;
}
*/
function lerp (start, end, amt){
return (1-amt)*start+amt*end;
}
function repeat(t, len) {
console.log('t: ' + t + ', len: ' + len);
return t - Math.floor(t / len) * len;
}
function pingPong(t, len) {
t = repeat(t, len * 2);
return len - Math.abs(t-len);
}
var transitionDuration = 1;
var startTime = Date.now()/1000;
var startPos = 0;
var endPos = 1;
setInterval(function () {
var currentTime = Date.now()/1000;
console.log('currentTime:', currentTime);
var adjustedTime = pingPong(currentTime-startTime, transitionDuration);
var x = lerp(startPos, endPos, adjustedTime);
console.log(Math.abs(x.toFixed(2)));
}, 100);
How can I do this?
The basic formula for linear interpolation would be something like
InterpolatedValue = X*t + Y*(1-t)
where X and Y are the values to be interpolated between and t is a parameter between 0 and 1 determining the degree of interpolation; 0 yields X and 1 yields Y. Furthermore, you would like to have some periodic movement with a period length of 5, alternating the direction of interpolation; this can be achieved as follows. If t is a nonnegative number growing over time, calculate
t' = t - t / 10
to remove all previous periods which have occured and
t'' = t' : t' in [0,5)
5 - t' : t' in [5,10)
and afterwards set
t''' = t' / 5
to normalize the parameter into [0,1] and use the basic interpolation formula from the beginning.
Note that linear interpolation and various other methods are collected here.
From your description, at any given frame there are 6 pieces of state:
Start time of current lerp
Lerp timespan
Current direction
Current time
Start value
End value
From these you can calculate the required progress value, say:
function progressValue(startTime, lerpSpanSeconds, dir,
currentTime X, Y, dir, currentTime) {
// lerp
return 0.42;
}
For requestAnimationFrame, you need a simple callback to pass in. That is, the function has to know everything it needs except what it can acquire when it runs. Here, when it runs it just needs to get the current time and work the rest out from there.
function animableThing() {
var startTime = 7;
var lerpSpanSeconds = 3;
var dir = +1;
var X = 0;
var Y = 1;
var currentTime = GetCurrentUnicornTime();
var thingToAnimate = document.getElementById('myAnimableElement');
var progress = progressValue(startTime, lerpSpanSeconds, dir,
currentTime, X, Y, dir, currentTime);
// reverse when we hit the end
if(progress > Y) {
dir *= -1;
startTime = currentTime;
progress = Y;
}
DrawAnimationThing(thingToAnimate, progress);
// continue the animation
window.requestAnimationFrame(animableThing);
}
But there's a problem; if you want to be able to set up the animation using values from the script or inputs from the screen, or up-to-date information about the elements on the screen, then you need to be able to make an animableThing callback fresh when you have new values. Behold, the mother:
function MotherOfAnimableThings(startTime, lerpSpanSeconds, dir, X, Y,
thingToAnimate)
{
// Passed in variables have scope outside the animableThing, these
// will be private to the animableThing function.
// Consider defaulting or validation here
// Construct a new function freshly each time the Mother is called,
// and return it to the caller. Note that we assign a variable here
// so that we can re-call RequestAnimationFrame to continue the loop
var callback = (function() {
var currentTime = GetCurrentUnicornTime();
var progress = progressValue(startTime, lerpSpanSeconds, dir,
currentTime, X, Y, dir, currentTime);
// reverse when we hit the end
if(progress > Y) {
dir *= -1;
startTime = currentTime;
progress = Y;
}
DrawAnimationThing(thingToAnimate, progress);
window.requestAnimationFrame(callback);
});
return callback;
}
We could go further, and make this general for other types of thing by letting the caller pass in a progressValue function to call, or in fact a callback, so that you could take any element, Draw function and setup function and make a thing that animates, but this is a reasonable starting point.
With the above, we just need to call Mother to create an animableThing function and call RequestAnimationFrame with that. From then on, it calls RequestAnimationFrame internally to continue the cycle.
Now, having done that, you will want to make it stop, so add in a variable in the callback which it can check, so that you can do
var animableThing = MotherOfAnimableThings(...);
window.requestAnimationFrame(animableThing);
// ... later
animableThing.stop = true; // it should stop on the next frame

Alter the Math functions in Javascript

I am trying to "alter" the sin cos and tan function from Math object so it can accept recognize if it is a degree "d" or radians. I have an idea on how to do it but I do not know to do it without changing my main function
(function() {
var angle;
while (angle = parseFloat(readline())) {
print(Math.sin(angle, "d").toPrecision(5)); // degrees
print(Math.sin(angle).toPrecision(5)); // radians
print(Math.cos(angle, "d").toPrecision(5));
print(Math.cos(angle).toPrecision(5));
print(Math.tan(angle, "d").toPrecision(5));
print(Math.tan(angle).toPrecision(5));
}
})();
How do alter does function so they can accept the "d" argument I tried use Object.create and another things like JSON.parse(JSON.stringify(Math)); but it doesn't work I need to know how to deep copy Math
You can override Math (in a closure) with an object which inherits from Math:
(function(globalMath) {
// Overriding Math:
var Math = Object.create(globalMath);
// Enhancing trigonometric methods:
var trig = ['sin', 'cos', 'tan'];
for(var i=0; i<3; ++i)
Math[trig[i]] = (function(trigFunc){
return function(angle, d) {
if(d==="d") angle *= Math.PI / 180;
return trigFunc(angle);
};
})(globalMath[trig[i]]);
// Now you can use the enhanced methods:
Math.sin(Math.PI/6); // 0.5
Math.sin(30, 'd'); // 0.5
// You can also use original methods:
globalMath.sin(Math.PI/6); // 0.5
globalMath.sin(Math.PI/6, 'd'); // 0.5 ('d' is ignored)
// Math is a shortcut of globalMath for other methods:
Math.max(1,2); // 2
})(Math);
Everything's an Object in JavaScript, so you can re-write the native Math functions. But this is not recommended, as other commentators have said.
It's simpler to create your own function that converts to degrees internally, like this:
function sinDegrees(angle) {
return Math.sin(angle * (Math.PI / 180));
}
It could even be part of the Math object, if you want:
Math.sinDegrees = sinDegrees;
If you still want to modify the Math.sin function like that, then you can do this:
Math._sin = Math.sin; // save a ref. to the old sin
Math.sin = function sin(angle, type) {
if (type == 'd')
return Math._sin(angle * (Math.PI / 180));
else
return Math._sin(angle);
}
The better solution here is to have a toRad function. It looks very similar to your target code without breaking basic good practices (don't modify objects you didn't create).
function toRad(angle){
return angle * (Math.PI / 180);
}
print(Math.sin(toRad(angle)).toPrecision(5)); // degrees
print(Math.sin(angle).toPrecision(5)); // radians
print(Math.cos(toRad(angle)).toPrecision(5));
print(Math.cos(angle).toPrecision(5));
print(Math.tan(toRad(angle)).toPrecision(5));
print(Math.tan(angle).toPrecision(5));
This also saves you from defining custom versions of each function.

Categories