Dracula — рисуем графы на JavaScript

6 сентября 2010

Недавно я писал о библиотеке Flot, предназначенной для создания динамических графиков средствами JavaScript. Dracula — это аналогичная библиотека для работы с графами.

Это интересно: Название библиотеки представляет собой игру слов — Граф Дракула, Dracula Graph Library.

На момент написания этого поста последней версией библиотеки была 0.0.3 alpha. Несмотря на свой малый возраст, уже сейчас Dracula умеет создавать достаточно сложные динамические графы. «Динамические» означает, что узлы графа можно перетаскивать мышью. «Достаточно сложные» — в плане оформления, а не числа узлов и ребер.

Пользоваться библиотекой — одно удовольствие:

<html>
<head>
<title>Dracula Test</title>
  <!-- подключаем необходимые js-файлы -->
  <script type="text/javascript" src="js/raphael-min.js">
  </script>
  <script type="text/javascript" src="js/dracula_graffle.js">
  </script>
  <script type="text/javascript" src="js/dracula_graph.js">
  </script>
</head>
<body>
<!-- здесь будет выведен граф -->
<div id="canvas"></div>
<script language="javascript" type="text/javascript">
var g = new Graph();
// добавляем узел с id "bebebe" и подписью "stand alone"
// последний аргумент метода addNode - необязательный
g.addNode("bebebe", { label: "stand alone" });

for(var i = 1; i <= 13; i++) {
 // метод addEdge(a, b) создает ребро между узлами а и b
 // если узлы a и b еще не созданы, они создадутся автоматически
 g.addEdge(i, (i + 3) % 5 + 1);
 var j = (i + 7) % 5 + 1;

 // можно указать дополнительные свойства ребра
 g.addEdge(i, j, {
   directed: true, // ориентированное ребро
   stroke: "#fff", fill: "#5a5", // цвета ребра
   label: i+":"+j } ); // надпись над ребром
}

// вычисляем расположение вершин перед выводом
var layouter = new Graph.Layout.Spring(g);
layouter.layout();

// выводим граф
var renderer = new Graph.Renderer.Raphael('canvas', g, 512, 368);
renderer.draw();
</script>
</body>
</html>

Данный код выводит вот такую красоту:

Граф, нарисованный библиотекой Dracula

Здесь я раскидал вершины подальше друг от друга — сама библиотека не всегда располагает их самым удачным образом. Еще один обнаруженный мной косяк — иногда во время перемещения вершины «улетают» за пределы холста и не желают оттуда возвращаться. Кроме того, библиотека довольно требовательна к ресурсам.

Приведенный пример работает на моем компьютере с небольшими тормозами, но они практически незаметны. Аналогичный граф, состоящий из 30 вершин, рисуется около трех секунд и ощутимо тормозит при перетаскивании вершин. На создание графа из 100 вершин уходит целых 5 секунд, что уже совершенно неприемлемо.

Однако при этом библиотека неплохо справляется с деревом, состоящим из 121-го узла (ему, конечно, нужен холст побольше, чем 512×368, как в приведенном примере). Таким образом, производительность Dracula в первую очередь зависит от структуры графа. Код для построения дерева:

var g = new Graph();
var counter = 1;

g.addNode("x", {label: "1"});
buildTree("x", 4);

function buildTree(node, level) {
  var left = node + "l";
  var right = node + "r";
  var center = node + "c";

  g.addNode(left, {label: ++counter});
  g.addNode(right, {label: ++counter});
  g.addNode(center, {label: ++counter});

  g.addEdge(node, left);
  g.addEdge(node, right);
  g.addEdge(node, center);
  if(level > 1) {
    buildTree(left, level - 1);
    buildTree(right, level - 1);
    buildTree(center, level - 1);
  }
}

Несмотря на недостатки библиотеки, я бы советовал держать ее на вооружении. Во-первых, в будущем производительность Dracula может быть улучшена (а может, на всех ПК будут 16-и ядерные процессоры?). Во-вторых, если вам нужно вывести схему локалки из десятка компьютеров или небольшую нейронную сеть, библиотека вполне справится с задачей.

На официальном сайте Dracula вы найдете пример кода, выводящего граф с вершинами произвольной формы. А в этом архиве находится приведенный в заметке пример вместе с библиотекой версии 0.0.3 alpha.

Дополнение: См также мой пост Рисуем красивые графы при помощи Graphviz.

Метки: .


Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.