misc/class
lib/jquery_pnotify, lib/moment, lib/lodash, misc/notification, site/engine, misc/social
if( $.browser.msie && $.browser.version <= 8 ) include('lib/respond'); $._social.__cfg = {"init":[{"service":"basic"},{"fb_app_id":"1997094873850041","service":"fb"},{"vk_app_id":"2978320","service":"vk"},{"service":"twi"}],"like":[{"service":"fb"},{"service":"vk"},{"via":"","channel":"","hash_tag":"","service":"twi"}]}; window._SiteEngine = new classes.SiteEngine( { user_id: 0, controller: 'content_tape', action: 'tag', content_css_version: '1459538664', social_enabled: 0} );

Faiwer

Блог web-программиста

Поиск по метке: SVG

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

16 ноября 2017

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