Source: directives/mapa-area-de-atuacao/mapa-area-de-atuacao.service.js

/**
 * @ngdoc service
 * @name MapaAreaDeAtuacaoService
 * @module s4c.directives.MapaAreaDeAtuacaoService
 *
 * @description
 * `MapaAreaDeAtuacaoService` Componente para acesso ao api do backend e/ou comunicação entre controllers
 * 
 * 
 */
(function () {
    'use strict';

    angular
        .module('s4c.directives.mapa-area-de-atuacao')
        .factory('MapaAreaDeAtuacao', MapaAreaDeAtuacao);

    MapaAreaDeAtuacao.$inject = ['$timeout', '$rootScope'];

    function MapaAreaDeAtuacao($timeout, $rootScope) {
        var service = {
            _novoDesenhoHandler: null,
            _map: null,
            _layer: null,
            _array_layer: [],
            _regiao: null,
            _popup: null,
            _eventos: {
                areaDeAtuacaoEditada: []
            },
            _triggers: {
                areaDeAtuacaoEditada: _triggerareaDeAtuacaoEditada
            },
            trigger: trigger,
            on: on,
            atualizarArea: atualizarArea,
            limparArea: limparArea,
            editarRegiao: editarRegiao,
            desativarEdicao: desativarEdicao
        };

       /**
         * Dispara um evento para avisar aos controllers que a área de atuação foi editada
         * 
         * @method _triggerareaDeAtuacaoEditada
         * 
         * 
         */           
        function _triggerareaDeAtuacaoEditada() {
            _.each(service._eventos.areaDeAtuacaoEditada, function (callback) {

                var geometryCollection = {
                    type: 'GeometryCollection',
                    geometries: []
                };

                _.each(service._array_layer, function (layer) {
                    if (layer.data._id == service._regiao._id) {

                        if (layer.toGeoJSON().type == "GeometryCollection") {
                            _.each(layer.toGeoJSON().geometries, function (feature) {
                                geometryCollection.geometries.push(feature);
                            });
                        }
                        else {
                            var geojson = layer.toGeoJSON().geometry;

                            if (geojson.type === 'GeometryCollection') {
                                _.each(geojson.geometries, function (geometry) {
                                    geometryCollection.geometries.push(geometry);
                                });
                            }
                            else {
                                if (geojson.type === 'MultiPolygon') {
                                    geojson.type = 'Polygon';
                                    geojson.coordinates = geojson.coordinates[0];
                                }

                                geometryCollection.geometries.push(geojson);
                            }
                        }
                    }
                });

                callback({
                    geojson: geometryCollection
                });

            });
        }

      /**
         * Dispara eventos
         * 
         * @method trigger
         * 
         * @param eventName {Object}
         * 
         */          
        function trigger(eventName) {
            service._triggers[eventName]();
        }

      /**
         * Listener de eventos
         * 
         * @method on
         * 
         * @param eventName {Object}
         * @param callback {Object}
         * 
         */          
        function on(eventName, callback) {
            service._eventos[eventName].push(callback);
        }

        /**
         * Atualiza a Área de Atuação com os novas geometrias
         * 
         * @method atualizarArea
         * 
         * @param regioes {Object}
         * @param opcoes {Object}
         * 
         */          
        function atualizarArea(regioes, opcoes) {

            _.each(service._array_layer, function (layer) {
                service._map.removeLayer(layer);
            });

            service._array_layer = [];

            if (opcoes.desenhar) {
                if (service._novoDesenhoHandler) {
                    service._novoDesenhoHandler.enable();
                } else {
                    service._novoDesenhoHandler =
                        new L.Draw.Polygon(service._map, new L.Control.Draw().options.polygon);
                    service._novoDesenhoHandler.enable();
                }

                $timeout(function () {
                    service._map.setView({
                        lat: -22.9009167,
                        lng: -43.1795591,
                    }, 13);
                    service._map.invalidateSize(true);
                }, 0);

            } else {

                if (service._novoDesenhoHandler) {
                    service._novoDesenhoHandler.disable();
                }

                var geometry;
                var geometryCollection = {
                    type: 'GeometryCollection',
                    geometries: []
                };

                _.each(regioes, function (regiao) {

                    if (typeof regiao.poiGeometrico === 'string' || regiao.poiGeometrico instanceof String) {
                        geometry = JSON.parse(regiao.poiGeometrico);
                    }
                    else {
                        geometry = regiao.poiGeometrico;
                    }

                    if (geometry != null) {

                        if (geometry.type == "GeometryCollection") {
                            _.each(geometry.geometries, function (_geometry) {
                                _geometry.regiao = regiao;
                                geometryCollection.geometries.push(_geometry);
                            });
                        }
                        else {
                            geometry.regiao = regiao;
                            geometryCollection.geometries.push(geometry);
                        }
                    }

                });

                service._layer = L.geoJson(geometryCollection).addTo(service._map);

                service._layer.eachLayer(function (layer) {
                    var index = 0;
                    layer.eachLayer(function (itemLayer) {
                        itemLayer.data = layer.feature.geometry.geometries[index].regiao;
                        delete layer.feature.geometry.geometries[index].regiao;
                        service._array_layer.push(itemLayer);
                        index++;
                        itemLayer.on('edit', function () {
                            service.trigger('areaDeAtuacaoEditada');
                        });

                        if (itemLayer.eachLayer) {
                            itemLayer.eachLayer(function (subItemLayer) {
                                subItemLayer.on({
                                    click: deleteDraw
                                });
                            });
                        }
                        else {
                            itemLayer.on({
                                click: deleteDraw
                            });
                        }
                    });

                    layer.setStyle({
                        weight: 5,
                        color: opcoes.cor,
                        dashArray: '',
                        fillOpacity: 0.2
                    });
                });

                $timeout(function () {
                    // bug do leaflet, definindo zoom quando abre o mapa pela primeira vez
                    if (service._layer != null) {
                        if (service._map.getBoundsZoom(service._layer.getBounds()) == 0) {
                            var center = service._layer.getBounds().getCenter();
                            service._map.setView(center, 12);
                        } else {
                            service._map.fitBounds(service._layer.getBounds());
                        }

                        service._map.invalidateSize(true);
                    }
                }, 0);
            }
        }

        /**
         * Edita as regiões da Área de Atuação
         * 
         * @method editarRegiao
         * 
         * @param regiao {Object}
         * 
         */         
        function editarRegiao(regiao) {

            if (service._map != null) {

                service._regiao = regiao;
                desativarEdicao();

                _.each(service._array_layer, function (layer) {
                    if (layer != undefined && regiao && layer.data._id == regiao._id) {
                        if (layer.eachLayer) {
                            layer.eachLayer(function (itemLayer) {
                                itemLayer.editing.enable();
                            });
                        }
                        else {
                            layer.editing.enable();
                        }
                    }
                });
            }
        }

        /**
         * Desativa a edição da Área de Atuação
         * 
         * @method editarRegiao
         * 
         * @param regiao {Object}
         * 
         */              
        function desativarEdicao() {

            if (service._map != null) {

                //Desativa as edições existentes
                _.each(service._array_layer, function (layer) {
                    if (layer.eachLayer) {
                        layer.eachLayer(function (itemLayer) {
                            itemLayer.editing.disable();
                        });
                    }
                    else {
                        layer.editing.disable();
                    }
                });
            }
        }

        /**
         * Remove do Mapa as camadas referente a Área de Atuação
         * 
         * @method limparArea
         * 
         * @param regiao {Object}
         * 
         */          
        function limparArea(regiao) {

            if (service._map != null) {

                service._regiao = null;
                var index = 0;
                var indexDelete = -1;

                _.each(service._array_layer, function (layer) {
                    if (!regiao || (layer != undefined && regiao && layer.data._id == regiao._id)) {
                        indexDelete = index;
                        service._map.removeLayer(layer);
                    }

                    index++;
                });

                if (indexDelete >= 0) {
                    service._array_layer.splice(indexDelete, 1);
                }
                else {
                    $timeout(function () {
                        service._map.setView({
                            lat: -22.9009167,
                            lng: -43.1795591,
                        }, 13);
                        service._map.invalidateSize(true);
                    }, 0);
                }
            }

            if (service._novoDesenhoHandler) {
                service._novoDesenhoHandler.disable();
            }
        }

        /**
         * Remove do mapa os desenhos referente a Área de Atuação
         * 
         * @method deleteDraw
         * 
         * @param e {Evento}
         * 
         */ 
        function deleteDraw(e) {
        	/*var element = angular.element('<div class="wrapper">Remover<md-icon ng-click="removerDesenho()" class="remover-desenho" md-svg-icon="menu:delete"></md-icon></div>');
        	var newScope = $scope.$new();
	    	$compile(element)(newScope, function(clonedElement, scope) {
	    		e.target.bindPopup.bindPopup(clonedElement[0]);
	    	});*/

            if (service._regiao != null) {
                service._popup = e.target.bindPopup('<div><a id="btRemoverLayer" href="#">' + $rootScope.res('COMUM_REMOVER') + '</a></div>');
                e.target.on('popupopen', function () {
                    L.DomEvent.on(
                        document.getElementById('btRemoverLayer'),
                        'click',
                        getHandlerForFeature(e.target)
                    );
                });
            }
        }

        /**
         * Função chamada no click do botão btRemoverLayer
         * 
         * @method getHandlerForFeature
         * 
         * @param layer {Object}
         * 
         */         
        function getHandlerForFeature(layer) {
            return function (ev) {
                if (service._regiao == null) {
                    service._map.closePopup();
                    return;
                }
                removerDesenho(layer);
            }
        }

        /**
         * Remove os desenhos da camada
         * 
         * @method removerDesenho
         * 
         * @param layerToRemove {Object}
         * 
         */         
        function removerDesenho(layerToRemove) {

            service._map.removeLayer(layerToRemove);

            var index = 0;
            _.each(service._array_layer, function (layer) {
                if (layer != undefined && layer != null && layer._leaflet_id == layerToRemove._leaflet_id) {
                    service._array_layer.splice(index, 1);
                }
                index++;
            });

            service.trigger('areaDeAtuacaoEditada');
        }

        return service;
    }

}());