我目前的程序需要在画布上绘制数万个矩形。这些矩形可以是灰色或红色,具体取决于它们所代表的含义。目前大约需要5秒钟来绘制100.000个这样的矩形,而前面的计算只需要不到100毫秒。很高兴我想优化这个程序的绘图部分,因为我觉得我在这里缺少优化的主要部分。
我目前的绘图代码如下:
function colourRect(i) {
// Those calculations are for the exact coordinates of the squares in the map
ctx.rect(((1 + (i - 1) * 12) - settingsWidth * 12 * parseInt((i - 1) / settingsWidth)), (1 + (parseInt((i - 1 / settingsStart) / settingsWidth) * 12) - (parseInt((settingsStart - 1 / settingsStart) / settingsWidth) * 12)), 10, 10);
}
canvas = document.getElementById("map");
ctx = canvas.getContext("2d");
ctx.beginPath();
var i = 0;
ctx.fillStyle = "#CCC";
while(i <= parseInt(settingsEnd)) {
if($.inArray(i, grey) == -1) { colourRect(i); }
i = i + 1;
}
ctx.closePath();
ctx.fill();
ctx.beginPath();
var i = 0;
ctx.fillStyle = "#900";
while(i <= parseInt(settingsEnd)) {
if($.inArray(i, grey) != -1) { colourRect(i); }
i = i + 1;
}
ctx.closePath();
ctx.fill();
编辑注释:色彩交换校正仅发生两次。 编辑注释2:纠正数组命名中的小错误(只有一个数组,而不是两个数组)
答案 0 :(得分:1)
1)避免改变颜色,这是很好的 2)你不应该反复迭代灰色和红色并测试它们的值对0和settingsEnd ??无论如何,我通过使用排序数组优化了处理 3)如果你将网格简化为一个10像素正方形的简单12像素间隔网格,你可以通过画布为你做数学来简化绘图(翻译+缩放12)。
下面的代码应该更快,注意我只改变了fillStyle的两倍:
function fillRect(i) {
ctx.fillRect(((1 + (i - 1) * 12) - settingsWidth * 12 * Math.floor((i - 1) / settingsWidth)), (1 + (Math.floor((i - 1 / settingsStart) / settingsWidth) * 12) - (Math.floor((settingsStart - 1 / settingsStart) / settingsWidth) * 12)), 10, 10);
}
function drawThings() {
var i = 0, j=0;
settingsEnd = parseInt(settingsEnd);
ctx.fillStyle = "#CCCCCC";
i=0;
if (greyNeedSort) {
grey.sort();
greyNeedSort = false ; }
j=0;
while(i <= settingsEnd) {
while(j<grey.length && grey[j]<i) {j++} // find j, a grey index >= i
if (j<grey.length && grey[j]==i) { fillRect(i); } // draw if found a grey value == i
else (if j== grey.length-1) break; // exit if no more grey available
i++;
}
ctx.fillStyle = "#990000";
i=0;
if (redNeedSort) {
red.sort();
redNeedSort = false; }
j=0;
while(i <= settingsEnd) {
while(j<red.length && red[j]<i) {j++}
if (j<red.length && red[j]==i) { fillRect(i); }
else (if j== grey.length-1) break; // exit if no more red available
i++; }
}
编辑:
1)当问题的代码或其他答案确实经常发生变化时,此代码只进行两次颜色交换。
2)在你的代码中,你按升序绘制所有灰色,所以你甚至可以做得更好:
if (greyNeedSort) {
grey.sort();
greyNeedSort = false ; }
// just iterate :
for (i =0; i<grey.length; i++ ) if (i< settingsEnd) fillRect(i);
(红色相同)。
3)你可以让画布为你做数学运算,你简化了fillRect,它变成了:
function fillRect(i) {
ctx.fillRect(i, i, 0.8, 0.8);
}
您可以通过以下方式更改绘图方法:
function drawThings() {
ctx.save();
ctx.scale(12, 12);
ctx.translate(0.2, 0.2); // top-left margin
/// same code ...
ctx.restore();
}
答案 1 :(得分:0)
优化代码的一些提示:
parseInt
很慢,在大多数情况下,还有其他选择:
Number
或unary operator(+
)转换为数字。|0
)或Math.trunc
的按位OR运算符截断为整数。此外,当您逐步从一个数字迭代到另一个数字时,您可以使用for
循环而不是while
循环。
然后,这应该更快:
canvas = document.getElementById("map");
ctx = canvas.getContext("2d");
var loopEnd = settingsEnd | 0;
ctx.beginPath();
for(var i=0; i <= loopEnd; ++i) {
if(!~grey.indexOf(i)) { colourRect(i, "#CCCCCC"); }
}
ctx.closePath();
ctx.fill();
ctx.beginPath();
for(var i=0; i <= loopEnd; ++i) {
if(~red.indexOf(i)) { colourRect(i, "#990000"); }
}
ctx.closePath();
ctx.fill();