source : facetEditor.js

(function (angular) {
    'use strict';
    /**
     * @memberof spApp
     * @ngdoc directive
     * @name spLegend
     * @description
     *    Panel displaying selected map layer information and controls
     */
    angular.module('facet-editor-directive', ['map-service', 'biocache-service', 'layers-service', 'popup-service'])
        .directive('facetEditor', ['$timeout', '$q', '$filter', 'MapService', 'BiocacheService', 'LayersService', 'ColourService', '$http', 'LayoutService', 'PopupService', 'LoggerService',
            function ($timeout, $q, $filter, MapService, BiocacheService, LayersService, ColourService, $http, LayoutService, PopupService, LoggerService) {
                var _httpDescription = function (method, httpconfig) {
                    if (httpconfig === undefined) {
                        httpconfig = {};
                    }
                    httpconfig.service = 'facetEditor';
                    httpconfig.method = method;
                    return httpconfig;
                };
                return {
                    scope: {
                        _onCustom: "&onCustom",
                        _facet: "=facet",
                        _settings: "=?settings"
                    },
                    templateUrl: '/spApp/facetEditorContent.htm',
                    link: function (scope, element, attrs) {
                        var labelLength = 10,
                            lineHeight = 20,
                            chartData = scope._facet.data || [],
                            tableFacetDisplay = 'table',
                            chartFacetDisplay = 'chart',
                            defaultFacetDisplay = tableFacetDisplay,
                            showChartForDataTypes = $SH.rangeDataTypes,
                            sortByDisplayName = 'displayname',
                            sortByCount = 'count',
                            lastChartInstance;
                        scope.baseUrl = $SH.baseUrl; // for image icons
                        scope.$i18n = $i18n;
                        if (scope._facet.filter === undefined) scope._facet.filter = '';
                        if (scope._facet.fq === undefined) scope._facet.fq = [];
                        if (scope._facet.sortType === undefined) scope._facet.sortType = 'count';
                        if (scope._facet.sortReverse === undefined) scope._facet.sortReverse = true;
                        if (scope._facet.isAllFacetsSelected === undefined) scope._facet.isAllFacetsSelected = false;
                        if (scope._facet.loading === undefined) scope._facet.loading = false;
                        if (scope._settings === undefined) scope._settings = {};
                        if (scope._settings.chart === undefined) scope._settings.chart = {colours: [], data: [], labels:[], datasets: {}};
                        if (scope._settings.slider === undefined) scope._settings.slider = {values: [0,1], min: 0, max: 1, active: false, initialiseSlider: true};
                        if (scope._settings.height === undefined) scope._settings.height = 50;
                        if (scope._settings.showFacetOnModal === undefined) scope._settings.showFacetOnModal = false;
                        scope.showTableOrChart = function() {
                            if (showChartForDataTypes.indexOf(scope._facet.dataType) >= 0)
                                scope.facetDisplay = chartFacetDisplay;
                            else
                                scope.facetDisplay = defaultFacetDisplay;
                        };
                        scope.inferSortOrder = function() {
                          if (Util.isFacetOfRangeDataType(scope._facet.dataType)) {
                              scope._facet.sortType = sortByDisplayName;
                              scope._facet.sortReverse = false;
                          } else {
                              scope._facet.sortType = sortByCount;
                              scope._facet.sortReverse = true;
                          }
                        };
                        scope.setLoading = function () {
                            if (scope._facet.data == undefined)
                                scope._facet.loading = true;
                            else
                                scope._facet.loading = false;
                        };
                        scope.switchOffLoading = function (status) {
                            scope._facet.loading = false;
                        };
                        scope.updateChartData = function () {
                            scope._settings.chart.data.length = 0;
                            scope._settings.chart.labels.length = 0;
                            chartData = $filter('orderBy')(scope._facet.data, scope.getPredicateField(), scope._facet.sortReverse, scope.compareFacetClasses);
                            chartData = $filter('filter')(chartData, scope._facet.filter);
                        };
                        scope.getPredicateField = function (){
                            if (scope._facet.sortType === 'displayname') {
                                 var aMin = scope._facet.data && scope._facet.data[0].min;
                                 return aMin != undefined ? 'min' : 'displayname';
                            }
                            return  scope._facet.sortType
                        };
                        scope.updateChartHeight = function () {
                            if (chartData && chartData.length) {
                                var height = chartData.length * lineHeight;
                                scope._settings.height = height;
                            }
                        };
                        scope.drawChart = function () {
                            if (scope._facet.data) {
                                scope.updateChartData();
                                scope.updateChartColour();
                                Util.convertFacetDataToChartJSFormat(chartData, scope._settings.chart);
                                scope.updateChartHeight();
                            }
                        };
                        scope.updateChartColour = function() {
                            Util.getBorderColour(chartData, scope.datasetOverride.borderColor);
                            Util.getBarColour(chartData, scope._settings.chart.colours, scope.formatColor);
                        };
                        scope.chartClick = function(elements, event) {
                            if (elements && elements.length > 0) {
                                scope.$apply(function () {
                                    scope.setSliderInactive();
                                    elements && elements.forEach(function (elem) {
                                        chartData[elem._index].selected = !chartData[elem._index].selected
                                    });
                                    scope.updateSelection();
                                })
                            } else {
                                // get the closest data point from y position of click
                                var chart = this.chart;
                                var element = Util.chartElementCloseToMouseClick(chart, event);
                                if (element)
                                    scope.$apply(function (){
                                        scope.setSliderInactive();
                                        chartData[element._index].selected = !chartData[element._index].selected;
                                        scope.updateSelection();
                                    });
                            }
                        };
                        scope.selectClassesInRange = function () {
                            scope.facetClearSelection();
                            var max = scope._settings.slider.max - scope._settings.slider.values[0],
                                min = scope._settings.slider.max - scope._settings.slider.values[1];
                            for (var i = min; i <= max; i++) {
                                chartData[i].selected = true;
                            }
                            scope.updateSelection();
                        };
                        scope.initialiseSliderMinMaxRange = function () {
                            var data = chartData || scope._facet.data;
                            if (data && data.length) {
                                scope._settings.slider.values[1] = scope._settings.slider.max =  data.length - 1;
                                scope._settings.slider.values[0] = scope._settings.slider.max - 1;
                                if ( scope._settings.slider.values[0] < 0 )
                                    scope._settings.slider.values[0] = 0;
                            } else {
                                scope._settings.slider.values[1] = scope._settings.slider.max = 1;
                                scope._settings.slider.values[0] = scope._settings.slider.min = 0;
                            }
                        };
                        scope.setSliderState = function(state) {
                            scope._settings.slider.active = !!state;
                        };
                        scope.setSliderActive = function () {
                            scope.setSliderState(true);
                        };
                        scope.setSliderInactive = function () {
                            scope.setSliderState(false);
                        };
                        scope.setSliderInactiveAndRedrawChart = function () {
                            scope.setSliderInactive();
                            scope.drawChart();
                        };
                        scope.info = function (item) {
                            bootbox.alert($i18n(397, "Metadata url") + ': <a href="' + item.url + '">' + item.url + '</a>')
                        };
                        scope.zoom = function (item) {
                            MapService.leafletScope.zoom(item.bbox)
                        };
                        scope.facetClearSelection = function () {
                            if (scope._facet !== undefined) {
                                for (var i = 0; i < scope._facet.data.length; i++) {
                                    scope._facet.data[i].selected = false
                                }
                                scope.updateSelection()
                            }
                        };
                        scope.checkAllFacets = function () {
                            if (scope._facet.isAllFacetsSelected) {
                                scope.facetSelectAll()
                            } else {
                                scope.facetClearSelection()
                            }
                        };
                        scope.isAllFacetsSelectedStateValid = function () {
                            var validState = scope.ifAllFacetsSelected();
                            if (validState !== scope._facet.isAllFacetsSelected)
                                scope._facet.isAllFacetsSelected = validState;
                        };
                        scope.validateState = function () {
                            scope.isAllFacetsSelectedStateValid();
                        };
                        scope.facetSelectAll = function () {
                            if (scope._facet !== undefined) {
                                for (var i = 0; i < scope._facet.data.length; i++) {
                                    scope._facet.data[i].selected = true
                                }
                                scope.updateSelection()
                            }
                        };
                        scope.ifAllFacetsSelected = function () {
                            if (scope._facet !== undefined) {
                                for (var i = 0; i < scope._facet.data.length; i++) {
                                    if (!scope._facet.data[i].selected) {
                                        return false;
                                    }
                                }
                                return true;
                            }
                            return false;
                        }
                        scope.updateSelection = function () {
                            scope._onCustom();
                            scope.updateChartColour();
                            scope.updateCount();
                            scope.validateState();
                        };
                        scope.updateCount = function () {
                            if (scope._facet.data !== undefined) {
                                var count = 0;
                                for (var i = 0; i < scope._facet.data.length; i++) {
                                    if (scope._facet.data[i].selected) {
                                        count += scope._facet.data[i].count;
                                    }
                                }
                                scope.selectionCount = count
                            } else {
                                scope.selectionCount = 0
                            }
                        };
                        scope.formatColor = function (item) {
                            var r = Number(item.red).toString(16);
                            if (r.length === 1) r = '0' + r;
                            var g = Number(item.green).toString(16);
                            if (g.length === 1) g = '0' + g;
                            var b = Number(item.blue).toString(16);
                            if (b.length === 1) b = '0' + b;
                            return r + g + b
                        };
                        scope.showFacetOnModalButton = function () {
                            return !scope._facet.loading && !scope._settings.showFacetOnModal;
                        };
                        scope.updateChart = function(){
                            scope.drawChart();
                            scope.updateSelection();
                        };
                        scope.openFacetInModal = function() {
                            LayoutService._closeOpen();
                            if (scope._settings.showFacetOnModal) {
                                scope._settings.slider.initialiseSlider = false;
                                LayoutService.openModal('facetEditorModal', {
                                    facet: scope._facet,
                                    settings: scope._settings,
                                    onUpdate: scope.updateChart
                                }, true);
                            }
                        };
                        scope.interceptChartEvents = function(instance){
                            var oldEventHandler = instance.eventHandler,
                                newEventHandler = function (event) {
                                    oldEventHandler.call(instance, event);
                                    Util.activateTooltip.call(instance, event);
                                };
                                instance.eventHandler = newEventHandler;
                        };
                        // slider configuration
                        scope.sliderOptions = {
                            orientation: 'vertical',
                            range: true,
                            stop: function() {
                                scope.$apply(function () {
                                    scope.setSliderActive();
                                    scope.selectClassesInRange();
                                });
                            }
                        };
                        // chart configuration
                        scope.chartOptions = {
                            maintainAspectRatio: false,
                            animation: false,
                            scales: {
                                yAxes: [{
                                    ticks: {
                                        callback: function(value, index, values) {
                                            var data = chartData[index];
                                            if (data.selected)
                                                value = "■ " + value;
                                            else
                                                value = "□ " + value;
                                            return value ? value.substr(0, labelLength) : '';
                                        }
                                    }
                                }],
                                xAxes: [{
                                    position: 'top'
                                }]
                            },
                            tooltips: {
                                enabled: true,
                                mode: 'label',
                                callbacks: {
                                    title: function(tooltipItems, data) {
                                        var idx = tooltipItems[0].index;
                                        return data.labels[idx];
                                    },
                                    label: function (tooltipItem, data) {
                                        var idx = tooltipItem.index,
                                            label = data.datasets[0].data[idx];
                                        return label;
                                    },
                                    afterLabel: function (tooltipItem, data) {
                                        var idx = tooltipItem.index,
                                            label;
                                        if (chartData[idx].selected)
                                            label = $i18n(450, "Selected");
                                        else
                                            label = $i18n(473, "Select by clicking label or bar");
                                        return label;
                                    }
                                }
                            },
                            hover: {
                                mode: "label",
                                onHover: function (chartElements) {
                                    if (lastChartInstance != this) {
                                        scope.interceptChartEvents(this);
                                        lastChartInstance = this;
                                    }
                                }
                            }
                        };
                        // selected facets on chart are highlighted using border colour.
                        scope.datasetOverride = {
                            borderColor: []
                        };
                        scope.$watch('_facet.data', function (newValue, oldValue) {
                            if (newValue !== oldValue) {
                                scope.setLoading();
                                scope.inferSortOrder();
                                scope.setSliderInactiveAndRedrawChart();
                                scope.initialiseSliderMinMaxRange();
                                scope.showTableOrChart();
                            }
                        });
                        scope.$watch('_facet.filter', function (newVal, oldVal) {
                            if (newVal !== oldVal) {
                                scope.setSliderInactiveAndRedrawChart();
                                scope.initialiseSliderMinMaxRange();
                            }
                        });
                        scope.setLoading();
                        scope.showTableOrChart();
                        scope.inferSortOrder();
                        if (scope._settings.slider.initialiseSlider) {
                            scope.setSliderInactiveAndRedrawChart();
                            scope.initialiseSliderMinMaxRange();
                        } else {
                            scope.drawChart();
                        }
                        scope.updateCount()
                    }
                }
            }])
}(angular));