При использовании динамической SVG
-графики, может возникнуть ситуация, когда удобно работать с каким-нибудь конкретным viewBox
-ом, указав ту координатную сетку, с координатами и размерами которой будет удобно работать. Однако не все векторные примитивы вам может захотеться рисовать в масштабе этой сетки. Какие-то из них вы пожелаете сохранить в пикселном представлении. Что же делать?
- Можно поменять
viewBox
таким образом, что бы1-ца сетки
в нём соответсвовала1px на канве
. Что далеко не всегда бывает удобным вариантом. - Можно подсчитать кол-во реальных px-й на 1 сетки viewBox-а и исходить из них.
В этом посту я остановлюсь на 2-ом варианте. Итак, с чего начнём? Начнём с того, что для границ-рамок-как-угодно-называйте, в общем для stroke
, есть уже готовый механизм: vector-effect: non-scaling-stroke
. Указав это свойство ваши stroke-width
будут задаваться в реальных пикселах, а не в масштабе SVG
.
А что делать, скажем, с радиусом
для circle
? Положим мы хотим нарисовать точку, но хотим чтобы её размер в px-ах не зависел от размеров канвы и масштаба на ней. Ну для начала посчитаем кол-во пикселей на 1-цу сетки
:
const { width: wpx, height: hpx } = svg.getBoundingClientRect(); const kx = wpx / wi; const ky = hpx / hi;
Где wi
и hi
это координатные width
и height
для viewBox
. Если kx === 10
, то на 1-цу сетки у вас 10 пикселей.
Ок, что дальше? Можно использовать эти коэффициенты на стороне JS
, а можно отдать почти всё на откуп CSS
, воспользовавшись CSS-variables
. Например так:
<svg viewBox="" style={{ '--var-kx': kx }}/>
а в CSS
используем calc
:
circle { r: calc(5 / var(--var-kx)); }
UPD: Firefox
не умеет r
в css :(
Хотелось бы, конечно, чего-то вроде vector-effect: non-scaling
и для других полей. Но меня устроил и этот вариант.