import angular from 'angular'; import _ from 'lodash'; import $ from 'jquery'; import baron from 'baron'; const module = angular.module('grafana.directives'); module.directive('graphLegend', (popoverSrv, $timeout) => { return { link: (scope, elem) => { let firstRender = true; const ctrl = scope.ctrl; const panel = ctrl.panel; let data; let seriesList; let i; let legendScrollbar; const legendRightDefaultWidth = 10; const legendElem = elem.parent(); scope.$on('$destroy', () => { destroyScrollbar(); }); ctrl.events.on('render-legend', () => { data = ctrl.seriesList; if (data) { render(); } ctrl.events.emit('legend-rendering-complete'); }); function getSeriesIndexForElement(el) { return el.parents('[data-series-index]').data('series-index'); } function openColorSelector(e) { // if we clicked inside poup container ignore click if ($(e.target).parents('.popover').length) { return; } const el = $(e.currentTarget).find('.fa-minus'); const index = getSeriesIndexForElement(el); const series = seriesList[index]; $timeout(() => { popoverSrv.show({ element: el[0], position: 'bottom left', targetAttachment: 'top left', template: '' + '', openOn: 'hover', model: { series: series, toggleAxis: () => { ctrl.toggleAxis(series); }, colorSelected: color => { ctrl.changeSeriesColor(series, color); }, }, }); }); } function toggleSeries(e) { const el = $(e.currentTarget); const index = getSeriesIndexForElement(el); const seriesInfo = seriesList[index]; const scrollPosition = legendScrollbar.scroller.scrollTop; ctrl.toggleSeries(seriesInfo, e); legendScrollbar.scroller.scrollTop = scrollPosition; } function sortLegend(e) { const el = $(e.currentTarget); const stat = el.data('stat'); if (stat !== panel.legend.sort) { panel.legend.sortDesc = null; } // if already sort ascending, disable sorting if (panel.legend.sortDesc === false) { panel.legend.sort = null; panel.legend.sortDesc = null; ctrl.render(); return; } panel.legend.sortDesc = !panel.legend.sortDesc; panel.legend.sort = stat; ctrl.render(); } function getTableHeaderHtml(statName) { if (!panel.legend[statName]) { return ''; } let html = '' + statName; if (panel.legend.sort === statName) { const cssClass = panel.legend.sortDesc ? 'fa fa-caret-down' : 'fa fa-caret-up'; html += ' '; } return html + ''; } function render() { const legendWidth = legendElem.width(); if (!ctrl.panel.legend.show) { elem.empty(); firstRender = true; return; } if (firstRender) { elem.on('click', '.graph-legend-icon', openColorSelector); elem.on('click', '.graph-legend-alias', toggleSeries); elem.on('click', 'th', sortLegend); firstRender = false; } seriesList = data; elem.empty(); // Set min-width if side style and there is a value, otherwise remove the CSS property // Set width so it works with IE11 const width: any = panel.legend.rightSide && panel.legend.sideWidth ? panel.legend.sideWidth + 'px' : ''; const ieWidth: any = panel.legend.rightSide && panel.legend.sideWidth ? panel.legend.sideWidth - 1 + 'px' : ''; legendElem.css('min-width', width); legendElem.css('width', ieWidth); elem.toggleClass('graph-legend-table', panel.legend.alignAsTable === true); let tableHeaderElem; if (panel.legend.alignAsTable) { let header = ''; header += ''; if (panel.legend.values) { header += getTableHeaderHtml('min'); header += getTableHeaderHtml('max'); header += getTableHeaderHtml('avg'); header += getTableHeaderHtml('current'); header += getTableHeaderHtml('total'); } header += ''; tableHeaderElem = $(header); } if (panel.legend.sort) { seriesList = _.sortBy(seriesList, series => { let sort = series.stats[panel.legend.sort]; if (sort === null) { sort = -Infinity; } return sort; }); if (panel.legend.sortDesc) { seriesList = seriesList.reverse(); } } // render first time for getting proper legend height if (!panel.legend.rightSide || (panel.legend.rightSide && legendWidth !== legendRightDefaultWidth)) { renderLegendElement(tableHeaderElem); elem.empty(); } renderLegendElement(tableHeaderElem); } function renderSeriesLegendElements() { const seriesElements = []; for (i = 0; i < seriesList.length; i++) { const series = seriesList[i]; if (series.hideFromLegend(panel.legend)) { continue; } let html = '
'; html += '
'; html += ''; html += '
'; html += '' + series.aliasEscaped + ''; if (panel.legend.values) { const avg = series.formatValue(series.stats.avg); const current = series.formatValue(series.stats.current); const min = series.formatValue(series.stats.min); const max = series.formatValue(series.stats.max); const total = series.formatValue(series.stats.total); if (panel.legend.min) { html += '
' + min + '
'; } if (panel.legend.max) { html += '
' + max + '
'; } if (panel.legend.avg) { html += '
' + avg + '
'; } if (panel.legend.current) { html += '
' + current + '
'; } if (panel.legend.total) { html += '
' + total + '
'; } } html += '
'; seriesElements.push($(html)); } return seriesElements; } function renderLegendElement(tableHeaderElem) { const legendWidth = elem.width(); const seriesElements = renderSeriesLegendElements(); if (panel.legend.alignAsTable) { const tbodyElem = $(''); tbodyElem.append(tableHeaderElem); tbodyElem.append(seriesElements); elem.append(tbodyElem); tbodyElem.wrap('
'); } else { elem.append('
'); elem.find('.graph-legend-scroll').append(seriesElements); } if (!panel.legend.rightSide || (panel.legend.rightSide && legendWidth !== legendRightDefaultWidth)) { addScrollbar(); } else { destroyScrollbar(); } } function addScrollbar() { const scrollRootClass = 'baron baron__root'; const scrollerClass = 'baron__scroller'; const scrollBarHTML = `
`; const scrollRoot = elem; const scroller = elem.find('.graph-legend-scroll'); // clear existing scroll bar track to prevent duplication scrollRoot.find('.baron__track').remove(); scrollRoot.addClass(scrollRootClass); $(scrollBarHTML).appendTo(scrollRoot); scroller.addClass(scrollerClass); const scrollbarParams = { root: scrollRoot[0], scroller: scroller[0], bar: '.baron__bar', track: '.baron__track', barOnCls: '_scrollbar', scrollingCls: '_scrolling', }; if (!legendScrollbar) { legendScrollbar = baron(scrollbarParams); } else { destroyScrollbar(); legendScrollbar = baron(scrollbarParams); } // #11830 - compensates for Firefox scrollbar calculation error in the baron framework scroller[0].style.marginRight = '-' + (scroller[0].offsetWidth - scroller[0].clientWidth) + 'px'; legendScrollbar.scroll(); } function destroyScrollbar() { if (legendScrollbar) { legendScrollbar.dispose(); legendScrollbar = undefined; } } }, }; });