Pemetaan dengan LeafLetJS dan OpenStreetMap

Dulu biasanya kita memakai GoogleMap, tapi setelah Google menerapkan kebijakan penggunaan yang baru, tentunya kita harus mencari alternatif lain.

Nah, extensi ini adalah alternatif yang sangat bagus. Kali ini kita akan mengimplementasikan LeafletJS untuk menampilkan data lokasi (latitude longitude) dengan peta dasar OpenStreetMap (OSM).

Kita di sini gak akan menggunakan LeafletJS secara langsung, tapi menggunakan wrapper yii2-locator yang dibuat oleh Sjaak Pristel.

Untuk contoh tampila nya bisa lihat di https://smf-climbing.org/climbing-spots/index.html.

Saya akan coba buat panduan step-by-step sbb:

  1. Buat tabel baru
CREATE TABLE `smf_climbing_spots` ( `id` int(5) UNSIGNED NOT NULL, `organization_id` int(4) UNSIGNED DEFAULT NULL, `location` point DEFAULT NULL, `title` varchar(300) DEFAULT NULL, `address` varchar(300) DEFAULT NULL, `type` varchar(100) DEFAULT NULL, `facility` varchar(300) DEFAULT NULL, `postedby` int(3) NOT NULL, `created_at` datetime NOT NULL, `updated_at` datetime NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;


ALTER TABLE smf_climbing_spots
ADD PRIMARY KEY (id);


ALTER TABLE smf_climbing_spots
MODIFY id int(5) UNSIGNED NOT NULL AUTO_INCREMENT;
COMMIT;

Field yang penting diperhatikan adalah location dengan format poin. Buat yang baru kenal format ini, poin adalah salah satu format utk geolocation yang ada di mysql atau postgresql atau sql lainnya.

lalu lakukan Gii biar terbentuk

  • model ClimbingSpots dan ClimbingSpotsSearch
  • controller ClimbingSpotsController
  • view climbing-spots (index, view, create, delete, update)
  1. Install yii2-locator dan yii2-spatial bisa pake composer atau manual

composer require sjaakp/yii2-locator “*”`
dan
composer require sjaakp/yii2-spatial "*"

atau tambahkan
“sjaakp/yii2-locator”: “"
“sjaakp/yii2-spatial”: "

di composer.json (jika menggunakan ini lakukan composer update di terminal)

  1. Tambahkan pada ClimbingSpots dengan
    use sjaakp\spatial\ActiveRecord;

Ubah file viewnya (index, view, _form).

  1. Index.php

Tambahkan

use sjaakp\locator\Locator;

Lalu hapus <?= GridView::widget() ?>
dan ganti dg

$map = Locator::begin([
   // 'tile' => 'Stamen.Watercolor', //water color of map
    'leafletOptions' => [
        'center' =>  [1.362391, 103.798577],   // SG Zoo
        'zoom' => 11,
        'popup ' =>true,
        'scrollWheelZoom' => false,
        // ... more options ...
    ],
    'popup' => true,
    'cluster' => false,
    'urlTemplate' => '/climbing-spots/info.html?id={id}',  //**Note-1**: untuk menampilkan popup jika mengklik marker.
]);

$map->modelFeatures($dataProvider, 'location'); 
$map->marker = [ 'type' => 'Marker', 'opacity' => 0.7 ];
Locator::end();

Tentunya teman2 jangan lupa itu di dalam <?php ?> ya…

Letakkan paling bawah kode javascript ini:

   <script type = "text/javascript">
    function showLocation(position) {
       var latitude = position.coords.latitude;
       var longitude = position.coords.longitude;
       alert("Latitude : " + latitude + " Longitude: " + longitude);
    }

    function errorHandler(err) {
       if(err.code == 1) {
          alert("Error: Access is denied!");
       } else if( err.code == 2) {
          alert("Error: Position is unavailable!");
       }
    }
       
    function getLocation() {
       if(navigator.geolocation) {
          // timeout at 60000 milliseconds (60 seconds)
          var options = {timeout:60000};
          navigator.geolocation.getCurrentPosition(showLocation, errorHandler, options);
       } else {
          alert("Sorry, browser does not support geolocation!");
       }
    }
 </script>

Klo sekarang temen-temen panggil di browser climbing-spots/index harusnya peta sudah muncul (asalkan ada koneksi internet ya). Tapi peta masih kosong, karena tabel kita khan juga belum ada datanya.

Lihat di kode ada kata ‘center’ dan ‘zoom’. Itu utk menentukan peta default nya berpusat dimana dan dengan zoom level berapa. Di sini saya tulis Singapore Zoo (cari pake Google Map aja biar gampang, haha) dan zoom level 11 (coba aja ganti mulai dari 1-20 lihat efek nya).

Khan ada
<?= Html::a('Create Calender', ['create'], ['class' => 'btn btn-success']) ?>

Tapi kalo diklik masih belum bisa dipake tuh…kita ubah sedikit _form nya.

  1. _form tambahkan diatas dengan

use sjaakp\locator\Locator;

lalu

Ubah seluruh nya jadi kayak gini:

<div class="climbing-spots-form">

<?php $form = ActiveForm::begin(); ?>

<?php
$map = Locator::begin([
    'leafletOptions' => [
        'center' =>  [1.362391, 103.798577],   // Zoo
        'zoom' => 11,
        'popup ' =>true,
        'scrollWheelZoom' => false,
    ],
]);

$map->activeMarker($model, 'location'); // allow the model's location to be changed

$map->finder(); // add an interactive Search control to the map

Locator::end();
?>

<div class="form-group">
    <?= Html::submitButton('Save', ['class' => 'btn btn-success']) ?>
</div>

<?php ActiveForm::end(); ?>
  1. view nya ubah juga biar lengkap

Tambahkan diatas dengan

use sjaakp\locator\Locator;

Ganti seluruh <?= DetailView::widget() ?> dengan ini:

    $map = Locator::begin([
        'leafletOptions' => [
            'center' =>  [1.362391, 103.798577],   // SG Zoo
            'zoom' => 11,
        ],
        'height' => 480,
        'marker' => 'DotMarker',
        'popup' => true,
        'cluster' => false,
        'urlTemplate' => '/climbing-spots/describe.html?id={id}',  //**Note-2**: ini untuk melakukan pengisian data selain id dan location.
        // ... other options ...
    ]);

$map->modelFeature($model, 'location'); // place a marker at the tower's location

$map->marker = [ 'type' => 'Marker', 'opacity' => 0.8 ];

Locator::end();

Tentunya teman2 jangan lupa juga itu di dalam <?php ?> ya…

Nah sekarang harusnya Create Spot nya sudah bisa dipake…

buktinya waktu diklik Create Spot gak ada error (palingan temen2 biar lancar kolom2 di tabel dibuat aja default nya NULL kecuali kolom id, klo tabel saya ada yg saya sengaja defaultnya tidak NULL) dan dibawah peta ada button Save…jalan itu…

Coba click cursor di peta, maka akan ada marker warna Biru nah lalu tekan Save. Akan balik view deh…kalau sudah sampe view itu bukti udah jalan peta kita. Coba ke tabel deh…akan ada satu row data…tapi cuma kolom id dan location aja yang keisi ya…untuk modifikasi nya kita akan aktifkan Note-2.

  1. Note-1 dan Note-2 sebetulnya barang yang sama. Bedanya adalah Note-1 untuk menampilkan data secara popup jika marker diklik, sedangkan Note-2 juga secara popup untuk mengisi data yang belum ada pada field-2 lain di tabel.

kode ini:

‘urlTemplate’ => ‘/climbing-spots/info.html?id={id}’,

Sebetulnya cuma ngomong,

  • controllernya: climbing-spots,
  • viewnya: info.html
  • untuk id yang ke- {id}

DI controller kasih tambahan spt ini:

public function actionInfo($id)
{
    return $this->renderAjax('info', [
        'model' => $this->findModel($id),
    ]);
}

Lihat agar tampil sbg popup kita harus pakai renderAjax().

Lalu file info.php nya berisi spt ini:

<?= DetailView::widget([
    'model' => $model,
    'attributes' => [
       // 'id',
        'title',
        'address',
        'type',
        'facility',
       // 'postedby',
        //'created_at',
        //'updated_at',
    ],
]) ?>

Ini khan cuma view.php hasil gii original yang saya clone lalu ganti nama jadi info.php.

Dengan cara yang sama untuk. Note-2

Tambahin controller dengan ini

public function actionDescribe($id)
{
    $model = $this->findModel($id);

    if ($model->load(Yii::$app->request->post()) && $model->save()) {
        if(empty($model->title) || empty($model->type) || empty($model->facility)){
            return $this->redirect(['view', 'id' => $model->id]);
        }
        else{
            return $this->redirect(['index']);
        }
    }
    return $this->renderAjax('describe', [
        'model' => $model,
    ]);
}

di sini juga dipakai renderAjax() agar tampil sbg popup.

Lalu buat file describe.php dan tempatkan di view nya. Biar gampang copy aja file create.php lalu ubah dikit isinya jadi spt ini:

$this->render('_formDescribe', [
    'model' => $model,
])

Hehe, sekarang buat file _formDescribe.php nya shg isinya spt ini:

use yii\helpers\Html;
use yii\widgets\ActiveForm;

<?php $form = ActiveForm::begin(); ?>

<?= $form->field($model, 'organization_id')->textInput(['maxlength' => true, 'placeholder'=>'Nomor organisasi..'])->label(false);?>

<?= $form->field($model, 'type')->dropDownList([
                                    'Indoors'=>'Indoors',
                                    'Outdoor'=>'Outdoor',
                                    'Mixed'=>'Mixed',
                                    ],
                            [ 'prompt' => 'Choose type' ]
                        )->label(false);?>

<?= $form->field($model, 'title')->textInput(['maxlength' => true, 'placeholder'=>'Place title'])->label(false) ?>

<?= $form->field($model, 'address')->textInput(['maxlength' => true, 'placeholder'=>'Complete address'])->label(false) ?>

<?= $form->field($model, 'facility')->textInput(['maxlength' => true, 'placeholder'=>'Lead, Speed, Bouldering, Shops, etc'])->label(false) ?>

<div class="form-group">
    <?= Html::submitButton('Save', ['class' => 'btn btn-success']) ?>
</div>

<?php ActiveForm::end(); ?>

Lah, ini khan file _form.php asli hasil gii tapi tanpa field location? Iya betul, krn khan location udah ada datanya, jadi gak perlu dientry lagi…

  1. Itu semua harusnya udah akan membuat menu climbing-spots (menampilkan, menambahkan data lokasi) jalan genks.

Semoga berhasil ya…