Реакция на изменение размера окна

Snap.svg предоставляет удобные инструменты для динамического управления SVG-графикой, однако она не имеет встроенного механизма автоматического реагирования на изменение размеров окна браузера. Для реализации адаптивной графики используется комбинация Snap.svg и стандартных возможностей Jav * aScript: события resize и методы перерасчёта размеров и координат элементов.

window.addEventListener('resize', resizeHandler);

function resizeHandler() {
    // Логика пересчета размеров SVG и элементов
}

Событие resize срабатывает каждый раз, когда изменяются размеры окна. Внутри обработчика можно изменять размеры контейнера <svg> или отдельных элементов.


Масштабирование контейнера SVG

Первый шаг — привязка размеров SVG к размерам окна:

var s = Snap("#svgCanvas");

function resizeSVG() {
    var width = window.innerWidth;
    var height = window.innerHeight;

    s.attr({
        width: width,
        height: height
    });
}

window.addEventListener('resize', resizeSVG);
resizeSVG(); // первичная установка размеров

Использование метода attr позволяет динамически менять атрибуты width и height SVG-контейнера без потери графики. Это особенно важно для интерактивных визуализаций, где размеры элементов должны оставаться пропорциональными экрану.


Пропорциональное масштабирование элементов

Изменение размеров окна требует корректировки размеров и координат отдельных элементов, чтобы сохранить визуальную целостность:

var circle = s.circle(100, 100, 50); // исходная позиция и радиус
var originalWidth = 800;
var originalHeight = 600;

function resizeElements() {
    var scaleX = window.innerWidth / originalWidth;
    var scaleY = window.innerHeight / originalHeight;

    circle.attr({
        cx: 100 * scaleX,
        cy: 100 * scaleY,
        r: 50 * Math.min(scaleX, scaleY)
    });
}

window.addEventListener('resize', resizeElements);
resizeElements();

В этом примере используется масштабирование по обеим осям с сохранением пропорций радиуса через Math.min(scaleX, scaleY). Такой подход предотвращает искажение кругов и квадратов.


Работа с группами и трансформациями

Snap.svg поддерживает <g>-элементы и методы трансформации (transform). Это позволяет масштабировать целые группы объектов относительно определённой точки:

var group = s.group(
    s.rect(50, 50, 100, 100),
    s.circle(150, 150, 50)
);

function scaleGroup() {
    var scaleX = window.innerWidth / originalWidth;
    var scaleY = window.innerHeight / originalHeight;

    group.transform(`scale(${scaleX}, ${scaleY})`);
}

window.addEventListener('resize', scaleGroup);
scaleGroup();

Использование transform с scale экономит вычисления координат каждого объекта, позволяя изменять размеры группы целиком.


Оптимизация обработки событий resize

Событие resize может срабатывать очень часто, что приводит к значительной нагрузке при сложной графике. Для оптимизации используется техника дебаунсинга:

let resizeTimeout;

window.addEventListener('resize', function() {
    clearTimeout(resizeTimeout);
    resizeTimeout = setTimeout(function() {
        resizeSVG();
        resizeElements();
        scaleGroup();
    }, 100);
});

Дебаунсинг гарантирует, что функции перерасчёта будут вызваны не чаще одного раза за указанный интервал, снижая нагрузку на браузер.


Адаптация к изменению соотношения сторон

При динамическом изменении окна важно учитывать, что соотношение ширины и высоты может меняться. Для сохранения макета используют нормированные координаты:

function normalize(value, maxValue) {
    return value / maxValue;
}

function resizeNormalized() {
    var width = window.innerWidth;
    var height = window.innerHeight;

    circle.attr({
        cx: normalize(100, originalWidth) * width,
        cy: normalize(100, originalHeight) * height,
        r: normalize(50, originalWidth) * width
    });
}

window.addEventListener('resize', resizeNormalized);
resizeNormalized();

Такой подход позволяет адаптировать любые фигуры, даже если размеры контейнера меняются не пропорционально.


Использование viewBox для адаптивного SVG

Snap.svg поддерживает атрибут viewBox, который обеспечивает автоматическое масштабирование содержимого:

s.attr({
    viewBox: `0 0 ${originalWidth} ${originalHeight}`,
    preserveAspectRatio: "xMidYMid meet",
    width: window.innerWidth,
    height: window.innerHeight
});

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


Комбинация методов для сложной графики

Для проектов с большим количеством элементов рекомендуется комбинировать методы:

  1. Использовать viewBox для глобального масштабирования.
  2. Масштабировать отдельные элементы через transform при необходимости.
  3. Применять нормированные координаты для интерактивных элементов.
  4. Оптимизировать обработку событий через дебаунсинг или троттлинг.

Такой подход обеспечивает плавную адаптацию графики, минимизирует вычислительные затраты и сохраняет визуальную целостность интерфейса при изменении размеров окна.