GIS 22 Jul 2026 93 views 0 komentar

WebGIS dengan OpenLayers GeoServer dan CI4 - Tutorial Lengkap Membangun Aplikasi Peta Online

WebGIS dengan OpenLayers GeoServer dan CI4 - Tutorial Lengkap Membangun Aplikasi Peta Online

Pernah nggak sih kamu diminta bikin aplikasi peta online yang bisa menampilkan data spasial dari database? Atau mungkin kamu pengen bikin web GIS sendiri tapi bingung mulai dari mana? Jangan khawatir, di artikel ini saya bakal jelasin step-by-step cara bikin WebGIS pakai OpenLayers, GeoServer, dan PHP CodeIgniter 4.

Kenapa kombinasi ini? Karena OpenLayers itu library JavaScript open-source yang powerful banget untuk rendering peta. GeoServer jadi backend yang serve data geospasial lewat standar OGC (WMS, WFS). Dan PHP di sisi server bisa handle bisnis logic, autentikasi, dan integrasi database. Kombinasi ketiganya menghasilkan aplikasi WebGIS yang robust dan scalable.

Apa itu OpenLayers dan Kenapa Harus Pakai Ini?

OpenLayers adalah library JavaScript open-source untuk menampilkan peta interaktif di browser. Dibandingkan Leaflet yang lebih ringan, OpenLayers punya fitur yang jauh lebih lengkap untuk kebutuhan GIS profesional. Beberapa keunggulan OpenLayers:

  • Support berbagai format data: GeoJSON, KML, GML, WKT, TopoJSON, dan masih banyak lagi
  • Standar OGC: Built-in support untuk WMS, WMTS, WFS, WCS, dan OGC API Tiles
  • Vector editing: Bisa edit geometri langsung di browser (draw, modify, snap)
  • Projection handling: Transformasi koordinat antar sistem referensi (misalnya EPSG:4326 ke EPSG:3857)
  • Performance: Rendering pakai WebGL untuk dataset besar

Install OpenLayers via npm gampang banget:


npm install ol

Atau kalau mau pakai CDN langsung:


<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/ol.css">
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/ol.js"></script>

Setup GeoServer sebagai Data Backend

GeoServer adalah server open-source yang meng-publish data geospasial lewat standar Open Geospatial Consortium (OGC). Dia bisa baca data dari berbagai sumber: PostGIS, Shapefile, GeoTIFF, Oracle Spatial, dan lain-lain.

Install GeoServer paling gampang pakai Docker:


docker run -d --name geoserver \
 -p 8080:8080 \
 -v geoserver_data:/opt/geoserver_data \
 -e GEOSERVER_DATA_DIR=/opt/geoserver_data \
 docker.osgeo.org/geoserver:2.26.2

Setelah GeoServer jalan, buka http://localhost:8080/geoserver dan login dengan default credentials (admin / geoserver). Langkah selanjutnya:

  1. Buat Workspace: Pergi ke Data → Workspaces → Add New Workspace. Isi nama (misalnya webgis_app) dan namespace URI
  2. Tambah Data Store: Kalau datanya di PostGIS, pilih PostGIS store. Kalau Shapefile, pilih Shapefile store
  3. Publish Layer: Setelah store dibuat, publish layer-nya. Atur Bounding Box dan style

Contoh mengkoneksikan PostGIS ke GeoServer:


# Pastikan PostGIS database sudah ada
psql -U postgres -d webgis_db -c "CREATE EXTENSION postgis;"

# Import shapefile ke PostGIS
shp2pgsql -s 4326:4326 /data/batas_kecamatan.shp public.batas_kecamatan | psql -U postgres -d webgis_db

Membuat Peta Dasar dengan OpenLayers

Sekarang kita bikin peta dasar yang menampilkan base map OSM dan layer dari GeoServer. Buat file HTML:


<!DOCTYPE html>
<html lang="id">
<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>WebGIS Indonesia</title>
 <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/ol.css">
 <style>
 #map { width: 100%; height: 600px; }
 .ol-popup {
 background: white;
 padding: 12px;
 border-radius: 8px;
 box-shadow: 0 2px 10px rgba(0,0,0,0.2);
 min-width: 200px;
 }
 </style>
</head>
<body>
 <div id="map"></div>
 <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/ol.js"></script>
 <script>
 // Base map layer (OpenStreetMap)
 const osmLayer = new ol.layer.Tile({
 source: new ol.source.OSM()
 });

 // WMS layer dari GeoServer
 const geoserverLayer = new ol.layer.Image({
 source: new ol.source.ImageWMS({
 url: 'http://localhost:8080/geoserver/webgis_app/wms',
 params: {
 'LAYERS': 'webgis_app:batas_kecamatan',
 'FORMAT': 'image/png',
 'TRANSPARENT': true
 },
 serverType: 'geoserver'
 })
 });

 // Inisialisasi peta
 const map = new ol.Map({
 target: 'map',
 layers: [osmLayer, geoserverLayer],
 view: new ol.View({
 center: ol.proj.fromLonLat([110.0, -7.5]),
 zoom: 8
 })
 });
 </script>
</body>
</html>

Di kode di atas, kita bikin dua layer: base map OSM dan WMS layer dari GeoServer. ol.source.ImageWMS mengambil gambar peta dari GeoServer berdasarkan extent dan zoom level yang aktif. Setiap kali user zoom atau pan, OpenLayers request gambar baru dari GeoServer.

Menambahkan Interaksi: Click untuk Info

Fitur wajib di WebGIS adalah ability untuk klik feature dan lihat atributnya. OpenLayers menyediakan ol.interaction.Select untuk ini, tapi kita bisa juga pakai WFS GetFeatureInfo:


// Tambahkan GetFeatureInfo pada click
map.on('singleclick', function(evt) {
 const viewResolution = map.getView().getResolution();
 const wmsSource = geoserverLayer.getSource();
 
 const url = wmsSource.getFeatureInfoUrl(
 evt.coordinate,
 viewResolution,
 map.getView().getProjection(),
 {
 'INFO_FORMAT': 'application/json',
 'FEATURE_COUNT': 5
 }
 );
 
 if (url) {
 fetch(url)
 .then(response => response.json())
 .then(data => {
 if (data.features && data.features.length > 0) {
 const props = data.features[0].properties;
 showPopup(evt.coordinate, props);
 }
 });
 }
});

function showPopup(coordinate, properties) {
 let html = '<div class="ol-popup">';
 html += '<h4>' + (properties.nama_kecamatan || 'Info') + '</h4>';
 html += '<table style="width:100%">';
 for (const [key, value] of Object.entries(properties)) {
 if (key !== 'geometry') {
 html += '<tr><td><strong>' + key + '</strong></td>';
 html += '<td>' + value + '</td></tr>';
 }
 }
 html += '</table></div>';
 
 // Tampilkan popup di koordinat yang diklik
 const popup = document.getElementById('popup');
 popup.innerHTML = html;
 popup.style.display = 'block';
 // Position popup using overlay (see below)
}

Integrasi dengan CodeIgniter 4

Sekarang kita integrasikan peta ke dalam CI4. Buat controller Webgis.php:


<?php

namespace App\Controllers;

class Webgis extends BaseController
{
 public function index()
 {
 $data['title'] = 'WebGIS Dashboard';
 $data['geoserver_url'] = 'https://geoserver.kinara.web.id/geoserver';
 $data['workspace'] = 'webgis_app';
 $data['center_lon'] = 110.0;
 $data['center_lat'] = -7.5;
 $data['zoom'] = 8;
 
 return view('webgis/index', $data);
 }
 
 // API endpoint untuk mengambil data layer list
 public function layers()
 {
 $geoserver = $this->request->getGet('server') ?? 'https://geoserver.kinara.web.id';
 $workspace = $this->request->getGet('workspace') ?? 'webgis_app';
 
 $url = "$geoserver/geoserver/$workspace/wms?service=WMS&version=1.1.1&request=GetCapabilities";
 
 $ch = curl_init($url);
 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
 $response = curl_exec($ch);
 curl_close($ch);
 
 // Parse XML untuk mendapatkan daftar layer
 $xml = simplexml_load_string($response);
 $layers = [];
 
 foreach ($xml->Capability->Layer->Layer as $layer) {
 $layers[] = [
 'name' => (string)$layer->Name,
 'title' => (string)$layer->Title
 ];
 }
 
 return $this->response->setJSON([
 'status' => 'success',
 'layers' => $layers
 ]);
 }
 
 // Proxy endpoint untuk menghindari CORS
 public function proxy()
 {
 $url = $this->request->getGet('url');
 
 if (!$url || !str_contains($url, 'geoserver')) {
 return $this->response->setStatusCode(403)->setJSON([
 'error' => 'Invalid URL'
 ]);
 }
 
 $ch = curl_init($url);
 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
 $response = curl_exec($ch);
 $contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
 curl_close($ch);
 
 return $this->response
 ->setHeader('Content-Type', $contentType)
 ->setBody($response);
 }
}

Buat view webgis/index.php:


<!DOCTYPE html>
<html lang="id">
<head>
 <meta charset="UTF-8">
 <title><?= $title ?></title>
 <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/ol.css">
 <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
 <style>
 #map { width: 100%; height: calc(100vh - 56px); }
 .layer-panel {
 position: absolute; top: 10px; right: 10px; z-index: 1000;
 background: white; padding: 15px; border-radius: 8px;
 box-shadow: 0 2px 10px rgba(0,0,0,0.2); width: 250px;
 }
 .layer-panel h5 { margin-bottom: 10px; font-size: 14px; }
 .layer-item { margin-bottom: 5px; }
 .layer-item label { font-size: 13px; cursor: pointer; }
 </style>
</head>
<body>
 <nav class="navbar navbar-dark bg-dark">
 <div class="container-fluid">
 <span class="navbar-brand"><?= $title ?></span>
 </div>
 </nav>
 
 <div id="map">
 <div class="layer-panel" id="layerPanel">
 <h5><i class="bi bi-layers"></i> Layer Control</h5>
 <div id="layerList">Loading...</div>
 </div>
 </div>
 
 <div id="popup" class="ol-popup" style="display:none;"></div>
 
 <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/ol.js"></script>
 <script>
 const GEOSERVER_URL = '<?= $geoserver_url ?>';
 const WORKSPACE = '<?= $workspace ?>';
 
 // Base layers
 const osmLayer = new ol.layer.Tile({ source: new ol.source.OSM(), title: 'OpenStreetMap' });
 
 const map = new ol.Map({
 target: 'map',
 layers: [osmLayer],
 view: new ol.View({
 center: ol.proj.fromLonLat([<?= $center_lon ?>, <?= $center_lat ?>]),
 zoom: <?= $zoom ?>
 })
 });
 
 // Load layers from GeoServer
 async function loadLayers() {
 try {
 const resp = await fetch('/webgis/layers?workspace=' + WORKSPACE);
 const data = await resp.json();
 const listEl = document.getElementById('layerList');
 listEl.innerHTML = '';
 
 data.layers.forEach((layer, idx) => {
 const wmsLayer = new ol.layer.Image({
 source: new ol.source.ImageWMS({
 url: GEOSERVER_URL + '/' + WORKSPACE + '/wms',
 params: { 'LAYERS': layer.name, 'FORMAT': 'image/png', 'TRANSPARENT': true },
 serverType: 'geoserver'
 }),
 title: layer.title,
 visible: true
 });
 map.addLayer(wmsLayer);
 
 const div = document.createElement('div');
 div.className = 'layer-item';
 div.innerHTML = '<input type="checkbox" id="layer_' + idx + '" checked> '
 + '<label for="layer_' + idx + '">' + layer.title + '</label>';
 listEl.appendChild(div);
 
 div.querySelector('input').addEventListener('change', function() {
 wmsLayer.setVisible(this.checked);
 });
 });
 } catch(e) {
 document.getElementById('layerList').innerHTML = 'Error loading layers';
 }
 }
 loadLayers();
 </script>
</body>
</html>

Tambahkan Routing di CI4

Jangan lupa tambahkan route di app/Config/Routes.php:


// WebGIS routes
$routes->group('webgis', function($routes) {
 $routes->get('/', 'Webgis::index');
 $routes->get('layers', 'Webgis::layers');
 $routes->get('proxy', 'Webgis::proxy');
});

Menambahkan Fitur Drawing (Digitasi)

Salah satu fitur penting di WebGIS adalah ability untuk menggambar (digitasi) geometri baru. OpenLayers punya built-in interaction untuk ini:


// Vector layer untuk menyimpan drawn features
const drawSource = new ol.source.Vector();
const drawLayer = new ol.layer.Vector({
 source: drawSource,
 style: new ol.style.Style({
 fill: new ol.style.Fill({ color: 'rgba(255, 100, 50, 0.3)' }),
 stroke: new ol.style.Stroke({ color: '#ff6432', width: 2 }),
 image: new ol.style.Circle({
 radius: 7,
 fill: new ol.style.Fill({ color: '#ff6432' })
 })
 })
});
map.addLayer(drawLayer);

// Fungsi untuk mengaktifkan drawing mode
let drawInteraction;

function startDrawing(geometryType) {
 if (drawInteraction) {
 map.removeInteraction(drawInteraction);
 }
 
 drawInteraction = new ol.interaction.Draw({
 source: drawSource,
 type: geometryType // 'Point', 'LineString', 'Polygon', 'Circle'
 });
 
 drawInteraction.on('drawend', function(event) {
 const feature = event.feature;
 const geometry = feature.getGeometry();
 const format = new ol.format.GeoJSON();
 const geojson = format.writeGeometry(geometry, {
 dataProjection: 'EPSG:4326',
 featureProjection: 'EPSG:3857'
 });
 
 console.log('GeoJSON:', geojson);
 
 // Kirim ke server untuk disimpan
 fetch('/webgis/save-feature', {
 method: 'POST',
 headers: { 'Content-Type': 'application/json' },
 body: JSON.stringify({
 layer: 'drawn_features',
 geometry: geojson,
 properties: { name: 'User drawn feature' }
 })
 });
 });
 
 map.addInteraction(drawInteraction);
}

// Tombol kontrol
// <button onclick="startDrawing('Polygon')">Draw Polygon</button>
// <button onclick="startDrawing('Point')">Draw Point</button>
// <button onclick="map.removeInteraction(drawInteraction)">Stop Drawing</button>

Tips Deploy untuk Production

Kalau kamu mau deploy WebGIS ini ke production, ada beberapa hal yang perlu diperhatikan:

  • CORS Configuration: GeoServer harus di-configure agar menerima request dari domain CI4 kamu. Buka Security → CORS di GeoServer admin dan tambahkan domain kamu
  • Nginx Reverse Proxy: Daripada expose GeoServer di port 8080, pakai nginx reverse proxy. Ini juga memudahkan SSL setup
  • Caching: WMS tiles bisa di-cache. Pakai nginx proxy_cache atau Cloudflare untuk cache WMS responses. Untuk WMTS, GeoServer bisa generate cached tiles pakai GeoWebCache
  • Database Connection Pooling: Kalau banyak user concurrent, pastikan PostGIS connection pool di GeoServer cukup besar
  • Security: Jangan pakai default credentials GeoServer di production. Ganti password dan restrict akses ke admin panel

Contoh nginx config untuk reverse proxy GeoServer:


server {
 listen 443 ssl;
 server_name geoserver.kinara.web.id;
 
 ssl_certificate /etc/letsencrypt/live/geoserver.kinara.web.id/fullchain.pem;
 ssl_certificate_key /etc/letsencrypt/live/geoserver.kinara.web.id/privkey.pem;
 
 location / {
 proxy_pass http://127.0.0.1:8080;
 proxy_set_header Host $host;
 proxy_set_header X-Real-IP $remote_addr;
 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 proxy_set_header X-Forwarded-Proto $scheme;
 
 # CORS headers
 add_header Access-Control-Allow-Origin "https://kinara.web.id" always;
 add_header Access-Control-Allow-Methods "GET, POST, OPTIONS" always;
 add_header Access-Control-Allow-Headers "Content-Type" always;
 }
}

Kesimpulan

Membangun WebGIS dengan OpenLayers + GeoServer + PHP CI4 itu nggak sesulit yang dibayangkan. Kuncinya adalah paham flow data: dari PostGIS → GeoServer (WMS/WFS) → OpenLayers (rendering di browser). CI4 di sisi server handle routing, autentikasi, dan business logic.

Kombinasi ini cocok banget untuk project GIS skala menengah sampai besar. Semua komponennya open-source, jadi nggak perlu khawatir soal lisensi. Kalau kamu butuh fitur editing geometri yang lebih advanced, OpenLayers juga support snapping, modify interaction, dan transform interaction.

Coba deh bikin project kecil dulu, misalnya peta yang menampilkan data kecamatan di kotamu dengan ability untuk klik dan lihat info. Dari situ kamu bisa kembangkan fitur-fitur lain seperti filtering, spatial query, dan export data.


Bagikan artikel ini:

Komentar (0)

Belum ada komentar. Jadilah yang pertama memberikan tanggapan!

Tinggalkan Komentar