My favorites | Sign in
Project Home Downloads Wiki Issues Source
Search
for
Documentation  
Описание библиотеки и принципов работы с ней
Featured
Updated Feb 4, 2010 by serge....@gmail.com

Для чего нужен декоратор картинок

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

Сегодня задача по скруглению уголков решается довольно легко: берем картинку в JPEG и пользуемся любым известным способом добавления поверх нее скругленных уголков (про некоторые способы можно узнать в техногрете).

Но что если задача немного усложняется и нужно именно вырезать уголки из картинки, чтобы они правильно стыковались с фоном?

Если вы делаете сайт на заказ, то я вижу два решения этой проблемы:

  • Обучить заказчика основам работы в графическом редакторе и заставить его вырезать уголки каждый раз, когда он добавляет иллюстрацию на сайт. Это самый фашистский метод, который вскоре приведет к тому, что заказчик скоро перестанет это делать.
  • Написать в CMS скрипт, который при добавлении иллюстрации сам срежет эти уголки. Этот способ гораздо ближе к определению «гуманный».

Но у обоих способов есть один большой недостаток: пользователю, зашедшему на ваш сайт, придется скачивать PNG-картинку вместо JPEG, так как именно PNG поддерживает полупрозрачность. То есть пользователь вынужден будет скачать в 3—4 раза больше только потому, что дизайнер решил придать округлые формы картинке.

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

Есть набор изображений, который отображаются в произвольном порядке на сайте, причем у первой картинки должен быть срезан верхний левый угол, а последней — правый нижний. Помимо срезанных уголков у картинок должна быть обводка.

Получается, что на сайте должно быть по три варианта каждого изображения, и нужно показывать один из этих вариантов в зависимости от того, где находится картинка. Я не говорю о том, что пользователям придется скачать тройной объем данных.

Декоратор картинок ictinus

Для решения подобных проблем был написан декоратор картинок под названием ictinus, который способен любой картинке в браузере добавить векторную маску или декорацию. Его основные возможности:

  • добавление векторной маски изображению;
  • добавление декорации изображению (например, обводка);
  • может просто отрисовать векторную форму, без использования изображения;
  • автоматическое масштабирование векторной формы под габариты изображения или контейнера;
  • импорт из SVG;
  • импорт/экспорт в JSON;
  • работает во всех современных браузерах: IE6+, Opera 9+, Safari 2+, Firefox 2+

Первое знакомство

Давайте создадим нашу первую декорацию. Для этого нужно подключить два файла на страницу — ictinus.css и ictinus.js — и написать вот такой JavaScript-код:

<img src="./img150x150.jpg" width="150" height="150" id="image" />
<script type="text/javascript">
	window.onload = function() {
		var shape = new ictinus.Shape('m0,150 L75,0 L150,150, L0,150');
		shape.decorate(document.getElementById('image'));
	}
</script>

Получим такой результат:

Давайте рассмотрим код подробнее.

Как видно из примера, декорация добавляется на window.onload. Это необходимое условие, так как картинка должна быть загружена до того, как будет добавлена декорация. Конечно, обработка window.onload не всегда будет правильным решением в таких ситуациях, особенно когда картинок много. В таких случаях лучше всего будет написать более сложный скрипт, который по очереди будет загружать картинки и украшать их, но это тема для отдельного разговора.

Для того, чтобы добавить декорацию картинке, необходимо создать форму, с помощью которой вы будете украшать картинку. Делается это с помощью класса ictinus.Shape:

var shape = new ictinus.Shape('m0,150 L75,0 L150,150, L0,150');

В качестве аргумента конструктора передается строчка с непонятными, на первый взгляд, данными. Те, кто работал с SVG, сразу же ее узнают: это ни что иное, как SVG Path Data, описывающий контур фигуры. ictinus писался полностью в соответствии со спецификацией SVG, поэтому вы можете не только вручную создавать контуры, но и импортировать их из SVG-файла (об этом позже). В данном примере мы нарисовали треугольник.

Далее, нам нужно украсить картинку. Для этого вызываем метод decorate() класса ictinus.Shape, в качестве аргумента передаем ему указатель на картинку:

shape.decorate(document.getElementById('image'));

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

Добавляем декорации: strokeWidth и strokeColor

В предыдущм примере мы просто добавили маску изображению, теперь давайте добавим маске двухпиксельную обводку:

window.onload = function() {
	var shape = new ictinus.Shape('m0,150 L75,0 L150,150, L0,150');
	shape.strokeWidth = 2;
	shape.strokeColor = '#ff0000';
	shape.decorate(document.getElementById('image'));
}

Как видно на примере, у маски добавилась двухпиксельная красная обводка:

Применяем одну форму к нескольким картинкам

Предположим, у вас есть одна маска, которую вы хотите наложить на несколько изображений. Причем все изображения разного размера, а вам нужно, чтобы маска растягивалась под размер картинки. Не спешите создавать новую форму — для решения таких задач есть метод updateSizeBy():

<img src="./img150x150.jpg" width="150" height="150" id="image1" />
<img src="./img300x210.jpg" width="300" height="210" id="image2" />
<script type="text/javascript">
	window.onload = function() {
		var img1 = document.getElementById('image1');
		var img2 = document.getElementById('image2');
		var shape = new ictinus.Shape('m0,150 L75,0 L150,150, L0,150');
		shape.decorate(img1);
		
		// обновляем размер формы под размер картинки
		shape.updateSizeBy(img2);
		shape.decorate(img2);
	}
</script>

И вот что у нас получилось:

Метод формы updateSizeBy() в качестве аргумента принимает указатель на HTML-элемент, по габаритам которого он меняет размер самой формы. Это удобный способ подстраивать размер формы под размер картинки, однако вы можете менять размер как вам захочется с помощью методов width(), height(), scaleX(), scaleY()`:

window.onload = function() {
	var img1 = document.getElementById('image1');
	var img2 = document.getElementById('image2');
	var shape = new ictinus.Shape('m0,150 L75,0 L150,150, L0,150');
	
	// уменьшим форму в два раза
	shape.scaleX(0.5);
	shape.scaleY(0.5);
	shape.decorate(img1);
	
	// узнаем текщую ширину формы
	alert(shape.width())
	
	// теперь выставим ей другой размер 
	shape.width(200);
	shape.height(200);
	shape.decorate(img2);
}

Вот что у нас получилось:

Вы можете менять размеры формы (width() и height()) либо ее масштаб (scaleX(), scaleY()). Вызов этих методов всегда возвращает значение параметра, вызов метода с аргументом еще и изменяет это значение.

Сетка масштабирования (scaleGrid)

Усложним задачу. Создадим прямогульник 100х100 и отрежем у него левый верхний угол c катетами в 10 пикселей:

Теперь добавим эту маску для нашей картинки:

<img src="./img300x210.jpg" width="300" height="210" id="image" />
<script type="text/javascript">
	window.onload = function() {
		var shape = new ictinus.Shape('m0,10 l10,-10 L100,0 L100,100 L0,100, L0,10');
		var img = document.getElementById('image');
		shape.strokeWidth = 1;
		shape.strokeColor = '#000000';
		shape.updateSizeBy(img);
		shape.decorate(img);
	}
</script>

Смотрим, что получилось:

Как видите, форма пропорционально растянулась под размер картинки, а вместе с ней и уголок. Но это не то, что мне нужно: я хочу, чтобы уголок всегда был размером 10х10 пикселей, независимо от того, как растянулась форма. Для достижения этого был введен такой механизм как сетка масштабирования (scale grid). Это четрые направляющие линии — две по горизонтали и две по вертикали — которые определяют, как должны масштабироваться определенные участки формы.

На этой иллюстрации:

  • зоны 1, 3, 7, 9 не растягиваются вообще;
  • зоны 2 и 8 растягиваются только по горизонтали;
  • зоны 4 и 6 растягиваются только по вертикали;
  • зона 5 растягивается по горизонтали и вертикали.

Если вы работали в Adobe Flash или Adobe Fireworks, вам должен быть знаком такой механизм под названием 9-grid scale.

Возвращаясь к нашему примеру, чтобы избавится от растягивания уголка, необходимо всего лишь зафиксировать его в зоне 1:

window.onload = function() {
	var shape = new ictinus.Shape('m0,10 l10,-10 L100,0 L100,100 L0,100, L0,10');
	var img = document.getElementById('image');
	shape.strokeWidth = 1;
	shape.strokeColor = '#000000';
	shape.setScaleGrid(10, 100, 10, 100);
	shape.updateSizeBy(img);
	shape.decorate(img);
}

Тем самым мы решили нашу проблему:

Сетка масштабирования идельно подходит для создания картинок со скругленными уголками, но об этом поговорим чуть позже.

Простое рисование формы

Как упоминалось ранее, можно не только украшать картинки с помощью векторных декораций, но и просто нарисовать векторную форму:

<div id="sample"></div>
<script type="text/javascript">
	var shape = new ictinus.Shape('m0,150 L75,0 L150,150, L0,150');
	shape.strokeWidth = 3;
	shape.strokeColor = '#0000ff';
	shape.fillColor = '#ff0000';
	shape.draw(document.getElementById('sample'));
</script>

Получим вот такой треугольник:

Вот что поменялось:

  • Вместо картинки используем обычный
    (или любой другой элемент).
  • Вместо вызова метода decorate() используем draw().
  • Можно задавать цвет заливки (атрибут fillColor). Если не хотите, чтобы рисовалась заливка, достаточно присвоить пустую строку атрибуту fillColor.

Скругленные уголки

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

Работает все довольно просто:

<img src="img300x210.jpg" width="300" height="210" id="image" />
<script type="text/javascript">
	window.onload = function(){
		ictinus.roundCorners(document.getElementById('image'), 30, {strokeWidth: 1, strokeColor: '#000000'});
	}
</script>

В пространстве имен ictinus появился метод roundCorners(), принимающий три аргумента: картинка, радиус скругления и параметры рисования. Два последних аргумента — необязательные.

По умолчанию радиус скругления равен 10 пикселям, параметры рисования отсутствуют. Но вы можете поменять их, чтобы каждый раз не передавать их как аргументы:

window.onload = function(){
	// задаем радиус по умолчанию
	ictinus.roundCorners.RADIUS = 20;
	
	// задаем параметры рисования по умолчанию
	ictinus.roundCorners.DRAW_PARAMS = {
		strokeWidth: 2,
		strokeColor: '#ff0000'
	};
	
	ictinus.roundCorners(document.getElementById('image'));
}

Пример

Метод ictinus.roundCorners() возвращает сгенерированную форму (объект класса ictinus.Shape()), которую вы можете в дальнейшем использовать.

Внимание! Чтобы не генерировать десятки одинаковых форм, в самом методе используется кэширование, ключом которого является радиус скругления. То есть если вы 10 раз вызовете метод ictinus.roundCorners() с радиусом, например, 20, — будет создан только один объект ictinus.Shape, все последующие вызовы будут использовать его, а не создавать новые формы.

Копаем глубже

Ознакомившись с базовыми возможностями ictinus, давайте узнаем, как это работает.

В качестве движка рисования используется VML (IE) и Canvas (все остальные браузеры). Когда вы вызываете метод decorate() или draw() на каком-нибудь элементе (для удобства назовем его elem), создается новый элемент с классом ictinus. Если elem — картинка, то ictinus-элемент создается перед elem, в остальных случаях он создается внутри elem. После успешной отрисовки формы элементу elem присваивается класс inctinus-init.

По умолчанию для класса ictinus прописаны CSS-свойства position: absolute; z-index: 1. Это наиболее безопасные свойства для того, чтобы показать декорированную картинку, но, как вы уже поняли, сработает это не всегда, поэтому придется для конкретной задачи дополнять эти правила.

Импорт из SVG

Так как формат строки, описывающий фигуру, полностью совместим с форматом Path data из SVG, вы можете легко создавать новые формы в вектороном редакторе, а затем импортировать их в ictinus:

<div id="svg_test"></div>
<script type="text/javascript">
	// для загрузки данных используется jQuery
	$.ajax({
		dataType : 'xml',
		success : function(data){
			var shape = ictinus.svgimport.read(data);
			shape.draw(document.getElementById('svg_test'));
		},
		type : 'get',
		url : 'example.svg'
	});
</script>

Пример

Метод ictinus.svgimport.read() в качестве аргумента принимает либо HTML-элемент, либо весь документ. В нем он ищет первый &lt;path&gt;-элемент, атрибуты которого используются для создания новой формы. Пока модуль импорта из SVG находится зачаточном состоянии, в дальнейшем планируется расширить список понимаемых элементов, а также добавить возможность импорта нескольких форм из одного файла.

JSON

Формат SVG является удобным во время разработки, когда необходимо быстро перенести информацию из графического редактора в ictinus. На рабочем же сайте его использовать совершенно неудобно: придется отдельным запросом доставать саму форму, а потом добавлять ей переметры типа сетки масштабирования.

Для этих целей рекомендуется использовать JSON: ictinus может сериализировать любую форму в JSON-объект, равно как и создать форму из такого объекта. Для преобразования объекта в строку рекомендую использовать библиотеку Дугласа Крокфорда (она не входит в состав ictinus):

<div id="sample"></div>
<script type="text/javascript">
	var shape = new ictinus.Shape('m0,150 L75,0 L150,150, L0,150');
	shape.strokeWidth = 3;
	shape.strokeColor = '#0000ff';
	shape.fillColor = '#ff0000';
	
	var json = shape.toJSON();
	alert(JSON.stringify(json));
	
	var shape2 = ictinus.Shape.fromJSON(json);
	shape2.draw(document.getElementById('sample'));
</script>

Пример

Comment by dfilato...@gmail.com, Dec 19, 2008

круто :)

Comment by dfilato...@gmail.com, Dec 19, 2008

А если понадобится тень от таких элементов?

Comment by krasnoda...@gmail.com, Jan 22, 2009

А если на сайте десятки фото? Напишите логику.

Comment by acros...@bk.ru, Mar 15, 2009

Нет логики, как я вижу. Если юзается cms - там извините, никто не будет открывать исходный код скрипта и в нем прописывать id новой картинки. Лучшая была бы реализация - один скрипт на один id, который можно присвоить сразу многим изображениям.

Comment by xadminxs...@gmail.com, Apr 7, 2009

Тени поддерживаются только в ФФ 3.1+

Comment by ruslanc...@gmail.com, Apr 14, 2009

Классная библиотека! Жаль вот только, что в ie8 не работает :-(

Comment by anep...@gmail.com, May 27, 2009

черт а почему IE 8 забыли? 8( кроссбраузерность дело такое.. тем более IE

вот обрадовался я .. какие идеи и будет ли фикс?

cпасибо

Comment by anep...@gmail.com, May 27, 2009

работает во всех современных браузерах: IE6+ ...

Comment by ruslanc...@gmail.com, Jun 19, 2009

В 6 ie почему-то не действует на каждый объект из цикла, когда применяешь на несколько объектов.

Comment by ibe...@gmail.com, Aug 5, 2009

"Жаль вот только, что в ie8 не работает :-( "

Может перевести браузер в режим рендеринга IE7, указав <meta http-equiv="X-UA-Compatible" content="IE=7" /> и будет всё ок.

Comment by goncharenko.roman, Aug 21, 2009

Вопрос - можно ли применять не только на картинках но и на <div>?

Comment by alexey.m...@gmail.com, Sep 1, 2009

Исправьте очепяточку:

...Это четрые направляющие линии...

Comment by platonis...@gmail.com, Sep 28, 2009

А если надо чтоб объект svg срабатывал например по onMouseOver и делал изменения в самой html странице это как? Точнее как из svg скрип заставить видеть дерево самого html, в котором svg и находится?

Comment by incredib...@gmail.com, Nov 13, 2009

Подскажите, пожалуйста. А как с помощью этого круги вырезать из картинки? С SVG не знаком ((

Comment by jman...@gmail.com, Dec 5, 2009

Я решил трабл с MSIE8. В принципе дописывать немного

Comment by jman...@gmail.com, Dec 5, 2009

Правда тестил я только на скруглении углов.

Comment by jman...@gmail.com, Dec 6, 2009

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

document.namespaces.add("v", "urn:schemas-microsoft-com:vml");
// setup default css
var ss = document.createStyleSheet();
ss.cssText = "v\\:* {behavior:url(#default#VML);display:block;}";

надо поменять на

document.namespaces.add("v", "urn:schemas-microsoft-com:vml", "#default#VML");
var ss = document.createStyleSheet();
/* сдесь надо перечислить все используемые селекторы,
 в MSIE8 v:* не работает.
 я на всякий случай написал те что знаю  */
ss.cssText = "v\\:polyline, v\\:line, v\\:fill,v\\:shape {behavior:url(#default#VML);display:block;}";
Comment by jman...@gmail.com, Dec 6, 2009

А вот как применять для нескольких картинок в MSIE...

Comment by driet...@gmail.com, Feb 25, 2010

Buddy, you truly rock big time. Congratulations for that solution. Wow.

Comment by t.nadd...@gmail.com, Aug 21, 2010

Есть объект в SVG. Как использовать библиотеку Дугласа Крокфорда, чтобы преобразовать его в строку?

Comment by nadd...@gmail.com, Oct 8, 2010

У меня косяки с IE8 не исправились, а с выходом IE9 появляются новые... Пора обновлять скрипт!

Comment by zlojkash...@gmail.com, Nov 15, 2010

можно ли такое применить к диву с текстом?

Comment by azazello...@gmail.com, Jan 14, 2011

В 8ie не работает совсем, в седьмом не отображает картинку у меня. Жаль.

Comment by mnogoko...@gmail.com, Oct 18, 2011

можно ли такое применить к диву с текстом? тоже интересует

Comment by a...@sageagestrategies.com, Jul 31, 2013

English


Awesome library. The only thing that would make it better would be if you could add alpha or image masking. I was looking at this as a fallback for CSS Masking/Clipping. While it does the clipping method well, I can't do faded images or anything like that. I would also be helpful to include image masking so you could load in a png image and make the visible pixels the shape of the mask.

Russian Translation - русский перевод


Высокий библиотеки. Единственная вещь, которая сделала бы его лучше было бы если бы вы могли добавить альфа или изображение маскировки. Я смотрел на это как обходной путь для маскировки CSS / отсечения. В то время как это делает метод отсечения Ну, я не могу сделать выцветших изображений или что-нибудь подобное. Я бы также полезно включить изображения маскировки, чтобы вы могли загрузить изображение в PNG и сделать видимых пикселей формы маски.


Sign in to add a comment
Powered by Google Project Hosting