javascript - 如何使用固定数量的矩形找出大小(矩形必须是)以将所有矩形放入画布内?
问题描述
语境
我正在创建一个着色像素游戏克隆,使用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}]
所以每个矩形都有x
和y
坐标。为了在屏幕上绘制矩形,我使用这个函数来计算每个“矩形”必须有多大才能适合画布边界:
// 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));
例如width
andheight
可能是800
和600
and the rectSize
might be 30
。rects
这计算了我可以在每个方向上画多少。
这是我绘制初始板的方式:
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
数组中每个矩形的 以适应新的width
and 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
,以便数组中的所有矩形都可以放入新的画布width
和height
. 这甚至可能吗,还是我需要旧rectSize
的才能进行计算?
所以TL;DR:每个矩形 x 有多大,以适合 y 画布中的所有 x 矩形。
非常感谢你!
解决方案
对不起,经过几个小时的努力,终于成功了。我做的计算:
// 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);
这现在完美无缺。
截屏:
推荐阅读
- php - Summernote 代码已将内联 CSS 样式标签写入 [已删除]
- ansible - 使用 parted 输出中的属性
- react-native - 我在渲染元素内使用带有 onPress 功能的地图功能时遇到了一些问题
- node.js - req.body.param 不断获得 undefined 的值
- python - 我想使用 python 列表理解来实现冒泡排序,但它显示为空白
- r - Chromedriver 与 Chrome 更新不兼容
- c# - 将 DB 列值映射到 C# 枚举属性值
- pandas - 循环滚动相关
- java - 在android中关闭应用程序后如何保存复选框的值?
- perl - Perl 无法识别文件夹