Как стать автором
Обновить

График «мастер-детали» средствами Highcharts и jQuery UI

Время на прочтение4 мин
Количество просмотров7.1K
При наличии большого количества статистических данных, например таких, как котировки валют (и прочие данные, связанные с финансовой тематикой), потребление чего-либо (воды и т.д.), вообще говоря, любых данных, которые так или иначе можно представить в виде пары «дата — значение», бывает удобно представить их в графическом виде. Так как данные могут быть собраны за достаточно большой период времени, имеет смысле представлять их в виде пары графиков: «мастер»-график, на котором будут отображены все точки, и график «детали», где будут отображены точки за требуемый период. В данной статье я постараюсь рассказать, как построить график подобного типа при помощи стандартных средств библиотек HighCharts и jQuery UI.

Приведенное ниже решение, в принципе, является велосипедом, т.к. с появлением нового продукта от разработчиков HighCharts, который получил название HighStock, необходимость в реализации подобным способом отпадает. Впрочем, HighStock пока еще в состоянии beta.

Как это будет выглядеть





На рисунке выше выделено 4 зоны, которые соответствуют тому, что будет необходимо реализовать:
  1. График «детали»
  2. График «мастер»
  3. Отображаемый период
  4. Скроллбар для перетаскивания периода

First look


Очевидно, что для отображения графиков будет использоваться HighCharts, а для слайдеров — jQuery UI Silder. HTML разметка представляет собой ни что иное, как 4 последовательно расположенных DIV'а, которые расположены в соответствии со списком выше. С JS не все так просто, тут основной проблемой является синхронизация действий скроллбара, слайдера и графика «детали». В создании и обновлении графиков нет никаких сложностей, с конфигурированием можно легко разобраться при помощи документации. Из принципиальных особенностей стоит отметить, что на «мастер»-графике стоит оставить только ось X и подписи к ней, а остальные служебные элементы — скрыть.

Слайдеры


Слайдеры создаются следующим образом:

function createSlider()
{
    var sliderId = "#" + _sliderContainerId;
   
    $(sliderId).slider({
        range: true,
        min: _minDate,
        max: _maxDate,
        values: [_minDate, _maxDate],
        stop: onSliderStop,
        slide: onSliderSlide
    });

    $(sliderId + " > .ui-widget-header").addClass(_sliderRangeClass);
    $(sliderId + " > .ui-slider-handle").addClass(_sliderHandleClass);
    $(sliderId).show();

    createScrollbar();
}

function createScrollbar()
{
    var scrollId = "#" + _scrollbarContainerId;
    $(scrollId).slider({
        min: _minDate,
        max: _maxDate,
        slide: onScrollbarSlide,
        stop: onScrollbarStop
    });

    $(scrollId + " > .ui-slider-handle").addClass(_scrollbarHandleClass);
    $(scrollId).show();
}

Предельные значения слайдера и скроллбара одинаковы: левая граница соответствует минимальной дате, правая — максимальной.

Range-слайдер (номер 3 на рисунке) позволяет изменять правую и левую границы отображаемого периода. Параллельно с изменением границ также должна изменяться ширина хэнлда слайдера №4, который используется в качестве скроллбара. Для этих целей соответствующие обработчики назначаются на событие slide. Обновление графика стоит назначить на событие stop слайдеров, дабы избежать тормозов из-за постоянной перерисовки при использовании любого из слайдеров.

Так как график №3 представляет собой range-слайдер, то при обновлении необходимо только устанавливать левую и правую границы, с остальным jQuery прекрасно справится сам. В случае со скроллбаром размер хэндла приходится изменять вручную, т.к. стандартно такая возможность не предусмотрена (да и правда, зачем?). При это необходимо сделать следующее:

scrollbar.css("margin-left", -1 * width / 2 - 1);

Данная мера позволит не уезжать хэндлу скроллбара визуально на полкорпуса за контейнер. Кроме того, т.к. этот слайдер принимает единственное значение, соответствующее середине хэндла, то значение скроллбара будет равно положению левого края плюс половина его ширины. Так же, при использовании скроллбара необходимо следить, не достиг ли он правого или левого края, и остановить его в этом случае (при помощи preventDefault).

Учитывая вышесказанное, в моем случае обработчики выглядели следующим образом:
function updateSlider(from, to)
{
    _from = from;
    _to = to;

    var $slider = $("#" + _sliderContainerId);
    $slider.slider("values", 0, from);
    $slider.slider("values", 1, to);
}

function updateScrollbar(from, to)
{
    var range = to - from;
    var $scrollbar = $("." + _scrollbarHandleClass);
    var width = $("." + _sliderRangeClass).width();
    $scrollbar.width(width);
    $scrollbar.css("margin-left", -1 * width / 2 - 1);
    $scrollbar.attr("range", range);

    $("#" + _scrollbarContainerId).slider("value", from + range / 2);
}

function onSliderSlide(event, ui)
{
    var from = _from = ui.values[0];
    var to = _to = ui.values[1];

    var fromDate = new Date(from).toUTCString();
    var toDate = new Date(to).toUTCString();

    updateScrollbar(from, to);
}

function onSliderStop(event, ui)
{
    updateChart(ui.values[0], ui.values[1]);
}

function onScrollbarSlide(event, ui)
{
    var value = ui.value;
    var range = $("." + _scrollbarHandleClass).attr("range") * 1;

    var minReached = value - _minDate < range / 2;
    var maxReached = _maxDate - value < range / 2;
    if (minReached)
    {
        updateSlider(_minDate, _minDate + range);
        event.preventDefault();
        return;
    }

    if (maxReached)
    {
        updateSlider(_maxDate - range, _maxDate);
        event.preventDefault();
        return;
    }

    updateSlider(value - range / 2, value + range / 2);
}

function onScrollbarStop(event, ui)
{
    var value = ui.value;
    var range = $("." + _scrollbarHandleClass).attr("range") * 1;

    updateChart(value - range / 2, value + range / 2);
}


Результаты


В итоге, следуя указаниям, можно создать что-то вроде этого: демо. При помощи CSS внешний вид можно сделать практически каким угодно. К полученному графику легко добавить такие вещи, как динамическая загрузка и обновление, сравнение данных и т.д.

Ссылки:
  1. HighCharts
  2. jQuery UI
  3. HighStock
Теги:
Хабы:
+33
Комментарии22

Публикации

Истории

Работа

Ближайшие события

Weekend Offer в AliExpress
Дата20 – 21 апреля
Время10:00 – 20:00
Место
Онлайн
Конференция «Я.Железо»
Дата18 мая
Время14:00 – 23:59
Место
МоскваОнлайн