Предисловие 👨

Это руководство существует как архив оригинальной публикации, написанной в 2010 году с использованием jQuery 1.4.2. Он поддерживает Internet Explorer 6 и до сих пор функционирует так же в современных браузерах, о чем свидетельствует живая демонстрация. Некоторые примеры кодирования, представленные в следующих разделах, могут показаться неоптимальными, и вы правы. Они не используют такие технологии, как гибкие боксы или альфа-прозрачность. В то время их просто не существовало. Бета-браузерные функции также были проигнорированы в пользу кросс-браузерной совместимости. В результате это руководство имеет обратную совместимость более чем на десять лет. Хотя я бы больше не рекомендовал многие из этих практик, нет необходимости изобретать велосипед. Продукт в этом руководстве находится в рабочем состоянии, и его переписывание не приведет ни к чему, кроме принесения в жертву обратной совместимости.

Введение 🏁

Этот скрипт принимает изображение и его миниатюру в качестве входных данных, а затем позволяет пользователю увеличивать область этой миниатюры в качестве вывода. Как автор веб-страницы вы можете сжать большое изображение до небольшого пространства. В этой демонстрации четыре изображения 1600x1280 уменьшены до 640x512 и 320x256.

Обратите внимание, что это не волшебным образом преобразует изображение с низким разрешением в изображение с высоким разрешением. Для этого требуются версии как с высоким, так и с низким разрешением. Он также поддерживает множество различных форм настройки, которые я попытался подчеркнуть в примерах - от пользовательских цветов до пользовательских «анимаций» (внутренних, размытых, тонированных и размытых тонированных). Это руководство научит вас создавать эти сценарии самостоятельно в всеми любимом jQuery, пройдя через используемые алгоритмы.

Настройка функции 👷

Первое, что нам нужно сделать, это настроить функцию, которая позволяет нам легко вызывать лупу. Чтобы создать функцию, мы должны сначала определить ее параметры; и чтобы определить его параметры, мы должны сначала определить, что может измениться для каждого вызова.

К динамическим характеристикам каждого блока относятся: размывается он или нет (blur: boolean), окрашивается или нет (tint: color), увеличивается ли он внутри миниатюры (inner: boolean), изображение с низким разрешением (filepath: string) и его размеры ( width: number и height: number), а также изображение с высоким разрешением (filepath: string) и его размеры (width: number и height: number). Учитывая, что в процессе увеличения участвуют три поля (эскиз, всплывающее окно, содержащее изображение с высоким разрешением, и поле, окружающее мышь, чтобы показать вам, какая область увеличивается), это много переменных!

Дав каждому блоку объект, мы оставили эффект, изображение с низким разрешением, изображение с высоким разрешением и информацию о стиле блоков. Четыре переменных.

Пример отправки этих переменных в функцию:

Ширина границы не включена в CSS по одной простой причине: эстетика и возможность расчета. Если ширина границы рамки мыши (рамки, которая окружает мышь при увеличении) не совпадает с шириной границы эскиза, его граница не может надлежащим образом перекрывать границу эскиза. Я не могу придумать ни одного сценария, в котором граница поля мыши должна отличаться от границы окна миниатюр, и многие ошибки и неприятности возникают в результате необходимости изменять ее в каждом объекте CSS.

Вы также должны убедиться, что все переменные эффекта установлены. Это позволяет использовать более короткий код. Вместо того, чтобы проверять, определена ли переменная и является ли она истинной (typeof(effect.blur) != "undefined" && effect.blur), вы можете просто проверить, истинна ли она.

Наконец, необходимо установить чрезвычайно важную переменную: отношение ширины к высоте между миниатюрой и полноразмерным изображением (называемым здесь «всплывающим окном», поскольку оно всплывает). Это необходимо для определения как размера поля мыши, так и того, как далеко можно прокручивать всплывающее окно при прокрутке мыши по миниатюре.

CSS 🎨

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

Во-первых, это самый внешний элемент, div.image-magnify, и три его наиболее важных внутренних элемента: div.box (поле мыши), div.popup (полноразмерное изображение) и div.thumbnail.

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

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

Поле должно иметь относительное положение, чтобы оно могло перемещаться при перемещении мыши.

В эстетических целях мы добавим div.thumbnail курсор «перемещение».

Теперь объясним алгоритм размытия и его CSS. На самом деле это очень простая идея, которую особенно легко реализовать с помощью встроенного обработчика полупрозрачности jQuery. Вы просто берете полупрозрачное изображение (я использую для этой лупы видимость 80%), которое было смещено влево на 3 пикселя, и помещаете его поверх того же полупрозрачного изображения, сдвинутого на 3 пикселя вверх. Затем поместите эти два изображения на одно и то же полупрозрачное изображение, сдвинутое вправо на 3 пикселя. Затем поместите эти три изображения на одно и то же полупрозрачное изображение, сдвинутое на 3 пикселя вниз. Если смотреть на каждое изображение частично, получается эффект размытия.

Теперь, когда вы понимаете, как он размывается, вы легко разберетесь с его CSS:

У нас также есть динамический CSS [в том смысле, что он изменяется в зависимости от увеличения], на который очень часто ссылаются в JavaScript. Я сжал его в переменную быстрого доступа, так как это упрощает использование каждый раз, чем ввод каждой строки.

cssCommon.background - фоновое изображение миниатюры, так как оно понадобится для div.thumbnail, div.box и всех div, участвующих в размытии. Тогда становится намного проще ссылаться на него каждый раз как на cssCommon.background, чем на его строковый эквивалент.

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

cssCommon.dimensions - это просто размеры миниатюры. Как и фоновое изображение, это применимо к div.thumbnail и размытию divs. Это не относится к div.box, поскольку его ширина определяется соотношением размеров между изображениями с низким и высоким разрешением; но это применимо к div.tint, которому нужно будет наложить миниатюру.

Наконец, в cssCommon у нас есть cssCommon.thumbnail, который представляет собой просто комбинацию фона и размеров.

В итоге это сокращенные приложения CSS для:

  • cssCommon.thumbnail: div.blur div, div.thumbnail
  • cssCommon.background: div.box
  • cssCommon.backgroundLarge: div.popup
  • cssCommon.dimensions: div.tint

В качестве последнего элемента CSS каждый элемент в div.image-magnify также не будет иметь повторяющегося фона. Мы хотим, чтобы он появлялся только один раз. Это особенно верно для div.blur, у которого смещено положение фона. Когда он смещается на 3 пикселя вверх, мы не хотим, чтобы эти верхние 3 пикселя отображались внизу блока и так далее, и так далее для каждого направления, в котором смещается каждый элемент размытия.

Элементы 🌎🔥🍃☔

Прежде всего, конечно, нам нужно создать элементы, чтобы назначить им обработчики событий. К сожалению, внутренний алгоритм увеличения несовместим с алгоритмами размытия и оттенка. Это просто из-за того, что миниатюра скрыта при внутреннем увеличении, поэтому она не может размываться или окрашиваться. Из-за этого и положения задействованных элементов (div.popup смещено влево, div.box не существует), внутренний алгоритм увеличения разбивается на совершенно другой раздел кода, чем алгоритмы размытия и оттенка.

Элементы внутреннего увеличения 🏡

Наиболее эффективная установка для внутреннего увеличения:

Хотя div.image-magnify.inner никогда не используется в этом руководстве, он помещен туда просто для удобства, если вы хотите добавить другие эффекты CSS.

В отличие от размытия и оттенка, div.popup будет отображаться поверх div.thumbnail. Для этого он соответствующим образом помещается в div.thumbnail. Теперь, чтобы перенести этот базовый HTML-макет в JavaScript, чтобы вставить его в функцию:

Здесь я пошел на шаг дальше, чем базовый HTML-макет: я применил динамический CSS, о котором говорилось ранее. div.thumbnail получает фоновое изображение и размеры эскиза, а div.popup получает фоновое изображение изображения с высоким разрешением и размеры эскиза.

Теперь, чтобы добавить последние штрихи к div.popup: из-за потенциальной границы на div.thumbnail, div.popup нужно будет сместить вверх влево на то же количество пикселей, что и ширина границы. В противном случае он появится внутри рамки div.thumbnail, тогда как нам нужно, чтобы он отображался поверх границы div.thumbnail.

Элементы увеличения размытия и оттенка 😵

В отличие от внутреннего увеличения, размытие и оттенок потребуют совершенно отдельного макета. Они должны быть разработаны таким образом, чтобы они работали одновременно, поскольку они совместимы друг с другом. Наиболее эффективная установка:

Как и div.image-magnify.inner, div.image-magnify.blur (не путать с div.image-magnify div.blur) и div.image-magnify.tint в этом руководстве не используются. Они перечислены просто для удобства настраиваемого CSS.

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

Не бойтесь тем из вас, кто интересуется атрибутами высоты и ширины div.box. Объяснять комментарии было просто слишком долго.

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

Переменная соотношения - это величина от всплывающего окна до миниатюры. Таким образом, для всплывающего окна шириной 500 и миниатюры шириной 250 будет коэффициент ratio.width, равный 2. thumbnail.x / ratio.x (где x - высота или ширина) означает, что 1 / ratio.x - это процент всплывающего окна, который будет отображаться. Если соотношение всплывающего окна к миниатюре составляет 2: 1, то при увеличении будет отображаться половина всплывающего окна. Для этого соотношения размер окна должен составлять 1/2 эскиза. Если соотношение всплывающего окна к миниатюре составляет 5: 1, то при увеличении будет отображаться 1/5 части всплывающего окна. Для этого соотношения размер окна должен составлять 1/5 эскиза. Таким образом, поле должно быть 1/ratio.x * thumbnail.x (или thumbnail.x / ratio.x).

Манипуляции с общими элементами 🔗

Также есть небольшие манипуляции, которые применяются как к внутренним эффектам, так и к эффектам размытия и оттенка. Вместо того, чтобы повторно размещать эти фрагменты в операторах if и else, мы будем выполнять их вне операторов. Им нужно будет следовать за условным условием, потому что div.image-magnify сначала должен существовать, чтобы им можно было манипулировать.

data() - очень полезный метод jQuery, который позволяет назначать элементу различные атрибуты. Нельзя присвоить атрибут (attr()) popupHeight div.image-magnify, потому что это недопустимый атрибут HTML. К счастью, jQuery сохранит его в data() этого элемента, чтобы потом можно было получить к нему доступ через $("#the-element").data("popupHeight"). effect.borderWidth, popup.height, popup.width, thumbnail.height и thumbnail.width - все переменные, к которым вам понадобится доступ в будущем. Они понадобятся для вычислений в различных обработчиках событий, которые не смогут читать данные, отправленные в imageMagnifier() функцию, поэтому мы храним их в удобном для доступа месте: div.image-magnify в data().

Наконец, мы применяем CSS. Сюда входят effect.borderWidth и css переменная. Каждый элемент получает одинаковую ширину границы, и здесь также будет назначен любой пользовательский CSS, отправленный через четвертый параметр (например, пользовательские цвета границ, стили границ).

И вы сделали! По крайней мере, с настройкой HTML. Все, что осталось, - это алгоритмы отображения определенных областей окна и всплывающего окна.

Алгоритм внутреннего увеличения 🔍

Для облегчения чтения я опущу уже установленные функции и объявления переменных и просто расскажу о коде, который необходимо добавить в скобки if (effect.inner) { }.

Нам понадобится триггер, чтобы div.popup появлялся и исчезал по мере необходимости. Эта часть очень проста.

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

Для тех, кто не знает, я объясню, какие переменные используются для вычисления x и y. e.pageX - горизонтальное положение мыши на странице: количество пикселей, на которое мышь находится от крайнего левого края окна или фрейма браузера. offset.left - горизонтальное положение миниатюры на странице: количество пикселей, на которое миниатюра находится от левого края окна или фрейма браузера. Вычитая offset.left и data.borderWidth (ширина границы миниатюры) из e.pageX, вы остаетесь с положением мыши по отношению к миниатюре. Например, если ваша мышь расположена в верхнем левом углу миниатюры, x будет 0, а y будет 0; если указатель мыши расположен посередине внизу миниатюры 320 × 240, x будет 160, а y будет 240.

Расположение фона div.popup немного сложнее. CSS для положения фона - в отличие от отступов, полей и т. Д. - состоит из левой позиции фона, за которой следует верхняя позиция фона. Поскольку эскиз меньше, чем всплывающее окно с высоким разрешением, именно здесь соотношение играет важную роль. Для каждого пикселя, на который мышь перемещается по миниатюре, мы хотим переместить во всплывающем окне на ratio.x пикселя; например если размер всплывающего окна в три раза превышает размер эскиза, нам нужно, чтобы оно перемещалось на три пикселя на каждый пиксель, на который мышь перемещается по эскизу. Тогда ваш алгоритм будет x * ratio.width и y * ratio.height.

К сожалению, это не так просто. x * ratio.width поместит пиксель в центр мыши в крайнем левом углу всплывающего окна, когда мы хотим, чтобы он находился в центре всплывающего окна. Используя этот код, когда вы наводите указатель мыши на крайний правый угол миниатюры, положение фона для всплывающего окна будет отрицательным по сравнению с шириной всего изображения с полным разрешением. Возьмем, к примеру, эскиз размером 320 × 240 и всплывающее окно размером 640 × 480: когда указатель мыши помещен в координату 320 x эскиза, положение фона будет -640 пикселей (положение мыши [320], умноженное на соотношение [2]). Если изображение с разрешением 640 пикселей сдвинуто влево на 640 пикселей, вы больше не сможете его увидеть! Это не то, что мы хотим.

Итак, как нам переместить позицию из крайнего левого угла в центр? Вы должны сначала отметить отрицательное значение перед значением в CSS. Число, которое мы вычисляем, - это то, на сколько пикселей вправо должно переместиться изображение; используя негатив, мы таким образом сдвигаем изображение влево. Остерегайтесь двойного отрицания в следующем алгоритме. -(a-b) на самом деле означает -a + b (перемещено a пикселей влево, затем b пикселей вправо). Неконденсированный алгоритм определения количества пикселей для перемещения изображения влево следующий: x * ratio.width - x / data.thumbnailWidth * data.thumbnailWidth. То есть позиция пикселя в изображении с полным разрешением (x * ratio.width) минус процент прокрученного изображения (x / data.thumbnailWidth; мы находимся в x пикселе из data.thumbnailWidth пикселей), умноженном на общее количество пикселей (data.thumbnailWidth). На английском языке, чем дальше мы прокручиваем вправо, тем больше мы хотим вычесть из x * ratio.width, до 100% ширины эскиза. Когда x равно data.thumbnailWidth (т. Е. Мышь находится в крайнем правом углу миниатюры), мы останемся с x * ratio.width - 1 * data.thumbnailWidth.

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

Наконец, если координаты x или y равны 0, просто используйте 0 вместо отрицательного значения пикселя, потому что «-0px» недопустимый CSS; таким образом, встроенные условные операторы (x > 0 ? "-Zpx" : 0).

Алгоритмы размытия и оттенка 🏽

Я опущу уже установленные части кода, чтобы избавиться от избыточности и бессмысленной прокрутки. Следующие ниже фрагменты необходимо добавить к блоку else { } кода.

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

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

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

Легкий! Теперь о страшном алгоритме.

Вот и все. Я считаю, что алгоритмы размытия и оттенка намного проще, чем внутренние, исключительно из-за того, что работа с полем мыши, предотвращающим прокрутку за пределы размеров миниатюры, упрощает вычисление фона всплывающего окна.

Для тех, кто задается вопросом, вполне возможно использовать алгоритм блока мыши во внутреннем увеличении (конечно, без отображения блока мыши). Я решил не делать этого по одной чисто эстетической причине. Когда поле достигнет размеров эскиза, прокрутка всплывающего окна прекращается. Это не очень заметно с рамкой мыши, потому что вы ожидаете, что она остановится, когда граница рамки коснется границы эскиза. Однако, когда нет направляющей границы, как при внутреннем увеличении, она кажется менее плавной и более изменчивой. Чтобы увидеть разницу, наведите указатель мыши на правый нижний угол любого из примеров увеличения в начале этого руководства. Если вы немного сдвинете его влево или вверх, ничего не изменится; блок мыши по-прежнему расположен как можно дальше вниз и вправо. Однако, если вы сделаете то же самое в примере с внутренним увеличением, он будет прокручиваться независимо от того, где находится ваша мышь. Прокрутка не прекращается до тех пор, пока указатель мыши не окажется в крайнем правом или дальнем нижнем углу эскиза.

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

Заключение 🔚

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

Чтобы читать больше моих колонок, вы можете подписаться на меня в LinkedIn и Twitter или проверить мое портфолио на CharlesStover.com.