p5js:如何在调整窗口大小时使随机生成的圆形包装草图/画布响应? [英] p5js: How do I make my randomly generated circle packing sketch/canvas responsive when the window is resized?

查看:127
本文介绍了p5js:如何在调整窗口大小时使随机生成的圆形包装草图/画布响应?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我从一个较窄的尺寸加载窗口并使其变宽时,添加的画布空间是白色的.

When I load the window from a narrow size and make it wider, the added canvas space is white.

画布从窄到宽调整:

当我从较大的窗口加载到较小的尺寸时,画布保持较大的尺寸,而 HTML 和 CSS 元素会做出响应.在第二张图片中,圆应该在黑色矩形的同一点处切掉.

When I load from a larger window to a smaller size, the canvas stays in the larger size, while HTML and CSS elements respond. In the second picture, the circles are supposed to cut off at the same point at the black rectangle.

我认为这是因为圆圈是随机生成的,并且每当页面加载/重新加载时它们的布局都不同.基本上,我必须刷新"新调整大小的画布工作的窗口.顺便说一句,我已经尝试过 WindowResized().*

I think this is happening because the circles are randomly generated and the layout of them is different whenever the page loads/reloads. Basically, I have to "refresh" the window for the new resized canvas to work. BTW, I tried WindowResized() already.*

var font;
var colors;
var bolder;
var canvas;

setup = () => {

    frameRate(2.5);

    function windowResized() {
        resizeCanvas(windowWidth, windowHeight);
    }

    canvas = createCanvas(windowWidth, windowHeight);
    canvas.position(0, 0);
    canvas.style('z-index', '-1');

    colors = [color(255, 0, 0), color(1, 130, 83), color(0, 0, 255), color(255, 255, 0), color(102, 0, 102), color(255, 107, 31)];

    for (var c = 0; c < 1000; c++) {
        var circle = {
            x: random(width),
            y: random(height),
            r: random(90, 15)
        };

        var overlap = false;

        var protection = 0;

        for (var j = 0; j < circles.length; j++) {
            var other = circles[j];
            var d = dist(circle.x, circle.y, other.x, other.y);
            if (d < circle.r + other.r) {
                overlap = true;
            }
        }

        if (!overlap) {
            circles.push(circle);
        }

        protection++;
        if (protection > 10000) {
            break;
        }
    }

    for (var i = 0; i < circles.length; i++) {

        fill(255, 255, 255);
        strokeWeight(4);
        ellipse(circles[i].x, circles[i].y, circles[i].r * 2, circles[i].r * 2);

    }
}

draw = () => {

    for (var i = 0; i < circles.length; i++) {
        if (mouseX > circles[i].x - circles[i].r && mouseX < circles[i].x + circles[i].r && mouseY > circles[i].y - circles[i].r && mouseY < circles[i].y + circles[i].r)

        {
            stroke(0, 0, 0);
            fill(random(colors));
            strokeWeight(4);
            noStroke;
            ellipse(circles[i].x, circles[i].y, circles[i].r * 2, circles[i].r * 2);

        }
    }
}

推荐答案

使用 windowResized() 和 resizeCanvas(),但是你错过了一个关于范围的重要细节:

You are on the right track using windowResized() and resizeCanvas(), however you missed an important detail regarding scope:

  • 在 JavaScript 中,您可以将函数嵌套在函数中:这就是您在代码中定义自定义 windowResized() 函数的方式,仅限于 setup()
  • 您可能打算使用 windowResized() 作为 setup()/draw() 的兄弟,覆盖 p5.js 的默认值:与上面链接的 resizeCanvas 示例相同
  • in JavaScript you can have functions nested within functions: that is how you've defined a custom windowResized() function in your code, local only to setup()
  • you probably meant to use windowResized() as a sibling of setup()/draw(), overriding p5.js's default: same as the resizeCanvas example linked above

第二个被忽视的细节与绘图有关:

The second overlooked detail has to do with drawing:

  • draw() 中,您没有清除画布(使用 background() 或类似的东西),这意味着您希望在 setup() 中绘制圆圈 保持绘制
  • resizeCanvas() 也可以清除画布
  • 您可以将在 setup() 中完成的圆形绘制分组到一个函数中,您可以在 windowResized()
  • 中再次简单地重新调用
  • in draw() you are not clearing the canvas (using background() or something similar) which means you expect the circles drawn in setup() to remain drawn
  • resizeCanvas() might clear the canvas as well
  • you can group the circle drawing done in setup() in a function you can simple re-call again in windowResized()

第三部分,你猜对了,注意代码中的细节:

The thirdpart, you guessed it, attention to details in code:

  • 您已经在顶部定义了 circles,现在您从未将其初始化为空数组:这将导致尝试 circles 的 undefined 错误.push
  • 在调用像 noStroke()
  • 这样的函数时不要忘记 ()
  • 尽量保持你的代码一致:如果你想使用 箭头函数表达式 而不是 function 你可以,但是当它是统一的时,它会更容易阅读/扫描代码.(最终,您将花更多的时间阅读代码而不是编写代码:让未来的自己轻松预测过去的自己编码的内容:)
  • you've defined circles at the top, nowever you've never initialized it to an empty array: this would cause an undefined error trying to circles.push
  • don't forget the () when calling a function like noStroke()
  • try to keep your code consistent: if you want to use arrow functions expressions instead of the function you can, but it would make it easier to read/scan the code when it's uniform. (In the end you'll spend more time reading the code than writing it: make it easy for your future self to easily predict what your past self coded :) )

这是您草图的修改版本,其中包含上述要点:

Here's a modified version of your sketch with the points above addressed:

var font;
var colors;
var bolder;
var canvas;
var circles;

setup = () => {

    frameRate(2.5);

    canvas = createCanvas(windowWidth, windowHeight);
    canvas.position(0, 0);
    canvas.style('z-index', '-1');

    colors = [color(255, 0, 0), color(1, 130, 83), color(0, 0, 255), color(255, 255, 0), color(102, 0, 102), color(255, 107, 31)];
    
    setupCircles();
}
// group circle drawing functionality in a re-usable
setupCircles = () => {
  circles = [];
  for (var c = 0; c < 1000; c++) {
      var circle = {
          x: random(width),
          y: random(height),
          r: random(90, 15)
      };

      var overlap = false;

      var protection = 0;

      for (var j = 0; j < circles.length; j++) {
          var other = circles[j];
          var d = dist(circle.x, circle.y, other.x, other.y);
          if (d < circle.r + other.r) {
              overlap = true;
          }
      }

      if (!overlap) {
          circles.push(circle);
      }

      protection++;
      if (protection > 10000) {
          break;
      }
  }

  for (var i = 0; i < circles.length; i++) {

      fill(255, 255, 255);
      strokeWeight(4);
      ellipse(circles[i].x, circles[i].y, circles[i].r * 2, circles[i].r * 2);

  }
  
  noStroke();
}

windowResized = () => {
    console.log('window resized');
    resizeCanvas(windowWidth, windowHeight, true);
    setupCircles();
}


draw = () => {

    for (var i = 0; i < circles.length; i++) {
        if (mouseX > circles[i].x - circles[i].r && mouseX < circles[i].x + circles[i].r && mouseY > circles[i].y - circles[i].r && mouseY < circles[i].y + circles[i].r)

        {
            stroke(0, 0, 0);
            fill(random(colors));
            strokeWeight(4);
            ellipse(circles[i].x, circles[i].y, circles[i].r * 2, circles[i].r * 2);

        }
    }
}

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

结束语:

我注意到您使用了 noStroke()frameRate(2.5),这让我相信您是关注视觉细节的视觉思考者.如果目的是避免过度绘制锯齿状圆边缘,并且不使用移动设备上的 CPU/电源,您可能会想看看 createGraphics():真的很酷.为了避免在 draw() 中持续渲染,如果您只想在悬停时填充圆圈,您可以使用 mouseMoved()

I've noticed you used noStroke() and frameRate(2.5) which leads me to believe you are visual thinker paying attention to visual details. If the intention is to avoid jagged circle edges from overdrawing and not using as much CPU/power on mobile devices you might want to check out createGraphics(): it's really cool. In terms of avoiding continously rendering in draw() if you simply want to fill circles when they're hovered you can use mouseMoved()

您可以在顶部使用全局图形对象,在 setup() 中填充圆圈,然后在移动鼠标时简单地填充圆圈.

You could use a global graphics object at the top that gets populated with circles in setup() then simply fill circles when the mouse is moved.

此外,您还可以进一步封装:

Additionally you could further encapsulate:

for (var i = 0; i < circles.length; i++) {
        if (mouseX > circles[i].x - circles[i].r && mouseX < circles[i].x + circles[i].r && mouseY > circles[i].y - circles[i].r && mouseY < circles[i].y + circles[i].r)

        {
            stroke(0, 0, 0);
            fill(random(colors));
            strokeWeight(4);
            ellipse(circles[i].x, circles[i].y, circles[i].r * 2, circles[i].r * 2);

        }
    }

类似的东西

isInsideCircle = (circle, x, y) => {
   return (x > circle.x - circle.r && x < circle.x + circle.r ) && (y > circle.y - circle.r && y < circle.y + circle.r);
}

getCircleAt = (circles, x, y) => {
   let numCircles = circles.length;
   for (let i = 0; i < numCircles; i++){
      if(isInsideCircle(circles[i], x, y){
         return circles[i];
      }
   }
}

mouseMoved = () => {
   circle = getCircleAt(circles, mouseX, mouseY);
   if(circle){
      fill(random(colors));
      ellipse(circle.x, circle.y, circle.r * 2, circle.r * 2);
   }
}

注意这是一个未经测试的片段,但希望它能说明所提到的一些想法.

Note this is an untested snippet, but hopefully it illustrated some of the ideas mentioned.

这篇关于p5js:如何在调整窗口大小时使随机生成的圆形包装草图/画布响应?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆