Reprise
Мой проект заключается в создании фона на основе SVG в стиле коврика для резки для инженеров-программистов (ну, я, а не кто-то другой, извините за эгоизм).
Как было сказано в предыдущем сообщении, я собираюсь начать с построения сетки размером 4000px на 2500px с ячейками по 250px в квадрате, ограниченными чуть более толстым прямоугольником. Также, как уже говорилось ранее, я выбрал цвет фона, основанный на жидкости для разметки инженера (#191662) и серый (#777) для линий сетки и обводки.
По окончании каждого этапа я буду публиковать SVG-изображение мата для резки через мой репозиторий на GitHub.
Построение сетки
Самый верхний элемент SVG-файла — это элемент <svg>
. SVG основан на XML и включает ссылку на пространство имен по умолчанию (http://www.w3.org/2000/svg) и номер версии (1.1).
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<!-- Content here. -->
</svg>
Элемент SVG может быть вложен для удобного размещения содержимого. Как уже говорилось ранее, SVG-файлы могут ссылаться на CSS-файлы и даже на файлы JavaScript. Также полезно указать целевую ширину и высоту содержимого в качестве атрибутов элемента SVG
.
<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
width="1400" height="1000">
<link xmlns="http://www.w3.org/1999/xhtml"
rel="stylesheet" type="text/css"
href="cutting-mat.css"/>
<!-- Content here. -->
<script href="cutting-mat.js"></script>
</svg>
Я обнаружил, что просмотр SVG в веб-браузере, таком как Chrome или Edge, особенно полезен, поскольку инструменты разработчика предоставляют доступ к объектной модели документа SVG (DOM), а также стилям, определенным в файле CSS, и коду, предоставляемому файлами JS.
Просмотр приведенного выше примера не покажет ничего особенного, поскольку элемент SVG по умолчанию прозрачный, а файлы CSS и JS, которые у нас сейчас есть, ничего не дают/не делают, поэтому давайте добавим прямоугольный фон, изменив файлы SVG и CSS следующим образом. Мы даже можем использовать пользовательские свойства в CSS.
:root {
--background-colour: #191662;
}
.backdrop {
fill: var(--background-colour);
}
Фон будет иметь форму прямоугольного элемента SVG <rect ... />
, расположенного в начале изображения и имеющего размер, позволяющий заполнить изображение.
<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
width="1400" height="1000">
<link xmlns="http://www.w3.org/1999/xhtml"
rel="stylesheet" type="text/css"
href="cutting-mat.css"/>
<rect x="0" y="0" width="1400" height="1000"
class="backdrop"></rect>
</svg>
Добавление обводки
Далее я хочу добавить обводку в правом нижнем углу с помощью элемента <text .../>
. По умолчанию текстовые элементы располагаются в левом нижнем углу блока, содержащего текст. Это можно изменить с помощью атрибута text-anchor
(или свойства CSS), чтобы текст располагался по центру блока или справа, как показано ниже.
.byline {
fill: var(--byline-colour);
font-size: 1.5rem;
text-anchor: end;
}
Мы также добавили еще один цвет к :root
и применили его к свойству/атрибуту fill элемента text. Также обратите внимание, что мы задали размер шрифта 1,5rem, а поскольку корневой элемент использует размер шрифта по умолчанию 16px, это обеспечит текст размером 24px. Теперь мы можем добавить текстовый элемент в SVG следующим образом.
<text x="1380" y="980"
class="byline">Created by T-G Gilmore, 2022, using hand-written SVG, CSS and JavaScript</text>
Далее я хочу добавить HTML-ссылку на лицензию creative-commons в левом нижнем углу, что можно сделать с помощью элемента foreignObject
для вставки HTML в SVG.
<foreignObject x="20" y="948" width="106" height="38">
<a xmlns="http://www.w3.org/1999/xhtml" rel="license"
href="http://creativecommons.org/licenses/by-nc-sa/4.0/">
<img alt="Creative Commons Licence"
src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" />
</a>
</foreignObject>
Время создать сетку
Мы добавим сетку в SVG-элемент, содержащийся внутри SVG-элемента всего документа, чтобы мы могли одновременно изменять размер и положение всего связанного содержимого.
<svg x="60" y="60" width="1280" height="800" id="grid">
<g>
<!-- Horizontal and vertical lines inserted here -->
</g>
<g>
<rect x="0" y="0" width="1280" height="800" class="border">
</rect>
</g>
</svg>
Содержащий SVG элемент имеет атрибут id
, используемый JavaScript для определения местоположения элемента в DOM. Другие четыре атрибута x, y, width, height
управляют положением и размером контейнера. Обратите внимание, что ширина составляет 1280px, что меньше, чем у всего SVG, и он позиционируется на 60px от левой стороны. Он также расположен на 60px сверху и имеет высоту 800px. Также обратите внимание на соотношение ширины и высоты, 1280:800 при делении на 80px дает 16:10, к которому я стремился в предыдущем сообщении.
Обратите внимание, что элемент SVG содержит два групповых элемента <g>
. Первая группа изначально содержит комментарий, но вскоре мы добавим JavaScript для создания горизонтальных и вертикальных линий сетки.
Второй элемент группы содержит элемент прямоугольника, который ограничивает линии. Прямоугольник (элемент rect
) имеет атрибут class, который мы будем использовать для стилизации границы и линий следующим образом.
#grid rect {
stroke: var(--grid-colour);
stroke-width: 3;
fill: transparent;
}
#grid line {
stroke: var(--grid-colour);
}
Как и HTML, SVG имеет порядок расположения элементов, который проще всего применить через порядок появления элементов в документе. Если поместить прямоугольник во вторую группу, он появится поверх линий сетки.
Мы добавим пользовательское свойство --grid-colour
к :root
со значением #777
, которое является средне-серым. Теперь о JavaScript, мы включаем следующие функции в файл ‘cutting-mat.js’.
(function () {
drawGrid();
// :
})();
function drawGrid() {
const gridSize = 40;
const grid = document.querySelector('#grid g');
function repeatFn(occurrence, fn) {
[...'*'.repeat(occurrence)].forEach(fn);
}
function drawLine(x1, y1, x2, y2, dash) {
return `<line x1="${x1}" y1="${y1}" x2="${x2
}" y2="${y2}" stroke-dasharray="4,${dash * 4}"></line>`;
}
repeatFn(16 * 2, (_, index) => {
const vert = gridSize * index;
grid.innerHTML += drawLine(vert, 0, vert, 800, index % 2);
});
repeatFn(10 * 2, (_, index) => {
const horiz = gridSize * index;
grid.innerHTML += drawLine(0, horiz, 1280, horiz, index % 2);
});
}
Я хочу, чтобы сетка была сформирована из чередующихся пунктирных и сплошных линий с интервалом в 40px (gridSize), все они вводятся в первую группу элемента #grid (сетка). Чтобы помочь повторить рисование линий, я создал вспомогательную функцию repeatFn
, которая принимает два параметра ‘occurrence’ и ‘fn’.
- occurrence: указывает, сколько раз должна быть выполнена функция.
- fn: является функцией, которая должна быть вызвана.
Другая вспомогательная функция drawLine
создает инструкцию SVG для заполнения SVG line
. Используя функцию repeatFn, мы вызываем drawLine 32 раза для вертикалей и 20 раз для горизонталей — все с помощью функции drawLine.
Почти закончили с сеткой
На этом все, но есть небольшая проблема. Согласно CSS, прямоугольник должен иметь ширину линии 3px. Но если вы следили за развитием событий, то заметите, что прямоугольник не выглядит таким толстым. Причина в том, что одна треть ширины выходит за границы контейнера SVG. Мы можем решить эту проблему путем;
- расширить SVG на несколько пикселей (4px в обоих направлениях) и
- сместить содержимое элемента SVG на -2px в обоих направлениях.
Для этого сначала увеличим ширину и высоту SVG-элемента и сместим его на -2px следующим образом.
<svg x="58" y="58" width="1284" height="804" id="grid">
Далее мы должны изменить систему координат внутри SVG-элемента, чтобы сместить все с помощью атрибута viewBox
, который состоит из четырех числовых значений. Первые два значения — это ‘x’ и ‘y’, которые мы будем смещать влево и вверх на 1px. Последние два значения — ширина и высота, которые останутся неизменными по сравнению с размером элемента svg
.
<svg x="58" y="58" width="1284" height="804"
viewBox="-2 -2 1284 804" id="grid">
И вот как это выглядит на данный момент:
В следующем посте мы будем рендерить разрешения экрана, как описано в моем первоначальном посте.