What is this Javascript function parameter doing? - javascript

Consider the following code (shortened for clarity):
Vertices.chamfer = function(vertices, radius, quality, qualityMin, qualityMax) {
radius = radius || [8];
if (!radius.length)
radius = [radius];
};
I'm reading the first part as (pseudocode):
if (radius array passed to function) then
radius = radius
else
radius = [8] // new array, single element of value 8
end if
but I don't get the second expression (the if(!radius.length) radius = [radius] part).
Could someone explain it to me?

Vertices.chamfer = function(vertices, radius, quality, qualityMin, qualityMax) {
// Set the radius to the value passed in.
// If the value passed in is undefined, set the radius to an
// array containing 8 (the "default")
radius = radius || [8];
// If radius isn't an array (i.e. length is 0 which evaluates to false),
// make it an array.
if (!radius.length)
radius = [radius];
};

The concept used here is known as duck typing - i.e. checking the type of a variable by looking for the presence (or absence) of some characteristic properties/methods. Author of this code assumed that if something has a length property it is an Array, and if not it can be converted to an Array by wrapping it in [].
The second part, converting x to a single-item Array containing x using x = [x] is totally OK.
The problem is there are other types in JavaScript that have a length so this test is not really reliable.
For example: "7".length returns 1, so if you passed the variable as a string instead of a number (easy enough to make this mistake for example by reading values from <input> fields) something would break down the line expecting an Array but getting a String.
Another type that has a length is a Function: (function(a,b){}).length == 2.
So yeah, this is not really good test but the basic idea makes sense. Should have used either Array.isArray or some other property/method that is unique to Arrays.
EDIT: I'd also point out the radius = radius || [8] construct is only OK if 0 is not allowed as the radius argument.

I'm reading the first part as (pseudocode):
if (radius array passed to function) then
radius = radius || [8] checks to see if radius is falsy, which might be not passed in at all (undefined), or passed in as undefined, or passed in as null, 0, "", NaN, or of course false.
But yes, it's probably intended to use [8] if no radius was specified.
but I don't get the second expression (the if(!radius.length) radius = [radius] part).
If radius was given but is either A) An array with no entries (radius.length is 0 and therefore falsy), or B) Not an array (radius.length is undefined and therefore falsy), we create an array and make it the first entry in that array.
That's not at all robust validation, lots of things have length (strings, for instance), but that's probably what it's meant to do.
The robust way to check if something is an array is to use Array.isArray, which was added in ES5 and which can be reliably shimmed/polyfilled for obsolete engines (like the one in IE8).

if imported radius is not an array and it has value, then it returns an array with the radius value inside.
if imported radius is empty then it returns an array with the number 8 inside: [8]
However, inside the pseudocode, it is not gonna get in if statement, if the imported radius is not an array.

Related

Javascript find intersections given two functions

I am trying today to solve for the coordinates where functions intersect. I am using the nerdarmer library right now, but it only returns only one solution out of all the possible solutions. For example, I want the code below to print -1, 0, 1 but it only outputs 0. Another example is if I want to find intersections between y = 0 and sin(x), I want the output to be ..., (-2pi, 0), (-pi, 0), (pi, 0), (2pi, 0), (3pi, 0), ...
intersect("x^3", "x")
function intersect(f1, f2){
var x = nerdamer.solve('f1', 'f2');
console.log(x.toString());
}
Is there any way to get all the possible solutions?
You've misunderstood the syntax of nerdamer.solve
The first argument is the formula or equation.
The second argument is the variable to solve for.
If the first argument is not an equation, it is assumed to be equal 0.
In your case x^3=0. which only has the solution 0.
If you want to intersect the equations you will need to set them equal to each other in the first argument. And in the second argument just specify x. (or change it to suit your needs if required).
intersect("x^3", "x")
function intersect(f1, f2){
var x = nerdamer.solve(f1+"="+f2, "x");
console.log(x.toString()); //outputs [0,1,-1]
}
Edit:
In your example you also directly put the strings "f1" and "f2" into the solve function which seems to just solve f=0;

Change pixel value in OpenCV.js

According to OpenCV.js docs to modify a pixel value you can use 3 methods:
Direct data manipulation
at() family of methods
ptr() family of methods
Althougth the header of the section in the docs say "Accessing and Modifying pixel values" it provides examples for retrieving a value but not for modifying them. The problem is that while in C++ this code using the at or ptr methods works:
mat.at<type>(row, col) = value;
The equivalent in javascript is not valid and gives an Invalid left hand side in assignment expression:
mat.floatAt(row, col)) = value;
I could make it work using the direct data manipulation method with:
mat.data[row * this.cols * this.channels() + col * this.channels()] = value;
But this method does not operate in pixel values but in the underlaying array data structure where a pixel may span more than one array index, so is not valid for my use case.
How can a pixel value at [row, col] position in a CvMat be modified using OpenCV.js?
I have been successful in setting single pixels of images (or matrices) with ucharPtr.
Instead of setting it like this:
img.ucharPtr(i, j) = 255
I set it like this:
img.ucharPtr(i, j)[0] = 255
Even if the image is black and white and only has one channel
If you want to set all 4 pixel values, you can do this:
src.ucharPtr(i, j)[0] = 255
src.ucharPtr(i, j)[1] = 255
src.ucharPtr(i, j)[2] = 255
src.ucharPtr(i, j)[3] = 0

Get computed histogram bin thresholds

I have correctly applied the d3 (v 4.0) histogram function to bin an array of data. My code looks like this:
var bins = d3.histogram()
.domain([data_points_min, data_points_max])
.thresholds(8)
(data_points);
Is there a function to retrieve the bin thresholds? I guess I could loop through the array and identify the max in each bin, but that would be tedious. Am guessing there must be a function, including one that produces bin thresholds that are 'pleasing to the human eye' and not some ghastly decimal number.
Pseudo code would be something like this:
var bin_thresholds = bin.thresholds();
There is no method (as far as I know) for returning the lower and upper limits for each bin. There is one method for returning the number of bins...
d3.thresholdSturges(values);
... which is clearly not what you want, specially because you're setting the number of bins already.
However, you don't need to "loop through the array and identify the max in each bin". The histogram generator generates two properties:
x0 - the lower bound of the bin (inclusive).
x1 - the upper bound of the bin (exclusive, except for the last bin).
So, you can loop through the result to get those properties only. For instance:
var data = d3.range(1000).map(() => Math.random() * 20);
var bins = d3.histogram()
.thresholds(8)(data)
bins.forEach(function(d, i) {
console.log("Array number " + i + " --> Lower limit: " + d.x0 + " Upper limit:" + d.x1)
})
<script src="https://d3js.org/d3.v5.min.js"></script>
PS: you don't need to set the domain, since you're just passing the min and max value of the array, which is the default domain:
If domain is specified, sets the domain accessor to the specified function or array and returns this histogram generator. If domain is not specified, returns the current domain accessor, which defaults to extent. (emphasis mine)

Heavily packed javascript, multiple questions from 219-byte (canvas, bitwise,...)

I came across a website today. It was a challenge of some developers about making the smallest game possible with certain requirements, and they released the final code of unbelievable size of 219 bytes and runnable on Chrome 17 (one of the requirements). I tried to explore the code (with the explanation provided from the site) and do researches on codes I didn't comprehend. However, the code was packed too heavily to my knowledge, so I am seeking for some helps.
Here is the code, after beautified:
<body id=b onkeyup=e=event onload=
z=c.getContext('2d');
z.fillRect(s=0,0,n=150,x=11325);
setInterval("
0<x%n
&x<n*n
&(z[x+=[1,-n,-1,n][e.which&3]]^=1)?
z.clearRect(x%n,x/n,1,1,s++)
:b.innerHTML='GameOver:'+s
",9)>
<canvas id=c>
The game is named "Tron", and just like classic snake game (without apple).
Anyway, here are my questions:
1) How can they select element with id 'c' without using getElementById() rather than a simple c
Look at the bottom of the code, there is a canvas with <canvas id=c>. I understand that advanced browsers will automatically fix the quotes "" for the id="c". However, when a function is called in onload event, it assigns z = c.getContent('2d'); and directly refers to the canvas without even applying anything such as document.getElementById(). Also the same when they referred to <body id=b>. How is that possible? Under which circumstances am I able to do similarly?
2) Will replacing parameters of a functions by quick assigning variables affect the function at all? If it does, how will it be calculated?
Particularly, take a look of the third line:
z.fillRect(s = 0, 0, n = 150, x = 11325);
I understand to the most basic level, fillRect() requires 4 parameters fillRect(x-cor, y-cor, width, height). However, the code above produces a rectangle 150x150. First of all, I read the description and they claimed that by default, the code would produce a rectangle 300x150, so I assumed that the assigning short functions would actually assign nothing to the parameters of the parent function. I did a test, and replaced n = 150 by n = 200. Weirdly enough, it produces a rectangle 200x150, so once again I agree that n = 150 did assign 150 to that slot. Hence, the code above can be written as:
z.fillRect(0, 0, 150, 11325);
However, another problem comes. Why isn't its height 11325px but 150px instead? I thought it was reset to default because 11325 excessed the handling of browsers, so I changed it to 500 instead; and it produced the same problem.
So generally, when you do short assigning inside a function (for instance: someCustomFunction.call(s = 1)), what really happens there? If nothing happens, why did the rectangle in the example above changed its size when replacing n = 200 but not when x = 200?
Additional question: this question is not the question I am really into, because it is too personal, but I would love to know. The source states that "x is going to be the tron's position, and is set to 11325 (11325 = 75 x 75 + 75 = center of the grid)", how does this kind of one-number-represents-position work?
3) What in the world does it mean?
This is the most headache part to me, because the author packed it too smartly.
&(z[x+=[1,-n,-1,n][e.which&3]]^=1)?
I broke it up, and figured that it was actually z[]^=1 in order to check the condition for the later ? : operators. But first:
What does ^=1 do?
Some people commented on the project and said it could be replaced by --. I think of it as a bitwise AND operator, but what does it have to do with --?
And next:
How did they use [e.which&3] together with the preset array to filter keystroke "i", "j", "k", "l" too effectively?
I notice the array has the length of 4, which is the length of the keys needs filtering. Also, pressing another key rather than "i", "j", "k", "l" also works. It leads me to believe that the &3 does something in filtering the 4 keys, but I don't know how.
Those are all I have to ask. The short but complicated code really excites me, and I really appreciate any help in understanding the code further.
Sidenote: I didn't actually look at the website, so if I'm covering anything they already have, I'm sorry. I realised there was a link to it halfway through my post.
Here is the code, unminified, with some adjustments.
HTML:
<body id=b>
<canvas id=c></canvas>
</body>
Javascript:
document.body.onkeyup = handleOnKeyUp;
document.body.onload = handleOnLoad;
function handleOnKeyUp(event) {
e = event;
}
function handleOnLoad(event) {
score = 0, n = 150, x = 11325;
context = c.getContext('2d');
context.fillRect(0, 0, n, n);
end = setInterval(function () {
if (typeof e === "undefined") return; // This isn't part of the original code - removes errors before you press a button
// Map key that was pressed to a "direction"
// l(76) i (73) j(74) k(75).
// If you AND those values with 3, you'd get
// l(0), i(1), j(2), k(3)
var oneDimDirs = [1, -n, -1, n];
var dirChoice = oneDimDirs[e.which & 3];
// Now add the chosen "direction" to our position
x += dirChoice;
if (x % n <= 0 || n * n <= x || // out of bounds
!(context[x] ^= 1) // already passed through here
) {
b.innerHTML = "GameOver:" + score;
clearInterval(end);
}
else {
score++;
context.clearRect(x % n,x / n, 1 , 1)
}
}, 9);
}
Generally, the code makes heavy use of a couple of hacks:
It makes heavy use of global variables and the fact that assigning to an undefined variable creates a global.
It also makes use of irrelevant function parameters to set or modify variables(this shortens the code length)
The code uses a one-dimensional representation of a two-dimensional space. Instead of moving you in two directions, x and y, it "flattens" the representation of the two-dimensional space(the gameboard) into a one-dimensional array. x represents your position on the overall game board. If you add 1 to x, you will move along the current "line"(until you get to its end). Adding n moves you a whole line forward, so it's similar to moving once down.
Your questions, one by one:
1) How can they select element with id 'c' without using getElementById() rather than a simple c
Kooilnc's answer already covers this. This is called "named access":
http://www.whatwg.org/specs/web-apps/current-work/#named-access-on-the-window-object
2) Will replacing parameters of a functions by quick assigning variables affect the function at all? If it does, how will it be calculated?
You misunderstood what is happening here. First, functions accept values as their parameters, and expressions produce values when they are evaluated. An assignment expression, n = 150, produces the value 150 when evaluated. As a side effect, it also assigns that value to the variable n. So calling a function func(n = 150) is almost equivalent to func(150), with the exception of that side effect. That side effect is used in the code to save space, instead of having to assign the variables on separate lines.
Now, for the canvas WTF - As far as I can tell, a canvas element's default width and height happen to be 300px and 150px. You cannot draw past those limits, so trying to execute z.fillRect(0, 0, 150, 11325); will not draw past the 150 height limit. The code authors use the fact that 11325 is bigger than 150 and is thus safe to pass as a parameter(the rectangle will still be drawn as 150x150). 11325 happens to be the one-dimensional coordinate of the starting position.
3) What in the world does it mean?
I hope I mostly answered it within the code. The inner part is unpacked and commented, which only leaves this part unexplained:
context[x] ^= 1.
(Note, ^ === XOR)
The idea is that the authors are using the context as an array to store which positions they've already visited. There are three reasons for doing it this way:
One, they want to assign some value to mark that they've passed through here. context[x] is usually undefined, undefined ^ 1 === 1, so they're assigning ones to the positions they pass through.
Next, they want to be able to check if they've passed through there. Coincidentally, 1 ^ 1 === 0, which makes it easy to check. Note what I mentioned about assignment expressions - the value of this assignment expression will be either 1, if the position has not been visited before, or 0, if it has. This allows the authors to use it as a check.
Since the check they use is something like expr & expr & expr, expressions which yield true/false or 1/0 values will work the same way as if it was expr && expr && expr(true and false are converted to the numbers 1 and 0 when used in &)
How did they use [e.which&3] together with the preset array to filter keystroke "i", "j", "k", "l" too effectively?
I hope I answered this sufficiently with comments in the code. Basically, using the onkeyup handler, they store the event which has the key that was pressed. On the next interval tick, they check e.which to determine which direction to go in.
About
1) How can they select element with id 'c' without using getElementById() rather than a simple c
In most browsers you can access an element using its ID as a variable in the global namespace (i.e. window). In other words, to retrieve <div id="c"> you can also use c, or window.c.
See also
The other questions I leave to smarter people ;)
1) How can they select element with id 'c' without using getElementById() rather than a simple c
I believe it was an old version of IE that originally allowed access of DOM elements in JS directly by their id, but a number of other browsers followed for compatibility with websites that rely on this. In general it's not a great thing because you can get weird bugs if you create variables with the same names as the element ids (not that that matters for this example).
2) Will replacing parameters of a functions by quick assigning variables affect the function at all? If it does, how will it be calculated?
You said within your point (2) that z.fillRect(s = 0, 0, n = 150, x = 11325); can be written instead as z.fillRect(0, 0, 150, 11325);, but that is true only in as far as having the function call to fillRect() work the same way. This change would break the overall program because the assignment statements are needed to create and set the n and x global variables.
In a general sense in JS the assignment operator = not only assigns the value from the right-hand operand to the variable on the left, but the whole expression gives the value of the right-hand operand. So someFunc(x = 10) sets the variable x to 10 and passes the value 10 to someFunc().
In the case of that fillRect(), the n and x variables have not previously been declared, so assigning a value to them creates them as globals.
3) What in the world does it mean? &(z[x+=[1,-n,-1,n][e.which&3]]^=1)?
Well, it's (obviously) kind of complicated. To answer the specific questions you mentioned about parts of it:
How did they use [e.which&3] together with the preset array to filter keystroke "i", "j", "k", "l" too effectively?
The keys "i", "j", "k", and "l" are a good choice for up/left/down/right controls in a game because their physical layout on a standard keyboard corresponds to up/left/down/right but also because those letters belong next to each other in the alphabet so they have contiguous keycodes too: 73, 74, 75, 76. So when you take those keycodes and do a bitwise AND with &3 you get the values 1, 2, 3, 0 which then act as appropriate indices into the [1,-n,-1,n] array.
What does ^=1 do? ... I think of it as a bitwise AND operator ...
It's not a bitwise AND operator. ^ is a bitwise XOR, and ^= is the bitwise XOR assignment operator. That is, x ^= 1 is equivalent to x = x ^ 1.

Linearly scaling a number in a certain range to a new range

I've made a scaling function that takes numbers in an interval [oldMin,oldMax] and scales them linearly to the range [newMin,newMax] . It does not seem to work when using negative values.
function linearScaling(oldMin, oldMax, newMin, newMax, oldValue){
var newValue;
if(oldMin !== oldMax && newMin !== newMax){
newValue = parseFloat((((oldValue - oldMin) * (newMax - newMin)) / (oldMax - oldMin)) + newMin);
newValue = newValue.toFixed(2);
}
else{
newValue = error;
}
return newValue;
}
This function seems to work when scaling a value from 0 -> 32761 to the range range 0 -> 10. However it does not seem to give the correct output when given a new negative range i.e. -10 -> 10
I have done my best to find an answer on this site. However the person who asked the question didn't mention what he ended up doing to fix it. That question says it could have something to do with mixed up data types, but i converted everything to a float did I miss anything?
Now that you showed how you call your function, I can reproduce your problem - namely that quoted numbers that should map to the negative domain don't.
It seems to be due to the fact that Javascript is very loose about the difference between a number and a string - and if it's not sure what to do about two numbers (because one of them appears to be a string), it assumes you want concatenation rather than addition. In other words - by passing the newMin value as '-10' rather than -10 you confused JS.
As a simple example,
document.write('1' + '-2');
produces
1-2
However,
document.write(1*'1' + 1*'-2');
results in
-1
The expression you had included a "possible concatenation" where it added oldMin:
newValue = (((oldValue - oldMin) * (newMax - newMin)) / (oldMax - oldMin)) + newMin;
With newMin set to '-10', you might get newValue to look like 6-10 instead of -4, to give an example. When you then did a parseFloat, Javascript would quietly work its way through the string up to the minus sign, and return 6 instead of evaluating the expression and coming up with -4.
To clear up the confusion, multiply each parameter by 1 to make it "a genuine number":
oldMin = 1*oldMin;
oldMax = 1*oldMax;
newMin = 1*newMin;
newMax = 1*newMax;
oldValue = 1*oldValue;
When you add these lines at the start of your function declaration, everything works smoothly - regardless of how you call the function. Or just call it with the newMin value not in quotes - it is the one causing the trouble in this particular instance.
document.writeln('the new code called with parameter = 100:\n');
document.writeln(linearScaling('0', '32761', '-10', '10', 100)+'<br>');
document.writeln('the old code called with parameter = 100:\n');
document.writeln(linearScalingOld('0.0', '32761.0', '-10.0', '10.0', '100.0')+'<br>');
document.writeln('the old code called with unquoted parameters:\n');
document.writeln(linearScalingOld(0.0, 32761.0, -10.0, 10.0, 100.0)+'<br>');
results in the following:
the new code called with parameter = 100: -9.94
the old code called with parameter = 100: 0.06
the old code called with unquoted parameters: -9.94
I hope this illustrates the cause of the problem, and the solution.

Categories

Resources