Tag: JS

Размеры SVG-элементов в реальных пикселах

При использовании динамической 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 и для других полей. Но меня устроил и этот вариант.