Веб-приложения должны предоставлять простые в использовании решения для загрузки и управления многофункциональным контентом. Этот процесс может создать трудности для некоторых пользователей, которые имеют минимальные навыки редактирования фотографий. Обрезка является одним из наиболее часто используемых методов манипулирования фотографиями, и этот пошаговый учебник охватит весь процесс разработки плагина для обрезки изображений для библиотеки jQuery JavaScript.
Шаг 1. Настройка рабочего пространства
Во-первых, мы собираемся настроить рабочее пространство нашего проекта для этого урока. Начните с создания иерархии каталогов и пустых файлов, названных так, как показано на рисунке ниже:
Затем вам нужно скачать библиотеку jQuery JavaScript и поместить ее в папку /resources/js/
. Изображение, используемое в этом руководстве, должно называться example.jpg
и помещаться в папку /resources/images/
. Вы можете использовать это изображение (спасибо gsso-stock ), поставляемый с исходными файлами этого руководства или одним из ваших собственных. И последний файл — это файл outline.gif
, который должен быть помещен в папку /resources/js/imageCrop/
.
Шаг 2. Создание тестовой страницы
Чтобы протестировать наш плагин, нам нужно прикрепить его к изображению. Прежде чем приступить к работе, мы создадим простую страницу с этим изображением.
HTML
Откройте файл index.html
в вашем любимом текстовом редакторе и напишите следующий код.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
<!DOCTYPE html PUBLIC «-//W3C//DTD XHTML 1.0 Transitional//EN» «http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd»>
<html lang=»en» xml:lang=»en» xmlns=»http://www.w3.org/1999/xhtml»>
<head>
<meta content=»text/html; charset=UTF-8″ http-equiv=»Content-Type» />
<title>jQuery Image Cropping Plug-In</title>
<link href=»style.css» media=»screen» rel=»stylesheet» type=»text/css» />
<link href=»resources/js/imageCrop/jquery.imagecrop.css» media=»screen» rel=»stylesheet» type=»text/css» />
<script src=»resources/js/jquery-1.6.2.min.js» type=»text/javascript»></script>
<script src=»resources/js/imageCrop/jquery.imagecrop.js» type=»text/javascript»></script>
</head>
<body>
<div id=»wrapper»>
<h1>jQuery Image Cropping Plug-In</h1>
<div class=»image-decorator»>
<img alt=»jQuery Image Cropping Plug-In» height=»360″ id=»example» src=»resources/images/example.jpg» width=»480″ />
</div><!— .image-decorator —>
</div><!— #wrapper —>
</body>
</html>
|
Здесь нет ничего необычного: просто HTML-код. Мы загрузили таблицу стилей для страницы, jQuery, наши плагины (которые в настоящее время пусты) и поместили изображение в документ.
CSS
Теперь отредактируйте style.css
как показано выше.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
* {
margin : 0;
outline : 0;
padding : 0;
}
body {
background-color : #ededed;
color : #646464;
font-family : ‘Verdana’, ‘Geneva’, sans-serif;
font-size : 12px;
text-shadow : 0 1px 0 #ffffff;
}
h1 {
font-size : 24px;
font-weight : normal;
margin : 0 0 10px 0;
}
div#wrapper {
margin : 25px 25px 25px 25px;
}
div.image-decorator {
-moz-border-radius : 5px 5px 5px 5px;
-moz-box-shadow : 0 0 6px #c8c8c8;
-webkit-border-radius : 5px 5px 5px 5px;
-webkit-box-shadow : 0 0 6px #c8c8c8;
background-color : #ffffff;
border : 1px solid #c8c8c8;
border-radius : 5px 5px 5px 5px;
box-shadow : 0 0 6px #c8c8c8;
display : inline-block;
height : 360px;
padding : 5px 5px 5px 5px;
width : 480px;
}
|
Мы настроили аспект нашей страницы, изменив цвет фона и добавив некоторые базовые стили к заголовку и изображению.
Шаг 3. Написание базового плагина jQuery
Давайте начнем с создания базового плагина jQuery.
«Узнайте больше о том, как написать свой собственный плагин, в этом посте . В нем изложены основы, лучшие практики и распространенные ошибки, на которые следует обратить внимание, когда вы начнете писать свой плагин».
Откройте /resources/js/imageCrop/jquery.imagecrop.js
и добавьте следующий код.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
// Always wrap a plug-in in ‘(function($) { // Plug-in goes here }) (jQuery);’
(function($) {
$.imageCrop = function(object, customOptions) {};
$.fn.imageCrop = function(customOptions) {
//Iterate over each object
this.each(function() {
var currentObject = this,
image = new Image();
// And attach imageCrop when the object is loaded
image.onload = function() {
$.imageCrop(currentObject, customOptions);
};
// Reset the src because cached images don’t fire load sometimes
image.src = currentObject.src;
});
// Unless the plug-in is returning an intrinsic value, always have the
// function return the ‘this’ keyword to maintain chainability
return this;
};
}) (jQuery);
|
Мы только что расширили jQuery, добавив новое свойство функции к объекту jQuery.fn
. Теперь у нас есть очень простой плагин, который перебирает каждый объект и присоединяет imageCrop
при загрузке объекта. Обратите внимание, что кэшированные изображения иногда не load
, поэтому для устранения этой проблемы мы сбрасываем атрибут src
.
Шаг 4. Добавление настраиваемых параметров
Возможность настройки параметров делает плагин гораздо более гибким для пользователя.
$ .imageCrop = function (object, customOptions) { // Вместо того, чтобы требовать большого количества аргументов, передайте // параметры плагина в литерале объекта, который может быть расширен // плагин по умолчанию var defaultOptions = { allowMove: true, allowResize: true, allowSelect: true, minSelect: [0, 0], контурOpacity: 0,5, overlayOpacity: 0,5, selectionPosition: [0, 0], selectionWidth: 0, selectionHeight: 0 }; // Установить параметры по умолчанию var options = defaultOptions; // И объединяем их с пользовательскими настройками setOptions (customOptions); };
Мы определили массив с параметрами по умолчанию, а затем объединили их с пользовательскими параметрами, вызвав функцию setOptions
. Давайте пойдем дальше и напишем тело этой функции.
... // Объединяем текущие параметры с пользовательским параметром function setOptions (customOptions) { options = $ .extend (options, customOptions); };
Функция $.extend()
объединяет содержимое двух или более объектов вместе в первый объект.
Варианты
Следующий список описывает каждую опцию плагина.
- allowMove — указывает, можно ли переместить выбор (значение по умолчанию —
true
). - allowResize — указывает, можно ли изменить размер выделения (значение по умолчанию —
true
). - allowSelect — указывает, может ли пользователь сделать новый выбор (значение по умолчанию —
true
). - minSelect — минимальный размер области для регистрации нового выбора (значение по умолчанию
[0, 0]
). - outlineOpacity — непрозрачность контура (значение по умолчанию
0.5
). - overlayOpacity — непрозрачность оверлея (значение по умолчанию
0.5
). - selectionPosition — позиция выбора (значение по умолчанию
[0, 0]
). - selectionWidth — Ширина выделения (значение по умолчанию
0
). - selectionHeight — Высота выделения (значение по умолчанию
0
).
Шаг 5. Настройка слоев
На этом шаге мы изменим DOM, чтобы подготовиться к следующему шагу: интерфейсу плагина.
Сначала мы инициализируем слой изображения.
... // Инициализируем слой изображения var $ image = $ (объект);
Теперь инициализируйте держатель изображения.
... // Инициализируем держатель изображения var $ holder = $ ('<div />') .css ({ положение: «родственник» }) .width ($ image.width ()) .height ($ image.height ()); // Обернуть держатель вокруг изображения $ Image.wrap ($ держатель) .css ({ позиция: «абсолют» });
Как вы можете видеть, слой держателя имеет тот же размер, что и изображение, и относительную позицию. Далее мы вызываем функцию .wrap()
чтобы поместить изображение в держатель.
Над изображением будет наложенный слой.
... // Инициализируем накладываемый слой и размещаем его над изображением var $ overlay = $ ('<div id = "image-crop-overlay" />') .css ({ непрозрачность: options.overlayOpacity, позиция: «абсолют» }) .width ($ image.width ()) .height ($ image.height ()) .insertAfter ($ изображения);
Этот слой имеет тот же размер, что и изображение, но также имеет абсолютное позиционирование. Мы получаем значение непрозрачности из options.overlayOpacity
и позволяем jQuery применять его. Этот элемент также имеет идентификатор, поэтому мы можем изменить его свойства с помощью таблицы стилей плагина. Внизу мы вызываем метод .insertAfter()
чтобы поместить слой наложения сразу после изображения.
Следующий уровень — уровень триггера; мы разместим его после наложенного слоя, как мы делали с предыдущими.
... // Инициализируем слой триггера и размещаем его над слоем наложения var $ trigger = $ ('<div />') .css ({ backgroundColor: '# 000000', непрозрачность: 0, позиция: «абсолют» }) .width ($ image.width ()) .height ($ image.height ()) .insertAfter ($ оверлей);
Цвет фона на самом деле не имеет значения, но он должен отличаться от прозрачного (что по умолчанию). Этот слой невидим для пользователя, но он будет обрабатывать некоторые события.
Мы разместим контурный слой над слоем триггера.
... // Инициализируем контурный слой и размещаем его над слоем триггера var $ outline = $ ('<div id = "image-crop-outline" />') .css ({ непрозрачность: options.outlineOpacity, позиция: «абсолют» }) .insertAfter ($ триггер);
И наконец последний слой.
... // Инициализируем слой выделения и размещаем его над слоем контура var $ selection = $ ('<div />') .css ({ background: 'url (' + $ image.attr ('src') + ') no-repeat', позиция: «абсолют» }) .insertAfter ($ очертание);
Метод .attr()
возвращает значение указанного атрибута. Мы использовали его, чтобы получить изображение src и установить его в качестве фона для слоя выделения.
Абсолютное позиционирование внутри относительного позиционирования
Вы, возможно, уже знаете это, но элемент с относительным позиционированием предоставляет вам элемент управления для абсолютного позиционирования элементов внутри него. Вот почему слой-держатель имеет относительную позицию, а все его дочерние элементы — абсолютную позицию.
Отличное объяснение этого трюка рассматривается в этой статье .
Шаг 6. Обновление интерфейса
Сначала мы инициализируем некоторые переменные.
... // Инициализируем глобальные переменные var selectionExists, selectionOffset = [0, 0], selectionOrigin = [0, 0];
selectionExists
сообщит нам, если выбор существует. selectionOffset
будет содержать смещение относительно источника изображения, а selectionOrigin
укажет источник выделения. После нескольких шагов все станет намного понятнее.
Следующие условия обязательны, если выбор существует при загрузке плагина.
... // Проверяем, больше ли выбранный размер, чем принятый минимум // и соответственно устанавливаем существование выделения if (options.selectionWidth> options.minSelect [0] && options.selectionHeight> options.minSelect [1]) selectionExists = true; еще selectionExists = false;
Далее мы впервые вызовем updateInterface()
для инициализации интерфейса.
... // Вызываем функцию updateInterface в первый раз, чтобы // инициализируем интерфейс плагина updateInterface ();
Мы напишем тело этой функции в ближайшее время. Прямо сейчас давайте позаботимся о нашем первом мероприятии.
... if (options.allowSelect) // Привязываем обработчик события к событию mousedown уровня триггера $ Trigger.mousedown (setSelection);
Мы вызываем .mousedown()
если options.allowSelect
имеет значение true
. Это свяжет обработчик события с событием mousedown
уровня триггера. Таким образом, если пользователь щелкает изображение, setSelection()
.
... // Получить текущее смещение элемента function getElementOffset (object) { var offset = $ (object) .offset (); return [offset.left, offset.top]; }; // Получить текущую позицию мыши относительно позиции изображения function getMousePosition (event) { var imageOffset = getElementOffset ($ image); var x = event.pageX - imageOffset [0], y = event.pageY - imageOffset [1]; х = (х <0)? 0: (x> $ image.width ())? $ image.width (): x; у = (у <0)? 0: (y> $ image.height ())? $ image.height (): y; возврат [х, у]; };
Первая функция, getElementOffset()
, возвращает левую и верхнюю координаты указанного объекта относительно документа. Мы .offset()
это значение, вызвав метод .offset()
. Вторая функция, getMousePosition()
, возвращает текущую позицию мыши, но относительно позиции изображения. Итак, мы будем работать со значениями, которые находятся только между 0 и шириной / высотой изображения на оси x / y соответственно.
Давайте напишем функцию для обновления наших слоев.
... // Обновляем слой наложения function updateOverlayLayer () { $ Overlay.css ({ display: selectionExists? 'блок': 'нет' }); };
Эта функция проверяет значение переменной selectionExists
и определяет, должен ли отображаться слой наложения или нет.
... // Обновляем слой триггера function updateTriggerLayer () { $ Trigger.css ({ курсор: options.allowSelect? перекрестие: по умолчанию }); };
Функция updateTriggerLayer()
меняет курсор на crosshair
или default
, в зависимости от значения options.allowSelect
.
Далее мы напишем updateSelection()
. Он обновит не только слой выделения, но и контурный слой.
... // Обновляем выбор function updateSelection () { // Обновляем контурный слой $ Outline.css ({ курсор: «по умолчанию», display: selectionExists? «блок»: «нет», слева: options.selectionPosition [0], top: options.selectionPosition [1] }) .width (options.selectionWidth) .height (options.selectionHeight); // Обновляем слой выбора $ Selection.css ({ backgroundPosition: (- options.selectionPosition [0] - 1) + 'px' + (- options.selectionPosition [1] - 1) + 'px', курсор: options.allowMove? 'move': 'default', display: selectionExists? «блок»: «нет», слева: options.selectionPosition [0] + 1, top: options.selectionPosition [1] + 1 }) .width ((options.selectionWidth - 2> 0)? (options.selectionWidth - 2): 0) .height ((options.selectionHeight - 2> 0)? (options.selectionHeight - 2): 0); };
Сначала эта функция устанавливает свойства слоя структуры: курсор, отображение, размер и его положение. Далее идет слой выбора; новое значение положения фона заставит изображения плавно перекрываться.
Теперь нам нужна функция для обновления курсора при необходимости. Например, когда мы делаем выделение, мы хотим, чтобы курсор оставался crosshair
независимо от того, над каким слоем мы находимся.
... // Обновляем тип курсора function updateCursor (cursorType) { $ Trigger.css ({ cursor: cursorType }); $ Outline.css ({ cursor: cursorType }); $ Selection.css ({ cursor: cursorType }); };
Да, это так просто, как кажется. Просто измените тип курсора на указанный!
А теперь последняя функция этого шага; нам нужно обновить интерфейс плагина в различных ситуациях — при выборе, изменении размера, отмене выделения и даже при инициализации плагина.
... // Обновляем интерфейс плагина function updateInterface (sender) { switch (отправитель) { case 'setSelection': updateOverlayLayer (); updateSelection (); перемена; case 'resizeSelection': updateSelection (); updateCursor ( 'перекрестие'); перемена; дефолт : updateTriggerLayer (); updateOverlayLayer (); updateSelection (); } };
Как видите, updateInterface()
фильтрует некоторые случаи и вызывает необходимые функции, которые мы только что написали.
Шаг 7. Установка выбора
До сих пор мы заботились о параметрах настройки и интерфейсе, но ничего не касалось того, как пользователь взаимодействует с плагином. Давайте напишем функцию, которая устанавливает новый выбор при нажатии на изображение.
... // Установить новый выбор function setSelection (event) { // Предотвращаем действие по умолчанию для события event.preventDefault (); // Предотвратить уведомление о событии event.stopPropagation (); // Привязываем обработчик событий к событиям mousemove и mouseup $ (Документ) .mousemove (resizeSelection) .mouseup (releaseSelection); // Сообщаем, что выбор существует selectionExists = true; // Сбросить размер выделения options.selectionWidth = 0; options.selectionHeight = 0; // Получить источник выбора selectionOrigin = getMousePosition (event); // И установить свою позицию options.selectionPosition [0] = selectionOrigin [0]; options.selectionPosition [1] = selectionOrigin [1]; // Обновляем только необходимые элементы интерфейса плагина // указав отправителя текущего вызова updateInterface ( 'setSelection'); };
Во-первых, функция setSelection
вызывает два метода: event.preventDefault()
и event.stopPropagation()
. Это предотвращает уведомление о событии действия по умолчанию и любых родительских обработчиков. Метод .mousemove()
связывает обработчик события с событием mousemove
. Это будет вызывать resizeSelection()
каждый раз, когда пользователь перемещает указатель мыши. Чтобы уведомить, что делается новый выбор, переменная selectionExists
становится true
а размер выбора устанавливается getMousePosition()
0. Далее, мы получаем источник выбора, вызывая нашу ранее написанную функцию getMousePosition()
, и передаем ее значение options.selectionPosition
. Наконец, мы вызываем updateInterface()
чтобы обновить интерфейс плагина в соответствии с внесенными изменениями.
Шаг 8. Изменение размера выделения
На предыдущем шаге мы написали функцию для установки нового выбора. Давайте теперь напишем функцию для изменения размера этого выбора.
... // Изменить размер текущего выбора function resizeSelection (event) { // Предотвращаем действие по умолчанию для события event.preventDefault (); // Предотвратить уведомление о событии event.stopPropagation (); var mousePosition = getMousePosition (event); // Получить размер выделения options.selectionWidth = mousePosition [0] - selectionOrigin [0]; options.selectionHeight = mousePosition [1] - selectionOrigin [1]; if (options.selectionWidth <0) { options.selectionWidth = Math.abs (options.selectionWidth); options.selectionPosition [0] = selectionOrigin [0] - options.selectionWidth; } еще options.selectionPosition [0] = selectionOrigin [0]; if (options.selectionHeight <0) { options.selectionHeight = Math.abs (options.selectionHeight); options.selectionPosition [1] = selectionOrigin [1] - options.selectionHeight; } еще options.selectionPosition [1] = selectionOrigin [1]; // Обновляем только необходимые элементы интерфейса плагина // указав отправителя текущего вызова updateInterface ( 'resizeSelection'); };
Чтобы изменить размер выделения, нам нужно получить текущую позицию мыши. Поскольку возвращаемое значение относится к размеру изображения, нам нужно заботиться только о отрицательных значениях. Это никогда не будет превышать границы изображения. Как вы знаете, мы не можем иметь отрицательное значение для свойств width
или height
элемента. Чтобы решить эту проблему, мы вызываем Math.abs()
чтобы получить абсолютное значение, а затем перемещаем выбор.
Шаг 9. Освобождение выбора
И теперь последняя функция:
... // Освободить текущий выбор function releaseSelection (event) { // Предотвращаем действие по умолчанию для события event.preventDefault (); // Предотвратить уведомление о событии event.stopPropagation (); // Отсоединяем обработчик события от события mousemove $ (Документ) .unbind ( 'MouseMove'); // Отсоединяем обработчик события от события mouseup $ (Документ) .unbind ( 'MouseUp'); // Обновляем источник выбора selectionOrigin [0] = options.selectionPosition [0]; selectionOrigin [1] = options.selectionPosition [1]; // Проверяем, больше ли выбранный размер, чем принятый минимум // и соответственно устанавливаем существование выделения if (options.selectionWidth> options.minSelect [0] && options.selectionHeight> options.minSelect [1]) selectionExists = true; еще selectionExists = false; // Обновляем только необходимые элементы интерфейса плагина // указав отправителя текущего вызова updateInterface ( 'releaseSelection'); };
Когда выбор освобождается, releaseSelection()
удаляет ранее присоединенные обработчики событий в функции setSelection()
, вызывая метод .unbind()
. Затем он обновляет источник выбора и проверяет минимальный размер, принятый для существования выбора.
Теперь мы почти готовы. Закройте этот файл и подготовьтесь к следующему шагу.
Шаг 10. Стилизация плагина
Откройте /resources/js/imageCrop/jquery.imagecrop.css
таблицу стилей и добавьте следующие строки.
1
2
3
4
5
6
7
8
9
|
div#image-crop-overlay {
background-color : #ffffff;
overflow : hidden;
}
div#image-crop-outline {
background : #ffffff url(‘outline.gif’);
overflow : hidden;
}
|
Здесь нет ничего сложного; мы добавили некоторые стили для слоев наложения и контура.
Шаг 11. Тестирование окончательного результата
Чтобы протестировать наш плагин, нам нужно прикрепить его к изображению. Давайте сделаем это и отредактируем страницу index.html
.
Откройте тег script
…
<script type = "text / javascript"> ... </ Скрипт>
… и напишите следующий код JavaScript.
$ (документ) .ready (function () { $ ( 'IMG # пример'). ImageCrop ({ overlayOpacity: 0,25 }); });
Мы подключили наш плагин к элементу изображения с example
id и установили некоторые пользовательские параметры. Мы использовали метод .ready()
чтобы определить, когда DOM полностью загружен.
Вот и все! Сохраните файл и откройте браузер, чтобы проверить его.
Что дальше
Теперь у нас есть базовый плагин для обрезки изображений, который позволяет нам выбрать область изображения. В следующем уроке мы добавим больше параметров настройки, создадим панель предварительного просмотра, напишем некоторые сценарии на стороне сервера, чтобы обрезать изображение … и многое другое. Надеюсь, вам понравилось время, которое мы провели вместе, и сочли этот урок полезным. Спасибо за прочтение!