P4A framework: utilizzare il widget P4A Google Maps per implementare uno store locator

 

Questo post ha più di 1 anno. Il contenuto potrebbe essere obsoleto, non più completamente accessibile o mancante di alcune informazioni.

P4A esempio di Store LocatorEcco un esempio di utilizzazione del widget P4A Google Maps per creare una mappa di riferimenti (negozi, magazzini, ecc) che siano compresi in un certo raggio di distanza in Km, a partire da un indirizzo prestabilito.
Ho cercato di utilizzare il widget di Alberto Galanti senza effettuare nessuna modifica al codice originale. Ho scelto, quindi di implementare un metodo che fornisce la georeferenza della località che funge da centro, per poi effettuare, attraverso una query, la selezione degli indirizzi compresi nel raggio di distanze prestabilito.
L’esempio utilizzato, per comodità, è lo stesso indicato dalla guida di Google Maps in questo articolo.

I passi principali prima di procedere:

  • Scaricare il widget P4A Google Maps qui
  • Creare un archivio di riferimenti che abbiano un indirizzo nel formato accettato da Google Maps (Es.: “Piazza Venezia, Roma, Italia”)
  • Georeferenziare tutti gli indirizzi (trovare latitudine e longitudine)

Utilizzando MySQL, la struttura dell’archivio suggerita da Google è questa:

1
2
3
4
5
6
7
8
CREATE TABLE `markers` (
  `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(60) NOT NULL,
  `address` VARCHAR(80) NOT NULL,
  `lat` FLOAT(10,6) NOT NULL,
  `lng` FLOAT(10,6) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1;

Per comodità potete scaricare l’sql completo dei dati di esempio di Google qui

Nel caso non si conoscano già le coordinate dei riferimenti, è possibile utilizzare il metodo suggerito in questo articolo sempre da Google. Questo sistema permette di aggiornare direttamente i dati di un database MySQL con le coordinate fornite da Google Maps per tutti gli indirizzi memorizzati.

La selezione dei record che sono compresi in un reggio di distanza in Km prefissato, avviene tramite una query che utilizza la formula della triangolazione sferica:
cos p = cos a cos b + sen a sen b cos φ,
per maggiori dettagli potete leggere questo post.

Ecco la query in pratica:

1
2
3
4
5
6
7
8
SELECT address, name, lat, lng, 
( 6371 * acos( cos( radians('Center_latitude')) * cos( radians( lat )) 
* cos( radians( lng ) - radians('Center_longitude')) 
+ sin( radians('Center_latitude'))
* sin( radians( lat )))) AS distance
FROM markers
HAVING distance < 'Radius'
ORDER BY distance

dove 'Center_latitude' è la latitudine del centro, 'Center_longitude' è la longitudine del centro e 'Radius' è il raggio in km dal centro.

Ed ecco dunque, il codice della maschera P4A:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
class GoogleMap extends P4A_Mask
{
  function GoogleMap()
  {
    parent::P4A_Mask();
    $this->setTitle("Google Map Store Locator Test");
    // Frame
    $this->build("p4a_frame", "frame");
    $this->frame->setWidth(800);
    //la chiave per localhost è disponibile nel file p4a_map.php
    $coordArray = $this->getLocationCoordinates("Mountain View, CA", 
                  "Inserire_chiave_Google"); 
    $radius = 12;
    // DB Source
    $this->build("p4a_db_source", "source");
    $query = "SELECT address, name, lat, lng, 
     CONCAT_WS('
', name, address) AS info,
     (6371 * acos(cos(radians('$coordArray[2]')) * cos(radians(lat))
     * cos( radians(lng) - radians('$coordArray[3]')) 
     + sin( radians('$coordArray[2]'))
     * sin( radians(lat)))) AS distance
     FROM markers
     HAVING distance < '$radius' ORDER BY distance"; $this->source->setQuery($query);
    $this->source->setPk("id");
    $this->source->load();
    // map
    $map =& $this->build("p4a_map","mappa");
    $map->setCenter("Mountain View, CA");
    $map->setZoom(10);
    $map->setWidth(750);
    $map->setHeight(500);
    // markers from datasource
    $map->setSourceAddressField("address");
    //$map->setSourceDescriptionField("distance");
    $map->setSourceDescriptionField("info");
    $map->setSource($this->source);
    // Layout
    $this->frame->anchorCenter($map);
    // Display
    $this->display("main", $this->frame);
   }
 /*
  * Return the coordinates of the location.
  * @param $location		valid Google Maps address of a location.
  * @param $googleMapKey		key for accessing Google Maps.	 
  * @return array  element[0] = status, element[2] = lat, element[3] = long
  */
 function getLocationCoordinates($location, $googleMapKey)
 {
  $base_url = "http://maps.google.com/maps/geo?output=csv&key=".$googleMapKey;
  $request_url = $base_url."&q=".urlencode($location);
  $csv = file_get_contents($request_url);
  if ($csv) {
    $csvSplit = split(",", $csv);
  }
  else{
    $csvSplit = array();
  }
    return $csvSplit;
  }
}

Note:

La query crea la sorgente dati per i markers, che vengono evidenziati automaticamente dalla classe p4a_map.
Al posto delle info, potete visualizzare la distanza di ogni marker dal centro (nell’esempio: “Mountain View, CA”) utilizzando l’istruzione: $map->setSourceDescriptionField("distance");.
Il metodo getLocationCoordinates() recupera le coordinate del centro per poter poi comporre la query.
La chiave per l’accesso a Google Map è quella valida per un server tipo “localhost” e la trovate all’interno del file: p4a_map.php che si trova nella directory libraries. Per avere quella per un dominio pubblico è necessario farla generare a Google Maps qui.
Non ho fatto controlli di errore, ad esempio per quanto riguarda la risposta del metodo getLocationCoordinates() sarebbe opportuno controllare che l’array non sia vuoto e anche lo status della risposta di Google Maps, e si dovrebbe anche limitare il risultato della query al numero di markers massimo gestiti dal widget (17 se non ricordo male…).

Download

Il widget con la maschera sopra descritta è scaricabile qui

Conclusioni:

Il risultato è già soddisfacente, anche se un po’ grezzo, ma credo ci siano molti margini di miglioramento per questo tipo di utilizzo di Google Maps in P4A. Spero di avere tempo per affinare ulteriormente sia questo programma che il widget, per renderlo utilizzabile anche per idee diverse! Suggerimenti e consigli sono molto ben accetti!!

Riferimenti ed approfondimenti: