Modelo de Visualização
Documentação do modelo de visualização.
Índice
Introdução
O viewTemplate é um componente central do sistema de visualização do mapa, usado para definir como as informações de polígonos ou outros elementos são renderizadas no frontend. Ele permite a criação de layouts personalizados para exibir dados de maneira estruturada e interativa, combinando wrappers (estruturas de container) e templates (componentes de conteúdo). Esta documentação detalha os tipos de wrapper e template disponíveis, explicando suas funcionalidades e casos de uso com exemplos práticos.
Usando EJS para Renderização
O sistema utiliza a linguagem de template EJS (Embedded JavaScript) para renderizar dinamicamente informações no viewTemplate. O EJS permite embutir lógica JavaScript diretamente nos templates, acessando propriedades de dados (como properties ou data) e gerando conteúdo condicional ou formatado. Por exemplo, expressões como <%- properties?.qt_area_terreno ?? '-' %> extraem valores de propriedades e fornecem um valor padrão (-) se os dados estiverem ausentes. O uso de EJS garante flexibilidade para criar visualizações ricas e adaptáveis ao usuário.
Wrappers
Wrappers são containers que organizam templates em estruturas visuais, como linhas, cartões ou listas. Eles definem o layout geral e podem conter outros wrappers ou templates como filhos.
Lista de Wrappers Disponíveis
Linha
O wrapper-row organiza templates em uma linha, aproveitando o sistema de grid do Bootstrap. Cada item no array templates corresponde a uma coluna no grid, permitindo layouts responsivos. Usuários podem especificar a largura de cada coluna usando a propriedade columnClass, que aceita qualquer classe de coluna do Bootstrap, como col-md-6 para meia largura em telas médias ou maiores.
- Propósito: Agrupar templates horizontalmente, como pares de rótulo-valor em colunas.
- Propriedades Raiz:
| Propriedade | Descrição | Exemplo |
|---|---|---|
type | Identificador do wrapper, deve ser "wrapper-row". | "wrapper-row" |
templates | Array de templates filhos ou wrappers a serem renderizados na linha. | [{ "type": "label-value", ... }] |
- Propriedades do Objeto
properties:
| Propriedade | Descrição | Exemplo |
|---|---|---|
columnClass | Classe CSS do Bootstrap para definir a largura da coluna para cada template. | "col-md-6" |
-
Exemplo:
{ "type": "wrapper-row", "templates": [ { "type": "label-value", "label": "Área do Terreno", "value": "<%- properties?.qt_area_terreno ?? '-' %>", "properties": { "columnClass": "col-md-6" } }, { "type": "label-value", "label": "Área Construída", "value": "<%- properties?.qt_area_construida ?? '-' %>", "properties": { "columnClass": "col-md-6" } } ] }Este exemplo cria uma linha com dois pares de rótulo-valor, cada um ocupando metade da largura disponível em telas médias ou maiores, usando o grid do Bootstrap.
Cartão
O wrapper-card exibe conteúdo em um cartão visual, tipicamente com um título (label) e um corpo contendo outros templates ou wrappers. É usado para agrupar informações relacionadas de maneira visualmente distinta.
- Propósito: Apresentar informações agrupadas, como detalhes de polígonos ou uma lista de interseções.
- Propriedades Raiz:
| Propriedade | Descrição | Exemplo |
|---|---|---|
type | Identificador do wrapper, deve ser "wrapper-card". | "wrapper-card" |
label | Título do cartão exibido no topo. | "Informações" |
templates | Array de templates filhos ou wrappers a serem renderizados no corpo. | [{ "type": "wrapper-row", ... }] |
- Propriedades do Objeto
properties:
| Propriedade | Descrição | Exemplo |
|---|---|---|
helper | Texto de ajuda | { "helper": "Informações sobre o conteúdo no cartão" } |
-
Exemplo:
{ "type": "wrapper-card", "label": "Informações", "templates": [ { "type": "wrapper-row", "templates": [ { "type": "label-value", "label": "Área do Terreno", "value": "<%- properties?.qt_area_terreno ?? '-' %>", "properties": { "columnClass": "col-md-6" } }, { "type": "label-value", "label": "Área Construída", "value": "<%- properties?.qt_area_construida ?? '-' %>", "properties": { "columnClass": "col-md-6" } } ] } ] }Este cartão exibe um título "Informações" e uma linha com dois pares de rótulo-valor.
Wrapper de Requisição
O wrapper-request realiza requisições HTTP para buscar dados a serem exibidos na interface, usando a configuração do Axios para definir os parâmetros da requisição. O resultado da requisição é armazenado na variável response no objeto principal, permitindo que templates filhos acessem esses dados para renderização.
- Propósito: Buscar dinamicamente dados de uma API e exibi-los em templates filhos ou wrappers, como cartões ou listas.
- Propriedades Raiz:
| Propriedade | Descrição | Exemplo |
|---|---|---|
type | Identificador do wrapper, deve ser "wrapper-request". | "wrapper-request" |
templates | Array de templates filhos ou wrappers a serem renderizados com os dados da requisição. | [{ "type": "wrapper-card", ... }] |
- Propriedades do Objeto
properties:
O objeto properties segue a tipagem da configuração de requisição do Axios (Axios), com a particularidade de que funções como transformRequest, transformResponse, paramsSerializer, e outras devem ser fornecidas como string functions (funções em formato de string), pois os dados são armazenados em JSON no banco de dados. As propriedades mais comuns incluem:
| Propriedade | Descrição | Exemplo |
|---|---|---|
url | URL do servidor para a requisição (obrigatório). | "https://api.mapa.urbis.sampa.br/geospatial-intersections" |
method | Método HTTP da requisição (padrão: "get"). | "post" |
data | Dados enviados no corpo da requisição, pode ser uma string function. O objeto passado para esta função é o objeto de configuração completo do formulário, contendo o polígono selecionado dentro da propriedade data. | "(data) => data" |
transformResponse | String function que transforma os dados da resposta antes de serem usados. | "(response) => { response = JSON.parse(response); return response; }" |
-
Notas:
- O resultado da requisição é armazenado na variável
responseno objeto principal, acessível via EJS em templates filhos, como<%- response?.properties?.key %>. - Funções devem ser serializáveis em JSON, então use string functions para configurações como
transformResponseoudata. - A função
datarecebe o objeto de configuração completo do formulário, que inclui o polígono selecionado na propriedadedata, permitindo acesso a informações comodata.geometrypara uso na requisição.
- O resultado da requisição é armazenado na variável
-
Exemplo:
{ "type": "wrapper-request", "properties": { "url": "https://api.mapa.urbis.sampa.br/geospatial-intersections", "method": "post", "data": "({data}) => data", "transformResponse": "(response) => { response = JSON.parse(response); const { features } = response; const fieldToLayerMap = { geom_zoneamento_2016: ['slui:zoneamento'], geom_subprefeitura: ['slui:subprefeitura'], geom_distrito: ['slui:distrito_municipal'], geom_tombado: ['slui:tombamentos-areas', 'slui:tombamentos-envoltorias-de-imoveis', 'slui:tombamentos-imoveis'], geom_uc: ['slui:parques_unidades_de_conservacao_e_apa'], geom_apa: ['slui:parques_unidades_de_conservacao_e_apa'], geom_area_contaminada: ['slui:areas_contaminadas'], geom_melhoramento_viario: ['slui:minianel_viario'], geom_area_manancial: ['slui:manancial_billings'], geom_area_manancial_guarapiranga: ['slui:manancial_guarapiranga'], geom_area_manancial_juquery: ['slui:manancial_juquery'], geom_area_envoltoria_iphan: ['slui:tombamentos_envoltorias_de_imoveis_IPHAN'], geom_area_envoltoria_conpresp: ['slui:tombamentos_envoltorias_de_imoveis_CONPRESP'], geom_area_envoltoria_condephaat: ['slui:tombamentos_envoltorias_de_imoveis_CONDEPHAAT'] }; const camadasTombamento = ['geom_tombado', 'geom_area_envoltoria_condephaat', 'geom_area_envoltoria_conpresp', 'geom_area_envoltoria_iphan']; const camadasPreservada = ['geom_apa', 'geom_area_manancial_juquery', 'geom_area_manancial_guarapiranga', 'geom_area_manancial_billings']; response.properties.cit_data = []; response.properties.restricoes = []; features.forEach((feat) => { const { properties } = feat; const { layer } = properties; if (properties?.cit_data?.situacao_do_imovel) response.properties.cit_data.push(properties.cit_data); Object.keys(fieldToLayerMap).forEach((key) => { if (fieldToLayerMap[key].includes(layer)) { response.properties.restricoes.push(key); } }); camadasTombamento.forEach((camada) => { if (response.properties.restricoes.includes(camada)) { response.properties.tombamento_restrito = true; } }); camadasPreservada.forEach((camada) => { if (response.properties.restricoes.includes(camada)) { response.properties.area_preservada = true; } }); }); return response; }" }, "templates": [ { "type": "wrapper-card", "label": "Restrições", "templates": [ { "type": "label-value", "label": "ITBI", "value": "<%= 'Indisponível' %>" }, { "type": "label-value", "label": "Tombamento", "value": "<%- response?.properties?.tombamento_restrito ? 'Tombado' : 'Sem restrição' %>" }, { "type": "label-value", "label": "Área de Preservação Ambiental", "value": "<%- response?.properties?.area_preservada ? 'Preservada' : 'Sem restrição' %>" }, { "type": "label-value", "label": "Árvores no Imóvel", "value": "<%= 'Indisponível' %>" } ] } ] }Este exemplo realiza uma requisição POST para a API de interseções geoespaciais, usando o objeto de configuração do formulário (contendo o polígono selecionado em
data) para enviar os dados, transforma a resposta para mapear restrições e exibe os resultados em um cartão com quatro pares de rótulo-valor.
Itens de Lista
O wrapper-list-items renderiza uma lista de itens, frequentemente usado para exibir dados filtrados ou relacionados, como lotes ou interseções. Ele suporta interações, como cliques em itens, e pode exibir informações em formato de uma ou duas linhas (twoLine).
- Propósito: Exibir listas dinâmicas, como lotes em um perímetro ou interseções geográficas, com suporte a ações de clique.
- Propriedades Raiz:
| Propriedade | Descrição | Exemplo |
|---|---|---|
type | Identificador do wrapper, deve ser "wrapper-list-items". | "wrapper-list-items" |
templates | Array de templates, tipicamente Item Primário e Item Secundário. | [{ "type": "primary-item", ... }] |
- Propriedades do Objeto
properties:
| Propriedade | Descrição | Exemplo |
|---|---|---|
data | Função JavaScript executada quando o componente inicializa, retornando dados da lista obtidos da API de interseções geoespaciais. | "(data) => data.response.features.filter(({ id }) => id.includes('lote_cidadao'))" |
twoLine | Booleano que habilita o modo de duas linhas para itens primários e secundários. | true |
onItemClick | Configuração para a ação disparada quando um item é clicado. | { "action": "openFeature", "params": { "template": "root" } } |
-
Exemplo:
{ "type": "wrapper-list-items", "properties": { "twoLine": true, "data": "(data) => data.response.features.filter(({ id }) => id.includes('lote_cidadao'))", "onItemClick": { "action": "openFeature", "params": { "template": "root" } } }, "templates": [ { "type": "primary-item", "value": "Identificador #<%- properties.id.replace('lote_cidadao.', '') %>" }, { "type": "secondary-item", "value": "SQL: <%- properties.cd_setor_fiscal %>-<%- properties.cd_quadra_fiscal %>-<%- properties.cd_lote %> <%- properties.cd_condominio %> <%- properties.nm_logradouro_completo ?? '-' %>" } ] }Este exemplo renderiza uma lista de lotes com duas linhas por item, onde clicar em um item abre detalhes usando o
viewTemplateda camada.
Templates
Templates são componentes que definem conteúdo específico a ser renderizado, como texto, mapas ou ações. Eles são frequentemente usados dentro de wrappers para exibir informações detalhadas.
Lista de Templates Disponíveis
Rótulo e Valor
O template label-value exibe um par de rótulo-valor, ideal para mostrar propriedades específicas do polígono, como área ou tipo.
- Propósito: Apresentar informações concisas em um formato de rótulo e valor dinâmico.
- Propriedades Raiz:
| Propriedade | Descrição | Exemplo |
|---|---|---|
type | Identificador do template, deve ser "label-value". | "label-value" |
label | Texto do rótulo exibido ao lado do valor. | "Área do Terreno" |
value | Expressão EJS que define o valor a ser exibido. | "<%- properties?.qt_area_terreno ?? '-' %>" |
- Propriedades do Objeto
properties:
| Propriedade | Descrição | Exemplo |
|---|---|---|
columnClass | Classe CSS do Bootstrap para grid layout, usado dentro de wrapper-row. | "col-md-6" |
helper | Texto de ajuda | { "helper": "Informações sobre o valor" } |
-
Exemplo:
{ "type": "label-value", "label": "Área do Terreno", "value": "<%- properties?.qt_area_terreno ?? '-' %>", "properties": { "columnClass": "col-md-6" } }Este template exibe o rótulo "Área do Terreno" e o valor correspondente da propriedade
qt_area_terreno.
Ação de Editar Polígono
O template edit-polygon é a ação para editar e iniciar um novo protocolo baseado no polígono.
- Propósito: Editar o polígono e criar um protocolo com suas informações.
- Propriedades Raiz:
| Propriedade | Descrição | Padrão | Exemplo |
|---|---|---|---|
type | Identificador do template, deve ser "edit-polygon". | - | "edit-polygon" |
label | O texto que será exibido no botão na tela. | "Ajustar Perímetro" | "edit-polygon" |
polygonTemplate | Array de wrappers ou templates a serem renderizados. Se não informado, o sistema buscará a configuração editFeatureTemplate que está na tabela map_config. | - | [{ "type": "wrapper-card", ... }] |
- Propriedades do Objeto
properties:
| Propriedade | Descrição | Exemplo |
|---|---|---|
| (Nenhuma) | Atualmente, não há propriedades específicas no objeto properties. | - |
Este template não será renderizado quando a visualização for para impressão
-
Exemplo:
{ "type": "edit-polygon", "polygonTemplate": [ { "type": "wrapper-card", "label": "Área Selecionada", "templates": [ { "type": "polygon-map", "properties": { "initialViewState": "(data) => { const centroid = utils.calculateCenterId(data.geometry.coordinates[0]); return { longitude: centroid[0], latitude: centroid[1], zoom: 16.5, pitch: 0, bearing: 0 }; }", "polygonProps": "(data) => ({ id: 'polygon-layer', data: [{ coordinates: data.geometry.coordinates }], pickable: false, stroked: true, filled: true, lineWidthMinPixels: 2, getPolygon: (d) => d.coordinates, getFillColor: [255, 165, 0, 100], getLineColor: [255, 140, 0] })" } } ] }, { "type": "wrapper-card", "label": "Lotes no Perímetro", "templates": [ { "type": "wrapper-list-items", "properties": { "twoLine": true, "data": "(data) => data.response.features.filter(({ id }) => id.includes('lote_cidadao'))", "onItemClick": { "action": "openFeature", "params": { "template": "root" } } }, "templates": [ { "type": "primary-item", "value": "Identificador #<%- properties.id.replace('lote_cidadao.', '') %>" }, { "type": "secondary-item", "value": "SQL: <%- properties.cd_setor_fiscal %>-<%- properties.cd_quadra_fiscal %>-<%- properties.cd_lote %> <%- properties.cd_condominio %> <%- properties.nm_logradouro_completo ?? '-' %>" } ] } ] } ] }Este exemplo combina um mapa com uma lista de lotes, cada um com uma ação de clique para abrir detalhes.
Ação de Botão
O template button é um botão simples com qualquer ação.
- Propósito: Renderizar um botão simples com rótulo e ação.
- Propriedades Raiz:
| Propriedade | Descrição | Padrão | Exemplo |
|---|---|---|---|
type | Identificador do template, deve ser "button". | - | "edit-polygon" |
label | O texto que será exibido no botão na tela. | "Ação" | "edit-polygon" |
- Propriedades do Objeto
properties:
| Propriedade | Descrição | Exemplo |
|---|---|---|
action | Uma função string que será disparada quando o botão for clicado. | (data) => console.log("Do nothing"); |
Este template não será renderizado quando a visualização for para impressão
-
Exemplo:
{ "type": "button", "label": "Imprimir", "properties": { "action": "(data) => console.log('DO NOTHING');" }, },Este exemplo renderiza um botão "Imprimir" que executa uma ação de log.
Mapa do Polígono
O template polygon-map renderiza um mapa não interativo com um polígono destacado, configurado com uma visualização inicial e propriedades visuais.
- Propósito: Exibir a geometria de um polígono em um mapa.
- Propriedades Raiz:
| Propriedade | Descrição | Exemplo |
|---|---|---|
type | Identificador do template, deve ser "polygon-map". | "polygon-map" |
- Propriedades do Objeto
properties:
| Propriedade | Descrição | Exemplo |
|---|---|---|
initialViewState | Função JavaScript que define a visualização inicial do mapa (longitude, latitude, zoom). | "(data) => { const centroid = utils.calculateCenterId(data.geometry.coordinates[0]); return { longitude: centroid[0], latitude: centroid[1], zoom: 16.5, pitch: 0, bearing: 0 }; }" |
polygonProps | Função JavaScript que configura as propriedades visuais do polígono (cor, contorno). | "(data) => ({ id: 'polygon-layer', data: [{ coordinates: data.geometry.coordinates }], pickable: false, stroked: true, filled: true, lineWidthMinPixels: 2, getPolygon: (d) => d.coordinates, getFillColor: [255, 165, 0, 100], getLineColor: [255, 140, 0] })" |
-
Exemplo:
{ "type": "polygon-map", "properties": { "initialViewState": "(data) => { const centroid = utils.calculateCenterId(data.geometry.coordinates[0]); return { longitude: centroid[0], latitude: centroid[1], zoom: 16.5, pitch: 0, bearing: 0 }; }", "polygonProps": "(data) => ({ id: 'polygon-layer', data: [{ coordinates: data.geometry.coordinates }], pickable: false, stroked: true, filled: true, lineWidthMinPixels: 2, getPolygon: (d) => d.coordinates, getFillColor: [255, 165, 0, 100], getLineColor: [255, 140, 0] })" } }Este template exibe um polígono centralizado com um preenchimento laranja e um contorno mais escuro.
Item Primário
O template primary-item define o conteúdo primário de um item em uma lista (Itens de Lista), tipicamente usado para o título ou informação principal.
- Propósito: Exibir o texto principal de um item de lista, como um identificador ou nome.
- Propriedades Raiz:
| Propriedade | Descrição | Exemplo |
|---|---|---|
type | Identificador do template, deve ser "primary-item". | "primary-item" |
value | Expressão EJS que define o conteúdo primário do item. | "Identificador #<%- properties.id.replace('lote_cidadao.', '') %>" |
- Propriedades do Objeto
properties:
| Propriedade | Descrição | Exemplo |
|---|---|---|
| (Nenhuma) | Atualmente, não há propriedades específicas no objeto properties. | - |
-
Exemplo:
{ "type": "primary-item", "value": "Identificador #<%- properties.id.replace('lote_cidadao.', '') %>" }Este template exibe o identificador de um lote sem o prefixo "lote_cidadao.".
Item Secundário
O template secondary-item define o conteúdo secundário de um item em uma lista (Itens de Lista), tipicamente usado para detalhes suplementares.
- Propósito: Exibir informações adicionais, como códigos ou descrições, em uma segunda linha.
- Propriedades Raiz:
| Propriedade | Descrição | Exemplo |
|---|---|---|
type | Identificador do template, deve ser "secondary-item". | "secondary-item" |
value | Expressão EJS que define o conteúdo secundário do item. | "SQL: <%- properties.cd_setor_fiscal %>-<%- properties.cd_quadra_fiscal %>-<%- properties.cd_lote %> <%- properties.cd_condominio %> <%- properties.nm_logradouro_completo ?? '-' %>" |
- Propriedades do Objeto
properties:
| Propriedade | Descrição | Exemplo |
|---|---|---|
| (Nenhuma) | Atualmente, não há propriedades específicas no objeto properties. | - |
-
Exemplo:
{ "type": "secondary-item", "value": "SQL: <%- properties.cd_setor_fiscal %>-<%- properties.cd_quadra_fiscal %>-<%- properties.cd_lote %> <%- properties.cd_condominio %> <%- properties.nm_logradouro_completo ?? '-' %>" }Este template exibe códigos fiscais e o endereço de um lote.