Local to global positions

Hi there;

Been dipping my toe in a little p5 and ran into what might be a common problem with what I hope is a common answer (although I couldn’t find one)

I have a sketch that creates a secondary canvas and centers it in the primary canvas within the secondary canvas I have a number of class based objects that should react to the distance from their mouse - but all the positioning seems to be based off the origin of the primary canvas. Hopefully my simplified example does a better job of explaining this, the red dot is in the same position within the primary canvas that the white dot is within the secondary - I know I need to use a custom distance calculation that somehow takes into consideration the origin of the secondary canvas - that’s as far as I’ve gotten - any guidance would be really appreciated.

let pg;
let dot;
let d;

function setup() {
  createCanvas(300, 300);
  background(0);
  pg = createGraphics(100, 100);
  pg.background(80);
  pg.noStroke();
  d = new Dot(pg, 25, 25);
  fill(255,0,0);
  ellipse(25,25,10);
}

function draw() {
  d.display();
  d.update(mouseX, mouseY);
  imageMode(CENTER);
  image(pg, width/2, height/2);
}

class Dot {
  constructor(_canvas, _x, _y) {
    this.canvas = _canvas;
    this.x = _x;
    this.y = _y;
    this.c = 255;
  }
  display() {
    this.canvas.fill(this.c);
    this.canvas.ellipse(this.x, this.y, 10);
  }
  update(mX, mY) {
    let ds = dist(mX, mY, this.x, this.y);
    console.log(ds);
    if (ds < 10) {
      this.c = 50;
    }else{
      this.c = 255;
    }
  }
}

1 Like

Hi! Welcome to the forum.

I quite don’t get what you mean - do you want to make the color react to the mouse close to the white circle instead of the red one? If so I guess you need a separate set of x/y in the Dot class to store the offset of the canvas, and add them when you calculate the distance.

Also ellipse/circle takes diameter not radius, just to let you know!

2 Likes

Store the x and y offset coordinates of the origin of the secondary canvas relative to the primary canvas as attributes in an object that relates to the secondary canvas. Then to convert x and y coordinates of mouse clicks into secondary canvas coordinates, subtract the x and y coordinates of the stored offsets from the x and y coordinates of the mouse clicks. So, if the origin of the secondary canvas is at 100, 100, and the mouse is clicked at 200, 300 on the primary canvas, the subtraction gives us 100, 200.

So assuming that the primary canvas is windowWidth and windowHeight and the secondary canvas is centered storing all that initial math is a great idea - i was just really hoping for some kind of global to local math I didn’t have to write - so such luck huh?

Create a method within the class that contains or references the secondary canvas to do the math. It should just get the coordinates of the mouse click, do the subtraction using the stored origin of the secondary canvas, and return the resulting converted coordinates. With the details handled by that method whenever the mouse is clicked, writing the rest of the code for the script should become easier. The idea is to contain the messy stuff within the method, then to use it as a convenience for writing the rest of the script.

EDIT (2x on April 13, 2021):

We could do this type of thing with any instance of an object that we can display in the sketch, whether or not it involves a secondary canvas.

Below is a simple example, wherein the origin of the displayed object is the center of that object. The object displays the mouse position relative to its own origin. In this case, the math is not very complicated, and is handled by the report_mouse_position() method. We could do the same with a secondary canvas.

let p;
function setup() {
  createCanvas(400, 400);
  textAlign(CENTER, CENTER);
  textSize(32);
  p = new Pancake(200, 200, 255);
}


function draw() {
   background(255);
   p.display();
}

class Pancake {
  constructor(x, y, diam) {
    this.x = x;
    this.y = y;
    this.diam = diam;
  }
  display() {
    circle(this.x, this.y, this.diam);
    let mp = this.report_mouse_position();
    text("" + mp[0] + ", " + mp[1], this.x, this.y);
  }
  report_mouse_position() {
    return [mouseX - this.x, mouseY - this.y];
  }
}

pancake

3 Likes

This really helps - curious is there a benefit to calling report_mouse_position from within display rather than having a separate call to it within Draw?

2 Likes

Either way is fine. It is just a matter of convenience. If you would like to use the information returned by the report_mouse_position() method within the draw() function, you should call it from there. Otherwise, it might be more convenient for you to have the display() method do that work for you. In this particular situation, it doesn’t make much difference. However, in a case where several different methods must be called to gather all the information together to display or perform some other operation on an object, it would be convenient to have the display() or other pertinent method belonging to the object do the work of gathering together and processing that information.