Trying to create x number of random rectangles by iterating through loop - but no overlapping

前端 未结 2 1186
无人及你
无人及你 2021-01-20 18:00

This one has be me stumped. This is more of a Math/logic issue then a specific JS issue, but it\'s JS that I am working in and and some point I will need to convert the resu

2条回答
  •  陌清茗
    陌清茗 (楼主)
    2021-01-20 18:28

    The answer from @g23 is the basis of this, but I wanted to post the end result I came up with in case anyone wants a complete working system for this dilema.

    The end result works by creating a box on the canvas where the user clicks then making 4 boxes around it. Those 4 boxes then use @g23 's original answer to divide it randomly into smaller boxes. The Box in the middle is the solution to having the very 1st divide line cut through the whole image and therefor make it look like two randomly divided boxes that just been stuck side by side. With this new system there will never be a line that cuts all the way across the canvas. I also added a Save button to download the result as well as sliders to control all of the settings and dimensions:

    Working Fiddle here

    var ImageWidth = 960
    var ImageHeight = 540
    
    var direction1 = "x";
    var direction2 = "y";
    var vert = true;
    
    var LargeVerticalBoxes = parseInt(document.getElementById("lvb").value);
    var inner = parseInt(document.getElementById("inner").value);
    var smallest = parseInt(document.getElementById("smallest").value);
    var totalboxes = "";
    
    var clickBoxWidth = 200;
    var clickBoxHeight = 100;
    var lineWidth = 5;
    
    var clickBox_xStart = 0;
    var clickBox_yStart = 0;
    
    var minSize = 0.1
    var maxSize = 0.9
    
    var canvas = document.getElementById('myCanvas');
    var ctx = canvas.getContext('2d');
    
    
    ctx.canvas.width = ImageWidth;
    ctx.canvas.height = ImageHeight;
    
    updateSettings();
    canvas.addEventListener('click', function(evt) {
      var mousePos = getMousePos(canvas, evt);
      //console.log(mousePos.x + ',' + mousePos.y);
    
      clearCanvas();
      ctx.beginPath();
      calcclickBox(mousePos.x, mousePos.y)
      ctx.rect(clickBox_xStart, clickBox_yStart, clickBoxWidth, clickBoxHeight);
      ctx.lineWidth = lineWidth;
      ctx.strokeStyle = 'black';
      ctx.stroke();
    
      ctx.closePath();
      reDraw();
    }, false);
    
    
    download_img = function(el) {
      var image = canvas.toDataURL("image/png");
      el.href = image;
    };
    
    
    function updateSettings() {
      lineWidth = parseInt(document.getElementById("linewidth").value,10);
      clickBoxWidth = parseInt(document.getElementById("boxWidth").value,10);
      clickBoxHeight = parseInt(document.getElementById("boxHeight").value,10);
      canvas.width = parseInt(document.getElementById("canWidth").value,10);
      canvas.height = parseInt(document.getElementById("canHeight").value,10);
      document.getElementById("dispW").innerText = "Width: " + canvas.width;
      document.getElementById("dispH").innerText = "Height: " + canvas.height;
      document.getElementById("canW").innerText = "Width: " + clickBoxWidth;
      document.getElementById("canH").innerText = "Height: " + clickBoxHeight;
    }
    
    
    function clearCanvas() {
      ctx.clearRect(0, 0, canvas.width, canvas.height);
    }
    
    
    function calcclickBox(x, y) {
      clickBox_xStart = x - clickBoxWidth / 2;
      clickBox_yStart = y - clickBoxHeight / 2;
      clickBoxWidth = clickBoxWidth;
      clickBoxHeight = clickBoxHeight;
    }
    
    
    
    function getMousePos(canvas, evt) {
      var rect = canvas.getBoundingClientRect();
      return {
        x: evt.clientX - rect.left,
        y: evt.clientY - rect.top
      };
    }
    
    function toggle() {
      vert = !vert;
      if (vert) {
        direction1 = "x";
        direction2 = "y";
      } else {
        direction1 = "y";
        direction2 = "x";
      }
    }
    
    function getTotal() {
      LargeVerticalBoxes = parseInt(document.getElementById("lvb").value);
      inner = parseInt(document.getElementById("inner").value);
      smallest = parseInt(document.getElementById("smallest").value);
      totalboxes = LargeVerticalBoxes * inner * smallest * 4 + 1
      document.getElementById("total").innerText = totalboxes
    }
    
    
    function getRandomArbitrary(min, max) {
      return Math.random() * (max - min) + min;
    }
    
    
    /////// big long function that does most of the work //////////
    function reDraw() {
    
      getTotal();
    
      // probably play around with this to get better splitting
      // maybe split near a mouse click
      let splitDimension = (l, n) => {
        let splits = [];
        let remaining = l;
        let x = 0;
        for (let i = 0; i < n - 1; i++) {
          let r = Math.random();
          let seg = remaining * (1 / n);
          let s = seg + 0.75 * (0.5 - r) * seg
          splits.push([x, s]);
          x += s;
          remaining -= s;
        }
        // add the last bit
        splits.push([x, remaining])
        return splits;
      };
      // the main idea
      class Box {
        constructor(x, y, w, h) {
          this.x = x;
          this.y = y;
          this.w = w;
          this.h = h;
          this.boxes = [];
    
        }
    
    
    
        draw(ctx) {
          ctx.beginPath();
          ctx.rect(this.x, this.y, this.w, this.h);
          ctx.stroke();
          this.boxes.forEach(box => {
            box.draw(ctx)
          });
        }
    
        addBoxes(n, dim) {
          let splits;
          if (dim == "x") {
            // split on width
            splits = splitDimension(this.w, n)
            // turn the splits into new boxes
            this.boxes = splits.map(([x, w]) => {
              return new Box(this.x + x, this.y, w, this.h)
            });
          } else {
            // split over height
            splits = splitDimension(this.h, n);
            // turn the splits into new boxes
            this.boxes = splits.map(([y, h]) => {
              return new Box(this.x, this.y + y, this.w, h);
            })
          }
        }
      }
    
    
      // let's make some boxes!
      let TopRightBox = new Box(clickBox_xStart,
        clickBox_yStart,
        canvas.width - clickBox_xStart,
        -clickBox_yStart);
    
      let BottomRight = new Box(clickBox_xStart + clickBoxWidth,
        clickBox_yStart,
        canvas.width - clickBox_xStart - clickBoxWidth,
        canvas.height - clickBox_yStart);
    
      let BottomLeft = new Box(clickBox_xStart + clickBoxWidth,
        clickBox_yStart + clickBoxHeight,
        -clickBox_xStart - clickBoxWidth,
        canvas.height - clickBox_yStart - clickBoxHeight);
    
      let TopLeft = new Box(0, 0, clickBox_xStart, clickBox_yStart + clickBoxHeight);
      TopRightBox.addBoxes(LargeVerticalBoxes, direction1);
      BottomRight.addBoxes(LargeVerticalBoxes, direction1);
      BottomLeft.addBoxes(LargeVerticalBoxes, direction1);
      TopLeft.addBoxes(LargeVerticalBoxes, direction1);
    
      // now add boxes on boxes on boxes
      TopRightBox.boxes.forEach(box => {
        box.addBoxes(inner, direction2);
    
        // also more boxes
        box.boxes.forEach(boxBox => {
          boxBox.addBoxes(smallest, direction1);
        });
      });
      BottomRight.boxes.forEach(box => {
        box.addBoxes(inner, direction2);
    
        // also more boxes
        box.boxes.forEach(boxBox => {
          boxBox.addBoxes(smallest, direction1);
        });
      });
    
      BottomLeft.boxes.forEach(box => {
        box.addBoxes(inner, direction2);
    
        // also more boxes
        box.boxes.forEach(boxBox => {
          boxBox.addBoxes(smallest, direction1);
        });
      });
      TopLeft.boxes.forEach(box => {
        box.addBoxes(inner, direction2);
    
        // also more boxes
        box.boxes.forEach(boxBox => {
          boxBox.addBoxes(smallest, direction1);
        });
      });
    
    
      // now draw the boxes!
      TopRightBox.draw(ctx);
      BottomRight.draw(ctx);
      BottomLeft.draw(ctx);
      TopLeft.draw(ctx);
      document.getElementById("total").innerText = totalboxes
    }
    
    
    
    
    
    click on the canvas to create start box and draw new layout
    Canvas:
    Width:
    Height:
    Start Box:
    Width:
    Height:
    Line Width: (changing these settings breaks stuff)

    Large Vertical Boxes:

    Medium inner Boxes:

    Smallest inner Boxes:

    toggle horizontal/vertical

    Total number of boxes:







提交回复
热议问题