Как залить SVG фоновой картинкой, без искажения фонового изображения?
Здравствуйте! Есть следующая конструкция:
div {
background: #f5f5f5;
margin: 20px;
padding: 20px;
text-align: center;
}
<div>
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="400px" height="55px" version="1.1" viewBox="0 0 47.22 6.49" xmlns:xlink="http://www.w3.org/1999/xlink" <defs>
<pattern id="img1" patternUnits="userSpaceOnUse" width="100%" height="100%"> <image xlink:href="https://i.ibb.co/XFK2qJK/pattern.jpg" width="500px" height="500px" />
</pattern>
</defs>
<path class="fil0" d="M44.45 0c0.27,1.28 1.41,2.24 2.77,2.24l0 1.42c-1.56,0 -2.83,1.27 -2.83,2.83l-41.56 0c0,-1.56 -1.27,-2.83 -2.83,-2.83l0 -1.42c1.35,0 2.5,-0.96 2.77,-2.24 1.73,2.13 10.4,3.74 20.84,3.74 10.44,0 19.11,-1.61 20.84,-3.74z" fill="url(#img1)"/>
</svg>
</div>
<div>
<img src="https://i.ibb.co/XFK2qJK/pattern.jpg">
</div>
Необходимо залить SVG картинкой, при этом чтобы картинка которая используется в качестве фонового изображения, не была растянута. т.е. если фоновое изображение 500x500px, то оно должно таким и оставаться (500x500).
Что я делаю неправильно? Почему у меня в примере реальный размер фонового изображения 500x500px но когда я добавляю его в SVG оно растягивается примерно до 4000x4000px. Помогите исправить ошибку.
Ниже в примере добавлено для наглядности просто изображение, так как оно должно быть, а в SVG сразу видно что оно растянуто
Благодарю за ответ!
Ответы (1 шт):
SVG имеет viewBox="0 0 47.22 6.49", то есть от изображения 500X500 нам видно только 47.22X6.49. ViewBox в аккурат захватывает ваш путь по габаритам, а атрибут width растягивает это "окно" до 400px. Одновременно растягивается и кусочек изображения, естественно.
Если не искать легких путей (давно хотел попробовать), то можно распарсить путь и отмасштабировать его на уровне строки d="M...z". Нужный масштаб получаю делением реальной ширины SVG на ширину viewBox:
scale = svg.getBoundingClientRect().width/svg.getAttribute('viewBox').split(' ')[2];
Так как сам путь уже будет растянут на ширину SVG, то атрибут viewBox в конце удаляем. Ведь в паре с width он работает только для правильного размещения пути. Подстраиваться под ширину контейнера SVG не будет.
Хотя viewBox можно и оставить, изменяя и его размеры и начальные точки:
svg.setAttribute('viewBox', svg.getAttribute('viewBox').split(' ').map(i => i * scale).join(' '));
let svg = document.querySelector('svg');
let pathEl = svg.querySelector('path');
let path = pathEl.getAttribute('d');
let pathWidth = svg.getAttribute('viewBox').split(' ')[2];
let svgWidth = svg.getBoundingClientRect().width;
let scale = svgWidth/pathWidth;
let path1 = path.replace(/(?<=[^\d.-]*)([\d.-]+)(?=[^\d.-]*)/g, m => m*scale);
svg.removeAttribute('viewBox');
pathEl.setAttribute('d', path1);
<svg viewBox="0 0 47.22 6.49" width="400px">
<defs>
<pattern id="_img1" patternUnits="userSpaceOnUse" width="100%" height="100%"> <image xlink:href="https://i.ibb.co/XFK2qJK/pattern.jpg" width="500px" height="500px" />
</pattern>
</defs>
<path class="fil0" d="M44.45 0c0.27,1.28 1.41,2.24 2.77,2.24l0 1.42c-1.56,0 -2.83,1.27 -2.83,2.83l-41.56 0c0,-1.56 -1.27,-2.83 -2.83,-2.83l0 -1.42c1.35,0 2.5,-0.96 2.77,-2.24 1.73,2.13 10.4,3.74 20.84,3.74 10.44,0 19.11,-1.61 20.84,-3.74z" fill="url(#_img1)"/>
</svg>
Или гораздо проще установить 1/масштаб самому изображению. Чтобы оно уменьшилось с 500*500 до соответствующего viewBox размера.
let svg = document.querySelector('svg');
let viewWidth = svg.getAttribute('viewBox').split(' ')[2];
let svgWidth = svg.getBoundingClientRect().width;
let scale = svgWidth/viewWidth;
svg.querySelector('pattern > image').setAttribute('transform', `scale(${1/scale})`);
<svg viewBox="0 0 47.22 6.49" width="400px">
<defs>
<pattern id="_img1" patternUnits="userSpaceOnUse" width="100%" height="100%"> <image xlink:href="https://i.ibb.co/XFK2qJK/pattern.jpg" width="500px" height="500px" />
</pattern>
</defs>
<path class="fil0" d="M44.45 0c0.27,1.28 1.41,2.24 2.77,2.24l0 1.42c-1.56,0 -2.83,1.27 -2.83,2.83l-41.56 0c0,-1.56 -1.27,-2.83 -2.83,-2.83l0 -1.42c1.35,0 2.5,-0.96 2.77,-2.24 1.73,2.13 10.4,3.74 20.84,3.74 10.44,0 19.11,-1.61 20.84,-3.74z" fill="url(#_img1)"/>
</svg>