首页 > 解决方案 > 如何使用固定数量的矩形找出大小(矩形必须是)以将所有矩形放入画布内?

问题描述

语境

我正在创建一个着色像素游戏克隆,使用canvas 我将画布的状态保存在一个如下所示的数组中:

[{\"x\":0,\"y\":0,\"pickedColor\":\"white\",\"colorCode\":null},{\"x\":0,\"y\":1,\"pickedColor\":\"white\",\"colorCode\":null},{\"x\":0,\"y\":2,\"pickedColor\":\"white\",\"colorCode\":null},{\"x\":0,\"y\":3,\"pickedColor\":\"#8bc34a\",\"colorCode\":null},{\"x\":0,\"y\":4,\"pickedColor\":\"#8bc34a\",\"colorCode\":null},{\"x\":0,\"y\":5,\"pickedColor\":\"#8bc34a\",\"colorCode\":null},{\"x\":0,\"y\":6,\"pickedColor\":\"#8bc34a\",\"colorCode\":null},{\"x\":0,\"y\":7,\"pickedColor\":\"#8bc34a\",\"colorCode\":null},{\"x\":0,\"y\":8,\"pickedColor\":\"#8bc34a\",\"colorCode\":null},{\"x\":0,\"y\":9,\"pickedColor\":\"#8bc34a\",\"colorCode\":null},{\"x\":0,\"y\":10,\"pickedColor\":\"#8bc34a\",\"colorCode\":null},{\"x\":0,\"y\":11,\"pickedColor\":\"#8bc34a\",\"colorCode\":null},{\"x\":0,\"y\":12,\"pickedColor\":\"#8bc34a\",\"colorCode\":null},{\"x\":0,\"y\":13,\"pickedColor\":\"white\",\"colorCode\":null},{\"x\":0,\"y\":14,\"pickedColor\":\"white\",\"colorCode\":null},{\"x\":0,\"y\":15,\"pickedColor\":\"white\",\"colorCode\":null},{\"x\":0,\"y\":16,\"pickedColor\":\"white\",\"colorCode\":null},{\"x\":0,\"y\":17,\"pickedColor\":\"white\",\"colorCode\":null},{\"x\":0,\"y\":18,\"pickedColor\":\"white\",\"colorCode\":null},{\"x\":0,\"y\":19,\"pickedColor\":\"white\",\"colorCode\":null},{\"x\":1,\"y\":0,\"pickedColor\":\"white\",\"colorCode\":null},{\"x\":1,\"y\":1,\"pickedColor\":\"white\",\"colorCode\":null},{\"x\":1,\"y\":2,\"pickedColor\":\"white\",\"colorCode\":null},{\"x\":1,\"y\":3,\"pickedColor\":\"white\",\"colorCode\":null},{\"x\":1,\"y\":4,\"pickedColor\":\"white\",\"colorCode\":null},{\"x\":1,\"y\":5,\"pickedColor\":\"white\",\"colorCode\":null},{\"x\":1,\"y\":6,\"pickedColor\":\"white\",\"colorCode\":null},{\"x\":1,\"y\":7,\"pickedColor\":\"white\",\"colorCode\":null},{\"x\":1,\"y\":8,\"pickedColor\":\"white\",\"colorCode\":null},{\"x\":1,\"y\":9,\"pickedColor\":\"white\",\"colorCode\":null},{\"x\":1,\"y\":10,\"pickedColor\":\"white\",\"colorCode\":null},{\"x\":1,\"y\":11,\"pickedColor\":\"white\",\"colorCode\":null},{\"x\":1,\"y\":12,\"pickedColor\":\"#8bc34a\",\"colorCode\":null},{\"x\":1,\"y\":13,\"pickedColor\":\"#8bc34a\",\"colorCode\":null},{\"x\":1,\"y\":14,\"pickedColor\":\"white\",\"colorCode\":null},{\"x\":1,\"y\":15,\"pickedColor\":\"white\",\"colorCode\":null},{\"x\":1,\"y\":16,\"pickedColor\":\"white\",\"colorCode\":null},{\"x\":1,\"y\":17,\"pickedColor\":\"white\",\"colorCode\":null},{\"x\":1,\"y\":18,\"pickedColor\":\"white\",\"colorCode\":null},{\"x\":1,\"y\":19,\"pickedColor\":\"white\",\"colorCode\":null},{\"x\":2,\"y\":0,\"pickedColor\":\"white\",\"colorCode\":null},{\"x\":2,\"y\":1,\"pickedColor\":\"white\",\"colorCode\":null},{\"x\":2,\"y\":2,\"pickedColor\":\"white\",\"colorCode\":null},{\"x\":2,\"y\":3,\"pickedColor\":\"white\",\"colorCode\":null}]

所以每个矩形都有xy坐标。为了在屏幕上绘制矩形,我使用这个函数来计算每个“矩形”必须有多大才能适合画布边界:

// width / height comes from props and rectSize comes from props
const [rectCountX, setRectCountX] = useState(Math.floor(width / rectSize));
const [rectCountY, setRectCountY] = useState(Math.floor(height / rectSize));

例如widthandheight可能是800600and the rectSizemight be 30rects这计算了我可以在每个方向上画多少。

这是我绘制初始板的方式:

const generateDrawingBoard = (ctx) => {
    // Generate an Array of pixels that have all the things we need to redraw

    for (var i = 0; i < rectCountX; i++) {
      for (var j = 0; j < rectCountY; j++) {
        // this is the quint essence whats saved in a huge array. 1000's of these pixels.
        // With the help of this, we can redraw the whole canvas although canvas has not state or save functionality :)
        const pixel = {
          x: i,
          y: j,
          pickedColor: "white",
          // we don't know the color code yet, we generate that afterwards
          colorCode: null,
        };
        updateBoardData(pixel);
        ctx.fillStyle = "white";
        ctx.strokeRect(i * rectSize, j * rectSize, rectSize, rectSize);
      }
    }
  };

这完美无缺。用户绘制画布并将其保存到数据库中。

问题

我有一个pixelArtPreview组件。这将从数据库中获取数据,并且对于每个像素艺术,它将绘制一个矩形,但尺寸较小,因此我可以在页面上放置许多矩形,以向用户呈现像素艺术列表。

因此我需要重新计算rectSize数组中每个矩形的 以适应新的widthand height。这正是我目前正在努力的地方。

所以这是我提到的组件:

import { useEffect, useRef, useState } from "react";
import { drawPixelArtFromState } from "../utils/drawPixelArtFromState";

const PixelArtPreview = ({ pixelArt }) => {
  const canvasRef = useRef(null);
  const [ctx, setCtx] = useState(null);
  const [canvas, setCanvas] = useState(null);

  useEffect(() => {
    const canvas = canvasRef.current;
    // This is where I scale the original size
    // the whole pixelArt comes from the database and looks like this (example data):

    // { pixelArtTitle: "some title", pixelArtWidth: 1234, pixelArtHeight: 1234, pixels: [... (the array I shows above with pixels)]}
    canvas.width = pixelArt.pixelArtWidth * 0.5;
    canvas.height = pixelArt.pixelArtHeight * 0.5;
    setCanvas(canvas);
    const context = canvas.getContext("2d");
    setCtx(context);
  }, []);

  useEffect(() => {
    if (!ctx) return;
    drawPixelArtFromState(pixelArt, ctx);
  }, [pixelArt, ctx]);
  return <canvas className="m-4 border-4" ref={canvasRef} />;
};

export default PixelArtPreview;

但是魔法发生在导入的函数内部drawPixelFromState(pixelArt, ctx)

这就是所说的功能(附注我的学习过程是什么):

export const drawPixelArtFromState = (pixelArt, ctx) => {
  // how much pixels have been saved from the original scale when the art has been created
  const canvasCount= JSON.parse(pixelArt.pixels).length;

  // how many pixels we have on X
  const xCount = JSON.parse(pixelArt.pixels)[canvasCount- 1].x;
  // how many pixels we have on Y
  const yCount = JSON.parse(pixelArt.pixels)[canvasCount- 1].y;

  // total pixles (canvas height * canvas.width with the scale of 0.5 so it matches the canvas from the component before)
  // this should give me all the pixels inside the canvas
  const canvasPixelsCount =
    pixelArt.pixelArtWidth * 0.5 * (pixelArt.pixelArtHeight * 0.5);

  // now i try to find out how big each pixel has to be
  const newRectSize = canvasPixelsCount / canvasCount;

  // this is for example 230 rects which can't be I see only 2 rects on the canvas with that much of a rectSize
  console.log(newRectSize);

  // TODO: Parse it instantly where we fetch it
  JSON.parse(pixelArt.pixels).forEach((pixel) => {
    ctx.fillStyle = "white";
    ctx.strokeRect(
      pixel.x * newRectSize,
      pixel.y * newRectSize,
      newRectSize,
      newRectSize
    );

    ctx.fillStyle = pixel.pickedColor;
    ctx.fillRect(
      pixel.x * newRectSize,
      pixel.y * newRectSize,
      newRectSize,
      newRectSize
    );
  });
};

这是该示例在屏幕上的样子(这些是 4 个单独的画布,可以在灰色边框上看到 - 我希望在小画布内看到整个像素艺术):

在此处输入图像描述

问题:

我需要找出正确的公式来计算新的rectSize,以便数组中的所有矩形都可以放入新的画布widthheight. 这甚至可能吗,还是我需要旧rectSize的才能进行计算?

所以TL;DR:每个矩形 x 有多大,以适合 y 画布中的所有 x 矩形。

非常感谢你!

标签: javascriptmathcanvas

解决方案


对不起,经过几个小时的努力,终于成功了。我做的计算:

// now i try to find out how big each pixel has to be
  const newRectSize = canvasPixelsCount / rectCount;

给我像素的面积。但我只需要它的一侧(因为canvas.fillRect只关心 x 值并关心该区域)。所以我需要它的平方根。

// now i try to find out how big each pixel has to be
  const newRectSize = Math.sqrt(canvasPixelsCount / rectCount);

这现在完美无缺。

截屏:

在此处输入图像描述


推荐阅读