Привет, Друзья!
Хотел поделиться с вами своим последним мини-проектом: трехмерной визуализацией всего npm. Вселенная выглядит примерно так:
Можно летать клавишами WASD, или если вы смотрите ее из телефона — просто вращая телефон вокруг (телефон должен поддерживать WebGL).
Много пакетов в центре, зависят от монстров типа lodash, request. Много изолированных пакетов, которые образуют кольцо астероидов:
Все исходники тут: github.com/anvaka/allnpmviz3d/
Интерактивная версия доступна здесь: anvaka.github.io/allnpmviz3d/
Видео демонстрация:
Надеюсь, вам понравится! Под катом немножко технических деталей о том, как это сделано
Как это сделано?
Проект построен на основе angular.js, twitter bootstrap и three.js. Все исходники проекта написаны в CommonJS стиле, что позволяет легко структурировать программу и использовать готовые модули из npm'a. Я использую gulp для создания финального файла. В gulpfile запускается browserify для обработки commonjs пакетов, и less для построения стилей бутстрапа.
Весь граф изначально укладывается на сервере, при помощи модулей из ngraph'a и утилит из пакета allnpm.
Отсылаем граф клиенту
Отослать граф с информацией о 100 тысячах узлах и 200+ тысячах связей в лоб (например как JSON) оказалось дорого — слишком большой размер графа. Потому придумал специальный двоичный формат для компактного хранения графа.
В этом формате каждый узел задается тремя 32-битным целыми: координаты узла x, y, z. Позиция узлов шлется сплошным потоком клиенту. Клиент читает тройки и запоминает их индекс:
Index Position
1 x1, y1, z1
2 x2, y2, z2
Как только клиент получил эти данные он начинает рисовать узлы в пространстве. Но как же передать связи? Связи хранятся в отдельном двоичном файле. Файл состоит из последовательно записанных int32. Некоторые числа отрицательные, некоторые положительные. Отрицательными числами я маркирую начало следующего узла, а положительные говорят с какими индексами связан последний отрицательный.
Например:
-1 2 -3 4 5
Это означает что вершина 1 связана с вершиной 2, а вершина 3 связана с вершинами 4 и 5. В итоге весь граф помещается в 2.5 MB.
Ну и наконец, отдельным json массивом шлется информация обо всех именах. Индекс в массиве соответствует индексу в файле с позициями.
Разве angular не медленный?
Смотря для чего. Angular.js прекрасная библиотека для создания UI. Я использую angular лишь для отображения результатов поиска и подсказок в интерфейсе. Сама сцена рисуются совершенно независимо от angular.
Многие мои коллеги говорят, что выбирая angular вы выбираете все или ничего. Сложно отказаться/заменить angular если уже начал писать на нем. Думаю они правы, ведь внедрение зависимостей и система модулей в angular чрезвычайно узконаправленная.
Но, если отказаться от использования angular.module() код внезапно перестает выглядеть angular кодом. Это обычные javascript функции, с обычными параметрами. А раз так, их тоже можно легко создавать и делиться ими на npm'e.
Так я и поступил. Заменил angular.module на простой пакет который «накапливает» анугляроподобные функции:
module.exports = require('an').controller(myController);
function myControlelr($scope) {
$scope.message = "Привет!";
}
и потом одним махом регистрирует накопленные функции когда запускается сайт:
var ngApp = angular.module('allnpmviz3d', []);
require('an').flush(ngApp);
angular.bootstrap(document, [ngApp.name]);
// Теперь myController - вполне закономерный житель в мире angular.js
Финальные заметки
Благодаря npm'у и commonjs'у проект состоит из примерно 1,700 моих строк кода и 63,300 не моих:
Я знаю, мерять код строками — так себе научно, но в целом, восприятие сложности проекта было значительно улучшено при помощи модульного подхода.
В проекте также есть пасхальное яйцо. Поскольку вы, дорогой читатель, дошли до самого конца, попробуйте ввести в поле поиска
:i love npm
и звезды должны вам ответить.
Надеюсь, вам понравилось! Буду рад вашим советам и комментариям!
Автор: anvaka