Всплывающие подсказки

Snap.svg предоставляет мощный инструмент для работы с векторной графикой в браузере. Одним из часто необходимых элементов интерактивного интерфейса являются всплывающие подсказки (tooltip). Они позволяют отображать дополнительную информацию при наведении на объекты SVG. Разберём процесс их создания детально.


Основные принципы работы с подсказками

Всплывающая подсказка в Snap.svg обычно представляет собой группу элементов: прямоугольник для фона и текст, расположенный поверх него. Эти элементы создаются динамически и позиционируются относительно объекта, на который наведен курсор. Основные задачи:

  1. Создать контейнер подсказки (g).
  2. Добавить фон (прямоугольник с закругленными углами и прозрачностью).
  3. Добавить текст подсказки.
  4. Настроить появление и скрытие при событиях mouseover и mouseout.
  5. Обеспечить динамическое позиционирование, чтобы подсказка не выходила за границы видимой области SVG.

Создание базовой подсказки

var s = Snap("#svg"); // Инициализация Snap.svg

var tooltip = s.group(); // Создание группы для подсказки
var rect = s.rect(0, 0, 0, 0, 5).attr({
    fill: "#333",
    opacity: 0.8,
    stroke: "#000",
    strokeWidth: 1
});
var text = s.text(0, 0, "").attr({
    fill: "#fff",
    fontSize: 12
});

tooltip.add(rect, text);
tooltip.attr({ visibility: "hidden" });

Здесь используется:

  • s.group() — контейнер для элементов подсказки.
  • rect() — фон с закругленными углами.
  • text() — отображаемый текст.
  • visibility: "hidden" — скрытие подсказки до наведения на объект.

Позиционирование подсказки

Правильное позиционирование подсказки предотвращает её обрезание за пределами SVG. Обычно рассчитывается смещение от курсора:

function showTooltip(evt, message) {
    text.attr({ text: message });
    var bbox = text.getBBox();
    rect.attr({
        width: bbox.width + 10,
        height: bbox.height + 6
    });

    var x = evt.clientX + 10;
    var y = evt.clientY + 10;

    tooltip.transform(`t${x},${y}`);
    tooltip.attr({ visibility: "visible" });
}

function hideTooltip() {
    tooltip.attr({ visibility: "hidden" });
}
  • getBBox() позволяет определить размеры текста.
  • Смещение +10 по координатам x и y создаёт отступ от курсора.
  • Метод transform("tX,Y") перемещает всю группу подсказки.

Привязка подсказки к объектам SVG

Для любого элемента Snap.svg можно добавить события:

var circle = s.circle(100, 100, 50).attr({
    fill: "#1E90FF"
});

circle.mouseover(function(evt) {
    showTooltip(evt, "Это синий круг");
});

circle.mouseout(function() {
    hideTooltip();
});

circle.mousemove(function(evt) {
    showTooltip(evt, "Это синий круг"); // Обновляем позицию при движении мыши
});
  • mouseover — отображение подсказки.
  • mouseout — скрытие подсказки.
  • mousemove — обновление позиции, если курсор перемещается по объекту.

Настройка внешнего вида подсказки

Для улучшения читаемости и эстетики применяются стили:

rect.attr({
    fill: "#222",
    stroke: "#fff",
    strokeWidth: 1,
    rx: 6,
    ry: 6
});

text.attr({
    fontFamily: "Arial, sans-serif",
    fontSize: 14,
    fontWeight: "bold"
});
  • rx и ry — закругление углов прямоугольника.
  • Прозрачность и контрастный цвет текста делают подсказку читаемой на разных фонах.
  • Шрифты и размеры текста могут динамически подстраиваться под содержимое.

Динамическая длина текста

Чтобы подсказка корректно масштабировалась под любую строку текста:

function updateTooltipSize() {
    var bbox = text.getBBox();
    rect.attr({
        width: bbox.width + 12,
        height: bbox.height + 8
    });
}

Вызов updateTooltipSize() после изменения текста гарантирует правильный размер прямоугольника.


Подсказки для нескольких элементов

Для множества объектов можно использовать единый tooltip:

var items = [
    { x: 50, y: 50, r: 30, label: "Красный круг", color: "#FF6347" },
    { x: 200, y: 80, r: 40, label: "Зеленый круг", color: "#32CD32" }
];

items.forEach(function(item) {
    var c = s.circle(item.x, item.y, item.r).attr({ fill: item.color });
    c.mouseover(function(evt) { showTooltip(evt, item.label); });
    c.mouseout(hideTooltip);
    c.mousemove(function(evt) { showTooltip(evt, item.label); });
});

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


Адаптивное позиционирование в пределах SVG

Чтобы подсказка не выходила за границы SVG, выполняется проверка координат:

function adjustPosition(x, y) {
    var bbox = tooltip.getBBox();
    var svgBBox = s.node.getBoundingClientRect();

    if (x + bbox.width > svgBBox.width) x -= bbox.width + 20;
    if (y + bbox.height > svgBBox.height) y -= bbox.height + 20;

    return { x, y };
}

function showTooltip(evt, message) {
    text.attr({ text: message });
    updateTooltipSize();
    var pos = adjustPosition(evt.clientX, evt.clientY);
    tooltip.transform(`t${pos.x},${pos.y}`);
    tooltip.attr({ visibility: "visible" });
}

Это предотвращает обрезку подсказки и улучшает взаимодействие с пользователем.


Анимация появления и скрытия

Для более плавного интерфейса можно использовать animate:

tooltip.attr({ opacity: 0, visibility: "visible" });
tooltip.animate({ opacity: 1 }, 200);

function hideTooltip() {
    tooltip.animate({ opacity: 0 }, 200, function() {
        tooltip.attr({ visibility: "hidden" });
    });
}
  • animate() позволяет плавно менять свойства.
  • Такой подход делает интерфейс современным и визуально приятным.

Эти приёмы формируют полный каркас системы всплывающих подсказок в Snap.svg: от базового создания элементов до адаптивного позиционирования и анимации. Их можно расширять, добавляя сложные формы, иконки и динамический контент, интегрируя подсказки в любые интерактивные SVG-графики.