Source: services/RepresentacaoService.js

    /**
     * @ngdoc service
     * @name RepresentacaoService
     * @module s4c.services.RepresentacaoService
     * 
     * @description  Componente para acesso a api do backend e/ou comunicação entre controllers
     * 
     *
     */  
     
(function () {
    angular.module('s4c.services')
        .factory('RepresentacaoService', RepresentacaoService);

    RepresentacaoService.$inject = ['$q'];

   /**	
	* @method RepresentacaoService
	* @param {*} $q
	*/
    function RepresentacaoService($q) {
        var service = {
            obterLayoutByZoom: obterLayoutByZoom,
            obterLayout: obterLayout,
            buildFeatureHtml: buildFeatureHtml,
            buildGeometryStyle: buildGeometryStyle,
            getFunctionResult: getFunctionResult
        };

  	   /**	
		* @method saveobterLayoutByZoom
		* @param {*} featureCollection
		* @param {*} mapa
		*/
        function obterLayoutByZoom(featureCollection, mapa) {

            if (!featureCollection.representacao) {
                return;
            }

            _.each(featureCollection.features, function (feature) {

                if (!feature.representacoesByZoom) {
                    return;
                }

                var featureHtml;
                for (var i = 0; i < feature.representacoesByZoom.length; i++) {

                    if (mapa.getZoom() >= feature.representacoesByZoom[i].minZoom
                        && mapa.getZoom() <= feature.representacoesByZoom[i].maxZoom) {
                        featureHtml = feature.representacoesByZoom[i].html;
                        break;
                    }
                }

                feature.representacao = {
                    iconAnchor: {
                        w: 60,
                        h: 30
                    },
                    html: featureHtml
                }
            });
        }

  	   /**	
		* @method obterLayout
		* @param {*} featureCollection
		* @param {*} mapa
		*/
        function obterLayout(featureCollection, mapa) {

            if (!featureCollection.representacao) {
                return;
            }

            _.each(featureCollection.features, function (feature) {

                if (!feature.geometry || feature.geometry.type == 'Point') {
                    if (featureCollection.representacao.pointLayout) {
                        buildFeatureHtml(featureCollection.representacao.pointLayout, feature, mapa);
                    }
                    return;
                }

                buildGeometryStyle(featureCollection.representacao.geometryStyle, feature);
            });
        }

  	   /**	
		* @method save
		* @param {*} alarme
		*/
        function buildGeometryStyle(representacao, feature) {

            feature.style = getFunctionResult(feature, representacao.funcao, representacao);
        }

  	   /**	
		* @method buildFeatureHtml
		* @param {*} representacao
		* @param {*} alarmefeature
		* @param {*} mapa
		*/
        function buildFeatureHtml(representacao, feature, mapa) {

            var deferred = $q.defer();

            loadRepresentationValues(feature, representacao);

            var htmlByZoom = [];
            var featureHtml;

            for (var index = 0; index < representacao.length; index++) {

                var html = obterHtml(representacao[index]);

                structure = {
                    html: html,
                    minZoom: representacao[index].minZoom,
                    maxZoom: representacao[index].maxZoom
                };

                htmlByZoom.push(structure);

                //A representação inicial será a primeira declarada no json de representação.
                if (!featureHtml) {
                    featureHtml = html;
                }
            }

            if (mapa) {
                mapa.pegarZoom(function (zoom) {

                    _.each(htmlByZoom, function (structure) {
                        if (zoom >= structure.minZoom && zoom <= structure.maxZoom) {
                            featureHtml = structure.html;

                            feature.representacoesByZoom = htmlByZoom;

                            feature.representacao = {
                                iconAnchor: {
                                    w: 60,
                                    h: 30
                                },
                                html: featureHtml
                            }

                        }
                    });
                });

                deferred.resolve(feature);
                return deferred.promise;
            }

            feature.representacoesByZoom = htmlByZoom;

            feature.representacao = {
                iconAnchor: {
                    w: 60,
                    h: 30
                },
                html: featureHtml
            }

            deferred.resolve(feature);
            return deferred.promise;
        }

       /**
        * Executa as funções contidas em cada json dos items da representação.
        */
  	   /**	
		* @method loadRepresentationValues
		* @param {*} feature
		* @param {*} representacaoArray
		*/
        function loadRepresentationValues(feature, representacaoArray) {

            if (!representacaoArray) {
                return;
            }

            for (var index = 0; index < representacaoArray.length; index++) {

                var representacao = representacaoArray[index];
                if (representacao.linhas) {

                    for (var i = 0; i < representacao.linhas.length; i++) {
                        for (var j = 0; j < representacao.linhas[i].items.length; j++) {

                            var item = representacao.linhas[i].items[j];
                            var result = getFunctionResult(feature, item.funcao);

                            if (item.tipo == 'icon') {
                                item.urlIcon = result;
                            } else {
                                item.valor = result;
                            }
                        }
                    }
                }

                if (representacao.circulo) {

                    var result = getFunctionResult(feature, representacao.circulo.centro.funcao);
                    if (result) {

                        if (representacao.circulo.centro.tipo == 'icon') {
                            representacao.circulo.centro.urlIcon = result;
                        } else {
                            representacao.circulo.centro.valor = result;
                        }

                    }
                }
            }
        }

        /**
         * Função para obter os extras de um poi de acordo com um label. Será usado dentro da função 
         * de representação de cada item.
         * 
         */
  	   /**	
		* @method getValueExtra
		* @param {*} extras
		* @param {*} label
		*/
        var getValueExtra = function (extras, label) {

            for (var index = 0; index < extras.informacoes.length; index++) {

                if (extras.informacoes[index].label.toLowerCase() == label.toLowerCase()) {
                    return extras.informacoes[index].valor;
                }
            }
        }

        /**
         * Executa apenas a função js dentro da representacao. Pode ser chamada externamente, como por exemplo na tabela do módulo de Pois.
         */
  	   /**	
		* @method getFunctionResult
		* @param {*} style
		* @param {*} feature
		* @param {*} funcao
		*/
        function getFunctionResult(feature, funcao, style) {

            var code;
            if (!feature.geometry || feature.geometry.type == 'Point') {
                code = 'var poi = ' + JSON.stringify(feature) + '; var getValueExtra = ' + getValueExtra.toString() + '; ' + funcao;
            } else if (style) {
                code = 'var style = ' + JSON.stringify(style) + '; var poi = ' + JSON.stringify(feature) + '; var getValueExtra = ' + getValueExtra.toString() + '; ' + funcao;
            }

            if (code) {
                var F = new Function(code);
                return F();
            }

            return '';
        }

        /**
         * Lógica para processar o json representação e converter em uma página html
         */
  	   /**	
		* @method obterHtml
		* @param {*} representacao
		*/
        function obterHtml(representacao) {

            var tmpDiv = document.createElement("div");
            var mainDiv = document.createElement("div");
            mainDiv.setAttribute('id', 'divMain');

            var ratioW = 7.3;
            var ratioH = 3;
            if (representacao.estilo != 'transparente') {
                mainDiv.setAttribute('style', 'border-color:#a9a9a9; border-width:2px; border-style: solid; background-color:#867979; margin-top:-'
                    + (representacao.height / ratioH) + 'px; margin-left:-' + representacao.width / ratioW + 'px;');
            } else {
                mainDiv.setAttribute('style', 'background-color:transparent; margin-top:-' + (representacao.height / ratioH) + 'px; margin-left:-' + representacao.width / ratioW + 'px;');
            }

            mainDiv.style.width = representacao.width + 'px';
            mainDiv.style.height = representacao.height + 'px';

            if (representacao.linhas) {

                //Verifica se há linhas horizontais no topo e adiciona na mainDiv
                _.each(representacao.linhas, function (linha) {
                    if (linha.tipo == 'top') {
                        mainDiv.appendChild(createRow(linha, representacao));
                    }
                });

                //Verifica se há linhas verticais na esquerda e adiciona na mainDiv
                _.each(representacao.linhas, function (linha) {
                    if (linha.tipo == 'left') {
                        mainDiv.appendChild(createRow(linha, representacao));
                    }
                });

                //Verifica se há a área central e adiciona na mainDiv
                if (representacao.circulo) {
                    mainDiv.appendChild(createCentralDiv(representacao));
                }

                //Verifica se há linhas verticais na direita e adiciona na mainDiv
                _.each(representacao.linhas, function (linha) {
                    if (linha.tipo == 'right') {
                        mainDiv.appendChild(createRow(linha, representacao));
                    }
                });

                //Verifica se há linhas horizontais no fundo e adiciona na mainDiv
                _.each(representacao.linhas, function (linha) {
                    if (linha.tipo == 'bottom') {
                        mainDiv.appendChild(createRow(linha, representacao));
                    }
                });

            } else {

                if (representacao.estilo != 'transparente') {
                    mainDiv.setAttribute('style', 'border-color:#a9a9a9; border-width:2px; border-style: solid; background-color:#867979;');
                } else {
                    mainDiv.setAttribute('style', 'background-color:transparent;');
                }

                //Verifica se há a área central e adiciona na mainDiv
                if (representacao.circulo) {
                    mainDiv.appendChild(createCentralDiv(representacao));
                }
            }

            tmpDiv.appendChild(mainDiv);
            return tmpDiv.innerHTML;
        }

  	   /**	
		* @method createCentralDiv
		* @param {*} representacao
		*/
        function createCentralDiv(representacao) {

            var div = document.createElement("div");
            div.setAttribute('id', 'divCentral');

            if (representacao.estilo != 'transparente') {
                div.setAttribute('style', representacao.circulo.background + ' display:table; margin:0 auto; margin-top:6px; margin-bottom:-4px;');
            } else {
                div.setAttribute('style', 'background-color:transparent; display:table; margin:0 auto; margin-top:6px; margin-bottom:-4px;');
            }

            div.style.width = (representacao.width - 4) + 'px';
            div.style.height = (representacao.circulo.height) + 'px';

            if (representacao.circulo.centro.tipo == 'icon') {

                var icon = document.createElement("span");
                icon.setAttribute('style', 'width:' + representacao.circulo.centro.iconWidth + '; display:table; margin:0 auto;' + representacao.circulo.centro.style || '');
                icon.appendChild(htmlToElement('<img style="width:' + representacao.circulo.centro.iconWidth + '; max-height:48px; color:#00ff00;" src="' + representacao.circulo.centro.urlIcon + '"></img>'));
                div.appendChild(icon);

            } else if (item.tipo == 'progress') {

                if (!representacao.circulo.centro.valor || representacao.circulo.centro.valor.toString().length == 0) {
                    return div;
                }

                div.appendChild(htmlToElement('<progress value="' + representacao.circulo.centro.valor + '" max="100" style="margin-left:3px; margin-top:4px;"></progress>'));

                if (representacao.circulo.centro.valor.toString().length > 4) {
                    representacao.circulo.centro.valor = parseFloat(representacao.circulo.centro.valor.toString().substring(0, 4));
                }

                var label = item.progress_label;
                if (!label || label.length == 0) {
                    label = representacao.circulo.centro.valor + '%';
                }
                else if (label.includes('*')) {
                    label = label.replace('*', '');
                    label = label + ' ' + representacao.circulo.centro.valor + '%';
                }
                div.appendChild(htmlToElement('<center><span style="width:100%; font-weight: bold; color:#696969; position: fixed; left: 0px; font-size: 10; z-index:100; margin-top:2px;">' +
                    label + '</span> </center>'));

            } else {

                var style = item.style;
                if (style) {
                    style = style + ' width:100%; margin-top:2px; text-align: center; z-index:100; min-height:18px;';
                } else {
                    style = 'width:100%; font-weight: bold; color:black; font-size: 11px; margin-top:2px; text-align: center; z-index:100; min-height:18px;';
                }
                div.appendChild(htmlToElement('<p style="' + style + '">' + item.valor + '</p>'));
            }

            return div;
        }

  	   /**	
		* @method htmlToElement
		* @param {*} html
		*/
        function htmlToElement(html) {
            var template = document.createElement('template');
            template.innerHTML = html;
            return template.content.firstChild;
        }

  	   /**	
		* @method createRow
		* @param {*} representacao
		* @param {*} linha
		*/
        function createRow(linha, representacao) {

            var div = document.createElement("div");

            if (representacao.estilo != 'transparente') {
                div.setAttribute('style', 'background-color:#333333; padding-left:1px;');
            } else {
                div.setAttribute('style', 'background-color:transparent; padding-left:1px;');
            }

            if (linha.tipo == 'top' || linha.tipo == 'bottom') {
                div.setAttribute("layout", "row");
                div.style.width = (representacao.width - 4) + 'px';
                div.style.height = "21px";
            } else {
                div.style.width = "10%";
                div.style.height = (representacao.height - 4) + 'px';
            }

            var count = 0;
            _.each(linha.items, function (item) {

                if (item.tipo == 'icon') {

                    var icon = document.createElement("span");

                    icon.setAttribute('style', 'width:' + item.iconWidth + '; padding-top:3px; display:table; margin:0 auto; ' + item.style || '');

                    var margin = '';
                    //Só coloca margem left nos itens diferentes do primeiro item.
                    if (count > 0) {
                        margin = 'margin-left:' + count + 'px;';
                    }

                    icon.appendChild(htmlToElement('<img src="' + item.urlIcon + '" style="width:' + item.iconWidth + '; ' + margin + '"></img>'));
                    div.appendChild(icon);

                } else if (item.tipo == 'progress') {

                    if (!item.valor || item.valor.toString().length == 0) {
                        return;
                    }

                    div.appendChild(htmlToElement('<progress value="' + item.valor + '" max="100" style="margin-left:3px; margin-top:4px;"></progress>'));

                    if (item.valor.toString().length > 4) {
                        item.valor = parseFloat(item.valor.toString().substring(0, 4));
                    }

                    var label = item.progress_label;
                    if (!label || label.length == 0) {
                        label = item.valor + '%';
                    }
                    else if (label.includes('*')) {
                        label = label.replace('*', '');
                        label = label + ' ' + item.valor + '%';
                    }
                    div.appendChild(htmlToElement('<center><span style="width:100%; font-weight: bold; color:#696969; position: fixed; left: 0px; font-size: 10; z-index:100; margin-top:2px;">' +
                        label + '</span> </center>'));

                } else {

                    var style = item.style;
                    if (style) {
                        style = style + ' width:100%; margin-top:2px; text-align: center; z-index:100; min-height:18px;';
                    } else {
                        style = 'width:100%; font-weight: bold; color:black; font-size: 11px; margin-top:2px; text-align: center; z-index:100; min-height:18px;';
                    }
                    div.appendChild(htmlToElement('<p style="' + style + '">' + item.valor + '</p>'));
                }

                count++;
            });

            return div;
        }

        return service;
    }
}());