CodingTrain / Suggestion-Box

A repo to track ideas for topics
573 stars 86 forks source link

Need to combine my class with the data from Json in p5 #1235

Closed MoodswingKS closed 5 years ago

MoodswingKS commented 5 years ago

This issue is that I don't know what is the best method to do this. I need to make a connection in between 'my class that defines my objects' and 'the actual data it receives from my json.'

The big question is, am I going to use syntax prototype or create another class that combines this. Prototype does the job, but is incredibly confusing to master especially since I'm still not experienced enough for advanced coding.

I want to be able to function draw my images in the if statements. The images have start at 0, and build up. The x, y, h, w are defined in JSON.

class Msimage { constructor(xax, yax, wpix, hpix) { //this.id = id; this.x = xax; this.y = yax; this.width = wpix; this.height = hpix; //display this.display = function() { image(this.x, this.y, this.width, this.height); } }
}

function preload() { data = loadJSON('database.json'); for (var i = 0; i < 18; i++) { images[i] = loadImage("ms-original/part"+i+".png"); } }

function loadData() { let imageData = data; for (let i = 0; i < imageData.length; i++) { let msimage = imageData[i]; let id = msimage['id']; let position = msimage['position']; let xax = position['xax']; let yax = position['yax']; let wpix = msimage['wpix']; let hpix = msimage['hpix']; msimages.push(new Msimage(xax, yax, wpix, hpix)); } }

Thank you for all the help I already received from watching your videos! You've been a great inspiration for me!

Californ1a commented 5 years ago

I'm assuming the database.json looks something like this?

[{
  "id": 0,
  "position": {
    "xax": 0,
    "yax": 0,
  },
  "wpix": 128,
  "hpix": 128,
}, {
  "id": 1,
  "position": {
    "xax": 128,
    "yax": 128,
  },
  "wpix": 256,
  "hpix": 256,
}]

It seems like you've already essentially done all you need to do, though instead of mixing classes and prototypes, you should change your Msimage class to be like this, with display being outside of the constructor:

class Msimage {
  constructor(xax, yax, wpix, hpix) {
    //this.id = id;
    this.x = xax;
    this.y = yax;
    this.width = wpix;
    this.height = hpix;
  }
  display() {
    image(this.x, this.y, this.width, this.height);
  }
}

Then in draw it seems like you're already done creating the msimages array inside loadData if you call that in setup, so you'd just have to call display on each one:

function setup() {
  createCanvas(1000, 1000);
  background(50);
  loadData();
}

function draw() {
  for (const img of msimages) {
    img.display();
  }
}
MoodswingKS commented 5 years ago

Well, this is only the data part. I want to load the images in a chosen range of frequency. As this is part of a music visualisation program. I already have that part done as well, I just need to figure out how to call the right ID that combines the above data.

My database.json looks like that, you are right.

You're solution doesn't work (yet), so I still need to work on it some more.

Got it to work thank you! Still working on the next to things. As I just loaded a second array of objects with json and used your solution to load it in as well.

I still need to figure out how to draw only 1 of them at a time.

Californ1a commented 5 years ago

What's your current code? And what exactly do you want them to do? Do you want them all to be shown on screen, but only load one at a time (appear with a delay beween each one appearing), or do you want it to hide the previous one when the next one appears?

This is a potential implementation:

class Msimage {
  constructor(xax, yax, wpix, hpix) {
    //this.id = id;
    this.x = xax;
    this.y = yax;
    this.width = wpix;
    this.height = hpix;
    this.hidden = false;
  }
  display() {
    if (!this.hidden) {
      image(this.x, this.y, this.width, this.height);
    }
  }
  toggleHide() {
    this.hidden = !this.hidden;
  }
}

Then in draw you can call img.toggleHide() when you want to hide/unhide that img.

MoodswingKS commented 5 years ago

Here's a short version of the code. I need to combine the array so the images(combined with the json values) appear in the right 'if' moment. I'm guessing the only thing missing is 2 lines of code in the draw section. After that's done, its only finetuning. There's one more thing, as you can see there is more than one image array, i plan to use keypressed to actively swap arrays while the program runs and thus change the images to appear.

As there are multiple groups in json, each group has 18 id's (0-17) and I keep that number the same for every group. Here's what the json looks like (partial):

[{

"id": 0,

"position": {
"xax": -200,
"yax": -165
},
"wpix": 400,
"hpix": 400

},

And here is a short version of the code used:

var oimages = [];   // Array for image paths
let database = {}; // Global object to hold results from the loadJSON call
let msimages = []; // Global array to hold all msimage objects
var nimages = [];

class Msimage {
  constructor(xax, yax, wpix, hpix) {
    this.x = xax;
    this.y = yax;
    this.width = wpix;
    this.height = hpix;
    }

    display() {
      image(this.x, this.y, this.width, this.height);
      }
  }

function preload() {
data = loadJSON('database.json');
for (var i = 0; i < 18; i++) {
oimages[i] = loadImage("/ms-original/part"+i+".png");
    }
for (var i = 0; i < 18; i++) {
nimages[i] = loadImage("/ms-neon/n"+i+".png");
    }
}

function loadData() {
  let imageData = data;
  for (let i = 0; i < imageData.length; i++) {
    let msimage = imageData[i];
    let id = msimage['id'];
    let position = msimage['position'];
    let xax = position['xax'];
    let yax = position['yax'];
    let wpix = msimage['wpix'];
    let hpix = msimage['hpix'];
    msimages.push(new Msimage(xax, yax, wpix, hpix));
  }}

function setup() {
  createCanvas(1000, 800);
  loadData();
  preload();
  mic = new p5.AudioIn();
  mic.start();
  fft = new p5.FFT();
  fft.setInput(mic);
}

function draw() {
  background(0);
  translate(width/2, height/2);

  var spectrum = fft.analyze();
                                              //volume different freq ranges
  var bass = fft.getEnergy("lowMid");         //log +-200
                                              //console.log(bass);

for (const images of msimages) {
  if (bass > 195) {

  }
}
}
Californ1a commented 5 years ago

I need to combine the array so the images(combined with the json values) appear in the right 'if' moment. I'm guessing the only thing missing is 2 lines of code in the draw section.

What is it that you're trying to check? When do you want the images to appear? Yes, you'll probably need an if condition, but when do you want each image to show up? I see you have if (bass > 195) {...}, is that when you want one of the images to appear, or all of them, or just some of them?

Also, there are a couple issues with the codeblock you have there outside of your question:

  1. You're mixing var and let throughout, just stick with let and const, don't use var.
  2. let database = {}; variable isn't actually used anywhere, maybe you meant for this to be data instead of database? In that case, you can just let data; and leave it undefined until it gets defined in preload().
  3. You shouldn't call preload() inside setup(), p5 calls it for you before setup() runs.
  4. You probably don't need two separate loops in preload(), since they're both the same length. You can load both images in the same loop unless you plan on having different lengths for each.
  5. Lastly, for image() in Msimage.display(), you need to actually specify which image, so you'll have to define which image, like this:
    
    class Msimage {
    constructor(img, xax, yax, wpix, hpix) {
    this.img = img;
    this.x = xax;
    this.y = yax;
    this.width = wpix;
    this.height = hpix;
    }
    display() {
    image(this.img, this.x, this.y, this.width, this.height);
    }
    }

function loadData() { const imageData = data; for (let i = 0; i < imageData.length; i++) { const msimage = imageData[i]; //const id = msimage.id; const position = msimage.position; const xax = position.xax; const yax = position.yax; const wpix = msimage.wpix; const hpix = msimage.hpix; const img = nimages[i]; // or oimages[i], whichever you're using // or both and pass both in if you're going to swap between them msimages.push(new Msimage(img, xax, yax, wpix, hpix)); } }

MoodswingKS commented 5 years ago

I know there are still a lot of issues, and I am planning to move the values to the class instead of draw. Giving each object/image their own value to react on.

But as for the main issue, you have just resolved what I needed. The other issues are something I'm going to deal with on my own, as i've been doing for weeks now. I will have a look at each one of them you pointed out!

Thank you so much! I have been working for weeks now for the solution to combine the arrays and I knew it was going to be something as simple as this. Still, it took so long for me to find it on my own, so I really appreciate the help!