Я недавно поигрался с объектом HTML5 Canvas для проекта (я знаю, что отстал от времени); но мне это нравится, и я подумал, что поделюсь небольшой частью создания сетки с использованием холста. Я использую Vue (и вы тоже должны это делать), но большая часть моего кода - это чистый javascript, поэтому не прекращайте читать, если вы все еще живете в прошлом.
Я также предполагаю, что вы знаете, как использовать элемент HTML5 Canvas; но если вы не заходите на w3schools.com.
Окружающий код
Хорошо, чтобы начать (и я обещаю, что после этого это будет просто чистый JS), шаблон (или HTML с привязанными свойствами ширины и высоты), сценарий (или JS для подачи связанных значений и управления объектом холста) и стиль (или CSS ):
<template>
<canvas class="gridCanvas"
:width="width"
:height="height"
></canvas>
</template>
<script>
export default {
props: [ 'width', 'height' ],
methods: {
drawGrid () {}
},
mounted () {
this.drawGrid()
}
}
</script>
<style scoped>
.gridCanvas {
position: relative !important;
border: lightgrey 1px solid;
border-radius: 5px;
box-shadow: 0 2px 3px rgba(0, 0, 0, 0.2);
}
</style>
Я надеюсь, что разделы ‹template› и ‹style› не требуют пояснений; однако ‹script› также довольно прост. Во Vue это базовая структура компонентов, которые могут использоваться в других компонентах, и весь этот код говорит следующее: Этот компонент имеет два свойства, которые вы можете установить (width и height ); у него есть один метод (drawGrid), который на данный момент пуст; и когда он смонтирован (аналогично onload), он должен запустить этот метод drawGrid…
Логика
Итак, цели следующие: холст с сеткой, у которого есть поля вокруг сетки; можно нарисовать, задав размер квадрата; может быть любой ширины или высоты; и не размывается (объяснено позже)

To draw this, we have the following variable to find: - Square size: s - Padding Left, Right, Top, and Bottom: pL, pR, pT, pB
Итак, если мы начинаем с определения размера квадрата (например, ширины / высоты 28 пикселей), мы уже знаем s (s = 28). Для простоты предположим, что отступ (pL, pR, pT, pB) также имеет ширину в один квадрат / высокий.
drawGrid () {
let ctx = this.$el.getContext('2d')
let s = 28
let pL = s
let pT = s
let pR = s
let pB = s
ctx.strokeStyle = 'lightgrey'
ctx.beginPath()
for (var x = pL; x <= this.width - pR; x += s) {
ctx.moveTo(x, pT)
ctx.lineTo(x, this.height - pB)
}
for (var y = pT; y <= this.height - pB; y += s) {
ctx.moveTo(pL, y)
ctx.lineTo(this.width - pR, y)
}
ctx.stroke()
}
Хорошо, я солгал. Еще одна вещь о Vue. Чтобы объяснить: эта первая строка получает контекст объекта холста из шаблона, но вы также можете просто присвоить холсту идентификатор и использовать document.getElementById (), чтобы сделать то же самое. После этого мы определяем наши переменные, устанавливаем цвет контекстной линии (обводки) холста и сообщаем его beginPath (). Затем мы проходим два цикла рисования линий, которые начинаются и заканчиваются в соответствующих точках заполнения и, наконец, рисуются на холсте с помощью stroke ():

Итак, есть две проблемы: 1) в нижнем ряду указаны дроби (квадратов); и 2) если вы присмотритесь, некоторые линии будут размытыми, а другие четкими.
Итак, дроби ... Проблема здесь в том, что когда мы устанавливаем размер квадрата (s), мы (ошибочно) предполагали, что s будет идеально делиться на ширину и высоту, чтобы дать нам красивое круглое количество квадратов в каждую сторону. Чтобы исправить это, нам нужно провести еще несколько математических расчетов и включить еще четыре переменных; Количество подходящих квадратов и общее заполнение для осей X и Y (nX, nY, pX и pY ):
let s = 28 let nX = Math.floor(this.width / s) - 2 let nY = Math.floor(this.height / s) - 2 let pX = this.width - nX * s let pY = this.height - nY * s let pL = pX / 2 let pR = pX / 2 let pT = pY / 2 let pB = pY / 2
Опять же, s устанавливается нами. Чтобы получить количество подходящих квадратов, мы можем разделить ширину на s и вычесть 2 (чтобы учесть левый и правый «квадраты» заполнения), чтобы получить количество квадратов по горизонтали (nX); и проделайте то же самое с высотой, чтобы получить количество квадратов по вертикали (nY). Эти числа также должны быть целыми, поэтому нам нужно round (), floor () или ceil () результаты. Причина, по которой мы используем floor (), заключается в том, что если мы в конечном итоге увеличиваем количество квадратов, мы рискуем, что сетка станет шире, чем размер холста.
Проблема в том, что, разрешив использовать только целые числа, у нас есть дополнительное пространство для управления, которое было бы дробями квадратов. Мы можем разделить это и добавить к отступу или просто вычислить наши общие отступы по осям X и Y (pX и pY) на общую ширину или высота минус ширина сетки (nX * s) или высота (nY * s ); а затем уменьшите их вдвое на pL, pR и pT, pB соответственно.
Теперь о размытых линиях
Это раздражающая причуда элемента Canvas (и, возможно, рисования в целом), но на самом деле довольно просто, если вы понимаете, как это работает:

Итак, после небольшого прочтения, большинство решений включали добавление 0,5 к пикселям, но не объясняли почему. Однако This place сработал, и вкратце: чтобы включить самый первый пиксель, вам нужна точка на {0,5, 0,5}, а не более интуитивно понятный {1, 1}. Итак, если вы нарисуете вертикальную линию с x = 0,5, вы получите линию из одного пикселя, а если вы используете x = 1, вы фактически получите двухпиксельную линию (включение пикселей в положениях 0,5 и 1,5)… Если это не ясно , посмотрите по этой ссылке аккуратную схему, которая это объясняет (я не буду ее красть).
Для нашего проекта это означает, что наша левая верхняя точка сетки ДОЛЖНА начинаться с координат, оканчивающихся на 0,5, а затем увеличиваться только в целых числах. Чтобы обеспечить это в нашей верхней левой точке, мы изменяем наши pL и pT на целое число, а затем вычитаем 0,5. Я использую Math.ceil (), потому что мы убираем 0,5, так что в итоге стороны выравниваются. Следовательно, pR и pB - это любое оставшееся пространство:
let pL = Math.ceil(pX / 2) - 0.5 let pT = Math.ceil(pY / 2) - 0.5 let pR = this.width - nX * s - pL let pB = this.height - nY * s - pT
Поскольку s уже является целым числом, все линии, проведенные из этой точки, будут заканчиваться на 0,5 и будут красивыми и четкими.
Вывод
Любой хороший программист знает, что дело не в количестве строк кода, а в том, как вы их используете. Хотя создание этой сетки - простая задача, у нее есть несколько подводных камней, которые могут стоить часов возни, чтобы выяснить, в чем проблема. Вы можете ознакомиться с полным кодом здесь, а также увидеть бонусный закомментированный раздел, если вы хотите начать с определения количества квадратов в верхнем ряду (nX) вместо квадрата. размер (s).