Обрезать в соответствии с рисунком SVG

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

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

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>, Для изображений соотношение сторон рассчитывается из соотношения ширины и высоты изображения, для всех остальных оно рассчитывается из чисел width:height в атрибуте viewBox.

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

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

Другая вещь, которую нужно знать, это то, что значение по умолчанию обычно не 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>
    

Output from the JS fiddle example, showing the images described

Исходное изображение Стефана Краузе из Wikimedia Commons. Исходное соотношение сторон составляет 4:6 портретного режима.

* Исправление 2015-04-03

Другие вопросы по тегам