В прошлый раз мы сделали генератор лабиринтов на JavaScript и показали результат в консоли браузера. В нём можно было разглядеть лабиринт и найти свободные пути, но такое решение выглядит не очень красиво. Сегодня нарисуем лабиринт красиво — на странице, используя холст и новый скрипт.
Что делаем
У нас уже есть скрипт, который составляет карту лабиринта. Теперь нам нужно нарисовать её на странице, чтобы можно было распечатать и отдать детям или пройти лабиринт самому.
Для этого мы добавим на страницу новый скрипт, который возьмёт готовую карту лабиринта, обработает её и покажет красивый результат в браузере.
Логика нового скрипта будет такой:
- Прописываем все необходимые переменные, которые нам понадобятся.
 - Нарисуем на холсте рамку по периметру — это будет внешняя граница лабиринта.
 - По очереди проходим по карте лабиринта и закрашиваем чёрным те ячейки, которые на карте помечены как стены.
 
Всё это сделаем в новом скрипте drawMaze.js.
Переменные
Чтобы было удобнее управлять всеми параметрами лабиринта из одного места, добавим в этот скрипт переменные, которые отвечают за количество клеток в лабиринте по вертикали и горизонтали. Ещё нам понадобится размер каждой клетки, чтобы знать, какого размера лабиринт у нас будет на экране. Финальный штрих — добавляем внешнюю границу лабиринта и тоже пишем её размер.
Также в этом блоке подключим холст — найдём его по тегу и сразу зададим нужные параметры.
// количество колонок в лабиринте
const columnsSize = 15;
// количество строк в лабиринте
const rowsSize = 15;
// размер клетки в лабиринте
const fieldSize = 7;
 // рамка (внешняя граница лабиринта)
const padding = 10;
// находим холст на странице по имени элемента
const canvas = document.querySelector('canvas');
// создаём переменную, через которую будем работать с холстом
const context = canvas.getContext('2d');
// создаём новую карту лабиринта, которую будем отрисовывать
const map = generateMaze(columnsSize, rowsSize);
Подготавливаем холст
Теперь у нас есть всё, чтобы начать рисовать. Вот что нам нужно сделать на этом этапе:
- Посчитать и установить фактические размеры холста в пикселях.
 - Закрасить весь холст чёрным.
 - Отступить на расстояние рамки от каждого угла и нарисовать белый прямоугольник внутри.
 
У нас получится на холсте чёрная рамка, внутри которой ничего нет. Это нормально — стены мы добавим на следующем шаге.
// рисуем рамку и готовимся к отрисовке лабиринта
function init () {
	// устанавливаем размеры холста
	canvas.width = padding * 2 + columnsSize * fieldSize;
	canvas.height = padding * 2 + rowsSize * fieldSize;
	// цвет заливки
	context.fillStyle = 'black';
	// рисуем прямоугольник на весь холст с координатами левого верхнего и правого нижнего углов
	context.rect(0, 0, canvas.width, canvas.height);
	// закрашиваем его выбранным цветом
	context.fill();
	// делаем белое поле внутри рамки, чтобы потом нарисовать на нём стены
	context.fillStyle = 'white';
	// сообщаем скрипту, что сейчас будем рисовать новую фигуру
	context.beginPath();
	// рисуем прямоугольник, отступив от границ холста на толщину рамки
	context.rect(padding, padding, canvas.width - padding * 2, canvas.height - padding * 2);
	// закрашиваем его белым 
	context.fill();
}
Рисуем стены
Нам осталось нарисовать стены на холсте, постоянно сверяясь с картой лабиринта. Мы будем каждый раз брать новые координаты лабиринта, смотреть, что там лежит, и, если там стена, — рисуем на этом месте чёрную клетку.
Получать значения ячейки из переменной с лабиринтом мы будем тем же способом, что и в прошлый раз: напишем отдельную функцию. Её задачей будет проверить координаты на правильность: если мы запросим значение ячейки с неверными координатами, то у нас программа не остановится, а просто проигнорирует этот запрос.
// получаем значение ячейки из лабиринта
function getField (x, y) {
	// если хотя бы одна из координат не находится в границах карты
	if (x < 0 || x >= columnsSize || y < 0 || y >= rowsSize) {
		// выходим из функции и говорим, что такой ячейки нет
		return null;
	}
	// если дошли досюда, значит, координата верная, и мы возвращаем её значение из карты лабиринта
	return map[y][x];
}
Теперь рисуем стены так: по очереди переберём все координаты карты с лабиринтом и те клетки, которые помечены как стена, на холсте нарисуем чёрными.
// отрисовываем карту
function drawMap () {
	// обрабатываем по очереди все ячейки в каждом столбце и строке
	for (let x = 0; x < columnsSize; x++) {
		for (let y = 0; y < rowsSize; y++) {
			// если на карте лабиринта эта ячейка помечена как стена
			if (getField(x, y) === '▉') {
				// берём чёрный цвет
				context.fillStyle = 'black';
				// начинаем рисовать новую фигуру
				context.beginPath();
				// делаем прямоугольник на месте этой ячейки
				context.rect(padding + x * fieldSize, padding + y * fieldSize, fieldSize, fieldSize);
				// закрашиваем его чёрным
				context.fill();
			}
		}
	}
}
Запускаем скрипт
Для запуска нам нужно добавить вызов функций init() и drawMap() в самый конец файла:
// рисуем рамку и готовимся к отрисовке лабиринта
init();
// рисуем лабиринт
drawMap();
Чтобы скрипт сработал, добавим его в наш исходный HTML-файл:
<!DOCTYPE html>
<html lang="ru">
<head>
	<meta charset="UTF-8">
	<title>Лабиринт</title>
</head>
<body>
	<!-- подготавливаем пустой холст, чтобы работать с ним из скрипта -->
	<canvas></canvas>
	<!-- скрипт, который создаёт лабиринт -->
	<script src="generateMaze.js">	</script>
	<!-- этот скрипт отвечает за отрисовку лабиринта -->
	<script src="drawMaze.js"></script>
</body>
</html>

Посмотреть лабиринт на странице проекта.
// количество колонок в лабиринте
const columnsSize = 51;
// количество строк в лабиринте
const rowsSize = 51;
// размер клетки в лабиринте
const fieldSize = 7;
 // рамка (внешняя граница лабиринта)
const padding = 10;
// находим холст на странице по имени элемента
const canvas = document.querySelector('canvas');
// создаём переменную, через которую будем работать с холстом
const context = canvas.getContext('2d');
// создаём новую карту лабиринта, которую будем отрисовывать
const map = generateMaze(columnsSize, rowsSize);
// рисуем рамку и готовимся к отрисовке лабиринта
function init () {
	// устанавливаем размеры холста
	canvas.width = padding * 2 + columnsSize * fieldSize;
	canvas.height = padding * 2 + rowsSize * fieldSize;
	// цвет заливки
	context.fillStyle = 'black';
	// рисуем прямоугольник на весь холст с координатами левого верхнего и правого нижнего углов
	context.rect(0, 0, canvas.width, canvas.height);
	// закрашиваем его выбранным цветом
	context.fill();
	// делаем белое поле внутри рамки, чтобы потом нарисовать на нём стены
	context.fillStyle = 'white';
	// сообщаем скрипту, что сейчас будем рисовать новую фигуру
	context.beginPath();
	// рисуем прямоугольник, отступив от границ холста на толщину рамки
	context.rect(padding, padding, canvas.width - padding * 2, canvas.height - padding * 2);
	// закрашиваем его белым 
	context.fill();
}
// получаем значение ячейки из лабиринта
function getField (x, y) {
	// если хотя бы одна из координат не находится в границах карты
	if (x < 0 || x >= columnsSize || y < 0 || y >= rowsSize) {
		// выходим из функции и говорим, что такой ячейки нет
		return null;
	}
	// если дошли досюда, значит, координата верная, и мы возвращаем её значение из карты лабиринта
	return map[y][x];
}
// отрисовываем карту
function drawMap () {
	// обрабатываем по очереди все ячейки в каждом столбце и строке
	for (let x = 0; x < columnsSize; x++) {
		for (let y = 0; y < rowsSize; y++) {
			// если на карте лабиринта эта ячейка помечена как стена
			if (getField(x, y) === '▉') {
				// берём чёрный цвет
				context.fillStyle = 'black';
				// начинаем рисовать новую фигуру
				context.beginPath();
				// делаем прямоугольник на месте этой ячейки
				context.rect(padding + x * fieldSize, padding + y * fieldSize, fieldSize, fieldSize);
				// закрашиваем его чёрным
				context.fill();
			}
		}
	}
}
// рисуем рамку и готовимся к отрисовке лабиринта
init();
// рисуем лабиринт
drawMap();
Что дальше
У нашего лабиринта есть две маленькие проблемы:
- Если число клеток по горизонтали и вертикали больше 150, страница грузится очень долго. Всё потому, что у нас только один трактор, который чистит лабиринт.
 - Непонятно, откуда начинать и куда идти, чтобы пройти лабиринт.
 
Исправим эти недочёты в следующей версии. Потом будет ещё одно продолжение этого же проекта.
						

