Sări la conținutul principal

Vizualizare hartă cu WMS

Cheia API trebuie să rămână pe server

Bibliotecile web-based pentru hărți (Leaflet, OpenLayers, Mapbox GL) nu pot adăuga antete Authorization personalizate la cererile de plăci WMS. Nu expune cheia API în JavaScript pe partea de client.

Utilizează un proxy backend care atașează cheia pe partea de server — vezi Ghid Proxy GeoServer pentru exemplu complet și executabil în Python.

Scenariu: Vrei să incorporezi un strat WMS Qarta ca suprapunere pe o hartă web interactivă (folosind Leaflet, OpenLayers sau Mapbox).

Flux de lucru:

  1. Descoperă straturi disponibile cu GetCapabilities
  2. Construiește URL strat WMS
  3. Adaugă-l hărții web ca suprapunere
  4. Opțional adaugă legendă și funcționalitate clic-pentru-interogare

Condiții prealabile: Proxy GeoServer rulând la http://localhost:8080.


Pasul 1: Descoperă straturi disponibile

Apelează GetCapabilities pentru a găsi straturi disponibile:

curl -X GET "https://graph.quarticle.ro/graph/layers/wms/GetCapabilities" \
-H "Authorization: YOUR_API_KEY" \
-G \
-d "service=WMS" \
-d "version=1.3.0" \
-d "request=GetCapabilities" \
| grep -o '<Name>[^<]*</Name>' | head -20

Pasul 2: Adaugă strat la hartă Leaflet

Incorporează strat WMS în Leaflet, rutând cererile de plăci prin proxy:

import L from 'leaflet';

const PROXY_URL = 'http://localhost:8080/wms/GetMap';
const layer = 'GRAPHRASTER:light_pollution';

// Creează hartă
const map = L.map('map').setView([40.7128, -74.0060], 10);

// Strat de bază
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);

// Suprapunere WMS — cererile merg la proxy, care adaugă cheia API pe partea de server
const wmsLayer = L.tileLayer.wms(PROXY_URL, {
layers: layer,
styles: '',
format: 'image/png',
transparent: true,
srs: 'EPSG:3857'
}).addTo(map);

Proxy-ul primește fiecare cerere de plăci de la Leaflet, atașează antetul Authorization și o redirecționează la Qarta. Vezi Ghid Proxy GeoServer pentru instrucțiuni de configurare.


Pasul 3: Integrare OpenLayers

import Map from 'ol/Map';
import View from 'ol/View';
import TileLayer from 'ol/layer/Tile';
import TileWMS from 'ol/source/TileWMS';
import OSM from 'ol/source/OSM';
import { fromLonLat } from 'ol/proj';

const PROXY_URL = 'http://localhost:8080/wms/GetMap';
const layer = 'GRAPHRASTER:light_pollution';

const map = new Map({
target: 'map',
layers: [
new TileLayer({
source: new OSM()
}),
new TileLayer({
source: new TileWMS({
url: PROXY_URL,
params: {
LAYERS: layer,
STYLES: '',
FORMAT: 'image/png',
TRANSPARENT: 'true',
VERSION: '1.3.0'
},
serverType: 'geoserver'
})
})
],
view: new View({
center: fromLonLat([-74.0060, 40.7128]),
zoom: 10
})
});

Pasul 4: Adaugă legendă

Prelucrează și afișează legenda straturilor prin proxy:

async function addLegend(layer) {
const params = new URLSearchParams({
service: 'WMS',
version: '1.0.0',
request: 'GetLegendGraphic',
layer: layer,
format: 'image/png',
width: '40',
height: '40'
});

const response = await fetch(
`http://localhost:8080/wms/GetLegendGraphic?${params}`
);

const blob = await response.blob();
const url = URL.createObjectURL(blob);

const legendContainer = document.querySelector('.legend');
legendContainer.innerHTML = `
<h4>${layer}</h4>
<img src="${url}" alt="Legend" />
`;
}

addLegend('GRAPHRASTER:light_pollution');

Pasul 5: Adaugă clic-pentru-interogare (GetFeatureInfo)

Interoghem caracteristici la clic hartă, rutând prin proxy:

map.on('click', async (e) => {
const layer = 'GRAPHRASTER:light_pollution';
const latlng = e.latlng;

// Convertește coordonate hartă la bbox WMS (exemplu simplificat)
const bounds = map.getBounds();
const bbox = `${bounds.getWest()},${bounds.getSouth()},${bounds.getEast()},${bounds.getNorth()}`;

const params = new URLSearchParams({
service: 'WMS',
version: '1.3.0',
request: 'GetFeatureInfo',
layers: layer,
query_layers: layer,
styles: '',
srs: 'EPSG:3857',
bbox: bbox,
width: map.getSize().x,
height: map.getSize().y,
x: Math.round((latlng.lng - bounds.getWest()) / (bounds.getEast() - bounds.getWest()) * map.getSize().x),
y: Math.round((bounds.getNorth() - latlng.lat) / (bounds.getNorth() - bounds.getSouth()) * map.getSize().y),
info_format: 'application/json',
feature_count: '5'
});

const response = await fetch(
`http://localhost:8080/wms/GetFeatureInfo?${params}`
);

const result = await response.json();
console.log('Features at click:', result.features);

// Afișează în popup
L.popup()
.setLatLng(latlng)
.setContent(`<pre>${JSON.stringify(result.features[0]?.properties, null, 2)}</pre>`)
.openOn(map);
});

Exemplu complet: Hartă interactivă

import L from 'https://esm.sh/leaflet';

const LAYER = 'GRAPHRASTER:light_pollution';
const PROXY_URL = 'http://localhost:8080/wms'; // Proxy GeoServer

// Creează hartă
const map = L.map('map').setView([40.7128, -74.0060], 10);

// Strat de bază
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap'
}).addTo(map);

// Suprapunere WMS (via proxy)
const wmsLayer = L.tileLayer.wms(`${PROXY_URL}/GetMap`, {
layers: LAYER,
transparent: true,
format: 'image/png'
}).addTo(map);

// Adaugă legendă
const legendContainer = document.querySelector('.legend');
legendContainer.innerHTML = `<h4>Loading legend...</h4>`;

async function addLegend() {
const response = await fetch(
`${PROXY_URL}/GetLegendGraphic?` + new URLSearchParams({
request: 'GetLegendGraphic',
layer: LAYER,
format: 'image/png'
})
);
const blob = await response.blob();
const url = URL.createObjectURL(blob);
legendContainer.innerHTML = `<h4>${LAYER}</h4><img src="${url}" style="max-width: 200px;" />`;
}

addLegend();

// Clic pentru interogare (via proxy)
map.on('click', async (e) => {
const bounds = map.getBounds();
const bbox = `${bounds.getWest()},${bounds.getSouth()},${bounds.getEast()},${bounds.getNorth()}`;

const params = new URLSearchParams({
service: 'WMS',
version: '1.3.0',
request: 'GetFeatureInfo',
layers: LAYER,
query_layers: LAYER,
styles: '',
srs: 'EPSG:3857',
bbox: bbox,
width: map.getSize().x,
height: map.getSize().y,
x: Math.round((e.latlng.lng - bounds.getWest()) / (bounds.getEast() - bounds.getWest()) * map.getSize().x),
y: Math.round((bounds.getNorth() - e.latlng.lat) / (bounds.getNorth() - bounds.getSouth()) * map.getSize().y),
info_format: 'application/json',
feature_count: '5'
});

const result = await fetch(`${PROXY_URL}/GetFeatureInfo?${params}`).then(r => r.json());

L.popup()
.setLatLng(e.latlng)
.setContent(`<pre>${JSON.stringify(result.features?.[0]?.properties, null, 2)}</pre>`)
.openOn(map);
});

Cazuri de utilizare

  • Imobiliare: Afișează straturi riscuri proprietăți (inundații, seismic) pe listinguri
  • Monitorizare mediu: Arată temperatură, poluare sau indici vegetație ca suprapuneri hartă
  • Planificare urbană: Vizualizează utilizare teren, zoning sau straturi infrastructură
  • Analiză climă: Afișează date climă sau meteo pe hărți interactive

Pași următori