javascriptp5.js

Drawing is off-center after translation in p5.js


I am trying to create a stary night behind a lunar eclipse but the orientation of the starts is off. Right now the stars are in the bottom right hand corner. I think the it has to do with translate. Any suggestions?

let slider ;
let val ;
var stars = [];

function setup() {
  createCanvas(600, 600);
  slider = createSlider(-80,0,-80);
  slider.position(10,10);
  slider.style('width', '100px');
  slider.style('border-radius', '50&');
  colorMode(HSB);
  
  for (var i = 0; i < 100; i++) {
    stars[i] = new Star();
  }
}

function draw() {
  background(30);
  
  val = slider.value();
  
  background(color(204,30,map(abs(val),0,80,10,80)));
  translate(width/2,height/2);
  
  fill('yellow');
  circle(0,0,80);
  //fill(color(204,30,map(abs(val),0,80,10,80)));
  //stroke(color(205,30,map(abs(val),0,80,50,90),.3));
  fill('white');
  circle(val,0,80);
    
  for (var i = 0; i < stars.length; i++) {
    stars[i].draw();   
  }
}


// star class //
class Star {
    constructor() { 
      
        this.x = random(width);
        //this.x = (width);
        this.y = random(height);
        this.size = random(.25,3);
        this.t = random(TAU);
    }
    
    draw() {
        this.t += 0.1;
        var scale = this.size + sin(this.t) * 2;
        noStroke();
        ellipse(this.x, this.y, scale, scale);
    }

}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.2/p5.js"></script>

When the moon passes over the sun using the slider, the daylight should fade and the starry night time sky should appear.


Solution

  • Your hunch about translate is correct. Usually, when using global canvas transformations, you want to save the context with push() before the translate operation, then pop() to restore it:

    let slider;
    const stars = [];
    
    function setup() {
      createCanvas(600, 600);
      slider = createSlider(-80, 0, -80);
      slider.position(10, 10);
      slider.style("width", "100px");
      slider.style("border-radius", "50&");
      colorMode(HSB);
    
      for (let i = 0; i < 100; i++) {
        stars[i] = new Star();
      }
    }
    
    function draw() {
      background(30);
      const val = slider.value();
      background(color(204, 30, map(abs(val), 0, 80, 10, 80)));
      stars.forEach(e => e.draw());
    
      push();
      translate(width / 2, height / 2);
      fill("yellow");
      circle(0, 0, 80);
      fill("white");
      circle(val, 0, 80);
      pop();
    }
    
    class Star {
      constructor() {
        this.x = random(width);
        this.y = random(height);
        this.size = random(0.25, 3);
        this.t = random(TAU);
      }
    
      draw() {
        this.t += 0.1;
        const scale = this.size + sin(this.t) * 2;
        noStroke();
        ellipse(this.x, this.y, scale, scale);
      }
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.2/p5.js"></script>

    Another option is to undo the translation with translate(width / -2, height / -2);, but push() and pop() is more general and easier to reason about.

    I'm drawing the stars before the sun and moon which is more astronomically correct.

    As an aside, avoid var in favor of const and let.