set variable by using localstorage - javascript

i am trying to create the driver performance assistant.
when i start up the page it needs to read the variable from the last time and use that to count up.
(i have created a dashboard that reads data through a plugin from a game. i am trying to create the driver performance assistant from DAF (truck brand). the way it should work is when rolling out the vehicle it counts up a variable accordingly to the time it is rolling out (this part i have created and it works) now my problem is. i am also trying to save it in the localstorage so it wont get lost. but the variable is doing weird things when i tries to read the localstorage data.
this code only needs to be in javascript.
// variables for driver score
var startBrake = 0;
var endBrake = 0;
var timeDiffBrake = 0;
var countBrake = localStorage.getItem('brake');
var startRollout = 0;
var endRollout = 0;
var timeDiffRollout = 0;
var countRollout = localStorage.getItem('rollout');
var speed = Math.abs(data.truck.speed > 0 ? Math.floor(data.truck.speed) : Math.round(data.truck.speed));
var throttle = utils.formatFloat(data.truck.gameThrottle, 2);
var serviceBrake = utils.formatFloat(data.truck.userBrake, 2);
var retarder = data.truck.retarderBrake;
var engineBrake = data.truck.motorBrakeOn;
var cruiseControl = data.truck.cruiseControlOn;
var fuelConsumption = data.truck.fuelAverageConsumption * 100;
// ANTICIPATE
// Braking to long
if (speed >= 50) {
if (serviceBrake < 0.1) {
startBrake = new Date();
} else if (serviceBrake > 0.25) {
endBrake = new Date();
timeDiffBrake = (endBrake - startBrake) / 1000;
if (timeDiffBrake > 5) {
countBrake -= 0.01;
// add "te lang remmen" display
}
}
}
localStorage.setItem('brake', countBrake);
// Rolling out
if (speed > 30 && speed < 89) {
if (throttle > 0) {
startRollout = new Date();
} else if (throttle < 0.05 && serviceBrake == 0) {
endRollout = new Date();
timeDiffRollout = (endRollout - startRollout) / 1000;
if (timeDiffRollout > 1) {
countRollout += 0.01;
// maybe add display
}
}
}
localStorage.setItem('rollout', countRollout);
// EFFICIENT BRAKING
var brake = localStorage.getItem('brake');
var rollout = localStorage.getItem('rollout');
var anticipate = brake + rollout;
var efficientBraking = 0; // haven't done this yet
var driverScore = Math.round((efficientBraking + anticipate) / 2);
data.drivingScorePercent = driverScore <= 0 ? 0 : driverScore >= 100 ? 100 : driverScore;
the main problem is this variable
var countRollout = localStorage.getItem('rollout');
it keeps saying my data is NAN (i think undefined)
i changed the lines to what "mister jojo" suggested but somehow i get some wierd data from the localstorage. i assumed that a "var += 0.01" would count 0.01 up but somehow it goes like this "0.010.010.010.010.01" instead of 0.01, 0.02, 0.03.

When you are declaring the countBrake and countRollout variables, the value are undefined because you didn't set the values to localStorage yet. So, you can check whether there is already a value set in localStorage and set default value incase the value isn't set yet:
var countBrake = localStorage.getItem('brake') !== undefined ? localStorage.getItem('brake') : 0;
var countRollout = localStorage.getItem('rollout') !== undefined localStorage.getItem('rollout') : 0;

more simple for Shuvo answer is
with the use of the Nullish coalescing operator (??)
var countBrake = localStorage.getItem('brake') ?? 0
, countRollout = localStorage.getItem('rollout') ?? 0
;

Related

Save sum in variable in jQuery each for range

I am working on a specific calculator and I need to sum up variables in my jQuery.each for a range from 0 to 4 (= 5 years).
I have found many pages where the solution is described, but only with references to an element, not to the range.
My code:
jQuery.each(new Array(duration),
function(n){
var investment = 1000; // 1000$
var duration = 5; // 5 years
var revenueRatio = 10; // 10% revenue / year
var reinvest = 50; // 50% reinvestment
if(n == 0){
var revenueReinvest = 0;
var newInvestment = investment;
}else{
console.log(revenueReinvest); // undefined
console.log(newInvestment); // undefined
var interest = ( ( newInvestment - investment ) * ( revenueRatio / 100 ) );
var removeInterest = interest * reinvest / 100;
var restIntereset = interest - removeInterest;
revenueReinvest += restIntereset;
newInvestment = newInvestment + revenueReinvest;
}
}
);
Any help or idea would be great! Thank you!
The issue with the code is that you have declared revenueReinvest and newInvestment inside the if block and using it inside the else block. This wont be possible. Declare revenueReinvest and newInvestment outside each loop and assign the values to them inside if statement. Now you can access the assigned values inside else statement.
You have to declare the variable outside the loop to prevent redeclaring of the variable inside the loop. Each time the variable gets redeclared inside the loop, old value will be lost.
The below code will work
$(document).ready(function () {
const duration = 4;
// Declare here
var revenueReinvest;
var newInvestment;
jQuery.each(new Array(duration),
function (n) {
var investment = 1000; // 1000$
var duration = 5; // 5 years
var revenueRatio = 10; // 10% revenue / year
var reinvest = 50; // 50% reinvestment
if (n == 0) {
// assign value here
revenueReinvest = 0;
newInvestment = investment;
} else {
var interest = ((newInvestment - investment) * (revenueRatio / 100));
var removeInterest = interest * reinvest / 100;
var restIntereset = interest - removeInterest;
revenueReinvest += restIntereset;
newInvestment = newInvestment + revenueReinvest;
}
}
);
console.log(revenueReinvest); // will be defined
console.log(newInvestment); // will be defined
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

JavaScript: Assigning a variable if variable changed

In JAVASCRIPT:
If I have a variable which value is constantly changing (100+ times a second). How do I 'record' a specific value at a specific point in time?
Added to this, how do I base this point in time off of another variable of which value has changed?
This needs to be strictly in JavaScript. I've looked at the onChange() method, but I'm unsure if I have to use this in conjunction with HTML for it to work. If not, could someone give me an example where this is not the case?
Cheers
I'm not 100% clear on what you're trying to do, but as Ranjith says you can use setTimeout to run arbitrary code at some (approximate) future time.
This example could likely be improved if I had a bit more detail about what you're doing.
If you're in a node environment you might consider using an event emitter to broadcast changes instead of having to have the variable in scope. (This isn't particularly hard to do in a browser either if that's where you are.)
The html/css parts of this are just for displaying the values in the example; not necessary otherwise.
const rand = document.getElementById('rand');
const snapshot = document.getElementById('snapshot');
let volatile = 0;
// update the value every ~100ms
setInterval(() => {
// assign a new random value
volatile = Math.random();
// display it so we can see what's going on
rand.innerText = volatile;
}, 100);
// do whatever you want with the snapshotted value here
const snap = () => snapshot.innerText = volatile;
// grab the value every 2 seconds
setInterval(snap, 2000);
div {
margin: 2rem;
}
<div>
<div id="rand"></div>
<div id="snapshot"></div>
</div>
Ok - well you can poll variable changes ... even though you can use setters...
Lets compare:
Polling:
let previous;
let watched = 0;
let changes = 0;
let snap = () => previous = watched !== previous && ++changes && watched || previous;
let polling = setInterval(snap, 100);
let delta = 1000 * 2
let start = Date.now();
let last = start;
let now;
let dt = 0
while(start + delta > Date.now()){
now = Date.now();
dt += now - last;
last = now;
if(dt > 100){
watched++;
dt = 0;
}
}
document.getElementsByTagName('h1')[0].innerText = (changes === 0 ? 0 : 100 * watched / changes) + "% hit"
if(watched - changes === watched){
throw Error("polling missed 100%");
}
<h1><h1>
emitting:
const dataChangeEvent = new Event("mutate");
const dataAccessEvent = new Event("access");
// set mock context - as it is needed
let ctx = document.createElement('span');
// add watchable variable
add('watched', 0);
//listen for changes
let changes = 0;
ctx.addEventListener('mutate', () => changes++);
let delta = 1000 * 2
let start = Date.now();
let last = start;
let now;
let dt = 0
while(start + delta > Date.now()){
now = Date.now();
dt += now - last;
last = now;
if(dt > 100){
ctx.watched++;
dt = 0;
}
}
document.getElementsByTagName('h1')[0].innerText = (changes === 0 ? 0 : 100 * ctx.watched / changes) + "% hit"
if(ctx.watched - changes === ctx.watched){
throw Error("trigger missed 100%");
}
function add(name, value){
let store = value
Object.defineProperty(ctx, name, {
get(){
ctx.dispatchEvent(dataAccessEvent, store)
return store;
},
set(value){
ctx.dispatchEvent(dataChangeEvent, {
newVal: value,
oldVal: store,
stamp: Date.now()
});
store = value;
}
})
}
<h1></h1>
The usage of a while loop is on purpose.

How to reduce number of computations during d3.js transition?

So right now, I'm trying to implement a search bar function into my d3.js plot. Right now it doesn't do anything, but that's not the issue at the moment. The problem is that when I type/delete something from the bar, there's visible lag/choppiness in the characters appearing/disappearing. I believe the issue is stemming from my plot. I have 140+ dots moving around the screen, and their position is being interpolated. So from the beginning to the end of the transition, my code has to compute 140 positions thousands of times over.
I've looked into trying to reduce the cardinality of the d3.interpolateNumber function, but it appears that there isn't a third argument to change the number of terms like in a linspace command. Right now I have an array of 1000 numbers for my function to run through, but I don't know how to pass the array to my other functions.
Below are the pertinent functions for this issue. The commented line in tweenPatch is the original code I had that made my code run, but gave my plot computational issues. Variables arr, curr, and step were my attempt to fix the situation, but I haven't been able to figure out how to pass the array into displayPatch().
function tweenPatch() {
var patch = d3.interpolateNumber(1, 26);
var arr = [];
var curr = 1;
var step = (26 - 1) / (1000 - 1);
for (var i = 0; i < 1000; i++) {
arr.push(curr + (step * i));
}
return arr.forEach(function(d) {
console.log(arr[d]);
displayPatch(arr[d]);
});
//return function(t) { displayPatch(t); };
}
function displayPatch(patch) {
dots.data(interpolateData(patch), function(d) { return d.name; }).call(position).sort(order);
var inter = Math.floor(patch);
var seas = 8;
var patc = 1;
if (inter > 24) {
seas = 9;
patc = inter - 24;
} else {
patc = inter;
}
label.text("Patch " + seas + "." + patc);
}
function interpolateValues(values, number) {
old = Math.floor(number);
upd = Math.ceil(number);
var old_data = values.filter(function(d) {return d.internal == old;});
var new_data = values.filter(function(d) {return d.internal == upd;});
var oobj = old_data[0];
var nobj = new_data[0];
var onum = oobj[Object.keys(oobj)[4]];
var nnum = nobj[Object.keys(nobj)[4]];
var difint = number - old;
var difdis = 0;
var newnum = nnum;
if (nnum > onum) {
difdis = nnum - onum;
newnum = ((difint) * difdis) + onum;
} else if (onum > nnum) {
difdis = onum - nnum;
newnum = onum - ((difint) * difdis);
}
return newnum;
}
I believe switching my SVG to a canvas may help things, but since I have no knowledge of canvas I'd rather leave that as a last resort.

Creating a slider between two numbers

So I've been working on re-producing the slider found here https://www.skylight.io/ ( Scroll down to find the price slider ).
So far Ive managed to create something similiar, but some numbers are hard coded, making it difficult to change and not very re-usable.
I've been researching around and I think I need to use Math.log() and Math.exp() together to achieve something like in the link above but I'm not sure.
Heres a jsfiddle of what I have so far https://jsfiddle.net/7wrvpb34/.
I feel that its the maths part of this problem that is halting me I think, so any help would be greatly appreciated.
Javascript code below:
var slider = document.getElementById("slider")
var sliderFill = document.getElementById("slider-fill")
var knob = document.getElementById("knob")
var mouseDown;
var mousePos = {x:0};
var knobPosition;
var minPrice = 20;
var price = 0;
var minRequests = 50;
var requests = 50 + ",000";
var incrementSpeed = 2;
var incrementModifier = 20;
var incrementValue = 1;
var minMillionCount = 1;
var millionCount = 1;
var previousRequestAmount = 0;
document.getElementById("price").innerHTML = price;
document.getElementById("requests").innerHTML = requests;
highlightTable(1);
document.addEventListener('mousemove', function(e) {
if(mouseDown) {
updateSlider(e);
}
})
function updateSlider(event) {
mousePos.x = event.clientX - slider.getBoundingClientRect().left;
mousePos.x -= knob.offsetWidth / 2;
console.log(mousePos.x);
if(mousePos.x < 0) {
knob.style.left = "0px";
sliderFill.style.width = "0px";
price = 0;
requests = 50 + ",000";
document.getElementById("price").innerHTML = price;
document.getElementById("requests").innerHTML = requests;
return
}
if(mousePos.x > slider.offsetWidth - 20) {
return
}
sliderFill.style.width = mousePos.x + 10 + "px";
knob.style.left = mousePos.x + "px";
//Increase requests by using X position of mouse
incrementSpeed = mousePos.x / incrementModifier;
requests = minRequests + (mousePos.x * incrementSpeed);
//Round to nearest 1
requests = Math.round(requests / incrementValue) * incrementValue;
if (requests >= 1000){
var m = requests/ 1000;
m = Math.round(m / 1) * 1;
//Problem, lower the modifier depending on requests
incrementModifier = 20 * 0.95;
document.getElementById("requests").innerHTML = m + " million";
//Adjust Prices
if(( requests >= 1000) && (requests < 10000)) {
var numOfMillions = requests / 100;
//Round to closest 10.
//10 * number of millions
var rounded = Math.round(numOfMillions / 10) * 10;
price = minPrice + rounded;
highlightTable(3);
}
//Adjust Prices
if(requests >= 10000) {
var numOfMillions = requests / 1000;
var rounded = Math.round(numOfMillions / 1) * 1;
var basePrice = minPrice * 6;
price = basePrice + rounded;
highlightTable(4);
}
} else {
incrementModifier = 20;
document.getElementById("requests").innerHTML = requests + ",000"
if(requests < 100) {
highlightTable(1);
price = 0;
} else {
highlightTable(2);
price = 20;
}
}
previousRequestAmount = requests;
document.getElementById("price").innerHTML = price;
}
knob.addEventListener('mousedown', function() {
mouseDown = true;
});
document.addEventListener('mouseup', function() {
mouseDown = false;
});
function highlightTable(rowNum) {
var table = document.getElementById("payment-table")
for(var i = 0; i < table.rows.length; ++i) {
var row = table.rows[i]
if(i == rowNum) {
row.style.background = "grey"
} else {
row.style.background = "white";
}
}
}
Thank you for your time.
If you want it to be reusable you need to create a mathematical function that assigns a result to the number of requests. I will give you a very easy example.
If you want a different result for 1,10,100,100,10000 etc
var d = Math.log10(requests);
if(d<1){
doSomething();
}else if(d<2){
doSomethingElse();
} //etc
This way if you want to change the specific values that create certain results, all you need to do is change the function.
This only works if your tiers of requests follow a math function, if they don't you need to hard code it.
However if say they don't follow a math function, but you know how you would like them to change based on a value then you can do this.
var changingValue = 4;
if(requests < 400*changingValue){
doSomthing();
}else if(requests <= 400*changingValue*changingValue){
doSomethingElse();
}else{// the requests is greater than any of the above
doTheOtherThing();
}
Edit:
For the second one you need to make sure that each condition if always larger than the other from top to bottom.
The description "increasingly increasing" matches an arbitrary number of functions. I assume you also want it to be continuous, since you already have a non-continuous solution.
TL;DR
Use an exponential function.
Generic approach
Assuming imin and imax are the minimal and maximal values of the slider (i for input) and omin and omax are the minimal and maximal values to be displayed, the simplest thing I can think of would be a multiplication by something based on the input value:
f(x)
{
return omin + (omax - omin) * g((x - imin) / (imax - imin));
}
This will pass 0 to g if x == imin and 1 if x == imax.
The return value r of g(y) should be
r == 0 for y == 0
r == 1 for y == 1
0 < r < y for 0 < y < 1
The simplest function that I can think of that fulfills this is an exponential function with exponent > 1.
An exponent of 1 would be a linear function.
An exponent of 2 would be make the middle of the slider display one fourth of the maximum price instead of half of it.
But you really need to find that exponent yourself, based on your needs.

Solving Linear Equations & similar Algebra Problems with JavaScript

I'm new to JavaScript and I am trying to write a simple script that solves linear equations. So far my script solves linear equations that are plus and minus only such as "2x + 28 - 18x = 36 - 4x + 10". I want it to also be able to solve linear equations/algebra problems that contain multiplication and division such as "2x * 3x = 4 / 2x".
I kind of have an idea of what to do next but I think the script I have right now maybe overly complex and it's only going to make it more complicated to add the multiplication and division.
Below is my script. I'm hoping for a few pointers on how I could improve and simplify what I already have and what the best way to add multiplication and division?
My script on JS Bin: http://jsbin.com/ufekug/1/edit
My script:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Problem Solver</title>
<script>
window.onload = function() {
// Total Xs on each side of equation
// Example problem: 5x + 2 = 10 - 2x
var leftSideXTotal = 0; // 5
var rightSideXTotal = 0; // -2
// Total integers on each side of equation
// Example problem: 5x + 2 = 10 - 2x
var leftSideIntTotal = 0; // 2
var rightSideIntTotal = 0; // 10
// Enter a math problem to solve
var problem = "5x + 2 = 10 - 2x";
// Remove all spaces in problem
// Example problem: 5x + 2 = 10 - 2x
problem = problem.replace(/\s/g,''); // 5x+2=10-2x
// Add + signs in front of all - signs
// Example problem: 5x + 2 = 10 - 2x
problem = problem.replace(/-/gi, "+-"); // 5x+2=10+-2x
// Split problem into left and right sides
// Example problem: 5x + 2 = 10 - 2x
var problemArray = problem.split("=");
var problemLeftSide = problemArray[0]; // 5x+2
var problemRightSide = problemArray[1]; // 10+-2x
// Split values on each side into an array
var problemLeftSideValues = problemLeftSide.split("+");
var problemRightSideValues = problemRightSide.split("+");
// Go through the left side values and add them up
for (var i = 0; i < problemLeftSideValues.length; i++) {
// Current value
var currentValue = problemLeftSideValues[i];
// Length of current value
var currentValueLength = currentValue.length;
if (currentValue.charAt(currentValueLength - 1) == "x") { //Check if current value is a X value
// Remove X from end of current value
currentValue = currentValue.split("x");
// Add to total Xs on left side
leftSideXTotal = Number(leftSideXTotal) + Number(currentValue[0]);
} else {
// Add to total integers on left side
leftSideIntTotal = Number(leftSideIntTotal) + Number(problemLeftSideValues[i]);
}
}
// Go through the right side values and add them up
for (var i = 0; i < problemRightSideValues.length; i++) {
// Current value
var currentValue = problemRightSideValues[i];
// Length of current value
var currentValueLength = currentValue.length;
if (currentValue.charAt(currentValueLength - 1) == "x") { //Check if current value is a X value
// Remove X from end of current value
currentValue = currentValue.split("x");
// Add to total Xs on right side
rightSideXTotal = Number(rightSideXTotal) + Number(currentValue[0]);
} else {
// Add to total integers on right side
rightSideIntTotal = Number(rightSideIntTotal) + Number(problemRightSideValues[i]);
}
}
// Compute
var totalXs = (leftSideXTotal - rightSideXTotal)
var totalIntegers = (rightSideIntTotal - leftSideIntTotal)
var solution = (totalIntegers / totalXs)
// Display solution
document.getElementById("divSolution").innerText = solution;
}
</script>
</head>
<body>
<div id="divSolution"></div>
</body>
</html>
You need to write (or use) an operator-precedence parser.
The idea is to turn the equation into a tree, e.g.
x + 3 = 3x - 2
Is really the structure
=
/ \
+ -
/ \ / \
x 3 * 2
/ \
3 x
Where each operator describes an operation between two "branches" of the tree. Using a javascript object it shouldn't be difficult to create the structure:
function tree(lterm,op,rterm) {
t.operator = op;
t.left = lterm;
t.right = rterm;
return t;
}
expression = tree("x", "/", tree("x","+",3) ); // x / (x+3)
Then by manipulating the tree you can resolve the equation, or carry out calculations. To evaluate an expression (with no unknowns), you run through the tree starting at the terminals, and upwards from intersection to intersection. You can replace a section of the tree with a result, or annotate it with a result - add a result variable to the tree object.
Here are some useful methods to include in a tree class:
getLeft
getRight
prettyPrint
evaluate
evaluate("x",5) // x=5, now evaluate
...
It's not just linear operations that can be "parsed" this way. Better parsers will have a list of operators that includes =*/+- but also unary operators: - ( ) sin cos...
I haven't used an operator-precedence parser in javascript, but some must exist prewritten. Surely a kind soul on this site will add a good link or two to my answer.
BTW, the tree approach has many applications. In a spreadsheet:
A2 = A1+B1
In a boolean solver:
A = not (B or C)
C = true
In XML parsing:
<main>
<part>A</part>
<part>B</part>
</main>
I have defined two functions:
getTotalX() : It will give you the count of x for any input string.
getTotalScalars() : It will give you the total of scalars (numbers).
And finally, your updated code (it still does only addition and subtraction):
<script>
window.onload = function() {
// Total Xs on each side of equation
// Example problem: 5x + 2 = 10 - 2x
var leftSideXTotal = 0; // 5
var rightSideXTotal = 0; // -2
// Total integers on each side of equation
// Example problem: 5x + 2 = 10 - 2x
var leftSideIntTotal = 0; // 2
var rightSideIntTotal = 0; // 10
// Enter a math problem to solve
var problem = "5x + 2 = 10 - 2x";
// Remove all spaces in problem
// Example problem: 5x + 2 = 10 - 2x
problem = problem.replace(/\s/g,''); // 5x+2=10-2x
// Add + signs in front of all - signs
// Example problem: 5x + 2 = 10 - 2x
problem = problem.replace(/-/gi, "+-"); // 5x+2=10+-2x
// Split problem into left and right sides
// Example problem: 5x + 2 = 10 - 2x
var problemArray = problem.split("=");
var problemLeftSide = problemArray[0]; // 5x+2
var problemRightSide = problemArray[1]; // 10+-2x
leftSideXTotal = getTotalX(problemLeftSide);
leftSideIntTotal = getTotalScalars(problemLeftSide);
rightSideXTotal = getTotalX(problemRightSide);
rightSideIntTotal = getTotalScalars(problemRightSide);
// Compute
var totalXs = (leftSideXTotal - rightSideXTotal)
var totalIntegers = (rightSideIntTotal - leftSideIntTotal)
var solution = (totalIntegers / totalXs)
// Display solution
document.getElementById("divSolution").innerText = solution;
// Find the total number of X in the string
function getTotalX(data) {
data = data.replace(/\s/g,'');
xCount = 0;
if(data.indexOf('x') != -1) {
if (data.indexOf('+') != -1) {
data = data.split('+');
for(var i = 0; i < data.length; i++) {
xCount += getTotalX(data[i]);
}
} else if (data.indexOf('-') != -1) {
data = data.split('-');
// Single negative
if(data[0] == "") {
xCount -= getTotalX(data[1]);
} else {
xCount += getTotalX(data[0]);
for(var i = 1; i < data.length; i++) {
xCount -= getTotalX(data[i]);
}
}
} else {
xCount = parseInt(data.split('x')[0]);
}
}
return xCount;
}
// Find the total of scalars
function getTotalScalars(data) {
data = data.replace(/\s/g,'');
intCount = 0;
if (data.indexOf('+') != -1) {
data = data.split('+');
for(var i = 0; i < data.length; i++) {
intCount += getTotalScalars(data[i]);
}
} else if (data.indexOf('-') != -1) {
data = data.split('-');
// Single negative
if(data[0] == "") {
intCount -= getTotalScalars(data[1]);
} else {
intCount += getTotalScalars(data[0]);
for(var i = 1; i < data.length; i++) {
intCount -= getTotalScalars(data[i]);
}
}
} else {
if(data.indexOf('x') == -1) {
intCount = parseInt(data.split('x')[0]);
} else {
intCount = 0;
}
}
return intCount;
}
}
</script>

Categories

Resources