PerfectVector
Автор: Irene Kim

SVG в узлах Cytoscape.js: вписывание и отступы

Впишите собственную SVG-графику в узлы Cytoscape.js с рабочим примером. Сравните пустое место исходника, contain и cover, затем проверьте загрузку и размещение подписей.

9 мин чтения
На этой странице

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

Cytoscape.js описывает SVG-фоны узлов, включая режимы вписывания contain, cover и none. В этом руководстве оригинальная эмблема из одного контура помогает отделить границы исходника от оформления графа. Держите редактируемый мастер графики рядом с конфигурацией графа.

Отделите исходное изображение от узла графа

Нужно проверить три прямоугольника: границы нарисованной графики, область просмотра SVG-изображения и тело узла. SVG viewBox задаёт прямоугольник исходных координат, отображаемый в область просмотра. Он может включать намного больше пространства, чем видимый рисунок.

Наш плотно ограниченный исходник имеет размер 120 × 60, а коралловая эмблема занимает x=6–x=114 и y=6–y=54. Центральное отверстие — часть того же контура:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg>
<svg xmlns="http://www.w3.org/2000/svg"
     width="120" height="60" viewBox="0 0 120 60">
  <path fill="#f36f59" fill-rule="evenodd"
    d="M6 30L30 6H90L114 30L90 54H30Z M50 20H70V40H50Z"/>
</svg>

Вариант с полями меняет только внешние размеры SVG и viewBox:

<svg xmlns="http://www.w3.org/2000/svg"
     width="200" height="140" viewBox="-40 -40 200 140">

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

Запустите пример с четырьмя случаями

Мы проверили Cytoscape.js 3.34.3 с официальной браузерной сборкой закреплённой версии, размещённой локально. Сохраните сборку из этого тега выпуска как cytoscape-3.34.3.min.js рядом с приведённым ниже example.html. Раздавайте папку по локальному HTTP, например с помощью python3 -m http.server 8000, и откройте http://localhost:8000/example.html.

Пример кодирует исходный SVG в data URI. encodeURIComponent() экранирует символы URI, включая # в цвете заливки. Рекомендации библиотеки для SVG советуют это кодирование вместо Base64 и показанный здесь заголовок XML. Это одна самодостаточная эмблема без внешних шрифтов или изображений.

<!doctype html>
<html lang="en">
<meta charset="utf-8">
<title>SVG node fit comparison</title>
<style>
  body { font: 16px system-ui; margin: 20px; }
  #cy { width: 1100px; height: 250px; border: 1px solid #ddd; }
  #status { white-space: pre-wrap; }
</style>
<div id="cy"></div>
<pre id="status">Loading images</pre>
<script src="cytoscape-3.34.3.min.js"></script>
<script>
const header = '<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg>';
const path = 'M6 30L30 6H90L114 30L90 54H30Z M50 20H70V40H50Z';
function artwork(padded) {
  const width = padded ? 200 : 120;
  const height = padded ? 140 : 60;
  const viewBox = padded ? '-40 -40 200 140' : '0 0 120 60';
  return header + `<svg xmlns="http://www.w3.org/2000/svg"
    width="${width}" height="${height}" viewBox="${viewBox}">
    <path fill="#f36f59" fill-rule="evenodd" d="${path}"/></svg>`;
}
const cases = [
  ['tight contain', false, 'contain'],
  ['tight cover', false, 'cover'],
  ['padded contain', true, 'contain'],
  ['padded cover', true, 'cover']
].map(([label, padded, fit]) => ({
  label, fit,
  image: 'data:image/svg+xml;utf8,' + encodeURIComponent(artwork(padded))
}));
Promise.all(cases.map(item => new Promise((resolve, reject) => {
  const image = new Image();
  image.onload = () => resolve({
    label: item.label,
    width: image.naturalWidth,
    height: image.naturalHeight
  });
  image.onerror = () => reject(new Error(item.label + ' failed to load'));
  image.src = item.image;
}))).then(loaded => {
  cytoscape({
    container: document.getElementById('cy'),
    elements: cases.map((item, index) => ({
      data: { id: 'n' + index, ...item },
      position: { x: 110 + index * 260, y: 95 }
    })),
    style: [{ selector: 'node', style: {
      width: 120, height: 80, padding: 0, shape: 'rectangle',
      'background-color': '#f1f3f5',
      'background-image': 'data(image)',
      'background-fit': node => node.data('fit'),
      'background-width': 'auto', 'background-height': 'auto',
      'background-width-relative-to': 'inner',
      'background-height-relative-to': 'inner',
      'background-position-x': '50%', 'background-position-y': '50%',
      'background-repeat': 'no-repeat', 'background-clip': 'node',
      'border-width': 1, 'border-color': '#222',
      label: 'data(label)', 'text-valign': 'bottom',
      'text-halign': 'center', 'text-margin-y': 10, 'font-size': 12
    }}],
    layout: { name: 'preset', fit: false },
    zoom: 1, pan: { x: 0, y: 0 },
    userZoomingEnabled: false, userPanningEnabled: false,
    boxSelectionEnabled: false
  });
  document.getElementById('status').textContent =
    'Cytoscape ' + cytoscape.version + '\n' +
    JSON.stringify(loaded, null, 2);
}).catch(error => {
  document.getElementById('status').textContent = error.message;
});
</script>
</html>

Блок состояния сообщает размеры изображений, предварительно загруженных до инициализации графа. naturalWidth читает собственную ширину изображения с поправкой на плотность в CSS-пикселях, как описано в MDN. В этом примере плотно ограниченные изображения сообщили 120 × 60, а изображения с полями — 200 × 140. Это размеры изображения, а не измерения кораллового контура.

Сравните изменения при одном размере узла

Все четыре модельных узла имеют размер 120 × 80 и нулевой внутренний отступ. Мы проверили исходный пример в Chrome при масштабе графа 1 и 1,5. Размер в стиле узла оставался 120 × 80; сообщаемые отрисованные размеры при 1,5 стали 180 × 120. Это статичное сравнение в данном браузере, а не проверка совместимости или производительности масштабирования.

Исходник и вписываниеНаблюдаемый вид в этом примере
Плотные границы, containПолная эмблема с видимыми заострёнными концами
Плотные границы, coverБолее крупная эмблема с левым и правым концами, обрезанными узлом
С полями, containМеньшая эмблема, окружённая значительным пустым пространством
С полями, coverНемного крупнее варианта с полями и contain, но всё ещё намного меньше вариантов с плотными границами

Плотно ограниченный исходник имеет пропорции изображения 2:1, а узел — 1,5:1. Вписывание полного изображения 120 × 60 внутрь 120 × 80 оставляет место по вертикали. Покрытие этого узла масштабирует изображение до 160 × 80 перед обрезкой, поэтому горизонтальные концы выходят за тело узла.

У исходника с полями доступный прямоугольник изображения включает по 40 дополнительных единиц с каждой стороны. При contain масштаб ограничивается отношением 80/140, а не 120/200. Поэтому неизменённая эмблема шириной 108 единиц занимает примерно 62 модельные единицы. Это арифметика из объявленных размеров, а не измерение пикселей снимка экрана.

Границы исходника и вписывание
Иллюстрация маленькой эмблемы с большим пустым пространством исходника, полной более крупной эмблемы внутри рамки узла и эмблемы с концами, обрезанными более узкой рамкой.
Иллюстрация: пустое место исходника и вписывание могут независимо менять видимую графику. Эта концептуальная схема не является снимком Cytoscape или результатом преобразования.

Выбирайте вписывание после проверки границ графики

Начните с плотных границ исходника и contain, если важна полная эмблема. Сохраняйте достаточный запас в исходнике для обводки или эффекта, который должен остаться видимым. Слишком сильное сужение области просмотра может обрезать нужную графику; это не указание убрать все поля.

Используйте cover, когда обрезка краёв допустима для дизайна. В нашем примере он скрывает заострённые концы, поэтому плохо подходит, если они определяют эмблему. Более широкий узел может изменить пропорции вписывания и открыть концы, но также меняет компоновку графа. Пропорциональное увеличение обоих размеров сохраняет ту же обрезку. Решите, какое ограничение хотите изменить.

Для этого сравнения оставьте background-width и background-height равными auto. Явные значения могут переопределить размеры изображения, используемые при вписывании. padding узла — ещё один отдельный фактор; библиотека описывает, включает ли размер фона этот отступ или использует внутреннее тело. Прежде чем добавлять эти настройки, см. справочник background-image. Наш пример с нулевым отступом сначала изолирует пустое пространство исходника.

Для решений meet, slice и выравнивания на уровне SVG перейдите к руководству по preserveAspectRatio. Изменение внутреннего вписывания SVG и изменение вписывания фона Cytoscape — разные операции.

Диагностируйте загрузку до обрезки

Если состояние сообщает об ошибке загрузки, смена contain на cover — не следующий шаг. Откройте ресурс изображения отдельно, проверьте URL и объявленные размеры, затем сократите его до самодостаточной эмблемы только из контуров, приведённой выше. Для data URI кодируйте всю строку SVG, а не склеивайте необработанную разметку или неэкранированное значение цвета.

SVG, используемый как изображение, имеет иные ограничения, чем SVG, открытый как документ. Руководство MDN по SVG как изображению описывает ограничения сценариев и внешних ресурсов в контексте изображения. Файлу графики, зависящему от внешней таблицы стилей или шрифта, нужна отдельная проверка передачи. Этот пример избегает таких зависимостей и размещает подписи графа вне SVG.

Если изображение загружается, проверьте вписывание и обрезку узла на явно широкой фигуре. Затем проверьте настоящую графику при размере узла и в браузерных средах, которые поддерживает приложение. Документация Cytoscape отмечает особенности SVG в разных браузерах; это наблюдение в Chrome не решает их для Firefox или любого другого движка.

Держите подписи отдельно от редактируемой графики

Пример использует label: 'data(label)' для подписей графа и не содержит текста SVG. Вы можете менять формулировки без перестроения эмблемы. Контур SVG остаётся в исходном мастер-файле, а граф управляет идентичностью узла, положением и связями.

Проверенный пример рисовал на поверхностях Canvas. Наличие SVG-фона там не превращает внутренние контуры в отдельно редактируемые элементы графа. Сохраняйте мастер, если нужно менять отверстие, силуэт или цвета. Экспорт графа — отдельный процесс, требующий выбранного экспортёра и проверки передачи; это руководство не обещает, что экспортированный граф сохранит редактируемые контуры эмблемы. Руководство по графике Graphviz исследует передачу ссылок на изображения в другом средстве отрисовки диаграмм.

Если ваша эмблема существует только в PNG или JPG, преобразуйте этот исходник в векторную графику, затем проверьте силуэт, отверстие и мелкие детали до настройки границ SVG. PerfectVector может помочь восстановить редактируемую исходную геометрию. Оформление фона, подписи узлов и экспорт графа остаются отдельными этапами. Уже подходящий SVG может сразу перейти к проверкам вписывания.

Частые вопросы

Почему SVG-изображение узла крошечное даже при cover? В исходном изображении может быть много пустого пространства области просмотра вокруг контура. Сравните копию с плотными границами при тех же размерах узла до изменения компоновки графа.

Выбрать contain или cover для собственной эмблемы? Выбирайте contain, когда важна полная эмблема. Выбирайте cover, только если наблюдаемая обрезка краёв допустима для дизайна, и проверяйте это на собственном исходнике и форме узла.

Создаёт ли SVG-фон узла редактируемые контуры графа? Проверенный пример Canvas использует SVG для рисования изображения. Держите мастер графики для правки контуров; внутренние контуры в этом примере не являются отдельными узлами или рёбрами графа.

Можно ли поместить подписи в SVG? Этот пример хранит подписи в данных графа и использует графику только из контуров. Текст SVG, шрифты и зависимости контекста изображения требуют собственных браузерных проверок и проверок передачи.

Источники

  1. Cytoscape.js — Фоновое изображение — оформление URL изображения, вписывание, переопределение размеров, опорные области отступов и особенности SVG.
  2. Cytoscape.js — Выпуск v3.34.3 — закреплённый выпуск, использованный в исходном примере.
  3. Cytoscape.js — Браузерная сборка v3.34.3 — официальная реализация из тега, локально размещённая для браузерного теста.
  4. MDN — viewBox — прямоугольник исходных координат и отображение в область просмотра.
  5. MDN — encodeURIComponent — экранирование компонента data URI SVG.
  6. MDN — naturalWidth — размеры загруженного изображения, отличающиеся от границ контура.
  7. MDN — SVG как изображение — ограничения контекста изображения и проверки зависимостей.

Если эмблема начинается с растра, создайте редактируемый мастер SVG, проверьте контуры и границы исходника, затем сравните contain и cover в собственной компоновке узлов.

Ещё из блога

PerfectVector

Начните с более чистого SVG,
который проще редактировать

Без банковской карты