Getting TypeError when trying to call multiline string in p5.js

落花浮王杯 提交于 2019-12-12 05:08:47

问题


I've been trying to work out a solution for taking single-line sentences (which I call "statements" in my code) and turning them into multiline sentences on my sketch. This question relates directly to another question I posted on SO, and I have been asked to post this new issue as a new question. The solution from @KevinWorkman got me the to this point. What's happening, though, is that I'm getting a TypeError: Cannot read property 'display' of undefined when I try to run the program. The sketch loads, but when I click within the sketch to start the animation, I get that error. I think it's because my original statements[] array is now no longer of a type that can be called in my draw() function as it is. But I'm not knowledgeable enough to know what the issue is and I've looked through all of my JS and p5.js references and can't find a solution.

I'm posting my complete code in an effort to provide a minimal, complete, verifiable example. Despite the fact, as a writer, I find "minimal" and "complete" to be contradictory terms and, therefore, very confusing, here goes:

var clContext;
var speed = 0.8;
var statements = [];
var canvas;

//load the table of Clinton's statements and their polarity
function preload() {
  clContext = loadTable("cl_context_rev.csv", "header");
}

function setup() {
  canvas = createCanvas(680, 420);
  canvas.mousePressed(inWidth);
  background(51);
  noStroke();
  // iterate over the table rows called in 'preload()' from .csv file
  for (var i = 0; i < clContext.getRowCount(); i++) {
    var statement = clContext.get(i, "statement");
    var polarity = clContext.get(i, "polarity");
    }
    statements[i] = new Statement(polarity, statement);
  }

function draw() {
  if (mouseIsPressed) {
    background(51);
    for (var i = 0; i < statements.length; i++) {
      statements[i].display();
    }
  }
}

// Function to align statements, categories, and polarity
function Statement(polarity, statement) {
  // Break up single-line statements in order to display as multiline
  this.statement = split(statement, "<br>");
  this.polarity = polarity;
  this.x = random(width);
  this.y = random(height);
  this.dx = random(-speed, speed);
  this.dy = random(-speed, speed);
}
// Attach pseudo-class methods to prototype;
// Maps polarity to color and x,y to random placement on canvas
Statement.prototype.display = function() {
  this.x += this.dx;
  this.y += this.dy;

// Make statements reappear if they move off of the sketch display
  if(this.x > width+10){
    this.x = -10
  }
  if(this.y > height+10) {
    this.y = -10
  }
// Map positive/negative statements to colors
  if(this.polarity == -1){
    fill(229,121,59);
  }
  else if(this.polarity == 1){
    fill(97,93,178);
  }
  textSize(14);
  // Was directed to add both 'text' statements
  text(this.statement[0], this.x, this.y);
  text(this.statement[1], this.x, this.y+25);
}

// Create functions for hiding and showing statements
function inWidth() {
  width = width+5;
};  

Note:

console.log(typeof this.statement[0])  // returns 'undefined'
console.log(typeof this.statement[1])  // returns 'undefined'
console.log(split(statement, "<br>"))  // returns 'undefined'  

console.log(statements) // returns 'object'
console.log(statements.length) // returns 20

回答1:


 for (var i = 0; i < clContext.getRowCount(); i++) {
  var statement = clContext.get(i, "statement");
  var polarity = clContext.get(i, "polarity");
 }
 statements[i] = new Statement(polarity, statement);

I think the last line here should be inside the for loop for this to do what you want.

Your error means that you are trying to call the display() method on a value that's undefined. The only place you are calling the display() method is inside your draw() function, when you loop through the statements array. This means that at one point your statements array contains an undefined value. You can verify this, by console logging the array.

I suspect the reason why you have undefined values, is because when you attempt to fill up the statements array in the setup() function, you only call statements[i] = once, after your for loop has finished. At this point the value of i is whatever it was at the end of the for loop, therefore your statements array becomes an array, where the i-th element is whatever you've set it, all the previous elements are undefined.

correct code:

 for (var i = 0; i < clContext.getRowCount(); i++) {
  var statement = clContext.get(i, "statement");
  var polarity = clContext.get(i, "polarity");
  statements[i] = new Statement(polarity, statement);
  // OR statements.push(new Statement(polarity, statement));
 }

As a generic JavaScript coding style principle it's also a good idea to Array.push() instead of direct assignment to add items to an array.




回答2:


Marton's answer is correct. I'm giving it an upvote, and I think you should accept it. But I'll try to expand on it, since I'm not sure you're understanding what it's saying.

Let's look at these lines:

for (var i = 0; i < clContext.getRowCount(); i++) {
    var statement = clContext.get(i, "statement");
    var polarity = clContext.get(i, "polarity");
}
statements[i] = new Statement(polarity, statement);

Please run through this code with some example data. Let's say that you have 3 rows.

  • The first time you run through the loop, i is 0. You get a statement and a polarity, but you don't do anything with them.
  • The second time you run through the loop, i is 1. You get a statement and a polarity, but you don't do anything with them.
  • The third time you run through the loop, i is 2. You get a statement and a polarity, but you don't do anything with them.
  • The loop then exits. The statement and polarity variables go out of scope, so they're undefined. Same with the i variable.

Basically, that loop doesn't do anything. We then get to this line:

statements[i] = new Statement(polarity, statement);

But we know that i, polarity, and statement are undefined, so what you're really doing is this:

statements[undefined] = new Statement(undefined, undefined);

You say that this use to work, but I highly doubt that. What you're doing here doesn't make any sense. That statement definitely belongs inside the for loop, which is where it was in my answer to your other question.

But with how you have it now, nothing has been added to the array, except maybe something at an undefined index. So then we get to this line:

for (var i = 0; i < statements.length; i++) {
  statements[i].display();
}

Now, I'd bet that statements.length is 1, since you have something at one undefined index (maybe that index is the last value of i, I don't know). But you certainly don't have anything at index 0. So then when you enter this loop, i is 0, but you don't have anything at that index. In other words, statements[0] is undefined. So the inner line is really doing this:

undefined.display();

That's what's causing your error. Fixing the first problem will get rid of this error, since you'll actually be adding stuff to your array.

Also, please note that these lines:

// Was directed to add both 'text' statements
  text(this.statement[0], this.x, this.y);
  text(this.statement[1], this.x, this.y+25);

This code I gave you was just an example. You're going to have to do something more intelligent here. I was just showing you how you might access two indexes of the statement array. You'll have to actually check the length of this array and loop through the sentences to do something. What that is depends entirely on what you want to happen.

On General Debugging

You seem to be having a lot of issues because you're trying to do everything at once. You'll save yourself a lot of headaches if you start working in smaller chunks. Instead of trying to add this functionality to your big main sketch, why don't you try to get a smaller example sketch working first? Try hardcoding the values so you can see exactly what's happening with the split() function. Use println() statements to understand what's going on. Trying to add everything all at once is just going to be confusing, for you and for us.

Please note that this is not a request for an MCVE (since you got angry last time I mentioned it), but honestly, the best thing you can do to help yourself is to start working in smaller steps.

You might also consider switching to regular Processing (Java mode), since it can give you more information on errors like this.




回答3:


I was finally able to fix this with a few easy changes to the code. It seems so very obvious once I thought of it that I'm not at all sure why it took me so long to figure it out.

I started by making changes to the setup() code:

function setup() {
  canvas = createCanvas(680, 420);
  canvas.mousePressed(inWidth);
  background(51);
  noStroke();
  // iterate over the table rows called in 'preload()' from .csv file
  for (var i = 0; i < clContext.getRowCount(); i++) {
    var statement = clContext.get(i, "statement");
    var polarity = clContext.get(i, "polarity");
    var stateSplit = split(statement, "<br>");            // split the statements in setup to avoid issues elsewhere
      for (var j = 0; j < stateSplit.length; j++) {
        var stateJoin = join(stateSplit, "\n");           // join the statements, inserting a line break, to make a new array
      statements[i] = new Statement(polarity, stateJoin); // put this in the for loop (per @marton)
    }
    }
}

Then I modified my constructor and prototype display function as follows:

Got rid of this, since it only broke up the statements, but didn't join them:

  this.statement = split(statement, "<br>"); 

And replaced it with this:

  this.stateJoin = stateJoin;                  

Then I got rid of these:

text(this.statement[0], this.x, this.y);
text(this.statement[1], this.x, this.y+25); 

And used this, instead:

    text(this.stateJoin, this.x, this.y)              

And voila! Thanks to @marton and @KevinWorkman for suggestions.



来源:https://stackoverflow.com/questions/37830451/getting-typeerror-when-trying-to-call-multiline-string-in-p5-js

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!