Обрезать, чтобы соответствовать шаблону svg

У меня есть шаблоны, в каждом из которых есть одно изображение. Мне нужно, чтобы изображения масштабировались до полной ширины или высоты их контейнеров, которые являются путями, сохраняя при этом их пропорции. По сути, они должны вести себя как HTML-изображение, если вы установите min-width:100%; min-height:100%;

Раньше я не использовал svgs и не знаю, какие атрибуты нужно изменить, чтобы получить такой тип поведения. Я пробовал всевозможные комбинации viewBox, preserveAspectRatio, patternUnits и других, но не могу получить то, что хочу.


person raphaeltm    schedule 05.04.2014    source источник
comment
Шаблоны на самом деле не подходят для такого варианта использования. Лучше использовать фильтр.   -  person Michael Mullany    schedule 05.04.2014
comment
@MichaelMullany Фильтры могут замедлить работу браузера, но размеры и единицы измерения, которые я описываю ниже, во многом такие же, как и для фильтра с элементом <feImage>.   -  person AmeliaBR    schedule 06.04.2014


Ответы (1)


Чтобы заставить это работать, вам нужно понять, как работают objectBoundingBox единицы в SVG, а также как работает preserveAspectRatio.

Единицы ограничивающей рамки объекта

Размер и содержимое градиентов, шаблонов и ряда других функций SVG можно указать в терминах размера объекта (path, rect, circle), который рисуется, указав objectBoundingBox в качестве единицы измерения. Противоположность всегда userSpaceOnUse, которая использует систему координат, в которой рисуется фигура.

Единицы ограничивающей рамки объекта обычно используются по умолчанию для объявления размера и положения графического элемента заливки; вы можете изменить это, установив свойство patternUnits для элемента <pattern>. Однако единицы пользовательского пространства обычно используются по умолчанию для любых единиц, используемых в графике содержимого; чтобы изменить это, вы устанавливаете свойство patternContentUnits.

Итак, первый шаг: Чтобы создать узор, полностью заполняющий фигуру, вам необходимо:

  • Объявить высоту и ширину шаблона как 100% (или 1); они будут по умолчанию интерпретироваться относительно ограничивающей рамки).
  • Объявить patternContentUnits="objectBoundingBox".
  • Измените размер содержимого (вашего изображения) так, чтобы его высота и ширина были равны 1.

Вы не можете использовать 100% в качестве синонима для 1 единицы ограничивающей рамки объекта в самом содержимом шаблона (т. е. размеры изображения); проценты интерпретируются относительно размера SVG, а не objectBoundingBox.*

Я должен упомянуть, поскольку вы говорите, что ваши фигуры состоят из <path> элементов, что ограничивающая рамка объекта — это наименьший прямоугольник, который перпендикулярен системе координат, в которой нарисован путь, и содержит все точки пути. Это не включает инсульт. Например, прямая горизонтальная линия имеет ограничивающую рамку нулевой высоты; угловая линия имеет ограничивающий прямоугольник прямоугольника, так что линия является диагональю прямоугольника. Если ваши пути имеют неправильную форму и/или не очень хорошо выровнены с системой координат, ограничивающая рамка может быть намного больше, чем путь.

Сохранение соотношения сторон

Свойство preserveAspectRatio применяется к изображениям и любому элементу, который может иметь свойство viewBox: родительскому <svg>, вложенным <svg>, <symbol>, <marker> и <pattern>. Для изображений соотношение сторон рассчитывается на основе соотношения ширины и высоты изображения, для всех остальных оно рассчитывается на основе значений ширины и высоты в атрибут viewBox.

Для любого типа элемента, если вы объявляете высоту или ширину для элемента, который не соответствует соотношению сторон, свойство preserveAspectRatio определяет, будет ли содержимое растянуто по размеру (none), подогнано под одно измерение и обрезано по размеру. другое (slice) или уменьшено для соответствия обоим размерам с дополнительным пространством (meet); для параметров meet и slice вы также указываете, как выровнять содержимое в пространстве.

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

Также следует знать, что значение по умолчанию обычно не none. Для элементов <image> и <pattern> по умолчанию используется значение xMidYMid meet, т. е. сжатие по размеру и по центру. Конечно, это значение по умолчанию влияет на элементы шаблона только в том случае, если элемент шаблона имеет свойство viewBox (в противном случае предполагается, что он не имеет соотношения сторон, которое необходимо сохранить).

Какое значение вы хотите использовать для preserveAspectRatio, будет зависеть от изображения и дизайна:

  • Следует ли растянуть изображение, чтобы оно соответствовало форме preserveAspectRatio="none"?
  • Следует ли сохранять соотношение сторон изображения, но размер должен полностью вписываться в форму или покрывать ее?

В первом случае (растяжение) вам не нужно ничего делать с элементом <pattern> (отсутствие viewBox означает отсутствие управления соотношением сторон), но вам необходимо специально отключить управление соотношением сторон на изображение.

Напротив, если вы хотите избежать искажения изображения, вам необходимо:

  • Установите свойства viewBox и preserveAspectRatio для элемента <pattern>;
  • Установите свойство preserveAspectRatio в <image>, если вы хотите что-то отличное от значения по умолчанию.

Рабочий пример

Эта скрипка показывает три способа получения изображения шаблона для заполнения формы.

  • В верхнем ряду отключено управление соотношением сторон.

    <!-- pattern1 - no aspect ratio control -->
    <pattern id="pattern1" height="100%" width="100%"
             patternContentUnits="objectBoundingBox">
        <image height="1" width="1" preserveAspectRatio="none" 
               xlink:href="/*url*/" />
    </pattern>
    
  • Средняя строка имеет управление соотношением сторон в элементе <image>, поэтому изображение обрезается, чтобы соответствовать шаблону, но изображение по-прежнему искажается, когда шаблон рисуется в прямоугольнике, потому что единицы objectBoundingBox, которые определяют систему координат, отличаются для высоты и ширины. . (Изображение в круге не искажено, потому что ограничивающая рамка круга представляет собой квадрат.)

    <!-- pattern2 - aspect ratio control on the image only -->
    <pattern id="pattern2" height="100%" width="100%"
             patternContentUnits="objectBoundingBox">
        <image height="1" width="1" preserveAspectRatio="xMidYMid slice" 
               xlink:href="/*url*/" />
    </pattern>
    
  • В нижней строке для изображения и для шаблона установлено значение preserveAspectRatio (а также для шаблона установлено значение viewBox). Изображение обрезается, но не растягивается.

    <!-- pattern3 - aspect ratio control on both image and pattern -->
    <pattern id="pattern3" height="100%" width="100%"
             patternContentUnits="objectBoundingBox" 
             viewBox="0 0 1 1" preserveAspectRatio="xMidYMid slice">
        <image height="1" width="1"  preserveAspectRatio="xMidYMid slice" 
               xlink:href="/*url*/" />
    </pattern>
    

Вывод из примера скрипта JS, показывающий описанные изображения

Исходное изображение Стефана Краузе, с Викисклада. Исходное соотношение сторон — портретный режим 4:6.

* Исправление от 03.04.2015

person AmeliaBR    schedule 05.04.2014
comment
Спасибо за чудесно подробный ответ! Я думаю, что главное, чего мне не хватало, это как использовать preserveAspectRatio, но я многому научился из этого. - person raphaeltm; 06.04.2014
comment
Рад, что ты разобрался. Я решил, что это достаточно запутанная тема, которая заслуживает обсуждения с ног до головы, которое могло бы помочь другим в будущем, вместо того, чтобы тратить дюжину комментариев туда-сюда, пытаясь понять, какая часть головоломки сбила вас с толку. вверх. - person AmeliaBR; 06.04.2014
comment
Амелия, это фантастическое объяснение. Вам следует подумать о том, чтобы внести какую-то версию этого в документ элемента шаблона на webplatform.org, который очень нуждается в содержании. - person Michael Mullany; 07.04.2014
comment
Спасибо @MichaelMullany. Да, я должен еще раз взглянуть на webplatform.org и посмотреть, могу ли я чем-нибудь помочь. Мне нравится идея проекта, но я знаю, что когда мне нужно что-то поискать самому, я все равно склонен возвращаться к MDN, потому что там больше контента. - person AmeliaBR; 07.04.2014
comment
@RobertLongson Рад видеть это редактирование! Спасибо за исправление. У меня есть аналогичная поправка, которую нужно внести в мою книгу: Мне нравится превращать предупреждения Это не работает в Если это не работает, ваш пользователь не обновлял свой браузер в последнее время. - person AmeliaBR; 20.05.2015
comment
@AmeliaBR Скрипт ссылки не работает Пожалуйста, исправьте, если возможно - person Alexandr_TT; 08.04.2019
comment
@Alexandr_TT Ссылка исправлена. Если в будущем вы столкнетесь с другими, вам нужно заменить http://fiddle.jshell.net на https://jsfiddle.net/. - person AmeliaBR; 09.04.2019
comment
@ AmeliaBR Спасибо за ответ. И спасибо за отличную статью, которая помогла мне разобраться в некоторых нюансах svg - person Alexandr_TT; 09.04.2019
comment
Я искренне хотел бы пожертвовать часть своей репутации этому ответу. Большое спасибо. Я никогда даже не знал, что Дефс был вещью, и, вероятно, никогда бы не знал, если бы не этот ответ. D3 стал намного проще. - person Native Coder; 09.05.2020