0

There's no div with the id of canvas, is all rendered through javascript. and with this method (this is reused code from other codePens) I'm not sure how to center the canvas created in view. It gets resized based on the browser size, but I need the image to be always in the center of the window based on the entire clientWidth. not sure how to do that within this code.

let img;
const detail = 1;
let particles = [];
let particleImage;
let ctx;
function preload() {
  img = loadImage('https://uploads-ssl.webflow.com/60e7fc673c4aab21388ab7a6/60f1ddf63d26403634b61e99_daniel3.jpg');
}

class Particle {
  constructor (x, y) {
    this.x = x || random(width);
    this.y = y || random(height);
    this.prevX = this.x;
    this.speed = 0;
    this.v = random(0, 0.7);
  }
  
  update (speed) {
    if (grid.length) {
      this.speed = grid[floor(this.y / detail)][floor(this.x / detail)] * 0.97;
    }
    this.x += (1 - this.speed) * 3 + this.v;
    
    if (this.x > width) {
      this.x = 0;
    }
  }
  
  draw () {
    image(particleImage, this.x, this.y);
  }
}

/* ====== STEP 6 ====== */
function goToStep6 () {
  ctx.globalAlpha = 1;
  loop();
  image(img, 0, 0, width, height);
  loadPixels();
  clear();
  noStroke();
  
  grid = [];
  for (let y = 0; y < height; y+=detail) {
    let row = [];
    for (let x = 0; x < width; x+=detail) {
      const r = pixels[(y * width + x) * 4];
      const g = pixels[(y * width + x) * 4 + 1];
      const b = pixels[(y * width + x) * 4 + 2];
      const _color = color(r, g, b);
      const _brightness = brightness(_color) / 100;
      row.push(_brightness);
    }
    grid.push(row);
  }
  
  particles = [];
  for (let i = 0; i < 3000; i++) {
    particles.push(new Particle(null, (i/3000) * height));
  }
}

function step6 () {
  ctx.globalAlpha = 0.05;
  fill(31,36,67);
  rect(0,0,width,height);
  ctx.globalAlpha = 0.2;
  particles.forEach(p => {
    p.update();
    ctx.globalAlpha = p.speed * 0.3;
    p.draw();
  });
}

function setup () {
  const canvas = createCanvas(100,100);
  ctx = canvas.drawingContext;
  
  pixelDensity(1);
  
  particleImage = createGraphics(8, 8);
  particleImage.fill(255);
  particleImage.noStroke();
  particleImage.circle(4, 4, 4);
  
  windowResized();
  if (window['goToStep' + 6]) {
    window['goToStep' + 6]();
  }
  draw();
}

function windowResized () {
  let imgWidthNew = img.clientWidth;
  const imgRatio = img.width/img.height;
  if (windowWidth/windowHeight > imgRatio) {
    resizeCanvas(floor(windowHeight * 4,5), floor(windowHeight));
    ctx.fillRect(100,100,canvas.width,canvas.height);
  } else {
    resizeCanvas(floor(windowHeight * 4,5), floor(windowHeight));
  }
  noiseSeed(random(100));
  if (window['goToStep' + 6]) {
    window['goToStep' + 6]();
  }
  draw();
}

function draw () {
  window['step' + 6]();
}
body {
  margin: 0;
  overflow: hidden;
  background:rgba(31,36,67,1);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.0.0/p5.min.js"></script>

And the access to the Codepen https://codepen.io/kubographics/pen/abWdeLo

Chris W.
  • 22,835
  • 3
  • 60
  • 94
Eu2019
  • 81
  • 7
  • So when you say you want it centered, do you mean just using the viewport height / width? Or are you trying to retain aspect ratios and center it as an element, or what would you like? Because your code is explicitly setting the height/width on both the canvas `height` & `width` attributes as well as hard setting them in the `style` of the rendered canvas element. Is this just a copy/paste you're trying to use? Oh and the id would be `defaultCanvas0` and the class appended is `p5Canvas` in your example. – Chris W. Jul 16 '21 at 22:08
  • @ChrisW. I've modified the aspect ratio on the windowResized function by giving the width a value of height * 4,5 (I've used a calculator to verify my image and check what was the actual aspect ratio of the image) since the height of the image will be always the height of the client it works just fine on all sizes, my problem is now that while increasing the size of the screen it moves to the left since it continues growing. I want to keep it fully centred on screen. – Eu2019 Jul 16 '21 at 22:13
  • I would prefer it to be appended to a div with id="canvas" but not sure how to do that in this case, I took a base code from internet and modified it to my terms (image, colors, particles size, etc) but now I'm facing this new issues @ChrisW. – Eu2019 Jul 16 '21 at 22:17

1 Answers1

1

I I understand correctly, what you want is to draw this image using a "cover" object-fit value.
The can also have such an object-fit CSS property set on it, but that would mean you'd be drawing many pixels that won't be seen ever.

So instead, you may prefer to set the canvas size to the window's size, and manipulate the call to image() so that it fits correctly.
Ken Fyrstenberg, (a.k.a epistemex) which used to be an SO user already provided the code to do this object-fit "cover" in this Q/A, I am thus reusing it, after simply changing the variable names so they're more readable.

The other change in your code is obviously in the windowResized event handler, which now only calls resizeCanvas with the window's innerWidth and innerHeight.

let img;
const detail = 1;
let particles = [];
let particleImage;
let ctx;
function preload() {
  img = loadImage('https://uploads-ssl.webflow.com/60e7fc673c4aab21388ab7a6/60f1ddf63d26403634b61e99_daniel3.jpg');
}

class Particle {
  constructor (x, y) {
    this.x = x || random(width);
    this.y = y || random(height);
    this.prevX = this.x;
    this.speed = 0;
    this.v = random(0, 0.7);
  }
  
  update (speed) {
    if (grid.length) {
      this.speed = grid[floor(this.y / detail)][floor(this.x / detail)] * 0.97;
    }
    this.x += (1 - this.speed) * 3 + this.v;
    
    if (this.x > width) {
      this.x = 0;
    }
  }
  
  draw () {
    image(particleImage, this.x, this.y);
  }
}

/* ====== STEP 6 ====== */
function goToStep6 () {
  ctx.globalAlpha = 1;
  loop();

  const
    imgWidth = img.width,
    imgHeight = img.height,
    ratio = Math.min(width / imgWidth, height / imgHeight);
  let
    newWidth = imgWidth * ratio,   // new prop. width
    newHeight = imgHeight * ratio,   // new prop. height
    sourceX, sourceY, sourceWidth, sourceHeight,
    aspectRatio = 1;

  // decide which gap to fill    
  if (newWidth < width) {
    aspectRatio = width / newWidth;
  }
  if (Math.abs(aspectRatio - 1) < 1e-14 && newHeight < height) {
    aspectRatio = height / newHeight;
  }
  newWidth *= aspectRatio;
  newHeight *= aspectRatio;

  // calc source rectangle
  sourceWidth = imgWidth / (newWidth / width);
  sourceHeight = imgHeight / (newHeight / height);

  sourceX = (imgWidth - sourceWidth) / 2;
  sourceY = (imgHeight - sourceHeight) / 2;

  // make sure source rectangle is valid
  if (sourceX < 0) sourceX = 0;
  if (sourceY < 0) sourceY = 0;
  if (sourceWidth > imgWidth) sourceWidth = imgWidth;
  if (sourceHeight > imgHeight) sourceHeight = imgHeight;

  // of course P5.js inverted the parameters...
  image(img, 0, 0, width, height, sourceX, sourceY, sourceWidth, sourceHeight);

  loadPixels();
  clear();
  noStroke();
  
  grid = [];
  for (let y = 0; y < height; y+=detail) {
    let row = [];
    for (let x = 0; x < width; x+=detail) {
      const r = pixels[(y * width + x) * 4];
      const g = pixels[(y * width + x) * 4 + 1];
      const b = pixels[(y * width + x) * 4 + 2];
      const _color = color(r, g, b);
      const _brightness = brightness(_color) / 100;
      row.push(_brightness);
    }
    grid.push(row);
  }
  
  particles = [];
  for (let i = 0; i < 3000; i++) {
    particles.push(new Particle(null, (i/3000) * height));
  }
}

function step6 () {
  ctx.globalAlpha = 0.05;
  fill(31,36,67);
  rect(0,0,width,height);
  ctx.globalAlpha = 0.2;
  particles.forEach(p => {
    p.update();
    ctx.globalAlpha = p.speed * 0.3;
    p.draw();
  });
}

function setup () {
  const canvas = createCanvas(100,100);
  ctx = canvas.drawingContext;
  
  pixelDensity(1);
  
  particleImage = createGraphics(8, 8);
  particleImage.fill(255);
  particleImage.noStroke();
  particleImage.circle(4, 4, 4);
  
  windowResized();
  if (window['goToStep' + 6]) {
    window['goToStep' + 6]();
  }
  draw();
  goToStep6();
}

function windowResized () {
  resizeCanvas(window.innerWidth, window.innerHeight);
  noiseSeed(random(100));
  goToStep6();
  draw();
}

function draw () {
  step6();
}
body {
  margin: 0;
  overflow: hidden;
  background:rgba(31,36,67,1);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.0.0/p5.min.js"></script>
Kaiido
  • 123,334
  • 13
  • 219
  • 285
  • wow @Kaiido thanks for the detailed explanation, It works like a champ! I'll review the code side by side to understand the changes :D I don't only want to solve this but understand it as well :) – Eu2019 Jul 17 '21 at 07:25
  • is too hard to place it within a canvas? instead of printing it directly from the javascript? because that way I can place it whenever I want. with absolute positioning within another div. right now is generated at the very bottom of my design. – Eu2019 Jul 18 '21 at 19:48
  • https://github.com/processing/p5.js/wiki/Positioning-your-canvas#relocating-the-canvas – Kaiido Jul 18 '21 at 23:38