Delta.Drawable — абстрактный класс, от которого наследуются все рисуемые объекты: Rect, Circle, Path, Image, Text, а также кастомные объекты (созданные через ctx.object).
Здесь перечислены их общие методы, а также некоторые другие общие особенности.
Любой объект можно создать двумя способами — передавая список аргументов или же объект с параметрами.
В первом случае первыми передаются параметры самого объекта, затем заливка и обводка (fill и stroke). Вместо заливки или обводки можно указать null или undefined.
// квадрат с заливкой и обводкой
ctx.rect(10, 10, 200, 200, 'black', '2px black round');
// квадрат без заливки с обводкой
ctx.rect(200, 200, 30, 30, null, '5pt green');
// квадрат без всего:
ctx.rect(10, 10, 10, 10, null, null);
// или:
ctx.rect(10, 10, 10, 10);
Во втором случае можно дополнительно передать свойства opacity, composite, clip, visible, interaction:
ctx.rect({
x: 10,
y: 10,
width: 200,
height: 200,
fill: 'black',
opacity: 0.8,
composite: 'xor'
});
Можно создавать объекты без заливки и обводки, либо со свойством visible в false: они будут невидимы, но при этом будут реагировать на события мыши (отключается через obj.attr('interaction', false)). Подобным образом можно создавать кликабельные области.
Везде в качестве координат можно указывать CSS-координаты:
var rect = ctx.rect('10pt', '10pt', '0.5em' '1em');
rect.attr('width', '1vw');
По умолчанию передаваемые числа считаются пикселями:
ctx.rect(10, 10, 10, 10);
// работает как
ctx.rect('10px', '10px', '10px', '10px');
Регулируется свойством Delta.defaultDistance (меняйте его до рисования!). По умолчанию равно px.
// внутри дельты всё всегда хранится в пикселях, но конвертится обратно внутри геттера attr
// return this.attrs.x / Delta.units[Delta.defaultDistance];
Кроме того, все переданные величины конвертируются в defaultDistance и возвращаются в таком виде.
// Delta.defaultDistance = 'px'
rect.attr('x', '20pt');
rect.attr('x'); // -> 26.6562 (20pt in pixels)
Многие CSS-координаты (pt, em и ряд других) независимы от разрешения экрана, что решает проблемы с Ретиной и не только.
Содержит стили, которые устанавливаются 2D-контексту перед рисованием. При изменении нужно вызвать метод update().
rect.styles.fillStyle = 'blue';
rect.update();
Работает только в canvas-рендере.
Практически все параметры следуют "jQuery-way": вместо 2 функций getAttr и setAttr здесь присутствует одна функция attr, которая ведёт себя по-разному в зависимости от аргументов. Отказ от традиционных свойств объекта (shape.fill = 'red') связан с тем, что изменение любого свойства вызывает перерисовку контекста, в традиционных свойствах это возможно только через геттеры / сеттеры ES5.
Также использование методов вместо свойств позволяет использовать чеининг:
shape.attr('fill', 'red')
.attr('stroke', 'blue 2px')
.on('click', 'fill', 'blue')
.rotate(45);
Возвращает значение параметра property.
var rect = ctx.rect({
x: 10,
y: 15,
width: 40,
height: 40
});
rect.attr('x'); // -> 10
Устанавливает значение параметра property в value.
rect.attr('x', 200);
Метод attr также позволяет получать и устанавливать свои собственные параметры.
Можно добавлять геттеры и сеттеры (и аниматоры) в Delta.Drawable.prototype.attrHooks. Этот объект является прототипом для attrHooks в наследниках класса Drawable (например, Delta.Rect), поэтому его изменение затронет также attrHooks дочерних классов. Подробнее — в Custom Objects.
Удаляет объект с контекста (но не из памяти, так что остаётся возможность добавить его туда вновь методом ctx.push).
Клонирует объект. Можно клонировать не полностью — например, оставить на два объекта один объект стилей (тогда при изменении стилей одного из объектов будет меняться и второй).
cloneAttrs — параметры.cloneStyles — стили (и трансформации).cloneEvents — события.По умолчанию все равны true (клонировать всё).
Возвращает boundbox объекта. transform = true, 'tight' or false around = 'fill', 'stroke', 'strokeExclude'
Возвращает точку boundbox объекта по её имени. Например:
var aabb = elem.bounds();
elem.corner('top left');
// вернёт [aabb.x1, aabb.y1]
elem.corner('center');
// вернёт [aabb.cx, aabb.cy]
elem.corner('right bottom');
// вернёт [aabb.x2, aabb.y2]
Все возможные точки:
left - центр левой стороны.right - центр правой стороны.top - центр верхней стороны.bottom - центр нижней стороны.left top, top left, lt, tl - верхний левый угол.left bottom, bottom left, lb, bl - нижний левый.right top, top right, rt, tr - верхний правый.right bottom, bottom right, rb, br - нижний правый.// todo: eventHooks
Добавляет объекту обработчик события.
rect.on('click', function(event){
this.attr('fill', 'blue');
});
В this обработчика — сам объект.
Как и в случае событий контекста, в event есть дополнительные свойства targetObject, contextX, contextY.
Также поддерживаются быстрые вызовы:
rect.on('click', 'remove');
// работает как
rect.on('click', function(){
this.remove();
})
rect.on('click', 'attr', 'fill', 'blue');
// работает как
rect.on('click', function(){
this.attr('fill', 'blue');
})
Если передано 2 параметра, убирает func как обработчик события event.
Если передан 1 параметр — убирает все обработчики события event.
rect.on('click', onContextClick);
function onContextClick(event){
console.log('Hello, Delta!');
rect.off('click', onContextClick);
// если вызвать rect.off('click'), удалятся вообще все обработчики кликов
}
Запускает все установленные обработчики события event, передавая в обработчик data.
rect.on('someCustomEvent', function(data){
console.log(data.text);
});
rect.fire('someCustomEvent', {
text: 'anytext'
});
Рисует объект на канвасе в памяти и возвращает картинку в формате Data:URL.
var rect = ctx.rect(10, 10, 200, 200, 'blue');
var image = rect.toDataURL();
window.open(image);
Первым аргументом можно передать формат (по умолчанию png), вторым качество (число между 0 и 1, по умолчанию 1).
rect.toDataURL('png', 0.9);
rect.toDataURL('image/jpeg'); // можно передать mimeType
Третьим аргументом можно передать произвольный boundbox для картинки.
Рисует объект и возвращает как canvas imageData. Можно передать произвольный boundbox.
// canvas.toBlob(callback, type, quality)
^ эти 3 метода должны быть у Context
Добавляет вместо объекта картинку из toDataURL()
Возвращает объект как JSON.
ctx.rect(10, 10, 200, 200, 'red').serialize(); // -> {}
Если параметр quickCalls = true, сохраняет также обработчики событий, которые добавлены с помощью быстрых вызовов.
rect.mouseover('attr', 'fill', 'red').
.mouseout('attr', 'fill', 'blue');
rect.serialize(); // -> {}
// если добавить к quickCalls ещё и возможность добавлять контекст, получится совсем мощно // при добавлении quickCall через on нужно просто где-нибудь дописывать там "listener.serializeString = '...';" К слову, при быстрых вызовах исключена возможность XSS.
Меняются методом attr.
Поддерживаются -1 / +1 мб?.. Но зачем? Лучше полную поддержку стека объектов.
fillRule мб в плагинах для path. nonzero / evenodd
Поддерживается css-like запись:
rect.attr('stroke', '10px blue round');
А также можно передать параметры объектом:
rect.attr('stroke', {
color: 'black'
}]);
Примечание: уже установленные свойства не обнуляются при записи других свойств.
rect.attr('stroke', 'blue');
rect.attr('stroke', '5px');
// работает как
rect.attr('stroke', 'blue 5px');
Возможные параметры:
width) — 2px, 0.5em, 8 и т.п.color) — #f00, green, rgb(0,0,0) и т.п.join) — miter, bevel, round.cap) — butt, square, round.dash) — [1,2,2], shortdash, shortdot, shortdashdot, shortdashdotdot, dot, dash, longdash, dashdot, longdashdot, longdashdotdot.miterLimit) — ml2px, ml8 и т.п.Также в css-like записи можно передать прозрачность (десятичная дробь меньше 1), в этом случае цвет переведётся в RGB. Пример:
rect.attr('stroke', '5px green .5');
// эквивалентно записи
rect.attr('stroke', '5px rgba(0, 128, 0, 0.5)');
В не-css записи можно передать в color градиент или паттерн:
// тут пример
Можно сбросить все параметры и убрать обводку вовсе, приравняв к null:
rect.attr('stroke', null);
Тень. Можно передать объект с параметрами:
shape.attr('shadow', {
x: 0,
y: 5,
blur: 5,
color: 'black',
opacity: 0.5
});
Можно передавать в CSS-форме (x y blur color):
shape.attr('shadow', '0 2px 2px red');
Можно сбросить, приравняв к null:
rect.attr('shadow', null);
Прозрачность (число от 0 до 1).
Функция наложения объектов друг на друга. Варианты: source-over, source-atop, source-in, source-out, destination-over, destination-atop, destination-in, destination-out, lighter, darker, copy, xor.
Некоторые браузеры поддерживают немного больше: normal, multiply, screen, overlay, darken, lighten, color-dodge, color-burn, hard-light, soft-light, difference, exclusion, hue, saturation, color, luminosity.
Стандарт: http://dev.w3.org/fxtf/compositing-1
MDN: http://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Compositing
Если установить в false, объект перестанет отрисовываться.
Если установить в false, объект перестанет реагировать на события мыши.
Курсор на объекте. Любые значения css-свойства cursor.
Чтобы отключить, установить в null.
strict для attrs + rotatePivot, scalePivot, etc
и free для функций
// не просто атрибуты сбрасывают всё, что сделано обычными функциями
https://habrahabr.ru/post/278597/
http://labs.hyperandroid.com/static/CAAT-Samples/demos/demo7/anchors.html для размышлений
Можно использовать краткую форму для on и fire:
ctx.click(function(){ console.log(3); });
// работает как ctx.on('click', function(){ console.log(3); });
ctx.click();
// работает как ctx.fire('click');
Все возможные алиасы:
clickdblclickmousedownmouseupmousemovemouseovermouseoutmouseentermouseleavemousewheelfocusblurkeypresskeydownkeyuptouchstarttouchmovetouchendtouchcancelpointeroverpointerenterpointerdownpointermovepointeruppointercancelpointeroutpointerleavegotpointercapturelostpointercaptureЗаливка объекта:
rect.fill('red');
rect.fill(); // -> 'red'
Объект со свойством colors воспринимается как градиент:
rect.fill({
colors:['red', 'green', 'black'],
from: 'top',
to: 'bottom'
});
Если передаётся объект со свойством image, картинка (обычный dom-элемент img или объект Image), или же строка, начинающаяся с http://, ./, ../ или data, это понимается как текстура.
rect.fill('./image.jpg');
При этом создаётся объект Gradient или Pattern, который можно дальше изменять:
rect.fill({
colors: ['white', 'black'],
from: 'top',
to: 'bottom'
});
rect.fill().color(0.5, 'red');
Обводка объекта:
rect.stroke('10px red');
rect.stroke(); // -> {color: 'red', width: 10}
Чтобы изменить, можно передать строку или объект:
rect.stroke('0.5em round square [1,2] green 0.5');
rect.stroke({
color: 'black',
width: '4px',
join: 'round',
cap: 'butt',
dash: 'dot'
});
При этом изменяются только указанные параметры:
rect.stroke('7pt'); // изменит только толщину, не тронув цвет и всё остальное
Можно сбросить все параметры (убрать stroke), передав null:
rect.stroke(null);
Прозрачность (число от 0 до 1).
Делают объект видимым / невидимым. Без анимации, просто отключают его отрисовку.
Ожидается, что невидимый объект не будет реагировать на события, поэтому hide / show также включают / отключают обработку событий мыши. Если требуется другое поведение, нужно использовать функцию mouse после этого.
Устанавливает курсор при наведении мыши на объект. (пока работает не всегда корректно)
rect.cursor('pointer');
Z-index объекта.
Z-index в понятии Graphics2D -- просто индекс элемента (а, соответственно, и каким по счёту отрисовывается):
// предполагается, что canvas пуст, так что начальный z-index = 0
var a = ctx.rect(10, 10, 200, 200);
var b = ctx.circle(100, 100, 50);
a.z(); // -> 0
b.z(); // -> 1
b.z(0);
b.z(); // -> 0
a.z(); // -> 1
Двух объектов с одинаковым индексом существовать на одном контексте не может.
Возвращает true, если точка (x; y) находится внутри объекта / фигуры, иначе false.
При этом учитывается сама фигура, а не её прямоугольник.
/* Возвращает прямоугольник (хитбокс) объекта. Свойства:
x, y или x1, y1 -- координаты левой верхней точки.x2, y2 -- координаты правой нижней точки.width, height = w, h -- ширина и высота.cx, cy -- координаты центра.Также можно передать объект со свойством transform (true / false) и stroke (true / false / 'exclude') -- обрабатывать ли трансформацию и обводку ('exclude' исключает размеры обводки из объекта):
var bounds1 = shape.bounds(),
bounds2 = shape.bounds({ transform: false });
По умолчанию transform: true, stroke: false. */
Возвращает координаты одного из углов объекта:
var coords = shape.corner('left top');
// -> [x, y]
Также можно передать объект со свойством from и отступом от угла:
shape.corner({ from: 'left top', x: 10, y: 50 });
// -> [x + 10, y + 50]
Возможные значения: углы (left top, right top, left bottom, right bottom), возможна перестановка слов (left top = top left), возможны сокращения (left top = lt = tl), также есть середины сторон (left, top, right, bottom) и центр (center).
Маска объекта (фигура, скрывающая часть исходного объекта).
Можно передать любой стандартный объект контекста:
shape.clip( ctx.path([[0, 0], [100, 100], [200, 0]]) );
Если передаются 4 аргумента, то создаётся прямоугольник (x, y, width, height). Передаются абсолютные координаты (координаты canvas-а, а не координаты самого объекта):
shape.clip( 0, 0, 30, 30 );
3 аргумента -- координаты круга (cx, cy, radius):
shape.clip( 50, 50, 100 );
1 аргумент -- путь:
shape.clip([[0, 0], [200, 200], [200, 0]]);
Или своя функция:
shape.clip({
processPath: function(ctx){
// ctx -- стандартный 2D Context
ctx.moveTo( 10, 10 );
ctx.lineTo( 300, 300 );
ctx.lineTo( 300, 0 );
ctx.closePath();
}
});
Переданный первым аргументом null удаляет маску:
shape.clip(null);
Удаляет объект из отрисовки контекста (но при этом объект остаётся в памяти, так что его можно использовать в дальнейшем, в т.ч. вставить обратно в контекст):
var rect = ctx.rect( 100, 100, 50, 50, 'blue' );
rect.remove();
rect.x(); // -> 100
ctx.push( rect ); // возвращает объект в контекст
Функции:
on(event, func)off(event, [func])fire(event, [object])clickdblclickmousedownmouseupmousemovemouseovermouseoutmousewheelfocusblur
работают абсолютно аналогично соответствующим функциям контекста.Включает / отключает обработку событий мыши. Объект, на котором отключена обработка событий мыши, становится "проницаемым": события мыши будут срабатывать на элементах под ним.
// отключаем
shape.mouse(false);
// включаем
shape.mouse(true);
Все трансформации (кроме translate) принимают параметр pivot -- центр трансформации (например, в случае с rotate -- вокруг какой точки происходит вращение). Можно передать как абсолютные координаты ([0,0], {x:10, y:10}), так и одну из точек фигуры: left, right, top, bottom, left top / top left / lt / tl и т.д.
По умолчанию точка -- центр фигуры.
rect.scale(2);
rect.scale(0.5, 0.5);
rect.scale(2, 'left top');
rect.scale(0.5, 0.5, 'center');
Увеличивает фигуру, можно передать как по x,y разные размеры, так и одинаковые.
rect.rotate(45);
rect.rotate(10, 'left');
Поворачивает фигуру, указываются градусы (можно перевести градусы в радианы как degree / 180 * Math.PI, а налогично наоборот rad / Math.PI * 180).
rect.skew(10, 0);
rect.skew(5);
rect.skew(-10, 0, 'left');
rect.skew(-5, 'top');
"Сдвигает" фигуру. Указываются градусы.
rect.translate(10, 10);
Сдвигает фигуру по осям координат. Полезно, когда мы по-разному трансформировали фигуру, у неё смещаются оси координат, и простое изменение её координат даст нам немного неожиданное поведение.
rect.transform(2, 0, 0, 1.5, 0, 0); // вокруг центра
rect.transform(0.5, 0, 0, 0.75, 0, 0, 'top');
Трансформирует фигуру. Как это делается, подробнее здесь: http://www.intuit.ru/studies/courses/1063/210/lecture/5434?page=5
Функция animate:
rect.animate('width', '2em');
// param, value, duration, easing, after
rect.animate('width', 200, 3000, 'bounceOut', function(){ this.fill('blue'); });
rect.animate({ width:200, x:0 }, 3000, 'bounceOut', afterfunc);
rect.animate({ fill: 'red', stroke:'4px' }, {
duration: 1000,
easing: function(x){ return Math.pow(x, 4) },
after: function(){ this.hide() }
});
Вроде бы всё понятно. Доступные параметры для анимирования:
opacityfill (без поддержки градиентов и текстур)stroke (только цвет и ширина)crop -- для изображенийx, y, width, height, cx, cy, radius -- параметры фигурrotate, scale, scaleX, scaleY, skew, skewX, skewY, translate, translateX, translateY -- трансформации. Все только вокруг центра фигуры, по-другому пока никак. Вот так: skew:[10,3] писать нельзя (пока что), нужно так: skewX:10, skewY:3.Можно добавить свои...