Использование AngularJS для визуализации данных
Перевод статьи Using AngularJS for Data Visualisations с сайта css-tricks.com, автор — Ник Мортон.
Перед вами гостевой пост от Ника Мортона. Должен сказать, что я весьма заинтригован этой идеей. Знаю, что я люблю работать с HTML, SVG и CSS, поэтому, когда Ник поделился со мной мыслью, что мы можем использовать это для создания структуры, и использовать данные непосредственно для стилизации графиков, я заинтересовался. Кроме того, понимание, что благодаря использованию Angular график может автоматически изменяться при изменении данных… это чертовски круто.
Как только я попробовал использовать AngularJS, меня осенило, что его способность брать данные и использовать их прямо в разметке может позволить создать очень быстрый и простой способ для визуализации данных.
В этом уроке я расскажу о создании трех различных видов графиков с помощью встроенных CSS и SVG.
Почему Angular?
Если вам когда-либо приходилось добавлять элементы в DOM с помощью JavaScript или jQuery, то вы знаете, как быстро ваш код может превратиться в кашу. Особенно, если вы используете несколько переменных. Angular позволяет использовать данные прямо в разметке, что ведет к чистому и простому для чтения и восприятия коду.
Конечно, существуют несколько великолепных библиотек для визуализации, но все они поставляются с установленными по умолчанию стилями. При использовании Angular визуализации получаются очень неприхотливыми, и они тут же подхватят любые заданные вами стили.
Я не утверждаю, что это самый лучший способ для создания визуализаций данных, но он точно мне по душе!
Примечание: в этой статье я не буду рассматривать все тонкости Angular, такие как работа приложений, контроллеров и т.д. – я буду сконцентрирован на данных. Я написал приложение 'Hello World на AngularJS', которое может помочь вам разобраться с некоторыми из этих вещей. Кроме того, существует множество великолепных ресурсов, которые помогут вам начать работать с Angular.
Настройка нашего приложения на Angular
Базовая настройка приложения
Для начала нам нужно настроить Angular-приложение и контроллер, в котором будут храниться наш функционал и данные.
(function(){ var app = angular.module('graphApp',[]); app.controller('graphController', function($scope){ // Здесь будет код! }); })();
Настройки по умолчанию
После этого мы установим значения нескольких переменных, используемых по умолчанию, которые привязаны к контексту ($scope) контроллера. Их мы будем использовать для управления размером нашего графика, а также метками осей X и Y.
$scope.width = 600; $scope.height = 400; $scope.yAxis = "Sales"; $scope.xAxis = "2014"
Данные
После этого мы добавим свои данные, записанные в формате JSON, и привяжем их к $scope
нашего контроллера.
$scope.data = [ { label: 'January', value: 36 }, { label: 'February', value: 54 }, // .... и так далее ..... { label: 'November', value: 252 }, { label: 'December', value: 342 } ];
Поиск максимального значения
Наконец, мы используем цикл, чтобы найти в наших данных максимальное значение и записать его в переменную. Это пригодится нам позже для размещения элементов в наших визуализациях.
$scope.max = 0; var arrLength = $scope.data.length; for (var i = 0; i < arrLength; i++) { // Найти максимальное значение на оси X if ($scope.data[i].value > $scope.max) $scope.max = $scope.data[i].value; }
И это весь JavaScript, что нам потребуется. По сути, мы только настроили наши данные и переменные для дальнейшего использования в разметке.
Настройка разметки, шаблонов и CSS
Теперь нам нужно настроить разметку и CSS нашего приложения для визуализации.
<div ng-app="graphApp"> <div ng-controller="graphController as graph"> <div class="graph" style="width:{{width}}px; height:{{height}}px;" > <div class="y" style="width:{{height}}px;">{{yAxis}}</div> <div class="x">{{xAxis}}</div> </div> </div> </div>
Внутри HTML мы можем использовать данные из JavaScript прямо в разметке, как в качестве контента (например, метки осей X и Y), так и во встроенных стилях для управления высотой и шириной нашего графика.
Примечание: div 'y' использует переменную {{height}} для CSS-свойства width — это связано с тем, что в CSS мы повернем эту ось на 90 градусов против часовой стрелки.
.chart { border-left: 1px solid black; border-bottom: 1px solid black; margin: 60px auto; position: relative; } .y { position: absolute; transform: rotate(-90deg); transform-origin: bottom left; bottom: 0; padding: 5px; } .x { position: absolute; top: 100%; width: 100%; padding: 5px; }
Гистограмма
Окей, для создания данных в наших таблицах мы будем использовать функцию Angular ng-repeat
. Она циклически пройдет по нашему массиву данных и для каждой записи выдаст ту разметку, в которую мы ее обернем.
Сперва мы создадим гистограмму. Для начала я задал для класса bar базовый стиль CSS, который устанавливает значение position: absolute
и добавляет цвет для заднего фона.
.bar { background: blue; position: absolute; bottom: 0; }
Затем, с помощью ng-repeat
создадим <div>
с классом 'bar' для каждой записи, которую мы будем выводить
<div ng-repeat="bar in data" class="bar"></div>
Этот код следует поместить внутрь нашего <divclass="graph"></div>
.
Теперь мы можем использовать наши данные Angular (и немного математики!) в некоторых встроенных стилях CSS для управления высотой и шириной каждого столбца.
<div ng-repeat="bar in data" class="bar" style="height:{{bar.value / max * height}}px; width:{{width / data.length - 5}}px;"></div>
Для расчета высоты мы возьмем значение, разделим его на максимум (заданный в нашем приложении Angular), и умножим на полную высоту нашего графика. Таким образом самое большое значение в наших данных будет занимать всю высоту графика.
Для расчета ширины мы разделим всю ширину на количество записей, добавив отступ в 5px, чтобы оставить немного места при размещении наших столбцов на оси X.
Наконец, нам нужно расположить столбцы вдоль оси X с помощью свойства CSS left
<div ng-repeat="bar in data" class="bar" style="height:{{bar.value / max * height}}px; width:{{width / data.length - 5}}px; left:{{$index / data.length * width}}px;"></div>
В этом примере мы используем $index
, переменную Angular, значения которой начинаются с 0 и увеличиваются для каждого последующего столбца. Мы делим значение индекса на общее количество записей и умножаем его на значение всей ширины графика. Таким образом первый столбец будет помещен в 0, а остальные будут равномерно распределены по всему графику.
Нужно отметить, что если вы хотите иметь "резиновый" график, то можете умножать на 100 и использовать в качестве единиц измерения %, а не пиксели.
Вот и все – наша гистограмма готова, и теперь вы можете немного поиграться с CSS, чтобы ее приукрасить!
Полный код для создания графика выглядит вот так:
<div class="chart" style="width:{{width}}px; height:{{height}}px;"> <!-- Метки --> <div class="y" style="width:{{height}}px;">{{yAxis}}</div> <div class="x">{{xAxis}}</div> <!-- Данные --> <div ng-repeat="bar in data" class="bar" style="height:{{bar.value / max * height}}px; width:{{width / data.length - 5}}px; left:{{$index / data.length * width}}px;"></div> </div>
Точечная диаграмма
Для создания точечной диаграммы используется очень похожий метод.
И снова я задаю для точек базовые стили CSS:
.dot { background: blue; width: 10px; height: 10px; border-radius: 50%; position: absolute; }
Работая с точками, нам не нужно переживать о высоте и ширине. Мы просто используем те же самые данные и математику для размещения точек, устанавливая отступы слева и снизу.
Единственная разница заключается в том, что мы добавляем к $index
0.5, чтобы точки располагались точно в центре выделяемого для них пространства.
<div ng-repeat="dot in data" class="dot" style="bottom:{{dot.value / max * height}}px; left:{{($index + 1) / data.length * width}}px;"></div>
Полный код для графика:
<div class="chart" style="width:{{width}}px; height:{{height}}px;"> <!-- Метки --> <div class="y" style="width:{{height}}px;">{{yAxis}}</div> <div class="x">{{xAxis}}</div> <!-- Данные --> <div ng-repeat="dot in data" class="dot" style="bottom:{{dot.value / max * height}}px; left:{{($index + 0.5) / data.length * width}}px;"></div> </div>
Как и в случае со встроенными стилями CSS, мы можем использовать значения данных Angular в данных SVG.
Для этого мы используем следующий код CSS:
svg { position: absolute; transform: rotateX(180deg); left: 0; } line { stroke:red; stroke-width:3px; }
Я поворачиваю SVG, поскольку по умолчанию оно обрабатывает значения сверху, а нам нужно развернуть его на 180 градусов, чтобы брать значения снизу.
Сперва нам нужно создать SVG, который будет занимать всю площадь нашего графика. После этого внутри мы используем ng-repeat
на элементе line
.
Каждый элемент line
требует начальной и конечной точки на осях X (x1, x2) и Y (y1, y2).
С осью X все довольно просто – мы действуем по той же схеме, что и раньше, чтобы все линии на графике располагались равномерно по всей его ширине, начиная с 0, используя $index
, а заканчивались там, где начинается следующая линия, используя $index + 1
.
На оси Y переменная $index
используется сама по себе, позволяя нам выбирать значения или предыдущих или следующих записей в нашем массиве.
Исходная точка Y каждой из линий получает значение из предыдущей записи данных с помощью data[$index - 1].value
, после чего мы используем расчеты, подобные использованным в предыдущих примерах. Для второй точки Y мы можем вызвать значение прямо из записи.
Это может показаться сложным (и я уверяю вас, что для того, чтобы дойти до этого, мне пришлось пораскинуть мозгами!), но я надеюсь, что мое объяснение вместе с представленным ниже кодом помогут вам разобраться, что к чему!
<svg style="width:{{width}}px; height:{{height}}px;"> <line ng-repeat="line in data" x1="{{$index / data.length * width}}" y1="{{data[$index - 1].value / max * height}}" x2="{{($index + 1) / data.length * width}}" y2="{{line.value / max * height}}"> </line> </svg>
Окончательный код для графика выглядит следующим образом:
<div class="chart" style="width:{{width}}px; height:{{height}}px;"> <!-- Метки --> <div class="y" style="width:{{height}}px;">{{yAxis}}</div> <div class="x">{{xAxis}}</div> <!-- Данные --> <svg style="width:{{width}}px; height:{{height}}px;"> <line ng-repeat="line in data" x1="{{$index / data.length * width }}" y1="{{data[$index - 1].value / max * height}}" x2="{{($index + 1) / data.length * width}}" y2="{{line.value / max * height}}"> </line> </svg> </div>
Что дальше?
Вы можете использовать переменную $index
и в именах классов, вот так <elementclass="classname{{$index}}">
, что позволит производить более тонкую настройку каждого из столбцов, точек или линий – что может пригодиться для анимации этих визуализаций.
Я разработал полный пример точечной/линейной диаграммы с анимацией и CSS-подсказками, используя метки для каждой из записей в наших данных. Взглянуть на него можно здесь.
Кроме того, я сделал проект на Codepen со всеми этими примерами.
Надеюсь, что вы извлекли пользу из этого урока, и я был бы счастлив узнать о визуализациях, которые вы создаете с помощью Angular!
P.S. Это тоже может быть интересно:
Это конечно хорошо, понимать как можно сварганить диаграмку. Но для более серьезных вещей все же стоит использовать что-то типа D3.js, дабы не плодить столько кода
1. если посмотреть в консоль на данной странице, то будет ад =)
2. код раздела "Базовая настройка приложения" можно переписать так
[code]angular
.module('graphApp',[])
.controller('graphController', function($scope){
// Здесь будет код!
});[/code]