Visão Geral
Neste tópico será apresentado um exemplo geração de mapa utilizando a biblioteca amCharts 4. Nele será usado, no padrão do geoJSON, o mapa do Brasil
amCharts 4
Documentação: amCharts 4 Documentation
Adicionar HTML Element
Para fazer a criação do mapa é necessário criar um campo do tipo HTMLElement, para isso siga os seguintes passos:
-
Clique com o botão direito no menu “Campos”
-
Clique em “adicionar”
-
No ComboBox selecione a opção “HTMLElement”
-
No campo “Template Html” insira a seguinte tag html
<div id="map" style="width: 100%; height: 100%"></div>
Carregamento pelo banco de dados
Para efetuar o carregamento pelo banco de dados, iremos adicionar mais alguns componentes, sendo dois procedimentos e uma variavel.
No procedimento “LoadMap” iremos criar um record para popular a variavel “customProperties”. Para a geração desse record temos a tabela exemplo states
CREATE TABLE IF NOT EXISTS samples.custom_properties
(
acronym text COLLATE pg_catalog."default" NOT NULL,
population integer NOT NULL,
gmt text COLLATE pg_catalog."default",
dtinc date,
CONSTRAINT states_pkey PRIMARY KEY (acronym)
)
Para popularmos a variavel iremos criar o record com as informações da tabela acima, siga o exemplo do código:
SELECT
'{
"tooltipText": "{id} - População: {populacao}",
"backgroundColor": "gainsboro",
"hoverColor": "aqua",
"labelProps": {
"fontSize": 12,
"color": "black"
},
"routes": [
{
"strokeWidth": 4,
"color": "red",
"target": {
"radius": 5,
"strokeWidth": 3,
"fillColor": "blue",
"color": "red",
"position": {
"longitude": -45.000000,
"latitude": -18.000000
}
},
"points": [
{
"longitude": -50.000000,
"latitude": -20.000000
},
{
"longitude": -45.000000,
"latitude": -18.000000
},
{
"longitude": -42.000000,
"latitude": -15.000000
},
{
"longitude": -40.000000,
"latitude": -8.000000
}
]
}
],
"properties":[
'
||
(
SELECT
string_agg(
'{ "id": "'
|| acronym
|| '", "labelText": "'
|| acronym
|| '", "populacao": '
|| population
|| ', "fill": "#00c735"'
|| ' }' ,
','
)
FROM samples.custom_properties
where case
when
'{?INPUT.DataInicial}' is not null and
'{?INPUT.DataFinal}' is not null
then
dtinc between '{?INPUT.DataInicial}' and '{?INPUT.DataFinal}'
else
true
end
)
||
'
]
}' as field
No comando populate informe o campo do record
Arquivos JS para carregar mapa
Agora iremos criar o arquivos JS para carregar o mapa, neste passo a passo iremos demonstrar um arquivo JS que será gerado no carregamento da tela e no momento com informações fixas:
-
Clique em “Arquivos Javascript”
-
Clique em “Novo arquivo”
-
Informe um nome e prossiga
-
Adicione o código a seguir para gerar o mapa com o AmCharts
const myForm = (function () {
// Adiciona Callbacks no Formulário
latromi.formManager.setOnFormCreatedCallback(onFormCreated);
latromi.formManager.setOnEventFiringCallback(onEventFiring);
latromi.formManager.setOnFieldValueChangedCallback(onFieldValueChanged);
// Ocorre logo após o form ser inicializado
function onFormCreated(ev) {
latromiExtensions.loadScripts(['https://www.amcharts.com/lib/4/core.js'
,'https://www.amcharts.com/lib/4/maps.js'
], loadJson);
}
// Ocorre quando um evento é disparado no Form
function onEventFiring(ev) {
}
// Ocorre quando o valor de um campo é alterado no Form
function onFieldValueChanged(ev) { }
// ========Inicio funções auxiliares==========
function getProperties() {
const jsonData = latromi
.formManager
.getFormInstance()
.getVariableValue("customProperties");
return JSON.parse(jsonData);
}
function findCustomProperties(geoJsonSetting, id) {
return geoJsonSetting.properties.find((prop) => prop.id == id);
}
function standardizeColor(str){
if (!str) return;
const ctx = document.createElement("canvas").getContext("2d");
ctx.fillStyle = str;
return ctx.fillStyle;
}
// ========Final funções auxiliares==========
// Captura dados de poligonos do mapa
function loadJson() {
fetch("https://cdn.amcharts.com/lib/4/geodata/json/brazilLow.json").
then(function (data) {
return data.json()
})
.then(function (json) {
loadMap(json)
})
}
// Carrega o mapa com suas modificações
function loadMap (geoJsonData) {
// amCharts4 examplo
// Cria instancia do mapa
const chart = am4core.create("map", am4maps.MapChart);
// Captura propriedades customizadas
const geoJsonSettings = getProperties();
// Configura opções do mapa
chart.geodata = geoJsonData;
// Configura projeção
chart.projection = new am4maps.projections.Miller();
// Cria uma serie poligonal do mapa
var polygonSeries = chart.series.push(new am4maps.MapPolygonSeries());
// Faz o carregamento dos poligonos do mapa (Ex.: Nomes dos países) dados do GeoJSON
polygonSeries.useGeodata = true;
polygonSeries.calculateVisualCenter = true;
// Configura as series
const polygonTemplate = polygonSeries.mapPolygons.template;
polygonTemplate.tooltipText = geoJsonSettings.tooltipText;
polygonTemplate.fill = am4core.color(standardizeColor(geoJsonSettings.backgroundColor));
polygonTemplate.propertyFields.id = "id";
// Modificar propriedades individualmente
polygonSeries.data = geoJsonSettings.properties;
polygonTemplate.propertyFields.fill = "fill";
// Adiciona as linhas no mapa
for (let index = 0; index < customProperties.routes.length; index++) {
const route = customProperties.routes[index];
// Adiciona a serie das linhas
const lineSeries = chart.series.push(new am4maps.MapLineSeries());
lineSeries.mapLines.template.strokeWidth = route.strokeWidth;
lineSeries.mapLines.template.stroke = am4core.color(standardizeColor(route.color));
lineSeries.mapLines.template.nonScalingStroke = true;
const line = lineSeries.mapLines.create();
line.multiGeoLine = [route.points];
// Adiciona um objeto por posição no mapa
const placeSeries = chart.series.push(new am4maps.MapImageSeries());
const place = placeSeries.mapImages.template;
place.nonScaling = true;
place.propertyFields.latitude = "latitude";
place.propertyFields.longitude = "longitude";
placeSeries.data = [route.target.position];
const circle = place.createChild(am4core.Circle);
circle.radius = route.target.radius;
circle.fill = am4core.color(standardizeColor(route.target.fillColor));
circle.stroke = am4core.color(standardizeColor(route.target.color));
circle.strokeWidth = route.target.strokeWidth;
}
// Configura labels nas series
const labelSeries = chart.series.push(new am4maps.MapImageSeries());
const labelTemplate = labelSeries.mapImages.template.createChild(am4core.Label);
labelTemplate.horizontalCenter = "middle";
labelTemplate.verticalCenter = "middle";
labelTemplate.fontSize = geoJsonSettings.labelProps.fontSize;
labelTemplate.stroke = am4core.color(standardizeColor(geoJsonSettings.labelProps.color))
labelTemplate.interactionsEnabled = false;
labelTemplate.nonScaling = false;
const allIdList = [];
for (let index = 0; index < geoJsonData.features.length; index++) {
allIdList.push(geoJsonData.features[index].id);
}
polygonSeries.events.on("inited", function () {
for (let index = 0; index < allIdList.length; index++) {
const polygon = polygonSeries.getPolygonById(allIdList[index]);
const label = labelSeries.mapImages.create();
const properties = findCustomProperties(geoJsonSettings, allIdList[index]);
if (!properties)
continue;
label.latitude = polygon.visualLatitude;
label.longitude = polygon.visualLongitude;
label.children.getIndex(0).text = properties.labelText ?? "";
}
})
// Cria uma estado de Hover e configura um preenchimento de cor alternativa
var hs = polygonTemplate.states.create("hover");
hs.properties.fill = am4core.color(standardizeColor(geoJsonSettings.hoverColor));
}
// Todas as funções acima são "privadas", e não podem ser chamadas externamente.
// As únicas funções que podem ser chamadas externamente são as que compões o resultado a seguir:
return {
load: () => {
latromiExtensions.loadScripts(['https://www.amcharts.com/lib/4/core.js'
,'https://www.amcharts.com/lib/4/maps.js'
], loadJson);
}
}
})();
Atualização de dados com filtro
Para complementar o exemplo iremos incluir um filtro por data inicial e final para atualizar o mapa. Para isso iremos criar 3 campos a mais e adicionar o evento de click para o botão