[英]Algorithm for Optimal Square Size in Canvas
I'm looking to create a grid of equally-sized squares whose size are based on the area of the canvas.我希望创建一个大小相等的正方形网格,其大小基于画布的面积。 I'd like the squares to take the maximum area possible in the container.
我希望正方形占据容器中可能的最大面积。
I know I can find the area of the canvas by:我知道我可以通过以下方式找到画布的区域:
area = canvas.width * canvas.height; // e.g. 640x360 = 230400
areaPerSquare = parseInt(area/squareCount); // e.g. with a shape count of 4, 28800
If I divide that by the number of squares, I get a result, but I'm unsure what to do next.如果我将其除以平方数,就会得到结果,但我不确定下一步该怎么做。 Maybe this isn't the way to go about it...
也许这不是解决问题的方法......
Here is where I am with the code.这是我使用代码的地方。 I've brute forced the square size and it works for the first three values, but I'm not able sure how to maximize the size when more squares can be fit in subsequent rows.
我已经强制使用正方形大小,它适用于前三个值,但是当更多正方形可以放入后续行时,我无法确定如何最大化大小。 How can I determine the optimal square size?
如何确定最佳正方形大小? Thank you!
谢谢!
EDIT: There can be empty space as all squares should be the same, maximum size.编辑:可以有空白空间,因为所有方块都应该是相同的,最大尺寸。
var canvas = document.querySelector("#canvas"); var ctx = canvas.getContext("2d"); var squareCountNum = document.querySelector("#squareCount"); var widthNum = document.querySelector("#width"); var heightNum = document.querySelector("#height"); var squareCount = squareCountNum.value; squareCountNum.onchange = function(e) { squareCount = e.target.value; draw(); } widthNum.onchange = function(e) { canvas.width = e.target.value; canvas.style.width = e.target.value + "px"; draw(); } heightNum.onchange = function(e) { canvas.height = e.target.value; canvas.style.height = e.target.value + "px"; draw(); } function draw() { ctx.clearRect(0,0,canvas.width,canvas.height); let area = canvas.width * canvas.height; let areaPerSquare = parseInt(area/squareCount); let size = 100; if (squareCount == 1) { if (canvas.width > canvas.height) { size = canvas.height; } else { size = canvas.width; } } else { if (canvas.width > canvas.height) { size = canvas.width/squareCount; } else { size = canvas.height/squareCount; } } let row = 0; let currentIndex = 0; for (let i=0; i<squareCount; i++) { ctx.beginPath(); if (currentIndex*size+size > canvas.width) { row++; currentIndex = 0; } ctx.rect(currentIndex*size, row*size, size, size); //how do I maximize size? ctx.fillStyle = "#"+Math.floor(Math.random()*16777215).toString(16); ctx.fill(); ctx.closePath(); currentIndex++; } } draw();
#canvas { width: 320px; height: 180px; border: 1px solid rgba(0,0,0,0.2); } #squareCount { margin-bottom: 20px; }
<canvas id="canvas" width="640" height="360"></canvas> <div><label>Square Count</label><input type="number" id="squareCount" value=1></input></div> <div><label>Width</label><input type="number" id="width" value=320></input></div> <div><label>Height</label><input type="number" id="height" value=180></input></div>
Here is an illustration of the desired result of the program with square count values 1-5:这是程序的期望结果的说明,其中平方计数值为 1-5:
Interesting problem, which is more math related than programming related...有趣的问题,与数学相关的比与编程相关的更多......
The crux of the problem is determining the appropriate number of rows and columns of squares that maximize area utilization.问题的关键是确定合适的正方形行数和列数,以最大限度地利用面积。 Towards that end, the algorithm below performs the following steps, using 19 squares in a 100 x 50 region as an example...
为此,下面的算法执行以下步骤,以 100 x 50 区域中的 19 个方块为例......
sqrt( 100 x 50 / 19 )
or 16.222
.sqrt( 100 x 50 / 19 )
或16.222
。 That is, if you could use the total area of 5000, and 19 squares fit perfectly into that area, then the squares will be 16.222 x 16.222 in dimension.100 / 16.222
or 6.1644
times.100 / 16.222
或6.1644
倍。 Thus, the optimal number of possible cols will range from 6 to 7 columns.50 / 16.222
or 3.0822
times for a possible optimal row range of 3 to 4 rows.50 / 16.222
或3.0822
倍。rows * cols
is greater than or equal to the number of squares.rows * cols
数rows * cols
大于或等于平方数。 Eg, 6 * 3
is only 18, so is not a valid option, whereas 6 * 4
, 7 * 3
, and 7 * 4
are all greater than 19, so qualify as candidates.6 * 3
只有 18,因此不是有效选项,而6 * 4
、 7 * 3
和7 * 4
都大于 19,因此有资格作为候选。reduce
function.reduce
函数提取最大区域利用率的方法。 function maximizeSquaresInRegion( squareCount, width, height ) { // // Calculate the maximum possible side of the square, assuming full // use of the area of the region. // let maxSqrSide = Math.sqrt( ( width * height ) / squareCount ); // // Using the maximum possible side of the square, let's determine the // low end and high end number of times it can squeeze into a particular // dimension. // let rowsLo = Math.floor( height / maxSqrSide ); let rowsHi = rowsLo + 1; let colsLo = Math.floor( width / maxSqrSide ); let colsHi = colsLo + 1; // // Okay, now that we have the possible range of number of times that // the square can fit into each dimension, let's loop through the // combinations, finding all that meet the required squareCount and // calculating the area used. // let options = []; for ( let row = rowsLo; row <= rowsHi; row++ ) { for ( let col = colsLo; col <= colsHi; col++ ) { if ( squareCount <= row * col ) { // // First thing, find the minimum length of the side depending // on the fit by width or height. // let squareSideLen = Math.min( width / col, height / row ); let area = Math.min( row * col, squareCount ) * squareSideLen * squareSideLen; options.push( { rows: row, cols: col, side: squareSideLen, area: area } ); } } } return options; } console.log( 'Size: 100 x 50' ); console.log( 'Squares 4: ' ); console.log( maximizeSquaresInRegion( 4, 100, 50) ); console.log( 'Squares 17: ' ); console.log( maximizeSquaresInRegion( 17, 100, 50) ); console.log( 'Squares 19: ' ); console.log( maximizeSquaresInRegion( 19, 100, 50) ); console.log( 'Squares 94: ' ); console.log( maximizeSquaresInRegion( 94, 100, 50) ); console.log( 'Squares 19 Best Fit: ' ); console.log( maximizeSquaresInRegion( 19, 100, 50).reduce(( bf, opt ) => bf.area > opt.area ? bf : opt) );
EDIT : Based on anomaly whereby maximum possible square size fits perfectly into the regions width or height, the resulting range being checked is only one value for that dimension.编辑:基于异常情况,最大可能的正方形大小完全适合区域宽度或高度,所检查的结果范围仅为该尺寸的一个值。 Eg, a region of 320 x 180 with a fit for 9 squares results in a maximum possible square size of 80 x 80, which goes evenly into 320 by 4 times.
例如,适合 9 个正方形的 320 x 180 区域导致最大可能的正方形大小为 80 x 80,它均匀地变成 320 乘以 4 倍。 This results in a range change for the width of only 4 to 4 columns.
这导致仅 4 到 4 列的宽度范围发生变化。 The adjustment to the code makes this check 4 to 5 columns.
对代码的调整使此检查有 4 到 5 列。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.