Как написать шахматную доску на Larana
Что такое Larana
Larana — это прежде всего философия в разработке графических интерфейсов и только потом фреймворк. И эта философия предполагает наличие нескольких важных компонентов:
- Фреймворк. Управляет всем.
- Layout. Расчитывает положение и размеры элементов на экране.
- Larana Render Queue (lareq). Содержит в себе набор команд для отрисовки.
- Рендерер (Colorana). Принимает очередь и отрисовывает её.
Фреймворк сейчас находится в стадии глубокого переосмысления, но остальные компоненты уже можно использовать в своих проектах. Например, есть библиотека chartography, которая позволяет рисовать графики.
Скоро тут будет ссылка на более подробный текст, но пока можно вдохновиться философией из записи доклада «LaranaJS: Настоящий SSR» на HolyJS Autumn 2024
Как работает очередь
Lareq представляет API для составления очереди команд. Если вы просто разрабатываете какой-то интерфейс, то об этом даже не нужно задумываться. Но если вам нужно сделать что-то на более низком уровне, то такая возможность у вас всё ещё есть — просто составьте очередь самостоятельно.
Этот низкоуровневый доступ полезен, если вы создаёте не классическое веб-приложение, а, например, какую-нибудь игру. Вот пример, где на lareq + colorana была написана имплементация Doom.
Смотрите запись доклада «Larana vs CSS» на HolyJS 2025 spring
Рисуем шахматную доску
Но а мы начнём погружение с чего-то более простого — шахматной доски:
Самый простой сособ сделать это — цикл внутри цикла и отрисовка каждого квадрата по отдельности. Для каждой клетки нам нужно дать три команды:
- Указать цвет.
- Разметить фигуру.
- Закрасить.
Вот как это выглядит в коде:
1const q = new RenderQueue()
2
3for (let i = 0; i < 8; i ++) {
4 for (let j = 0; j < 8; j++) {
5 // Определяем цвет для каждой клетки отдельно
6 q.command.setCtx({ fillStyle: getRectColor(i, j) })
7 q.command.rect(getRectBox(i, j))
8 q.command.fill()
9 }
10}
И вот какая из этого получается очередь:
1[
2 { "c": 25, "o": { "fillStyle": "white" } },
3 { "c": 15, "o": { "x": 64, "y": 64, "w": 64, "h": 64 } },
4 { "c": 9 },
5 // ...
6]
Итого получается 3 × 64 = 192
команды. Кажется, мы можем придумать что-то получше.
Рисуем сначала все белые, потом все чёрные
Мы сократим количество команд, если чутка изменим алгоритм — укажем цвет, разметим все клетки этого цвета, а потом закрасим:
1q.command.setCtx({ fillStyle: LIGHT_CELL_COLOR })
2for (...) {
3 q.command.rect(getRectBox(...))
4}
5q.command.fill()
6
7q.command.setCtx({ fillStyle: DARK_CELL_COLOR })
8for (...) {
9 q.command.rect(getRectBox(...))
10}
11q.command.fill()
С таким подходом мы сократили количество команд почти в 3 раза: (32 + 2) × 2 = 68
. Можем ли мы придумать что-то ещё более эффективное?
Рисуем белый фон, а потом только чёрные
Зачем рисовать отдельно каждую клетку, если можно закрасить один большой квадрат, а потом просто рисовать поверх него?
1// Рисуем фон
2q.command.setCtx({ fillStyle: LIGHT_CELL_COLOR })
3q.command.rect({ x: 0, y: 0, w: WIDTH, h: HEIGHT })
4q.command.fill()
5
6// Рисуем всё остальное
7q.command.setCtx({ fillStyle: DARK_CELL_COLOR })
8q.command.beginPath()
9
10for (let i = 0; i < 8; i++) {
11 for (let j = 0; j < 8; j++) {
12 if (isLight(i, j)) {
13 continue
14 }
15 q.command.rect(getRectBox(i, j))
16 }
17}
18q.command.fill()
Итого: 3 + 3 + 32 = 38
. Сокращение почти в 2 раза по сравнению предыдущим способом.
Можно ли выжать ещё хоть что-то?
В последнем примере мало что можно оптимизировать, но с посленего релиза v.1.1.6 lareq научился вырезать дублирующиеся параметры. Вот как это влияет на каждый из этих способов рисования доски:
Метод | Длина очереди | Размер (КБ) | Сжатая длина | Сжатый размер (КБ) |
Рисуем каждую ячейку отдельно | 192 | 5 505 | 130 | 3 335 |
Рисуем сначала белые, потом чёрные | 68 | 2 839 | 68 | 2 839 |
Рисуем чёрные на белом фоне | 38 | 1 513 | 38 | 1 513 |
Чем меньше значения, тем лучше.
Как видно, на последних двух вариантах алгоритм проигрывает человеческому интеллекту, но это большое обновление для тех, кто не готов оптимизировать свои приложения на более низком уровне.
За написание алгоритма спасибо @iamshvetsov