Javascript: why is the alert saying undefined and not the letter "k" - javascript

I can get my array to work and display perfectly as a 2d array but the second I attempt to add another element it never shows it always stays undefined. I tried many different methods, in this version I attempted to duplicate the way that I add the 2d elements.
Ultimately I want to save data to the array to make the walls "#" that are displaying correctly to have further data stating "solid" and then I would be able to test for that before moving the "#"
I actually have a working version of this but using a second array which would get very cumbersome if I add further data.
Also as it is right now I am surprised the entire map is not getting overwritten with the letter k
function gameloop(){
var mainArray = [];
var mapSizeX = 32;
var mapSizeY = 128;
var arrayDepth = 10;
var idPos = {x:0, y:0};
function initMap(mainArray, mapSizeX, mapSizeY){
for (var i = 0; i < mapSizeX; i++) {
mainArray.push([0])
for (var j = 0; j < mapSizeY; j++) {
mainArray[i][j] = ".";
if(j == 0){mainArray[i][j] = "#";}
if(j == mapSizeY-1){mainArray[i][j] = "#";}
if(i == 0){mainArray[i][j] = "#";}
if(i == mapSizeX-1){mainArray[i][j] = "#";}
for (var k = 0; k < arrayDepth; k++) {
mainArray[i][j][k] = "k";
}
}
}
}
function nl(){GameScreen.innerText += "\n";}
function render() {GameScreen.innerText = mainArray.map(arr => arr.join("")).join("\n");
nl(); nl();}
function reposition(xChange,yChange,strA){
//mainArray[idPos.x][idPos.y] = ".";
//idPos.x = idPos.x + xChange;
//idPos.y = idPos.y + yChange;
//mainArray[idPos.x][idPos.y] = "#";
if(mainArray[idPos.x+xChange][idPos.y+yChange][1] === "Solid"){GameLog.innerText ="You can not travel in that direction"}
else{
mainArray[idPos.x][idPos.y] = ".";
idPos.x = idPos.x + xChange;
idPos.y = idPos.y + yChange;
mainArray[idPos.x][idPos.y] = "#";
GameLog.innerText = "You take a step to the " + strA
alert(mainArray[0][0][1]);
}
render();
}
//Startup
initMap(mainArray, mapSizeX, mapSizeY);
idPos.x = mapSizeX/2; idPos.y = mapSizeY/2;
mainArray[idPos.x][idPos.y] = "#";
//First Render
render();
document.addEventListener('keydown', function(event) {
if(event.keyCode === 38 ){reposition(-1,0,"North");}
if(event.keyCode === 40 ){reposition(1,0,"South");}
if(event.keyCode === 37 ){reposition(0,-1,"West");}
if(event.keyCode === 39 ){reposition(0,1,"East");}
//alert(event.keyCode);
});
}
gameloop();
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hello</title>
</head>
<body>
<br>
<p style="color:#7d7d7d;font-family:Lucida Console;">Dungeon Valley.<br>
<font style="color:#ABABAB;font-family:Lucida Console;font-size:0.5em";>
Taming the Borderlands.<br>
v0.005 By heromedel. </P></font>
<P>
<section id="GameScreen" style="color:#000000;font-family:Lucida Console;"></section>
<P>
<section id="GameLog" style="color:#000000;font-family:Lucida Console;">Arrow Keys to move.<br></section>
<script src="main.js"></script>
</body>
</html>

If I'm understanding what you're trying to do, this is wrong:
for (var k = 0; k < arrayDepth; k++) {
mainArray[i][j][k] = "k";
}
mainArray is supposed to be a 2d array of strings, right? So why are you using var k to add a 3rd dimension to it? Unless you're trying to append to the string? In Javascript you append to strings with +, not with [].
By the way, this is also wrong:
mainArray.push([0])
You want to push an empty array [], not an array with a 0 in it [0].

Related

Is it possible to show interpolated data using dygraphs?

I have been working for the last months with dygraphs. It is a incredible library and I have got great results but I´m having some problems to find the way of interpolating data from different signals to be shown in the same chart.
The data I received from different sensors have not the same timestamp for the different samples, so for the most of the points of the x axe timestamps I have only the value of one signal. The chart is plotted perfectly, but I would like to see the interpolated value of the rest of the signals in that x point I am pointing over. Below I have the chart I get.
Reading on the dygraph documentation I have seen that when you have independent series, it is possible to see at least the value "undefined" for the signals without data in that point of the x axe.
The csv I use to plot the data is shown below. It has the same structure indicated in the dygraph documentation but I don´t get this undefined label neither.
TIME,LH_Fuel_Qty,L_Left_Sensor_NP
1488801288048,,1.4411650490795007
1488801288064,0.478965502446834,
1488801288133,,0.6372882768113235
1488801288139,1.131315227899919,
1488801288190,1.847605177130475,
1488801288207,,0.49655791428536067
1488801288258,0.45488168748987334,
1488801288288,,1.3756073145270766
1488801288322,0.5636921255908185,
1488801288358,,1.1193344122758362
Thanks in advance.
This is an approach that does not add any data to your csv data and still provides interpolated values for all the columns as you move your mouse around. It adds a listener to the mousemove event within dygraph and interpolates the closest points for all of the data. At the moment I have simply shown it in an extra DIV that is after the graph but you can display it however you like:
function findNextValueIndex(data, column, start) {
var rows = data.length;
for (var i = start; i < rows; i++) {
if (data[i][column] != null) return (i);
}
return (-1);
}
function findPrevValueIndex(data, column, start) {
for (var i = start; i >= 0; i--) {
if (data[i][column] != null) return (i);
}
return (-1);
}
function interpolate(t0, t1, tmid, v0, v1) {
return (v0 + (tmid - t0) / (t1 - t0) * (v1 - v0));
}
function showValues(headers, colors, vals) {
var el = document.getElementById("info");
var str = "";
for (j = 1; j < headers.length; j++) {
str += '<p style="color:' + colors[j] + '";>' + headers[j] + ": " + vals[j] + "</p>";
}
el.innerHTML = str;
document.getElementById("hiddenDiv").style.display = "none";
}
function movecustom(event, dygraph, point) {
var time = dygraph.lastx_;
var row = dygraph.lastRow_;
var vals = [];
var headers = [];
var colors = [];
var cols = dygraph.rawData_[0].length;
// draw a line on the chart showing the selected location
var canvas = dygraph.canvas_;
var ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.lineWidth = 1;
ctx.strokeStyle = "rgba(0,200,200,0.1)";
ctx.moveTo( dygraph.selPoints_[0].canvasx, 0);
ctx.lineTo( dygraph.selPoints_[0].canvasx, 1000);
ctx.stroke();
for (var j = 1; j < cols; j++) {
colors[j] = dygraph.colors_[j - 1];
if (dygraph.rawData_[row][j] == null) {
var prev = findPrevValueIndex(dygraph.rawData_, j, row - 1);
var next = findNextValueIndex(dygraph.rawData_, j, row + 1);
if (prev < 0)
vals[j] = dygraph.rawData_[next][j];
else if (next < 0)
vals[j] = dygraph.rawData_[prev][j];
else {
vals[j] = interpolate(dygraph.rawData_[prev][0], dygraph.rawData_[next][0], time, dygraph.rawData_[prev][j], dygraph.rawData_[next][j]);
}
} else {
vals[j] = dygraph.rawData_[row][j];
}
}
headers = Object.keys(dygraph.setIndexByName_);
showValues(headers, colors, vals);
}
window.onload = function() {
new Dygraph(
document.getElementById('graph'), document.getElementById('csvdata').innerHTML, {
connectSeparatedPoints: true,
drawPoints: true,
labelsDiv: "hiddenDiv",
interactionModel: {
'mousemove': movecustom
}
}
);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/dygraph/2.0.0/dygraph.js"></script>
<div id="graph" style="height:120px;"></div>
<div id="info"></div>
<div id="hiddenDiv" style="display:none"></div>
<pre id="csvdata" style="display:none">
TIME,LH_Fuel_Qty,L_Left_Sensor_NP
1488801288048,,1.4411650490795007
1488801288064,0.478965502446834,
1488801288133,,0.6372882768113235
1488801288139,1.131315227899919,
1488801288190,1.847605177130475,
1488801288207,,0.49655791428536067
1488801288258,0.45488168748987334,
1488801288288,,1.3756073145270766
1488801288322,0.5636921255908185,
1488801288358,,1.1193344122758362
</pre>
It seems that the best way to do this is to massage the data before submitting it to the dygraph call. This means the following steps:
1) parse the csv file into an array of arrays.
2) go through each line of the array to find where the holes are
3) interpolate to fill those holes
4) modify the constructed arrays to be displayed by dygraph
5) call dygraph
Not the most attractive code, but seems to work...
function findNextValueIndex(data, column, start) {
var rows = data.length;
for(var i=start;i<rows;i++) {
if(data[i][column].length>0) return(i);
}
return(-1);
}
function interpolate(t0, t1, tmid, v0, v1) {
return((v0 + (tmid-t0)/(t1-t0) * (v1-v0)).toString());
}
function parseCSV(string) {
var data = [];
// first get the number of lines:
var lines = string.split('\n');
// now split the first line to retrieve the headings
var headings = lines[0].split(",");
var cols = headings.length;
// now get the data
var rows=0;
for(var i=1;i<lines.length;i++) {
if(lines[i].length>0) {
data[rows] = lines[i].split(",");
rows++;
}
}
// now, fill in the blanks - start by finding the first value for each column of data
var vals = [];
var times = [];
for(var j=1;j<cols;j++) {
var index = findNextValueIndex(data,j,0);
vals[j] = parseFloat(data[index][j]);
}
// now put those start values at the beginning of the array
// there is no way to calculate the previous value of the sensor missing from the first sample
// so we use the first reading and duplicate it
for(var j=1;j<cols;j++) {
data[0][j] = vals[j].toString();
times[j] = parseInt(data[0][0]);
}
// now step through the rows and interpolate the missing values
for(var i=1;i<rows;i++) {
for(var j=1;j<cols;j++) {
if(data[i][j].length>0) {
vals[j] = parseFloat(data[i][j]);
times[j] = parseInt(data[i][0]);
}
else {
var index = findNextValueIndex(data,j,i);
if(index<0) // no more data in this column
data[i][j] = vals[j].toString();
else
data[i][j] = interpolate(times[j],parseInt(data[index][0]),parseInt(data[i][0]),vals[j],data[index][j]);
}
}
}
// now convert from strings to integers and floats so dygraph can handle it
// I've also changed the time value so that it is relative to the first element
// it will be shown in milliseconds
var time0 = parseInt(data[0][0]);
for(var i=0;i<rows;i++) {
data[i][0] = parseInt(data[i][0]) - time0;
for(var j=1;j<cols;j++) {
data[i][j] = parseFloat(data[i][j]);
}
}
var obj = {
labels: headings,
data: data
}
return(obj);
}
window.onload = function () {
var data_obj = parseCSV(document.getElementById('csvdata').innerHTML);
new Dygraph(
document.getElementById('graph'), data_obj.data,
{
labels: data_obj.labels,
connectSeparatedPoints: true,
drawPoints: true
}
);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dygraph/2.0.0/dygraph.js"></script>
<div id="graph" style="height:200px;"></div>
<pre id="csvdata" style="display:none">
TIME,LH_Fuel_Qty,L_Left_Sensor_NP
1488801288048,,1.4411650490795007
1488801288064,0.478965502446834,
1488801288133,,0.6372882768113235
1488801288139,1.131315227899919,
1488801288190,1.847605177130475,
1488801288207,,0.49655791428536067
1488801288258,0.45488168748987334,
1488801288288,,1.3756073145270766
1488801288322,0.5636921255908185,
1488801288358,,1.1193344122758362
</pre>
Does
connectSeparatedPoints: true
Not do what you need?

Getting an infinite loop and can't see why - Javascript

I'm writing a simple little Connect 4 game and I'm running into an infinite loop on one of my functions:
var reds = 0;
var greens = 0;
function checkEmpty(div) {
var empty = false;
var clicked = $(div).attr('id');
console.log(clicked);
var idnum = parseInt(clicked.substr(6));
while (idnum < 43) {
idnum = idnum + 7;
}
console.log("idnum=" + idnum);
while (empty == false) {
for (var i = idnum; i > 0; i - 7) {
idnumStr = idnum.toString();
var checking = $('#square' + idnumStr);
var str = checking.attr('class');
empty = str.includes('empty');
console.log(empty);
var divToFill = checking;
}
}
return divToFill;
}
function addDisc(div) {
if (reds > greens) {
$(div).addClass('green');
greens++;
console.log("greens=" + greens);
} else {
$(div).addClass('red');
reds++;
console.log("reds=" + reds);
};
$(div).removeClass('empty');
}
$(function() {
var i = 1;
//add a numbered id to every game square
$('.game-square').each(function() {
$(this).attr('id', 'square' + i);
i++;
//add an on click event handler to every game square
//onclick functions
$(this).on('click', function() {
var divToFill = checkEmpty(this);
addDisc(divToFill);
})
})
})
Here is a link to the codepen http://codepen.io/Gobias___/pen/xOwNOd
If you click on one of the circles and watch the browser's console, you'll see that it returns true over 3000 times. I can't figure out what I've done that makes it do that. I want the code to stop as soon as it returns empty = true. empty starts out false because I only want the code to run on divs that do not already have class .green or .red.
Where am I going wrong here?
for (var i = idnum; i > 0; i - 7);
You do not change the i.
Do you want to decrement it by 7?
Change your for loop to the one shown below:
for (var i = idnum; i > 0; i -= 7) {
// ...
}
You also do not use loop variable in the loop body. Instead, you use idnum, I think this can be issue.
while (empty == false) {
for (var i = idnum; i > 0; i -= 7) {
idnumStr = i.toString(); // changed to i
var checking = $('#square' + idnumStr);
var str = checking.attr('class');
empty = str.includes('empty');
console.log(empty);
var divToFill = checking;
// and don't forget to stop, when found empty
if (empty) break;
}
}
I add break if empty found, because if we go to next iteration we will override empty variable with smallest i related value.
You can also wrap empty assignment with if (!empty) {empty = ...;} to prevent this override, but I assume you can just break, because:
I want the code to stop as soon as it returns empty = true
Offtop hint:
while (idnum < 43) {
idnum = idnum + 7;
}
can be easy replaced with: idnum = 42 + (idnum%7 || 7)
Change to this:
for (var i = idnum; i > 0; i = i - 7) {
You are not decrementing the i in your for loop
Building on what the others have posted You would want to change the value of empty inside the for loop. because obviously the string still checks the last string in the loop which would always return false.
while(empty==false){
for (var i = idnum; i > 0; i -= 7) {
// your other codes
if (!empty) {
empty = str.includes('empty');
}
}

My JavaScript is not working! Help :(

I'm new here. I have spent the entire day trying to figure out what is wrong with my code. Yes, it might be a simple questions for you, since I just started JavaSript about a month ago. Anyways, your help in identifying the error in my code is greatly appreciated!
==========================================================================
The Question:
Code a function called extremeValue. It takes 2 parameters. The first is an array of integers (you do not need to validate this). The second parameter is either the String “Minimum” or “Maximum”. The function returns the minimum or maximum element value in the array depending on the second parameter’s value.
Do not use Math.min or Math.max. The standard algorithm for finding a minimum value in an array is to assume the first element (at index 0) is the current minimum. Then process the array repetitively from its second element to its last. On each iteration compare the current element being processed with the current minimum. If it’s less than the minimum set it as the current minimum. In this way at the end of processing the current minimum holds the minimum element value in the array. A similar process will work for finding the maximum. Test your code. (1 mark)
This function does two different jobs depending on its second parameter. What are the pros and cons of this approach to coding functions?
My Answer (which doesn't work):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Eng1003 Workshop Code Week 04</title>
<style>
#outputArea{
padding: .25em;
border: solid black 2px;
margin: 3em;
height: 20em;
width: 20em;
overflow-y: scroll;
font-family: arial "sans serif";
font-size: 1em;
color: rgb(50, 50, 250);
background-color: rgb(225,225,225) ;
}
</style>
</head>
<body>
<!-- -->
<div id="outputArea"></div>
<script>
function maximum(setOfValues){
var retVal = "" ;
var length = setOfValues.length ;
var max = 0 ;
for (var i = 0; i < length; i++){
if (setOfValues[i] > max){
max = setOfValues[i] ;
}
}
retVal = max ;
return retVal ;
}
function minimum(setOfValues){
var retVal = "";
var length = setOfValues.length ;
var min = 0 ;
for (var i = 0; i < length; i++){
if (setOfValues[i] < min){
min = setOfValues[i] ;
}
}
retVal = min;
return retVal ;
}
function extremeValue(setOfValues, command){
var outString = "" ;
var retVal = "" ;
if (command = "Maximum"){
outString = "The maximum value is " + maximum(setOfValues) + "." ;
} else if (command = "Minimum"){
outString = "The minimum value is " + minimum(setOfValues) + "." ;
} else {
outString = "Sorry, but your command is unclear. Please ensure that your input is either 'Maximum' or 'Minimum'." ;
}
retVal = outString ;
return retVal ;
}
var target = document.getElementById("outputArea") ;
var inputCommand = prompt("What is your command?") ;
var inputValues = [10,30,500, 1000] ;
var finalAnswer = "" ;
finalAnswer = extremeValue(inputValues, inputCommand) ;
target.innerHTML = finalAnswer ;
</script>
</body>
The problem is the way you're checking your prompted value:
if (command = "Minimum")
if (command = "Maximum")
Here you're assigning strings to command. The code should be (assuming we're using strict equality):
if (command === "Minimum")
if (command === "Maximum")
DEMO
In you HTML page, call the Result function as below:
<script>
Result.init();
</script>
var Result = function () {
var maximum = function (array) {
var val = 0;
for (var i = 0; i < array.length; i++) {
if (array[i] > val) {
val = array[i];
}
}
return val;
}
var minimum = function (array) {
var val = 0;
for (var i = 0; i < array.length; i++) {
val = array[i];
if (array[i] < val) {
val = array[i];
}
}
return val;
}
var start = function () {
var inputValues = [10, 30, 500, 1000];
var min = minimum(inputValues);
var max = maximum(inputValues);
}
return {
init: function () {
start();
}
};
}();

dat.GUI create multiple buttons with same name

I try to use dat.GUI to create multiple buttons all with same name "ShowCoord", is this possible? What I have currently is:
for (i = 0; i < overlay.numElements; i ++)
{
var length = overlay.elementNumVertices[i];
var subObj = {
'name' : overlay.elementNames[i],
'index' : i,
'numVertices': overlay.elementNumVertices[i],
"ShowCoord" : function(){
console.log("i is " + subObj['index']);
var verts = overlay.elementVertices[i];
for(var j = 0; j < subObj['numVertices']; j ++)
{
console.log("The coordinates are " + verts[3*j] + ", "+ verts[3*j+1] +", "+verts[3*j+2]);
}
}
};
subObjArray.push(subObj);
}
for(i = 0; i < subObjArray.length; i ++)
{
var currObj = subObjArray[i];
var subGui = gui.addFolder(currObj['name']);
subGui.add(currObj, 'numVertices');
subGui.add(currObj, "ShowCoord");
}
I now have the correct currObj['name'] and currObj['numVertices'] displayed. But all the "ShowCoord" button only contains information of the very last subObj (so console.log("i is " + subObj['index']) will print out 148 every time even if I click different button). How can I make it work? Thanks a lot!
Try moving subGui outside the for loop and modifiy you code so that you don't reassign subGui varialbe.
var subGui = new dat.GUI();
for(i = 0; i < subObjArray.length; i ++)
{
var currObj = subObjArray[i];
subGui.addFolder(currObj['name']);// <--- work on this line
subGui.add(currObj, 'numVertices');
subGui.add(currObj, "ShowCoord");
}
Otherwise it will always be redefined with the last iterated element of for loop
Note: This is just a hint, I can't conclude more from your code.

How do I create n canvases from within Javascript?

I am looking for a way to create canvases as I need them at run time. my code so far is
var isCanv = new Array();//bool array for which places in the arrays are/are not in use
var canv = new Array();//for the canvases
var ctx = new Array();//for the contexts
var inhtml = new Array();//for the html canvas tags for each canvas
var upperBound = -1;//the highest index used so far
function createCtx(){
var i = 0;
while(isCanv[i]){
i++;
}
inhtml[i] = '<canvas id="canv'+i+'" width="'+800+'px" height="'+800+'px" style="display:block;background:#ffffff+;"></canvas>';
isCanv[i] = true;
if(i>upperBound){
upperBound = i;
}
var tohtml = '';
for(var j = 0; j<= upperBound; j++){
if(isCanv[i]){
tohtml+=inhtml[j];
}
}
document.getElementById('game').innerHTML=tohtml;
canv[i] = document.getElementById('canv'+i);
ctx[i] = canv[i].getContext('2d');
return(i);
}
function keyEvent(event) {
var i = 0;
while(isCanv[i]){
ctx[i].fillStyle="#00FFFF";
ctx[i].fillRect(0,0,800,800);
i++;
}
}
and the html looks like this
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>redicated</title>
</head>
<body style="background:#333333;" onkeydown="keyEvent(event)">
<div id="game"></div>
<script src="game.js"></script>
</body>
</html>
This works for the first canvas, but any subsequent addition breaks it all.
Does anyone know how I could fix this, or of a better way of doing it?
Edit:
I figured it out. I need to recreate the context every time there is an addition. now my code looks like
function createCtx(){
var i = 0;
while(isCanv[i]){
i++;
}
inhtml[i] = '<canvas id="canv'+i+'" width="'+800+'px" height="'+800+'px" style="display:block;background:#ffffff+;"></canvas>';
isCanv[i] = true;
if(i>upperBound){
upperBound = i;
}
var tohtml = '';
for(var j = 0; j<= upperBound; j++){
if(isCanv[j]){
tohtml+=inhtml[j];
}
}
document.getElementById('game').innerHTML=tohtml;
for(var j = 0; j<= upperBound; j++){
if(isCanv[j]){
canv[j] = document.getElementById('canv'+j);
ctx[j] = canv[j].getContext('2d');
}
}
return(i);
}
The for loop:
for(var j = 0; j<= upperBound; j++){
if(isCanv[i]){
tohtml+=inhtml[j];
}
is only ran once since when it is first executed j == upperBound. To fix this try removing
if(i>upperBound){
upperBound = i;
}
and whats the point of upperBound anyways it will always be equivalent to i so why not just use that.

Categories

Resources