Naimikan/angular-mapboxgl-directive

View on GitHub
src/directives/glControls.js

Summary

Maintainability
C
1 day
Test Coverage
angular.module('mapboxgl-directive').directive('glControls', ['$rootScope', 'Utils', 'mapboxglControlsAvailables', '$timeout', function ($rootScope, Utils, mapboxglControlsAvailables, $timeout) {
    function mapboxGlControlsDirectiveLink (scope, element, attrs, controller) {
        if (!controller) {
            throw new Error('Invalid angular-mapboxgl-directive controller');
        }

        var mapboxglScope = controller.getMapboxGlScope();

    var _controlsCreated = {
      custom: []
    };

        var drawFeaturesAdded = false, drawControlAdded = false;

      var addNewControlCreated = function (controlName, newControl, isCustomControl, controlEvents, isEventsListenedByMap) {
        var mapListenEvents = angular.isDefined(isEventsListenedByMap) ? isEventsListenedByMap : false;
        var events = angular.isDefined(controlEvents) && angular.isArray(controlEvents) ? controlEvents : [];

        if (isCustomControl) {
          _controlsCreated.custom.push({
            name: controlName || 'customControl_' + Utils.generateGUID(),
            control: newControl,
            isEventsListenedByMap: mapListenEvents,
            events: events
          });
        } else {
          _controlsCreated[controlName] = {
            control: newControl,
            isEventsListenedByMap: mapListenEvents,
            events: events
          };
        }
      };

      var removeEventsFromControl = function (control, events, isEventsListenedByMap, map) {
        var listener = isEventsListenedByMap ? map : control;

        events.map(function (eachEvent) {
          listener.off(eachEvent);
        });
      };

      var removeAllControlsCreated = function (map) {
        if (angular.isDefined(map) && map !== null) {
          for (var attribute in _controlsCreated) {
            if (attribute !== 'custom') {
              var controlToRemove = _controlsCreated[attribute];

              removeEventsFromControl(controlToRemove.control, controlToRemove.events, controlToRemove.isEventsListenedByMap, map);

              map.removeControl(controlToRemove.control);
            } else {
              var customControls = _controlsCreated[attribute];

              for (var iterator = 0, length = customControls.length; iterator < length; iterator++) {
                var eachCustomControl = customControls[iterator];

                removeEventsFromControl(eachCustomControl.control, eachCustomControl.events, eachCustomControl.isEventsListenedByMap, map);

                map.removeControl(eachCustomControl.control);
              }
            }
          }
        }

        // Reset controls created
        _controlsCreated = {
          custom: []
        };
      };

      var removeControlCreatedByName = function (map, controlName) {
        var found = false, removed = false;

        for (var attribute in _controlsCreated) {
          if (controlName === attribute) {
            found = _controlsCreated[attribute];
          }
        }

        if (!found) {
          _controlsCreated.custom.map(function (eachCustomControl) {
            if (eachCustomControl.name === controlName) {
              found = eachCustomControl.control;
            }
          });
        }

        if (found) {
          try {
            removeEventsFromControl(found.control, found.events, found.isEventsListenedByMap, map);

            map.removeControl(found.control);
            removed = true;
          } catch (error) {
            throw new Error('Error removing control \'' + controlName + '\' --> ' + error);
          }
        }

        return removed;
      };

        controller.getMap().then(function (map) {
            mapboxglScope.$watch('glControls', function (controls) {
        if (angular.isDefined(controls)) {
                    // Remove all created controls
                    removeAllControlsCreated(map);

                    mapboxglControlsAvailables.map(function (eachControlAvailable) {
                        if (angular.isDefined(controls[eachControlAvailable.name]) && angular.isDefined(controls[eachControlAvailable.name].enabled) && controls[eachControlAvailable.name].enabled) {
                            if (angular.isDefined(eachControlAvailable.constructor) && angular.isFunction(eachControlAvailable.constructor)) {
                                var ControlConstructor = eachControlAvailable.constructor.bind.apply(eachControlAvailable.constructor, controls[eachControlAvailable.name].options);
                                var control = new ControlConstructor(controls[eachControlAvailable.name].options);

                                addNewControlCreated(eachControlAvailable.name, control, false, eachControlAvailable.eventsAvailables, eachControlAvailable.listenInMap);

                                if (angular.isDefined(eachControlAvailable.eventsAvailables) && angular.isDefined(eachControlAvailable.eventsExposedName)) {
                                    var listener = eachControlAvailable.listenInMap ? map : control;

                                    eachControlAvailable.eventsAvailables.map(function (eachControlEvent) {
                                        listener.on(eachControlEvent, function (event) {
                                            var eventName = eachControlAvailable.eventsExposedName + ':' + eachControlEvent;

                                            $rootScope.$broadcast(eventName, event);
                                        });
                                    });
                                }

                                var position = controls[eachControlAvailable.name].options && controls[eachControlAvailable.name].options.position ? controls[eachControlAvailable.name].options.position : undefined;

                                map.addControl(control, position);

                                if (eachControlAvailable.name === 'draw' && controls[eachControlAvailable.name].features && Array.isArray(controls[eachControlAvailable.name].features) && controls[eachControlAvailable.name].features.length > 0) {
                                    var featureIds = [];

                                    controls[eachControlAvailable.name].features.map(function (eachFeature) {
                                        var thisFeatureId = control.add(eachFeature);
                                        featureIds = featureIds.concat(thisFeatureId);
                                    });

                                    control.changeMode(control.modes.SIMPLE_SELECT, {
                                        featureIds: featureIds
                                    });

                                    $timeout(function () {
                                        control.changeMode(control.modes.SIMPLE_SELECT);
                                    }, 400, true);
                                }
                            } else {
                                console.warn(eachControlAvailable.pluginName + ' plugin is not included.');
                            }
              }
                    });

                    // Custom Controls
                    if (angular.isDefined(controls.custom)) {
                        if (angular.isArray(controls.custom)) {
                            controls.custom.map(function (eachCustomControl) {
                  if (angular.isDefined(eachCustomControl.constructor)) {
                    var CustomControlFn = eachCustomControl.constructor.bind.apply(eachCustomControl.constructor, eachCustomControl.options);
                    var customControl = new CustomControlFn(eachCustomControl.options);

                                    var customControlEvents = angular.isArray(eachCustomControl.events) ? eachCustomControl.events : [];

                                    addNewControlCreated(eachCustomControl.name, customControl, true, customControlEvents, eachCustomControl.listenInMap);

                                    var listener = eachCustomControl.listenInMap ? map : customControl;

                                    customControlEvents.map(function (eachCustomControlEvent) {
                                        listener.on(eachCustomControlEvent, function (event) {
                                            var eventName = 'mapboxgl:' + eachCustomControl.name + ':' + eachCustomControlEvent;

                                            $rootScope.$broadcast(eventName, event);
                                        });
                                    });

                                    var position = eachCustomControl.options && eachCustomControl.options.position ? eachCustomControl.options.position : undefined;

                                    map.addControl(customControl, position);
                  }
                });
                        } else {
                            console.error('\'custom\' must be an array');
                        }
          }

                    $rootScope.$broadcast('mapboxglMap:controlsRendered', _controlsCreated);
        }
            });
        });

        scope.$on('$destroy', function () {
            removeAllControlsCreated();
        });
    }

    var directive = {
        restrict: 'A',
        scope: false,
        replace: false,
        require: '?^mapboxgl',
        link: mapboxGlControlsDirectiveLink
    };

    return directive;
}]);