Issue with for loop and if statements in javascript - javascript

I am using Javascript and Openlayers library in order to style a vector feature on the map.
I have written the following script:
var gidS = response[Object.keys(response)[Object.keys(response).length - 1]] // get the data from json obj
// ADD STYLING - DIFFERENT COLORS FOR WHAT IS COMPLETE
var styleContext = {
getColor: function (feature) {
var objectKeys = Object.keys(gidS); // use objectkeys to loop over all the object properties //use it to get the length
for (var i = 0; i < objectKeys.length; i++){
//alert(i);
//////////////////
if(gidS[i][1]=="MT"){
//alert(gidS[i][1]);
return "green";
}
else if(gidS[i][1]=="IRU"){
alert(gidS[i][1]);
return "#780000"; //no images on this line
}
///////////////////////
}
}
};
If I run the script without the if conditions (between the slashes) then I get a correct incremental value of i based on the maximum length of gidS.
But when I include the if statements for some reason the variable i doesn't increment. It remains 0.
EDITED
The getColor function is executed later like this
// define Style
var defaultStyle = new OpenLayers.Style({
fillColor: "${getColor}",
fillOpacity:"1",
strokeColor: "${getColor}",
strokeOpacity: "1",
strokeWidth: 8,
cursor: "pointer",
pointRadius: 8
}, {
context: styleContext
});
What am I doing wrong here?
Thanks a lot.
D.

Capture the color in a variable, for example: color, and return it at the end of the function:
getColor: function (feature) {
var color = '';
var objectKeys = Object.keys(gidS); // use objectkeys to loop over all the object properties //use it to get the length
for (var i = 0; i < objectKeys.length; i++){
if(gidS[i][1]=="MT"){
color = "green";
}
else if(gidS[i][1]=="IRU"){
color = "#780000"; //no images on this line
}
}
return color;
}
By looping through every property of the object, and then returning, you're effectively getting the last possible matching "MT" or "IRU", if any. If you return out of the function as soon as you find a match, then your getting the first possible matching "MT" or "IRU".
For example, given the set: [[435,'IRU'],[34324,'MT'],[343,'MT']] My method will return green, and your method will return #780000.

don't use the return, it immediately stop after used .
try this altough i dont know the gidS.
if(gidS[i][1]=="MT"){
gidS[i]['color']='green';
}
else if(gidS[i][1]=="IRU"){
gidS[i]['color']='#780000';
}

Related

How can I access a property within a "if" statement?

Here is my block of code,obviously quite simple. Learning by myself but getting there!I'm trying to figure out how to compare two objects that I created out of my constructor. But I don't get the function to work. I'm not sure how to trigger the property within objects. Am I missing a fundamental knowledge here?
Don't want to sound cheezy, but thank you everyone for sharing and helping others-humanity. There's so much info available, and that is because of you. The ultimate goal of knowledge, is to share it.
function rectangle (length,breadth,colour){
this.length= length;
this.breadth= breadth;
this.colour= colour;
this.area= function(){
return this.length * this.breadth;
} /**The property (area) value is a function.**/
}
var Rectangle1 = new rectangle (5,3.5,"Green");
var Rectangle2 = new rectangle (7, 5.5, "Green");
function compareRectangles (Rectangle1, Rectangle2){
/**How can I target the property "area" within 'if' statement? or Did I get it all wrong?**/
if (Rectangle1 > Rectangle2){
return console.log(Rectangle1 + " is greater than Rectangle2 ");
}
else if (Rectangle1 < Rectangle2) {
return console.log(Rectangle2 + "is greater than Rectangle1");
}
else {
return console.log("They're same size");
}
}
compareRectangles(Rectangle1, Rectangle2);
Consider the following (added extra comments for your learning experience):
// capitalized Rectangle here to indicate it's a class (convention)
function Rectangle (length,breadth,colour){
this.length = length;
this.breadth = breadth;
this.colour = colour;
// removed quotes around area here
this.area = function () {
return this.length * this.breadth;
}
// removed the ; after the } as it's not necessary after function declarations
}
// renamed Rectangle to rectangle1 to align with what you use in the function
// also lowercased the variables because they're instances of a class and not the class constructor itself
function compareRectangles (rectangle1, rectangle2){
// check the .area method of the rectangle
// you can access properties and methods through a dot
// since area is a function, you need to execute with () to get the return value
if (rectangle1.area() > rectangle2.area()){
// changed console logs to not use the instance in the log.
// Since the instance is an object it would try to parse it as a string, resulting in showing [Object object] or something like that
// if you do want to log the rectangle, you should probably split that by adding an argument:
// console.log("the greater rectangle is:", rectangle1);
console.log("Rectangle1 is greater than Rectangle2");
// I changed your return value, since console.log returns nothing
// I figured it would be more relevant to return the 'winning' rectangle
return rectangle1;
}
else if (rectangle1.area() < rectangle2.area()) {
console.log("rectangle2 is greater than rectangle1");
return rectangle2;
}
else {
console.log("They're same size");
// no winning rectangle makes it return null, so you can recognize it when calling the function
return null;
}
}
// Removed capitals for the variables as they are not class constructors but instances of the class.
// Also changed this to let instead of var,
// you may want to read up on const/let and try to forget about the existence of var
// Currently these could be const since they are never reassigned, but I can imagine it is easier for you currently to stick to let instead
let rectangle1 = new Rectangle (5,3.5,"Green");
let rectangle2 = new Rectangle (7, 5.5, "Green");
// you'll need to 'send over' the rectangles that you're expecting in your function
let returnedValue = compareRectangles(rectangle1, rectangle2);
console.log('Received return value:', returnedValue);
When comparing their area property, use
Rectangle1.area(); //Notice the (), because you wanted to call that function in the...
Rectangle2.area(); //...code
Simply using Rectangle1 > Rectangle2 will compare them as objects. These themselves cannot normally be compared via > and <. You need to compare them with some of their property, which I know you are trying to do. But look at your code.
if (Rectangle1 > Rectangle2){
return console.log(Rectangle1 + " is greater than Rectangle ");
}
You only put Rectangle1 in the left-hand side of the operator. That is an object. To access its property, for example, length, you use Rectangle1.length
So do the same to access the function area, Rectangle1.area, thus call the function via Rectangle1.area().
if (Rectangle1.area() > Rectangle2.area()){
return console.log(Rectangle1 + " is greater than Rectangle2 ");
}
Essentially, just use the syntax:
object.property
Since the property is a function, you have to call it Rectangle1.area()
Also, you have to call the compareRectangles() function and pass the two rectangles you made:
function rectangle (length,breadth,colour){
this.length = length;
this.breadth = breadth;
this.colour = colour;
this.area = function(){
return this.length * this.breadth;
}
};
function compareRectangles(r1, r2){
if (r1.area() > r2.area()){
return console.log("Rectangle 1 is greater than Rectangle 2");
} else if (r1.area() < r2.area()) {
return console.log("Rectangle 2 is greater than Rectangle 1");
} else {
return console.log("They're same size");
}
};
var Rectangle1 = new rectangle (5,3.5,"Green");
var Rectangle2 = new rectangle (7, 5.5, "Green");
compareRectangles(Rectangle1, Rectangle2)
Output:
Rectangle 2 is greater than Rectangle 1
You simply have to call the area() method on the object to get the value
function compareRectangles (Rectangle1, Rectangle2){
if (Rectangle1.area() > Rectangle2.area()){
return console.log("Rectangle1 is greater than Rectangle2");
}
else if (Rectangle1.area() < Rectangle2.area()) {
return console.log("Rectangle2 is greater than Rectangle1");
}
else {
return console.log("They're same size");
}
}
call the function with required arguments
compareRectangles(Rectangle1, Rectangle2);
(Your question is improved. Please, go through your question to see miskates you made)

Javascript Simon Game, how to check the answer

I am trying to make a simon game with Javascript for school. I currently have the code set up to create an array sequence of colors on it's own and have also successfully saved the users answers into it's own array, which gets cleared upon a new sequence. I am now trying to see if said color sequence matches the users color sequence, but I am unsure how to check this without any loopholes. The best I have gotten is being able to test the userClicks array length to the gamePattern array length and to ensure that the last click was indeed correct, but can't figure out a good way to test if the entire userClicks array is equivalent to the gamePattern array. I will also run into the problem that the array must be filled in an allotted time, I'll probably use the setTimout() function to achieve this. There must be an easier way to test if a given array is equal to another.
/*************VARIABLES*************/
//store colors
var buttonColors = [
"green", //0
"red", //1
"yellow", //2
"blue" //3
]
//Game Pattern Storage
var gamePattern = [ /*Added From nextSequence*/ ];
var userClicks = [ /* Added from userClickHistory*/ ];
var level = 0;
var gameOn = false;
/******************BASIC FUNCTIONS*********************/
/*AWAIT KEYPRESS TO BEGIN GAME*/
//some document listener to look for keypress changing gameOn to `true`
//display the level to user
//activate nextSequence();
//log user clicks after nextSequence has executed, check the userClicks vs gamePattern
$(`.btn`).click(function () {
var buttonClicked = $(this).attr(`id`);
userClicks.push(buttonClicked);
animate(buttonClicked);
playSound(buttonClicked);
checkAnswer(userClicks);
});
function checkAnswer(userClicksArray) {
//display the current level to user
//NOT SURE WHAT TO DO ANYMORE
}
/************* NEXT SEQUENCE TO PROGRESS GAME *********/
function nextSequence() {
userClickPattern = [];
level++;
console.log(level);
randomNumber = Math.floor(Math.random() * 4)
randomChosenColor = buttonColors[randomNumber];
gamePattern.push(randomChosenColor);
animate(randomChosenColor);
playSound(randomChosenColor);
}
/******************** SOUNDS AND ANIMATIONS*************************************/
//buttons animations
function animate(clickedButton) {
$(`#` + clickedButton).fadeOut(100).fadeIn(100);
};
//Play a sound in corellation to randomChosenColor
function playSound(color) {
var sound = new Audio('sounds/' + color + '.mp3');
sound.play();
};
You should start by comparing the lengths and if they are the same, just loop through the arrays and check that the value at each index is the same.
If the array is "flat" (no nested arrays or objects), this works nicely. If you have nested objects, you'll need something like this: How to compare arrays in JavaScript?
function checkAnswer(gamePattern, userClicks) {
const len = gamePattern.length;
if (len !== userClicks.length) {
// The lengths of the arrays don't match
return false;
}
for (let i = 0; i < len; i++) {
if (gamePattern[i] !== userClicks[i]) {
// The values at the same index don't match
return false;
}
}
return true;
}
console.log(checkAnswer(['red', 'blue', 'green'], ['red', 'blue', 'green']));
console.log(checkAnswer(['red', 'blue', 'green'], ['red', 'yellow', 'green']));

Optimized the color render function

I have a big data to handle.
They need to be classified into 4 colors, and render to the SVG.
My function is:(parameter A B C are used to do something....)
function mapRender(dataArray,A,B,color1,color2,color3,color4,C){
//......do somthing.......
var colorPlusAry = $.grep(dataArray, function(item,key){
var vote_percentage = parseInt(item.vote_percentage);
var result = vote_percentage>=0 && vote_percentage <50;
return result;
});
//......do somthing.......
}
I use grep to generate the new array which the item has same color, and render to SVG.
function colorDistrict(colorArray,color){
var village = '';
var fillColor = 'fill:'+color;
for(var item in colorArray) {
village = colorArray[item].village;
$('svg').find('path').each(function(){
var id = $(this).attr('id');
if(village) {
if(id.substring(6) === village){
$(this).attr('style',fillColor);
}
}
});
}
}
colorDistrict(colorPlusAry,color1); //Render 4 array
It works successfully, but the data is too large and make render slowly, when I trigger the function, it takes several seconds to react...
How can I optimize this function to render the color?
Optimization is a difficult business without the real data, and without knowing the precise DOM structure. I can only give some hints from what I see:
The costly process is interacting with the DOM. Looking at the colorDistrict() function, the two loops seem to be independent. It would then make sense to run the .each() loop only once, and the loop over the colorArray as the nested one. The latter only contains precomputed values and should run much faster.
Looking at what these loops really do, you can write them much more semantic. You compare the collection of all paths and the colorArray for intersection, and then assign a style to a filtered list of paths.
function colorDistrict (colorArray, color){
var fillColor = 'fill:' + color;
// filter the paths to find those mentioned in colorArray
var relevantPaths = $('svg').find('path').filter(function () {
var village = $(this).attr('id').substring(6);
// boolean to indicate the village is part of the colorArray
var included = colorArray.some(function (item) {
return item.village === village;
});
return included;
});
relevantPaths.attr('style', fillColor);
}
If I understand correctly what you are doing, the colorDistrict() function is executed multiple times, once for every color you assign. Do the <path> elements change between rendering the different colors? If not, you should execute $('svg').find('path') only once and cache the found paths for reuse inside that function.
var paths = $('svg').find('path');
function colorDistrict (colorArray, color){
var fillColor = 'fill:' + color;
var relevantPaths = paths.filter(function () {
...
});
}

JavaScript default constructor| array | loops

I need to make a script but I have no idea how to complete it.
This is what I have to do:
(1) Write a class Boxes. this class has a default constructor and an empty array named boxes.
further has this class 3 methods:
1) insert add method to put Box into the boxes-array.
2) insert method size to get the actual size of the array.
3) insert toString method which give color and volume back in one string.
(2) continue in the init function:
2.3 turn a loop around every object from the array objects to add it to the array boxes
2.4 make a toString method to give back every object from your array in one HTML P-tag.
I hope this makes sense to you guys and it would be a big help if somebody could help me!
A big thanks in advance!
Update: I have edited the code to what I have now.
window.addEventListener("load", init, false);
function init() {
// (2.1)
let object1 = new Box(20, 8, 3, "white");
let object2 = new Box(30, 20, 10, "Brown");
let object3 = new Box(50, 40, 20);
// (2.2)
let boxes = new Boxes();
// (2.3)
boxes.push(object1);
boxes.push(object2);
boxes.push(object3);
// 2.4
var str=""
for (let i = 0 ; i < boxes.size() ; i++){
str += "<p>"+boxes.toString(i)+"<p>"
}
}
class Box {
constructor(length, width, height, color = "blue") {
this.length = length;
this.width = width;
this.heigt = height;
this.color = color;
}
volume() {
return this.length * this.width * this.height;
}
toString() { // String templates
return `Volume: ${this.volume()} --- Kleur: ${this.color}`;
}
}
// (1) class Boxes
class Boxes {
constructor(){
this.boxes = [];
}
add(Box){
this.boxes.push(Box);
}
size(){
return this.boxes.length;
}
toString(i){
this.boxes[i].toString();
}
}
I don't quite get what's 3) means so I would assume that you want to get the box color and volume given the index (correct me if I'm wrong)
class Boxes{
//init property called boxes to an empty array when creating Boxes object
constructor(){
this.boxes = [];
}
//return the length of the boxes
size(){
return this.boxes.length;
}
//add a box by pushing it to the array
add(box){
this.boxes.push(box);
}
//print the volume and color of a box given the index
toString(i){
this.boxes[i].toString();
}
}
for number 2:
//2.3
//do you have to push the objects to object?
//use this if you don't have to
boxes.push(object1);
boxes.push(object2);
boxes.push(object3);
//use this if you pushed your objects into an array called object
objects.forEach(function(singleObject){
boxes.push(singleObject);
});
//2.4
//Iterate every object in boxes and print out their volume and color
//Do you have to create a P tag or just wrapped the string with <p></p>?
//This answer assumes that you just wrap it with <p></p>. Correct me if I'm wrong
var str = "";
//option 1 Using foreach loop
boxes.boxes.forEach((singleBox){
str += "<p>"+singleBox.toString()+"</p>";
});
//option 2 Using for loop
for(var i = 0; i < boxes.size(); i++){
str += "<p>"+boxes.toString(i)+"</p>";
}
//now str contains every object's color and volume wrapped in P tag
I would recommend you to go through this course https://www.codecademy.com/learn/javascript

JS multidimensional array spacefield

i wanna generate a 3x3 field. I want to do this with JS, it shall be a web application.
All fields shall inital with false. But it seems so that my code is not working correctly, but i don't find my fault. The goal is, that every spacesector is accessible.
Thats my idea:
// define size
var esize = generateSpace(3);
}
space[i] = false is replacing the array with a single boolean value false, not filling in all the entries in array you just created. You need another loop to initialize all the elements of the array.
function generateSpace(x) {
var space = [];
for (var i = 0; i < x; i++) {
space[i] = [];
for (var j = 0; j < x; j++) {
space[i][j] = false;
}
}
return space;
}
Also, your for() loop condition was wrong, as you weren't initializing the last element of space. It should have been i < space.length.
And when it's done, it needs to return the array that it created.
Since I got somewhat bored and felt like messing around, you can also initialize your dataset as shown below:
function generateSpace(x) {
return Array.apply(null, Array(x)).map(function() {
return Array.apply(null, Array(x)).map(function() {
return false;
});
});
}
The other functions work equally well, but here's a fairly simply looking one using ES6 that works for any square grid:
function generateSpace(x) {
return Array(x).fill(Array(x).fill(false));
}

Categories