Trouble with setTimeout in javascript for MaxMSP - javascript

I've already looked at quite a few other questions but I can't seem to fix this issue with setTimeout
So I've been working on this and came to this, but for some reason the setTimeout does not work, any tips?
function curves(val_name, mini, maxi, t_amount, steps) {
//t_amount MUST be in ms
for (x = 0; x < steps; x++) {
var x_mod = scale(x, -6, 0, 0, steps);
var value = setTimeout(calculate_curve, (t_amount / steps), x_mod);
switch (val_name) {
case "vol_stretch1":
var vol_stretch1 = this.patcher.getnamed("stretching").subpatcher(0).getnamed("vol_stretch1");
vol_stretch1 = value
break;
case "vol_stretch2":
var vol_stretch2 = this.patcher.getnamed("stretching").subpatcher(0).getnamed("vol_stretch2");
vol_stretch2 = value
break;
case "vol_stretch3":
var vol_stretch3 = this.patcher.getnamed("stretching").subpatcher(0).getnamed("vol_stretch3");
vol_stretch3 = value
break;
}
}
}
function calculate_curve(x) {
var constant_e = 2.718281828459;
var result = (1 / 1 + (constant_e ^ (x * -1))) * -1; //sigmoid function * -1 to have the nice rise
}
function scale(unscaledNum, minAllowed, maxAllowed, minimum, maximum) {
return (maxAllowed - minAllowed) * (unscaledNum - minimum) / (maximum - minimum) + minAllowed;
}
You can ignore the switch as it works with an extension for MaxMSP but isn't very important here. The error I get back is "Javascript ReferenceError: setTimeout is not defined". Any help is greatly appreciated!

I've not worked with Max before, but from a small amount of searching it looks like you're writing something along the lines of a plugin.
It looks like Max is running it's own Javascript environment of some sort. setTimeout is a method on the window object of browsers in Javascript, and as such it is not necessarily implemented in Javascript outside of the browser, as Max appears to be.
The recommended alternative seems to be to use the Task object exposed by the environment, which has some documentation here:
https://docs.cycling74.com/max5/vignettes/js/jstaskobject.html
I have no way of testing this, but from the documentation it looks like something along the lines of the below should work:
var task = new Task(function() {
calculate_curve(x_mod);
}, this);
task.schedule((t_amount / steps));

Related

Javascript | Parsing error: unexpected token if

Before reading below, do note that I have only recently started learning Javascript.
I am interested in making a text-based survival game. When trying to subtract a random number of survivors from the whole, I attempted to write what I think is, "A raid happens if the number is 0.50 - 1.00, and if the raid is successful, the group loses a random number of survivors between 1, and however many survivors there are." However, when I write this, I get an ESLint error, stating: ERROR: Parsing error: Unexpected Token if I don't know how I would rewrite it, or how to reformat it to work, if it is at all possible. The issue is in the code below, on lines 10, 11, & 12.
//constants
var EVENT_CHANCE = 0.15;
var EVENT_TYPE = 0.50;
var FOOD_CONSUMPTION = FOOD_CONSUMPTION;
var MATERIALS_CONSUMPTION = 1;
var ENEMY_STRENGTH = 10;
var SURVIVOR_STRENGTH = 1;
//equations
this.FOOD_CONSUMPTION = (this.food - this.surviors);
this.raid = if ( EVENT_TYPE > 0.50);{
this.survivors - Math.floor((Math.random() * this.surviors) + 1);
};
Let me know if I left anything important out
Note: I copied this post from the game development stack exchange, because they had advised me it is more of a stack overflow question, as it relates more to JS as a whole, than game development.
You have a semicolon after the condition
To conditionally assign a variable you need to use the ternary operator, for example:
const thing = condition ? ifTrue : ifFalse;
Or for your code:
this.raid = EVENT_TYPE > 0.50 ?
this.survivors - Math.floor((Math.random() * this.surviors) + 1) :
null;
//replace the null with what you want the variable to be if the condition is false
You can't use a statement as the right-hand side of an assignment, which is what you're trying to do here:
this.raid = if ( EVENT_TYPE > 0.50);{
this.survivors - Math.floor((Math.random() * this.surviors) + 1);
};
If you want to set this.raid to the result of EVENT_TYPE > 0.50, you just do that directly:
this.raid = EVENT_TYPE > 0.50;
If you then want to use that in a branch, you can follow it with the if testing this.raid:
this.raid = EVENT_TYPE > 0.50;
if (this.raid) {
this.survivors - Math.floor((Math.random() * this.survivors) + 1);
}
(I also fixed a typo in that, the second survivors was missing a v. But there's still a problem I didn't know how to fix: It calculates a value without storing it anywhere. It's not an error in JavaScript, but it probably isn't what you wanted. You may have meant -= instead of -.)
Note that neither of the ; that were originally in that if belonged there. You don't put ; after the () in an if, and you don't put a ; after the block attached to a flow-control statement (if, while, etc.).

How to convert String into Math Function just once?

I want to build something similar to desmos, where you can draw a graph in a canvas and then move it around.
I've been successful so far, but the only thing left is the user input.
Using a <input type="text"> tag I want the user to write for example:
"5x + 2"
The result should be:
var f = 5*x + 2;
I searched a lot for a way to do this and the only things I found were some Maths libraries in JavaScript and the eval() function. The last one is really helpful, because I could replace the x with the x value in the graph and it would work to build the graph of the function. The problem is that it lags a lot when I want to move the graph around so it is not the best idea.
I'm sure that it lags because the eval() function has to convert the string each time for every x value of the canvas for about 40-50 times a second.
What I want to achieve is convert the string into a Math function just once, and then use it.
Is it possible? Can anyone please help
EDIT 1:
This is my function:
function f (pixelX) {
var x = getCoordX (pixelX);
var f = 2 * x + 2;
return getPixelY(f);
}
To answer your question (even though this won't solve your problem).
You can do this.
var myString = "5 * x + 2";
var f = Function("x", "return " + myString);
This creates a function from a string. The first argument is the name of the first parameter, x, and the second argument is the body of the function (the return statement);
And then you can call it like:
f(3) and the result would be 17.
Note that you have to write multiplication in your equation like 5 * x not like 5x.
This way you only evaluate the string into a function once, and then you can call it as many times you want with different parameters.
Your problem is not that eval takes a long time to compute but that re-drawing the canvas is very expensive. Try limiting the number of draws or only calling the draw function inside a requestAnimationFrame callback, this way the browser will redraw the canvas only when it is ready to do it.
You can use eval, but it may behave differently on each browser's JavaScript engine.
This is an easy find-and-replace:
function solveForX(equation, xValue) {
var expanded = equation.replace(/(\d+(?:\.\d+|))x/g, '$1 * x');
return eval(expanded.replace(/x/g, xValue));
}
console.log(solveForX("5x + 2", 3)); // 17
console.log(solveForX("-4.2x + 3x", 5)); // -6
.as-console-wrapper { top: 0; max-height: 100% !important; }
Advanced — Multi-variable Expressions
const expFormat = '(\\d+(?:\\.\\d+|)){{#}}';
var expressionCache = {};
function lookupExpansion(v) {
if (!expressionCache[v]) {
expressionCache[v] = new RegExp(expFormat.replace(/\{\{\#\}\}/, v), 'g');
}
return expressionCache[v];
}
function toFunction(equation, variables) {
variables.forEach(variable => {
equation = equation.replace(lookupExpansion(variable), '$1 * ' + variable);
});
equation = equation.replace(/\b([a-z])([a-z])\b/g, '$1 * $2');
console.log('[DEBUG]: Expanded => ' + equation);
return Function.apply(null, variables.concat('return ' + equation));
}
// ======================== Simple ============================== //
var simpleMultiVariableFn = toFunction("x + 4x + 2y", ['x', 'y']);
console.log(simpleMultiVariableFn(3, 5)); // 25
// ======================== Advanced ============================ //
var slopeInterceptFunction = (slope, yIntercept) => {
return x => toFunction("mx + b", ['m', 'x', 'b']).call(null, slope, x, yIntercept);
};
var interceptFn = slopeInterceptFunction(1, 2); // Reusable!
console.log(interceptFn(3)); // 5
console.log(interceptFn(4)); // 6
.as-console-wrapper { top: 0; max-height: 100% !important; }
Works with floats and negative numbers.

Is Javascript multiplying these values wrong?

Allright, I know what machine precision is, but this, I can't understand...
Code:
console.log("meanX",meanX);
meanX2 = meanX * meanX; //squared
console.log("meanX2",meanX2);
Console output:
meanX 300.3
meanX2 28493.4400000000002
In case you are wondering, the correct value for meanX2 would be 90180.09
And this is only one of the many examples visible in the screenshot..
.toFixed(6) seems to fix this... But I have no idea why it doesn't work without it.
Edit
Ok, I don't want to post the whole program code here because in first place I'm not the only author, and second, I also wouldn't like this to be copied without our permission. But I'll gladly explain how I get this error and will post the whole method/function code here.
This code belongs, as you may have guessed from the window title, to a lane detection algorithm. We use Three.js/webgl to run some pre processing shaders on each frame of a video and then we analyze the resulting image. The method/function you see on the screenshot is a perpendicular line fitting algorithm and is part of the whole thing.
I can see the algorithm running nicely because I have the lane being drawn on top of the video, and It is well placed. Until suddenly the lane turns into an horizontal bar. This unexpected behavior happens exactly because of the phenomenon I described here, since it's from that moment that I start to see wrong math in the console.
Also, because the video and algorithm run at slightly different fps everytime, the problem doesn't always happen in the same moment of the video, and sometimes It doesn't happen at all.
Here is the code (it has some alterations because I was trying to isolate the issue):
this.perpendicularLineFit = function (points, slopeSign) {
var count = points.length;
var sumX = 0,
sumY = 0;
var sumX2 = 0,
sumY2 = 0,
sumXY = 0;
var meanX, meanY;
var i, lowp = {}, highp = {};
var B;
var slope;
var originY;
for (i = 0; i < count; i++) {
sumX += points[i].x;
sumY += points[i].y;
sumX2 += points[i].x * points[i].x;
sumY2 += points[i].y * points[i].y;
sumXY += points[i].y * points[i].x;
}
meanX = sumX / count;
meanY = sumY / count;
//If you uncoment this, problem reappears:
//var numeratorLeft = meanY * meanY;
console.log("meanX",meanX);
var meanX2 = meanX*meanX;
console.log("meanX2",meanX2);
var numerator = (sumY2 - count * (meanY * meanY)) - (sumX2 - count * meanX2);
var denominator = (count * meanX * meanY - sumXY);
B = 0.5 * (numerator / denominator);
slope = -B + slopeSign * Math.sqrt(B * B + 1);
originY = meanY - slope * meanX;
slope = isNaN(slope) ? slopeSign : slope;
originY = isNaN(originY) ? originY : originY;
lowp.y = this.lowY;
lowp.x = (this.lowY - originY) / slope;
highp.y = this.highY;
highp.x = (this.highY - originY) / slope;
return {
low: lowp,
high: highp
};
};
Now, I was trying to understand what was causing this, and the most bizarre thing is that it seems that when I place a statement of this form
var x = ... meanY * meanY ...;
before the meanX2 attribution, the issue happens. Otherwise it doesn't.
Also, I tried to catch this anomaly in the debugger but just when I enter the debugging tab, the problem disapears. And the values turn correct again.
I certainly don't believe in black magic, and I know that you are probably skeptic to this.
I would be too. But here is a link to a video showing it happening:
The video
Edit2:
I managed to reproduce this issue in another computer.. Both having ubuntu and using firefox (versions 20 and 21).
Edit3:
I'm sorry it took so much time! Here is a zip containing the issue. Just run it in any webserver. The code mentioned is in LaneDetection.js. Search for "HERE" in the file to find it.
https://docs.google.com/file/d/0B7y9wWiGlcYnYlo1S2pBelR1cHM/edit?usp=sharing
The problem might not happen in the first attempts. If that's the case refresh the page and try again. When the lines get horizontal you know it's there. As I said, I saw this problem happening in firefox versions 20 and 21 on ubuntu. In chrome it never happened.
By the way, I noticed that changing javascript.options.typeinference flag in firefox seems to stop the problem... I don't know exactly what that flag does, but maybe this optimization is not correctly implemented in firefox?
I can't say for sure that I actually have an answer but I think that I have confirmed that basilikum was correct to suggest a memory problem. Here's what I did: I took the first ten entries from your screenshot and calculated the correct answer. I then converted the correct answer and the wrong answer into the hexidecimal representation of the double-precision float. What I ended up with was the following:
292.416^2 = 85507.506 = 40F4E0381C71C71E
changed to 27583.373 = 40DAEFEB1C71C722
293.166^2 = 85946.694 = 40F4FBAB1C71C72A
changed to 27583.373 = 40DAEFEB1C71C722
295.818^2 = 87508.396 = 40F55D4658DC0876
changed to 28041.024 = 40DB62419637021F
294.500^2 = 86730.250 = 40F52CA400000000
changed to 27583.373 = 40DAEFEB1C71C722
297.000^2 = 88290.000 = 40F58E2000000000
changed to 28041.024 = 40DB62419637021F
221.750^2 = 49173.062 = 40E802A200000000
changed to 24964.000 = 40D8610000000000
300.300^2 = 90180.090 = 40F6044170A3D70A
changed to 28493.440 = 40DBD35C28F5C290
220.200^2 = 48488.040 = 40E7AD0147AE147B
changed to 25408.360 = 40D8D0170A3D70A4
300.600^2 = 90360.360 = 40F60F85C28F5C29
changed to 28493.440 = 40DBD35C28F5C290
213.000^2 = 45369.000 = 40E6272000000000
changed to 28032.326 = 40DB6014E5E0A72E
There's no persistent pattern to the change but there are a couple instances that are very telling of a memory issue. In the first two entries you can see that bytes 1, 2 and 3 were unchanged. In the 9th entry there's something even more odd. It would appear that bytes 0 - 3 were shifted left by exactly 4 bits! Upon considering the statement that the problem doesn't arise until after some time has passed and in light of these two anomalies, I'm fairly confident that you're encountering some sort of memory issue. Could it be, dare I say, a stack overflow?

How can one force the browser to redraw an image?

I'm working on a JavaScript game that involves throwing a snowball. I need the snowball to render as often as possible during its flight path. Chrome does all the calculations, including setting the style.left and style.top properties, but doesn't actually redraw the snowball until it reaches its destination. Opera doesn't have this problem.
A relevant point is that putting in an alert() after renderSnowball() fixes the problem, except using the alert() is an obvious issue.
Here's my code so far:
function throwSnowball()
{
var theta = parseFloat(angleField.value) * Math.PI/180 ;
var Vir = parseFloat(velocityField.value) ;
if (!isNaN(Vir) && !isNaN(theta) )
{
Vix = Math.cos(theta) * Vir * 50;
Viy = Math.sin(theta) * Vir * 50;
time = new Date() ;
var timeThrown = time.getTime() ;
while (snowballPosY > 0)
{
current = new Date() ;
var currentTime = current.getTime() ;
var timeElapsed = (currentTime - timeThrown)/5000 ;
snowballPosX += Vix * timeElapsed;
snowballPosY += Viy * timeElapsed;
Viy -= GRAVITY * timeElapsed ;
renderSnowball() ; //renderSnowball() sets the style.left
// and style.top properties to snowballPosX pixels
// and snowballPosY pixels respectively
timeThrown = currentTime ;
}
snowballPosX = 0 ;
snowballPosY = 50 ;
renderSnowball() ;
}
}
You're totally blocking the main thread. Have you tried using a setTimeout (even with a zero timeout) to allow other things to happen during your animation?
If you're willing to use experimental technology, requestAnimationFrame would be even better.
Edit: the setTimeout approach would look something like this (replacing the while loop):
var drawAndWait = function() {
if (snowballPosY > 0) {
// movement/drawing code here
setTimeout(drawAndWait, 20 /* milliseconds */);
} else {
// reset code that would normally go after your while loop
}
};
drawAndWait();
So each time the drawing finishes, it arranges for itself to be invoked again, if appropriate. Note that your throwSnowball function will return quickly; the throwing isn't actually done until later on. This takes awhile to get used to doing correctly; don't be too concerned if it's not intuitive at first.
Try getting out of the tight loop. Chrome may not want to redraw until your function exits. Try using setInterval or setTimeout to give Chrome a chance to repaint.

javascript timed function - expected identifier

I am having a problem with a simple script that is supposed to update a page with some values(user input) that are turned from monthly to yearly (the numbers go into numeric fields created by confirmIT)
<script>
function update() {
for (var i = 0; i < 9; i++) {
var ans = parseInt(document.getElementById("bq10a_" + i).value, 10);
if (!isNaN(ans)) {
var new = ans * 12;
document.getElementById("bq10a_" + i + "calc").value = new;
}
}
}
return;
}
setInterval("update()", 1000);
</script>
this yields an Expected identifier error on line
var new = ans*12;
and i would appreciate any help on how to solve it
The word new is a reserved word in JavaScript and cannot be used as the name of a variable.
The error means that the parser expected an "identifier", which is to say that it expected to see a valid identifier.
Change the name of the variable and things should improve. In the code you've posted I think there's a { } nesting problem; there appears to be one too many before the return of the function.
edit — also as jbabey notes in a comment, your setInterval() call should be
setInterval(update, 1000);
It's not a good idea, generally, to pass strings to setInterval(), despite the advice of thousands of mouldy old instructional websites.
Word "new" -- is special in javascript language:
line is incorrect:
var new = ans*12;
try this:
var newvalue = ans*12;
More information on:
http://javascript.about.com/library/blreserved.htm
http://www.ecma-international.org/publications/standards/Ecma-262.htm

Categories