Nous allons voir comment réaliser un tableau de bord avec l'API Google Maps sous la plateforme Pentaho. Ce tableau de bord devra permettre l'affichage sur la carte des différents clients d'une entreprise ainsi que le nombre de rendez-vous déjà effectués avec ceux-ci. Lorsque l'on cliquera sur un point de la carte, une petite fenêtre apparaîtra avec une jauge représentant le nombre de rendez-vous par rapport à un nombre maximal défini. Les points sur la carte pourront prendre 3 couleurs différentes selon la valeur du nombre de rendez-vous. Il sera possible de changer les valeurs des intervalles ce qui influera en temps réel sur la couleur des points.

pentaho-gm1

Pour se faire, nous allons créer et modifier plusieurs fichiers. La première étape consiste à présenter succinctement la table qui contiendra nos données. Le modèle physique est le suivant :

TABLE client(id,org_name,adr_town,adr_one_locality,adr_one_postalcode,rdv) 
id : identifiant, clé primaire, ENTIER
org_name : nom du client, CHAINE
adr_town : adresse du client, CHAINE
adr_one_locality : ville du client, CHAINE
adr_one_postalcode : code postal, CHAINE
rdv : nombre de rendez-vous, ENTIER

Dans le répertoire d'installation de pentaho, allez sous « pentaho-solutions », puis dans le répertoire où vous souhaitez voir apparaître votre tableau de bord.

1.Créez un sous-répertoire « google »

2.A l'intérieur de celui-ci, créez un fichier « index.xml » qui contiendra le code suivant :

<index> 
	<name>%name</name> 
	<description>%description</description> 
	<icon></icon> 
	<visible>false</visible> 
	<display-type>list</display-type> 
</index>

3.Créez un fichier « index.properties » :

description=Google maps
name=Google

4.Dans le répertoire de niveau supérieur, créez un fichier google_map.url, ce fichier va nous permettre de spécifier le fichier à appeler pour l'affichage.

[InternetShortcut] 
URL=/pentaho/Map2 
[navigation] 
Name=%url_name 
Description=%url_description 
Icon=dashboard.jpg 
Target=google_map

5.Créez un fichier google_map.properties :

url_description= Pentaho google maps
url_name = Localisation clients

6.Editez le fichier « web.xml » et ajoutez l'appel à une page JSP que vous créerez pour l'occasion et qui sera une copie de celle fournie par Pentaho.

7.Créez un fichier Xaction et sauvegardez-le dans le sous-répertoire « google » sous map1.xaction

<?xml version="1.0" encoding="UTF-8"?> 
<action-sequence> 
  <name>CurrentPositionTitles.xaction</name> 
  <title>data for map</title> 
  <version>1</version> 
  <logging-level>debug</logging-level> 
  <documentation> 
    <author>Votre nome</author>  
    <description>description</description>  
    <help/>  
    <result-type>rule</result-type>  
    <icon></icon> 
  </documentation> 

  <inputs> 
    <dept type="string"> 
      <default-value>Google maps</default-value>  
      <sources> 
        <request>dept</request> 
      </sources> 
    </dept> 
  </inputs> 

  <outputs> 
    <data type="result-set"/> 
  </outputs> 

  <resources/> 
  
  <actions> 
    <action-definition> 
      <component-name>SQLLookupRule</component-name> 
      <action-type>Perform SQL Query</action-type> 
      <action-inputs> 
        <dept type="string"/> 
      </action-inputs> 
      <action-outputs> 
        <query-result type="result-set" mapping="data"/> 
      </action-outputs> 
      <component-definition> 
      <jndi>Nom du datasource</jndi>  
    	<query><![CDATA[votre requête SQL]]></query> 
      </component-definition> 
    </action-definition> 
 
  </actions> 
</action-sequence>

8. Ouvrez le fichier jsp créé à l'étape 6, nous allons y apporter quelques modifications et éclairer quelques points intéressants.

int topthreshold = 100000;
int bottomthresold = 50000;

correspondent aux deux seuils servant d'intervalles à la coloration des points.

<script language=\"javascript\" src=\"js/pentaho-ajax.js\"></script>\n
[...]
<script language=\"javascript\" src=\"js/google-demo.js\"></script>\n" ); 
[...]
"onload=\"load()\" onunload=\"GUnload()\"

Nous appelons ici deux fichiers javascript fournis par Pentaho : pentaho-ajax.js et google-demo.js

Faites une copie de google-demo.js et modifiez le lien ci-dessus.

Nous constatons qu'au chargement de la page, la fonction load() de google-demo est appelée.

runtime = SolutionHelper.doAction( "repertoire",  "sous-repertoire",  	"map1.xaction",  	"MyMap.jsp",  parameters,  userSession,  messages,  null 	);

Répertoire : votre répertoire de travail Sous-répertoire : le sous-répertoire où se trouve map1.xaction (par défaut google).

Par défaut sont déclarées les variables suivantes :

String customerNum = ""; 
String customer = ""; 
String city = ""; 
String state = ""; 
String zip = ""; 
String value = "";

Changeons-les en :

String id =""; 
String org_name=""; 
String adr_town=""; 
String adr_one_postalcode=""; 
String adr_one_locality=""; 
String rdv="";

Ensuite, nous arrivons sur la fonction « addPoints » qui va permettre l'ajout des points sur la carte via un enchaînement d'appel à des fonctions javascript. La boucle « for » va traiter chaque ligne retournée par la requête SQL de map1.xaction, il faut modifier le bloc d'attribution des variables de la façon suivante, afin de caster correctement les variables.

id  = results.getValueAt(row,0).toString(); 
org_name = (String)results.getValueAt(row,1); 
adr_town = (String)results.getValueAt(row,2);				 
adr_one_postalcode = (String)results.getValueAt(row,3); 
adr_one_locality = results.getValueAt(row,4).toString(); 
rdv = results.getValueAt(row,5).toString();

row est une ligne de résultat, l'indice correspond à la position de la valeur à rechercher dans row.

showAddress est ensuite utilisée. Cette fonction prend plusieurs paramètres :

  • l'adresse à trouver
  • le nom du client
  • l'identifiant
  • le nombre de rendez-vous
  • un booléen à laisser à faux

on a donc le code suivant :

showAddress( "<%= adr_town %>,<%= adr_one_locality %>, <	%=adr_one_postalcode %>,FRANCE", "<%= org_name %>", "<%= id %>", <%= rdv 	%>, false );

On peut bien évidemment changer « FRANCE » par un autre pays. Le reste du code est de l'HTML et va générer l'affichage. Vous pouvez le modifier comme bon vous semble. Il convient juste de garder un div ayant comme id la valeur « map », ce div contiendra la carte. Il y a deux select box qui permettent de changer à la volée les valeurs des intervalles. On peut bien évidemment modifier ces valeurs pour que cela corresponde au minimum et au maximum fournis par nos données.

Passons maintenant au fichier « google-demo.js ». Il faut commencer par changer les valeurs des variables : topThreshold et bottomThreshold pour qu'elles correspondent aux valeurs fournies dans le fichier jsp. Ensuite, nous déclarons trois types d'icônes qui vont être utilisés pour différencier les groupes de valeurs (vert, jaune, rouge).

La première fonction est load(), elle permet de charger une carte, de la centrer sur un point précis, d'y ajouter les contrôles de zoom et de switch d'affichage, et les points sur la carte via « addPoints ».

La seconde fonction, « customerClick » va gérer les actions lors du clic sur un point. On appelle la méthode ajax pentahoAction sur le fichier dial1.xaction en passant des paramètres : - le client - la valeur courante du nombre de rendez-vous - la valeur max du nombre de rendez-vous - la valeur du premier seuil - la valeur du second seuil Enfin, on indique que le callback se fera sur la méthode UpdateInfoWindow.

UpdateInfoWindow va afficher une petite boîte contenant les informations renvoyées par dial1.xaction, notamment le graphique type jauge.

Il faut ensuite commenter l'appel à chart.xaction qui lui, génère un ensemble de statistiques. Il ne nous intéresse pas dans notre exemple

La fonction showAddress que nous utilisons via le fichier JSP va générer un tableau contenant différentes informations puis appeler la fonction qui affiche le marqueur sur la carte. La fonction showMarker va permettre d'attribuer une couleur à chaque marqueur selon la valeur des intervalles et la valeur de l'enregistrement passé en paramètre.

Enfin, la méthode update, appelée lors du changement d'une valeur des select box, s'occupe de régénérer les points avec les bonnes couleurs de marqueurs en rapport aux nouvelles valeurs.

Nous avons fait le tour des principales fonctions et fichiers à utiliser pour créer notre tableau de bord et pouvons maintenant étudier une fonctionnalité intéressante de Google Maps, la création de zones de sélection cliquable.

Nous allons utiliser une surcouche javascript disponible sous licence Creative Commons. Ce fichier « epoly.js » est disponible sur le site suivant : http://econym.googlepages.com/index.htm

pentaho-gm2

Ce fichier JS est à inclure dans le fichier JSP. Ensuite, il faut créer un fichier XML qui respecte la nomenclature suivante :

<states> 
<state name ="nom_pays" colour="couleur_carte" >
	<point lat=valeur lng=valeur />
	<point lat=valeur lng=valeur />
	etc...
</state>
<state>
...
</state>
</states>

Chaque polygone sera donc défini par un ensemble de points.

Dans le fichier JSP, il faut ajouter le code suivant :

 //<![CDATA[ 
  if (GBrowserIsCompatible()) { 
 
      var polys = []; 
      var labels = []; 

      // Récupération de la carte, ajout des contrôles et centrage
      var map = new GMap2(document.getElementById("map")); 
      map.addControl(new GLargeMapControl()); 
      map.addControl(new GMapTypeControl()); 
      map.setCenter(new GLatLng(42.16,-100.72),4); 

	// Définition de la méthode appelée lors du click sur une zone
      GEvent.addListener(map, "click", function(overlay,point) { 
        if (!overlay) { 
          for (var i=0; i<polys.length; i++) { 
            if (polys[i].Contains(point)) { 
              var area = polys[i].Area()/1000000; 
              var sqmiles = area/2.58998811; 
              map.openInfoWindowHtml(point,"You clicked on "+labels[i]+"<br>The 			area of "+labels[i]+" is "+parseInt(area) 
                 	+" sq km.<br>that's "+parseInt(sqmiles)+" square miles<br>" 
                  +"Its boundary is "+parseInt(polys[i].Distance()/1609.344)+" 			miles long" 
              );
              i = 999; // Jump out of loop 
            } 
          } 
        } 
      }); 

      // Lecture du fichier XML
      var request = GxmlHttp.create(); 

	// récupération du fichier XML
      request.open("GET", "jsp/states.xml", true); 
      request.onreadystatechange = function() { 
      if (request.readyState == 4) { 
          var xmlDoc = GXml.parse(request.responseText); 
	 
          // Récupération des élements « state »
          var states = xmlDoc.documentElement.getElementsByTagName("state"); 
	 
	    // Création des polygones
          for (var a = 0; a < states.length; a++) { 
            var label  = states[a].getAttribute("name"); 
            var colour = states[a].getAttribute("colour"); 
            var points = states[a].getElementsByTagName("point"); 
            var pts = []; 
            for (var i = 0; i < points.length; i++) { 
               pts[i] = new GLatLng(parseFloat(points[i].getAttribute("lat")), 
                                   parseFloat(points[i].getAttribute("lng"))); 
            } 
	 
            var poly = new Gpolygon(pts,"#000000",1,1,colour,0.5,					{clickable:false}); 
            polys.push(poly); 
            labels.push(label); 
            map.addOverlay(poly); 
          } 
          // ================================================           
        } 
      } 
      request.send(null); 
    } 

  
    
    // Si le navigateur n'est pas compatible
    else { 
      alert("Sorry, the Google Maps API is not compatible with this browser"); 
    } 

    // Ajout d'une icône sur la carte
    var tinyIcon = new GIcon(G_DEFAULT_ICON); 
    tinyIcon.image = "http://labs.google.com/ridefinder/images/mm_20_red.png"; 
    tinyIcon.iconSize = new GSize(12, 20); 
    tinyIcon.shadowSize = new GSize(22, 20); 

    var markerOptions = { icon:tinyIcon }; 
    var point = new GLatLng(35.8659,-108.5715); 
    map.addOverlay(new GMarker(point,markerOptions)); 
     
    //]]> 
    </script>

Ces exemples sont bien évidemment paramètrables à volonté, notamment via la requête SQL et les interactions que l'on souhaite offrir à l'utilisateur.