Постепенно закрасить все координаты плоскости с интервалом в 1 секунду
Необходимо закрасить все поле вот таким вот образом, как на изображении (квадрат должен увеличиваться на 3 клетки во все стороны каждую секунду). Проблема в том, что на середине программа начинает тормозить и с каждым новым вызовом функции все медленнее и медленнее работает. Подскажите пожалуйста, как можно оптимизировать программу, чтобы поле заполнялось корректно?
let field = document.getElementById('field')
function addCell(field) {
let coordinates = [], i, j;
for(i = 0; i<50; i++) {
coordinates[i] = new Array()
for (j = 0; j<50; j++){
let cell = document.createElement('div')
cell.setAttribute('class','cell')
cell.setAttribute('x',(i+1).toString())
cell.setAttribute('y',(j+1).toString())
coordinates[i][j] = cell
field.appendChild(cell)
}
} return coordinates
}
let coordinates = addCell(field)
function setBomb(coordinates) {
function getRandomInt(max) {
return Math.floor(Math.random() * max);
}
let x = getRandomInt(coordinates.length)
let y = getRandomInt(coordinates.length)
function setAffected(coordinates, x, y) {
if(coordinates[x][y].getAttribute('class') === 'cell') {
if ((x >= 0) && (x < coordinates.length) && (y >= 0) && (y < coordinates.length)) {
coordinates[x][y].setAttribute('class', 'affected')
}
}else return
}
setAffected(coordinates,x,y)
getCoords(coordinates,x,y)
function getCoords(coordinates,x,y) {
let yright1 = y + 1
let yright2 = y + 2
let yleft1 = y - 1
let yleft2 = y - 2
let xtop1 = x + 1
let xtop2 = x + 2
let xbot1 = x - 1
let xbot2 = x - 2
setAffected(coordinates, x, yright1)
setAffected(coordinates, x, yright2)
setAffected(coordinates, x, yleft1)
setAffected(coordinates, x, yleft2)
setAffected(coordinates, xtop1, y)
setAffected(coordinates, xtop2, y)
setAffected(coordinates, xbot1, y)
setAffected(coordinates, xbot2, y)
setAffected(coordinates, xtop1, yright1)
setAffected(coordinates, xtop1, yright2)
setAffected(coordinates, xtop2, yright1)
setAffected(coordinates, xtop2, yright2)
setAffected(coordinates, xtop1, yleft1)
setAffected(coordinates, xtop1, yleft2)
setAffected(coordinates, xtop2, yleft1)
setAffected(coordinates, xtop2, yleft2)
setAffected(coordinates, xtop1, yright2)
setAffected(coordinates, xbot1, yleft1)
setAffected(coordinates, xbot1, yleft2)
setAffected(coordinates, xbot2, yleft1)
setAffected(coordinates, xbot2, yleft2)
setAffected(coordinates, xbot1, yright1)
setAffected(coordinates, xbot1, yright2)
setAffected(coordinates, xbot2, yright1)
setAffected(coordinates, xbot2, yright2)
function explode(coordinates,xtop1,xtop2,yright2,yleft2){
getCoords(coordinates, xtop2, yright2)
getCoords(coordinates, xtop2, yleft2)
getCoords(coordinates, xbot2, yleft2)
getCoords(coordinates, xbot2, yright2)
}
return setTimeout(explode,1000,coordinates,xtop1,xtop2,yright2,yleft2)
}
}
setBomb(coordinates)
Ответы (1 шт):
Могу только предложить свое решение на canvas. Тут вообще нечему тормозить. Можно решетку перенести на другой слой и тогда рисовать квадраты раз в секунду будет еще менее затратней)))
Пока идет взрыв, закладывать нельзя. Можно это убрать.
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
const w = canvas.width = 400;
const h = canvas.height = 400;
const col_num = 50;
const row_num = 50;
const cell_w = w / col_num;
const cell_h = h / row_num;
is_exploding = false;
drawNet();
canvas.addEventListener('click', setBomb);
function drawNet() {
let net_path = '';
for (let i = 0; i < col_num + 1; i++) {
net_path += `M ${i*cell_w} 0 V ${h} `;
}
for (let i = 0; i < row_num + 1; i++) {
net_path += `M 0 ${i*cell_h} H ${w} `;
}
ctx.stroke(new Path2D(net_path));
}
function explode(c_x, c_y, blow_radius) {
is_exploding = true;
ctx.clearRect(0, 0, w, h);
const x = (c_x - blow_radius) * cell_w;
const y = (c_y - blow_radius) * cell_h;
const blow_w = (blow_radius * 2 + 1) * cell_w;
const blow_h = (blow_radius * 2 + 1) * cell_h;
ctx.save();
ctx.fillStyle = 'red';
ctx.fillRect(x, y, blow_w, blow_h);
ctx.restore();
drawNet();
const max_dist_to_edge = Math.max((c_x - blow_radius),
(col_num - c_x - blow_radius - 1),
(c_y - blow_radius),
(row_num - c_y - blow_radius - 1));
if (max_dist_to_edge > 0) {
blow_radius += 3;
setTimeout(() => explode(c_x, c_y, blow_radius), 1000);
} else {
is_exploding = false;
setTimeout(() => {
ctx.clearRect(0, 0, w, h);
drawNet();
}, 2000);
}
}
function setBomb(e) {
if (!is_exploding) {
const x = e.offsetX;
const y = e.offsetY;
const c_x = Math.floor(x / cell_w);
const c_y = Math.floor(y / cell_h);
explode(c_x, c_y, 1);
}
}
<canvas></canvas>
<p style="position:fixed; right:20px; top:20px">Кликните на клетку<br> для запуска устройства</p>
Увеличил поле и теперь можно взрывать одновременно в нескольких точках, сетку перенес на другой холст. Можете попробовать "загрузить" анимацию, одновременно натыкав десятки взрывов.
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
const w = canvas.width = net.width = 2000;
const h = canvas.height = net.height = 1200;
const col_num = 400;
const row_num = 240;
const cell_w = w / col_num;
const cell_h = h / row_num;
drawNet();
canvas.addEventListener('click', setBomb);
function drawNet() {
let net_path = '';
for (let i = 0; i < col_num + 1; i++) {
net_path += `M ${i*cell_w} 0 V ${h} `;
}
for (let i = 0; i < row_num + 1; i++) {
net_path += `M 0 ${i*cell_h} H ${w} `;
}
net.getContext('2d').stroke(new Path2D(net_path));
}
function explode(c_x, c_y, blow_radius) {
const x = (c_x - blow_radius) * cell_w;
const y = (c_y - blow_radius) * cell_h;
const blow_w = (blow_radius * 2 + 1) * cell_w;
const blow_h = (blow_radius * 2 + 1) * cell_h;
ctx.save();
ctx.fillStyle = 'red';
ctx.fillRect(x, y, blow_w, blow_h);
ctx.restore();
const max_dist_to_edge = Math.max((c_x - blow_radius),
(col_num - c_x - blow_radius - 1),
(c_y - blow_radius),
(row_num - c_y - blow_radius - 1));
if (max_dist_to_edge > 0) {
blow_radius += 3;
setTimeout(() => explode(c_x, c_y, blow_radius), 1000);
}
}
function setBomb(e) {
const x = e.offsetX;
const y = e.offsetY;
const c_x = Math.floor(x / cell_w);
const c_y = Math.floor(y / cell_h);
explode(c_x, c_y, 1);
}
canvas {
position: fixed;
top: 0;
left: 0;
}
#net {
z-index: 1;
pointer-events: none;
}
<canvas></canvas>
<canvas id="net"></canvas>
Или можно добавить еще цвета))
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
const w = canvas.width = net.width = 2000;
const h = canvas.height = net.height = 1200;
const col_num = 400;
const row_num = 240;
const cell_w = w / col_num;
const cell_h = h / row_num;
drawNet();
canvas.addEventListener('click', setBomb);
function drawNet() {
let net_path = '';
for (let i = 0; i < col_num + 1; i++) {
net_path += `M ${i*cell_w} 0 V ${h} `;
}
for (let i = 0; i < row_num + 1; i++) {
net_path += `M 0 ${i*cell_h} H ${w} `;
}
net.getContext('2d').stroke(new Path2D(net_path));
}
function explode(c_x, c_y, blow_radius, color){
const x = (c_x - blow_radius)*cell_w;
const y = (c_y - blow_radius)*cell_h;
const blow_w = (blow_radius*2 + 1)*cell_w;
const blow_h = (blow_radius*2 + 1)*cell_h;
ctx.save();
ctx.fillStyle = color;
ctx.fillRect(x,y,blow_w,blow_h);
ctx.restore();
const max_dist_to_edge = Math.max((c_x - blow_radius),
(col_num - c_x - blow_radius - 1),
(c_y - blow_radius),
(row_num - c_y - blow_radius - 1));
if(max_dist_to_edge > 0){
blow_radius += 10;
setTimeout(() => explode(c_x, c_y, blow_radius, color), 100);
}
}
function setBomb(e){
const x = e.offsetX;
const y = e.offsetY;
const c_x = Math.floor(x/cell_w);
const c_y = Math.floor(y/cell_h);
const random_color = `rgb(${random255()},${random255()},${random255()})`;
explode(c_x,c_y,1,random_color);
}
function random255(){
return Math.floor(Math.random()*256);
}
canvas {
position: fixed;
top: 0;
left: 0;
}
#net {
z-index: 1;
pointer-events: none;
}
<canvas></canvas>
<canvas id="net"></canvas>
