canvas | Строительные пути

canvas | Строительные пути

Объекты, реализующие интерфейс CanvasPath, имеют путь. Путь (path) имеет список из нуля или более подпутей. Каждый подконтур состоит из списка из одной или нескольких точек, соединенных прямыми или сегменты изогнутой линии (curved line segments), и флага, указывающего, является ли подконтур закрытым или нет. Замкнутый подконтур — это тот, в котором последняя точка подконтура соединена с первой точкой подконтура прямой линией. Подконтуры только с одной точкой игнорируются при рисовании пути.

Пути имеют флаг необходимости нового подпути (need new subpath). Когда этот флаг установлен, некоторые API создают новый подпуть, а не расширяют предыдущий. Когда путь создан, необходимо установить флаг необходимости нового подпути.

При создании объекта, реализующего интерфейс CanvasPath, его путь должен быть инициализирован нулевыми подпутями.

 

Для веб-разработчиков (не нормативно)

context.moveTo(xy)

path.moveTo(xy)

Создает новый подпуть с заданной точкой.

context.closePath()

path.closePath()

Отмечает текущий подконтур как закрытый и начинает новый подконтур с точки, совпадающей с началом и концом вновь закрытого подконтура.

context.lineTo(xy)

path.lineTo(xy)

Добавляет заданную точку к текущему подпути, соединенному с предыдущим прямой линией.

context.quadraticCurveTo(cpxcpyxy)

path.quadraticCurveTo(cpxcpyxy)

Добавляет заданную точку к текущему подпути, соединенному с предыдущим квадратичной кривой Безье с заданной контрольной точкой.

context.bezierCurveTo(cp1xcp1ycp2xcp2yxy)

path.bezierCurveTo(cp1xcp1ycp2xcp2yxy)

Добавляет заданную точку к текущему подпути, соединенному с предыдущим кубической кривой Безье с заданными контрольными точками.

context.arcTo(x1y1x2y2radius)

path.arcTo(x1y1x2y2radius)

Добавляет дугу с заданными контрольными точками и радиусом к текущему подконтуру, соединенному с предыдущей точкой прямой линией.

Выдает DOMException «IndexSizeError«, если заданный радиус отрицательный.

arcTo1
arcTo1
arcTo2
arcTo2
arcTo3
arcTo3

 

context.arc(xyradiusstartAngleendAngle [, counterclockwise ])

path.arc(xyradiusstartAngleendAngle [, counterclockwise ])

Добавляет точки к подпути таким образом, что дуга, описанная окружностью окружности, описанной аргументами, начинающаяся с заданного начального угла и заканчивающаяся заданным конечным углом, идущая в заданном направлении (по умолчанию по часовой стрелке), добавляется к путь, соединенный с предыдущей точкой прямой линией.

Выдает DOMException «IndexSizeError«, если заданный радиус отрицательный.

arc1
arc1

context.ellipse(xyradiusXradiusYrotationstartAngleendAngle [, counterclockwise])

path.ellipse(xyradiusXradiusYrotationstartAngleendAngle [, counterclockwise])

Добавляет точки к подпути таким образом, что дуга, описываемая окружностью эллипса, описанного аргументами, начинающаяся с заданного начального угла и заканчивающаяся заданным конечным углом, идущая в заданном направлении (по умолчанию по часовой стрелке), добавляется к путь, соединенный с предыдущей точкой прямой линией.

Выдает DOMException «IndexSizeError«, если заданный радиус отрицательный.

context.rect(xywh)

path.rect(xywh)

Добавляет к пути новый замкнутый подконтур, представляющий заданный прямоугольник.

context.roundRect(xywhradii)

path.roundRect(xywhradii)

Добавляет новый замкнутый подконтур к пути, представляющему заданный прямоугольник со скругленными углами. radii представляет собой список радиусов углов прямоугольника в пикселях. Количество и порядок этих радиусов действуют так же, как свойство CSS ‘border-radius‘.

Если w и h оба больше или равны 0 или оба меньше 0, то путь рисуется по часовой стрелке. В противном случае он рисуется против часовой стрелки.

Когда w отрицательно, скругленный прямоугольник отражается по горизонтали, что означает, что значения радиуса, которые обычно применяются к левым углам, используются справа, и наоборот. Точно так же, когда h отрицательно, закругленный прямоугольник переворачивается по вертикали.

Когда значение r в radii является числом, соответствующие углы рисуются как дуги окружности радиуса r.

Когда значение r в радиусах является объектом со свойствами { x, y }, соответствующие углы рисуются в виде эллиптических дуг, радиусы x и y которых равны r.x и r.y соответственно.

Когда сумма радиусов radii двух углов одного ребра больше длины ребра, все радиусы radii прямоугольника со скругленными углами масштабируются с коэффициентом длины / (r1 + r2). Если этим свойством обладают несколько ребер, используется коэффициент масштабирования ребра с наименьшим коэффициентом масштабирования. Это согласуется с поведением CSS.

Выдает RangeError, если радиусы radii не являются списком размера один, два, три или четыре.

Выдает RangeError, если значение в радиусах radii является отрицательным числом или представляет собой объект { x, y }, чьи свойства x или y являются отрицательными числами.

 

Следующие методы позволяют авторам управлять путями объектов, реализующих интерфейс CanvasPath.

Для объектов, реализующих интерфейсы CanvasDrawPath и CanvasTransform, точки, переданные методам, и результирующие строки, добавленные этими методами к текущему пути по умолчанию, должны быть преобразованы в соответствии с текущей матрицей преобразования перед добавлением к пути.

Метод moveTo(x, y) при вызове должен выполнить следующие шаги:

1. Если любой из аргументов бесконечен или NaN, то возврат.
2. Создайте новый подконтур с указанной точкой в качестве первой (и единственной) точки.

Когда пользовательский агент должен убедиться, что есть подпуть (ensure there is a subpath) для координаты (x, y) на пути, пользовательский агент должен проверить, установлен ли для пути новый флаг подпути. Если это так, то пользовательский агент должен создать новый подпуть с точкой (x, y) в качестве первой (и единственной) точки, как если бы был вызван метод moveTo(), а затем должен отменить установку флага нового подпути пути.

Метод closePath() при вызове не должен ничего делать, если путь к объекту не имеет подпутей. В противном случае он должен пометить последний вложенный путь как закрытый, создать новый вложенный путь, первая точка которого совпадает с первой точкой предыдущего вложенного пути, и, наконец, добавить этот новый вложенный путь в путь.

Примечание

Если последний подпуть имел более одной точки в своем списке точек, то это эквивалентно добавлению прямой линии, соединяющей последнюю точку обратно с первой точкой последнего подпути, таким образом «закрывая» подпуть.

 

Новые точки и соединяющие их линии добавляются к подконтурам описанными ниже способами. Во всех случаях методы изменяют только последний подпуть в пути к объекту.

Метод lineTo(x, y) при вызове должен выполнить следующие шаги:

1. Если любой из аргументов бесконечен или NaN, то возврат.
2. Если путь объекта не имеет подпутей, убедитесь, что есть подпуть для (x, y).
3. В противном случае соедините последнюю точку подконтура с заданной точкой (x, y) прямой линией, а затем добавьте данную точку (x, y) к подконтуру.

Метод quadraticCurveTo(cpx, cpy, x, y) при вызове должен выполнить следующие шаги:

1. Если какой-либо из аргументов бесконечен или NaN, то возврат.
2. Убедитесь, что есть подпуть для (cpx, cpy)
3. Соедините последнюю точку подпути с заданной точкой (x, y), используя квадратичную кривую Безье с контрольной точкой (cpx, cpy). [БЕЗЬЕ]
4. Добавьте заданную точку (x, y) к подпути.

Метод bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) при вызове должен выполнить следующие шаги:

1. Если какой-либо из аргументов бесконечен или NaN, то возврат.
2. Убедитесь, что существует подпуть для (cp1x, cp1y).
3. Соедините последнюю точку подпути с заданной точкой (x, y), используя кубическую кривую Безье с контрольными точками (cp1x, cp1y) и (cp2x, cp2y). [БЕЗЬЕ]
4. Добавьте точку (x, y) к подпути.

 

Метод arcTo(x1, y1, x2, y2, radius) при вызове должен выполнить следующие шаги:

1. Если какой-либо из аргументов бесконечен или NaN, то возврат.

2. Убедитесь, что есть подпуть для (x1, y1).

3. Если радиус radius отрицательный, выдайте DOMException "IndexSizeError".

4. Пусть точка (x0, y0) будет последней точкой подпути, преобразованной обратной матрицей текущего преобразования (так, чтобы она находилась в той же системе координат, что и точки, переданные в метод).

5. Если точка (x0, y0) равна точке (x1, y1), или если точка (x1, y1) равна точке (x2, y2), или если радиус равен нулю, то добавляем точку (x1, y1) к подпути и соедините эту точку с предыдущей точкой (x0, y0) прямой линией.

6. В противном случае, если все точки (x0, y0), (x1, y1) и (x2, y2) лежат на одной прямой, то добавьте точку (x1, y1) к подконтуру и соедините эту точку с предыдущую точку (x0, y0) прямой линией.

7. В противном случае пусть Дуга The Arc будет кратчайшей дугой, заданной окружностью окружности, которая имеет радиус radius и имеет одну точку, касающуюся полубесконечной линии, которая пересекает точку (x0, y0) и заканчивается в точке (x1, y1), и у которого есть другая точка, касающаяся полубесконечной прямой, которая заканчивается в точке (x1, y1) и пересекает точку (x2, y2). Точки, в которых эта окружность касается этих двух линий, называются соответственно начальной и конечной точками касания. Соедините точку (x0, y0) с начальной точкой касания прямой линией, добавив начальную точку касания к подпути, а затем соедините начальную точку касания с конечной точкой касания с помощью Дуги The Arc, добавив конечную точку касания к контуру подпуть.

 

Метод arc(x, y, radius, startAngle, endAngle, counterclockwise) при вызове должен выполнять шаги метода ellipse с this, x, y, radius, radius, 0, startAngle, endAngle и counterclockwise.

Примечание

Это делает его эквивалентным ellipse(), за исключением того, что оба радиуса равны, а вращение равно 0.

Метод ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, counterclockwise) при вызове должен выполнять шаги метода эллипса с this, x, y, radiusX, radiusY, rotation, startAngle, endAngle и counterclockwise.

1. Шаги метода эллипса, заданные canvasPath, x, y, radiusX, радиусY, вращение, startAngle, endAngle и против часовой стрелки:
2. Если какой-либо из аргументов бесконечен или NaN, то возврат.
3. Если radiusX или radiusY отрицательны, то генерируется исключение DOMException «IndexSizeError».
4. Если путь canvasPath имеет какие-либо вложенные пути, добавьте прямую линию от последней точки вложенного пути к начальной точке дуги.

Добавьте начальную и конечную точки дуги к подконтуру и соедините их дугой. Дуга и ее начальная и конечная точки определяются следующим образом:

Рассмотрим эллипс с началом в точке (x, y), радиусом большой оси radiusX и радиусом малой оси radiusY, который повёрнут вокруг своего начала так, что его большая полуось наклонена в радианах вращения rotation по часовой стрелке от ось х.

Если против часовой стрелки counterclockwise ложно и endAngle-startAngle больше или равно 2π, или, если против часовой стрелки counterclockwise верно и startAngle-endAngle равно или больше 2π, то дуга представляет собой всю окружность этого эллипса, а точка в startAngle вдоль окружности этого круга, измеренной в радианах по часовой стрелке от большой полуоси эллипса, действует как начальная точка и конечная точка.

В противном случае точки startAngle и endAngle вдоль окружности этого круга, измеренные в радианах по часовой стрелке от большой полуоси эллипса, являются соответственно начальной и конечной точками, а дуга является путем вдоль окружности этого эллипса от начальной точки до конечная точка, двигаясь против часовой стрелки, если counterclockwise истинно, и по часовой стрелке в противном случае. Поскольку точки находятся на эллипсе, а не просто под углами от нуля, дуга никогда не может охватывать угол, превышающий 2π радиан.
Примечание

Даже если дуга покрывает всю окружность эллипса и на подпути нет других точек, путь не закрывается, пока не будет соответствующим образом вызван метод closePath().

 

Метод rect(x, y, w, h) при вызове должен выполнить следующие шаги:

1. Если какой-либо из аргументов бесконечен или NaN, то возврат.
2. Создайте новый подконтур, содержащий только четыре точки (x, y), (x+w, y), (x+w, y+h), (x, y+h), в указанном порядке, с этими четырьмя соединенными точками. по прямым линиям.
3. Отметьте подпуть как закрытый.
4. Создайте новый подконтур с точкой (x, y) в качестве единственной точки в подконтуре.

 

Метод roundRect(x, y, w, h, radii) при вызове должен выполнить следующие шаги:

1. Если любой из x, y, w или h бесконечен или NaN, то возврат.
2. Если радиусы radii не являются списком размера один, два, три или четыре, выдайте RangeError.
3. Пусть normalizedRadii будет пустым списком.
4. Для каждого радиуса radius из радиусов radii:
  4.1 Если радиус radius является DOMPointInit:
    4.1.1 Если radius["x"] или radius["y"] бесконечен или NaN, возврат.
    4.1.2 Если radius["x"] или radius["y"] отрицательный, выдаётся RangeError.
    4.1.3 В противном случае добавьте радиус radius к normalizedRadii.
  4.2 Если радиус radius является неограниченным двойным unrestricted double:
    4.2.1 Если радиус radius бесконечен или NaN, вернитесь.
    4.2.2 Если радиус radius отрицательный, выдайте RangeError.
    4.2.3 В противном случае добавьте «[ "x" → radius, "y" → radius ]» к normalizedRadii.
5. Пусть upperLeft, upperRight, lowerRight и lowerLeft равны нулю.
6. Если размер normalizedRadii равен 4, установите для upperLeft значение normalizedRadii[0], для upperRight — значение normalizedRadii[1], для lowerRight — значение normalizedRadii[2], а для lowerLeft — значение normalizedRadii[3].
7. Если размер normalizedRadii равен 3, установите для upperLeft значение normalizedRadii[0], для upperRight и lowerLeft — значение normalizedRadii[1], а для lowerRight — значение normalizedRadii[2].
8. Если размер normalizedRadii равен 2, установите для upperLeft и lowerRight значение normalizedRadii[0], а для upperRight и lowerLeft — значение normalizedRadii[1].
9. Если размер normalizedRadii равен 1, установите для upperLeft, upperRight, lowerRight и lowerLeft значение normalizedRadii[0].
10. Угловые кривые не должны перекрываться. Масштабируйте все радиусы, чтобы предотвратить это:
  10.1 Пусть top будет upperLeft["x"] + upperRight["x"].
  10.2 Пусть right будет upperRight["у"] + lowerRight["у"].
  10.3 Пусть bottom будет lowerRight["x"] + lowerLeft["x"].
  10.4 Пусть left будет upperLeft["у"] + lowerLeft["у"].
  10.5 Пусть масштаб scale будет минимальным значением отношений w / top, h / right, w / bottom, h / left.
  10.6 Если масштаб scale меньше 1, задайте для элементов x и y элементов upperLeft, upperRight, lowerLeft и lowerRight их текущие значения, умноженные на масштаб scale.
11. Создайте новый подпуть:
  11.1 Перейти к точке (x + upperLeft["x"], y).
  11.2 Проведите прямую к точке (x + wupperRight["x"], y).
  11.3 Проведите дугу к точке (x + w, y + upperRight["y"]).
  11.4 Проведите прямую линию к точке (x + w, y + hlowerRight["y"]).
  11.5 Проведите дугу к точке (x + wlowerRight["x"], y + h).
  11.6 Проведите прямую линию до точки (x + lowerLeft["x"], y + h).
  11.7 Проведите дугу к точке (x, y + hlowerLeft["y"]).
  11.8 Проведите прямую линию к точке (x, y + upperLeft["y"]).
  11.9 Проведите дугу к точке (x + upperLeft["x"], y).
12. Отметьте подпуть как закрытый.
13. Создайте новый подконтур с точкой (x, y) в качестве единственной точки в подконтуре.

 

Примечание

Это сделано для того, чтобы вести себя аналогично свойству CSS ‘border-radius‘.

 

Информационные ссылки

Стандарт HTML — Раздел «4.12.5.1.5 Building paths» — https://html.spec.whatwg.org/#building-paths