Google Maps embedden voor 1 of meer instanties

In Relatics is het mogelijk om een Google Maps Viewer te tonen waarin projectinformatie van een enkel element is toegevoegd . We kunnen de visualisatie nog aantrekkelijker maken door een verzameling van informatie op een kaart weer te geven. Als functioneel beheerder heb jij de mogelijkheid om met een basisbestand een Maps-viewer op de Overview én Detail Presentation van een element weer te geven. Deze kaart schaalt ook nog eens mee met de aangeleverde locaties! In dit artikel beschrijf ik hoe je dit kunt instellen.

Voorbereiding

In dit artikel ga ik er vanuit dat je reeds een API key voor de Maps Embed API hebt aangevraagd. Hier staat uitgelegd hoe je deze kunt aanvragen.

Datatype GPS van een Eigenschap meegeven in een rapportage

In Relatics kun je op een eigenschap het datatype GPS instellen, zoals hier beschreven op de Knowledge Base here. Ik zie dat GPS in de praktijk nog niet vaak gebruikt wordt, terwijl deze juist erg waardevol is! Doordat de GPS erg gemakkelijk via de mobiele telefoon is in te stellen, kan een eindgebruiker (al dan niet via een Context Portal) snel de workspace van GPS-coördinaten voorzien. Dit is erg handig voor bijvoorbeeld risico’s, keuringen, locaties van vergaderingen of waarnemingen ‘in het veld’.

In dit artikel beschrijf ik de instelling van een Object met een eigenschap Locatie, waarop het datatype GPS is toegepast. Op basis van deze eigenschap gaan we een kaartje tonen op de Detail Presentation van het betreffende Object, waarbij het Object met een marker is aangewezen. Deze kun je ook nog eens in Google Street View bekijken! De tabel laat zien waar je het datatype instelt. Deze kun je vervolgens in een rapportage query meegeven. Hieronder zie je hoe in het model het datatype GPS is ingesteld:

02_datatype_gps

Instellen van de Report voor de viewer

De rapportage die ik gebruik is eenvoudig. Er zijn een aantal bijzonderheden die hieronder worden opgesomd:

  • OutputExtension: HTML
  • ReportFields:
    • Height (hiermee kunnen we de hoogte van de viewer aanpassen)
    • MinZoom (hiermee kunnen we minimale zoom van de viewer aanpassen)
    • APIkey [Default value: YOUR_API_KEY]
  • Query:
    • De root-node maakt gebruik van een constraint query die zorgt dat alleen de elementen met een ingevulde locatie worden getoond.
    • Je kunt ook gebruik maken van een constraint op de @ID-parameter zoals ik in dit kennisartikel deed voor een kaart op de detailpagina.

Ik ontsluit het Value-attribuut van de eigenschap Location.

03_rapportage_query

Het XSLT-bestand opstellen voor de viewer (de componenten)

Het XSLT-bestand dat ‘achter’ deze viewer zit is een uitbreiding op die van het vorige artikel, maar zal in dit stuk in het geheel worden besproken. De viewer maakt gebruik van het feit dat Relatics een web-based applicatie is. Dat wil zeggen dat je op basis van de data in Relatics een HTML-pagina kan maken, die je ergens in Relatics kan laten zien. Door de Google Maps JavaScript API op te nemen kunnen we een Google Maps viewer maken.

In de XSLT nemen we daarom onderstaande code op:

XSLT: Google Maps JavaScript API inladen

...

  <head>

    <script>

      <xsl:attribute name="src" select="concat('https://maps.googleapis.com/maps/api/js?key=',Report/@APIkey)"/>

    </script>

  </head>

...

Naast HTML gaan we ook JavaScript laten genereren met de XSLT. Deze hebben we nodig om op de API van Google in te haken, zodat deze (client-sided) een Google Maps viewer zal genereren. Hierin zullen we namelijk gegevens uit onze Report gaan toevoegen.

De code hieronder is een combinatie van Javascript en XSLT. Het uiteindelijke doel is om een code van JavaScript (JS) te maken, waar onze data in verwerkt zit. Dat laatste wordt dan weer met een XSLT gedaan. In principe is de gehele XSLT aan te passen, maar het rode deel is variabel afhankelijk van jouw Report. Misschien herken je hier al een patroon in van de rapportage query (bijvoorbeeld de Locatie of het report field ‘MinZoom’):

XSLT: Generating the JavaScript code for the Google Maps API

...

  function initialize() {

    <!--Get all locations into an array-->

    var locations = [

    <xsl:for-each select="Report/Data/System_Object/Location[@Location!='']">

      [

      <xsl:value-of select="@Location"/>

      ]

      <xsl:if test="position()!=last()">

      ,

      </xsl:if>

      </xsl:for-each>

    ];

 

    <!--Get the boundaries of the map based on the locations-->

    var bounds = new google.maps.LatLngBounds();

    for (i = 0; i &lt; locations.length; i++) {

      bounds.extend( new google.maps.LatLng(locations[i][0],locations[i][1]));

    }

 

    <!--Add Map-visualisation options-->

    var mapOptions = {

      center: bounds.getCenter()

    };

 

    <!--Load the map-->

    var map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);

 

    <!--Fit the map to the boundaries and set a minimal zoom-->

    map.fitBounds(bounds);

 

    var listener = google.maps.event.addListenerOnce(map, "idle", function() {

      if (map.getZoom() &gt; <xsl:value-of select="Report/@MinZoom"/>) {

        map.setZoom( <xsl:value-of select="Report/@MinZoom"/>);

      }

    });

 

    <!--Add the markers to the map-->

    var markers =[];

    for (i = 0; i &lt; locations.length; i++) {

      markers[i] = new google.maps.Marker({

        position: new google.maps.LatLng(locations[i][0],locations[i][1]),

        map: map

      });

    }

  }

 

  <!--Start loading Google Maps when page is ready-->

  $(document).ready(function(){

    initialize();

  });

...

Naast de hierboven beschreven code, die zorgt dat de viewer zal gaan laden, zullen we ook nog een HTML-element moeten toevoegen die als een ‘fotolijstje’ zal gaan fungeren. Herken je de ‘map-canvas’ uit de bovenstaande code hieronder?

XSLT: Adding the div-element for the actual viewer

...

              <div id="map-canvas">

                <xsl:attribute name="style" select="concat('height:',Report/@Height,';width:100%;border: 1px solid black;')"/>

              </div>

...

Het XSLT-bestand opstellen voor de viewer (het geheel)

Wanneer we de bovenstaande stukken code samenvoegen (en er een klein beetje standaard XSLT-code aan toevoegen) komen we tot het onderstaande resultaat:

Final XSLT: Embedding Google Maps on a Detail Presentation of an element

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions">

  <xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes"/>

    <xsl:template match="/">

      <html>

        <head>

          <script>

            <xsl:attribute name="src" select="concat('https://maps.googleapis.com/maps/api/js?key=',Report/@APIkey)"/>

          </script>

        </head>

        <body>

          <div class="map">

            <xsl:if test="exists(Report/Data/System_Object/Location[@Location!='']) ">

              <script>

                function initialize() {

                  <!--Get all locations into an array-->

                  var locations = [

                  <xsl:for-each select="Report/Data/System_Object/Location[@Location!='']">

                    [

                    <xsl:value-of select="@Location"/>

                    ]

                    <xsl:if test="position()!=last()">

                    ,

                    </xsl:if>

                    </xsl:for-each>

                  ];

 

                  <!--Get the boundaries of the map based on the locations-->

                  var bounds = new google.maps.LatLngBounds();

                  for (i = 0; i &lt; locations.length; i++) {

                    bounds.extend( new google.maps.LatLng(locations[i][0],locations[i][1]));

                  }

 

                  <!--Add Map-visualisation options-->

                  var mapOptions = {

                    center: bounds.getCenter()

                  };

 

                  <!--Load the map-->

                  var map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);

 

                  <!--Fit the map to the boundaries and set a minimal zoom-->

                  map.fitBounds(bounds);

 

                  var listener = google.maps.event.addListenerOnce(map, "idle", function() {

                    if (map.getZoom() &gt; <xsl:value-of select="Report/@MinZoom"/>) {

                      map.setZoom( <xsl:value-of select="Report/@MinZoom"/>);

                    }

                  });

 

                  <!--Add the markers to the map-->

                  var markers =[];

                  for (i = 0; i &lt; locations.length; i++) {

                    markers[i] = new google.maps.Marker({

                      position: new google.maps.LatLng(locations[i][0],locations[i][1]),

                      map: map

                    });

                  }

                }

 

                <!--Start loading Google Maps when page is ready-->

                $(document).ready(function(){

                  initialize();

                });

              </script>

              <div id="map-canvas">

                <xsl:attribute name="style" select="concat('height:',Report/@Height,';width:100%;border: 1px solid black;')"/>

              </div>

            </xsl:if>

          </div>

        </body>

      </html>

   </xsl:template>

</xsl:stylesheet>

De rapportage ontsluiten op een Overview Presentation

Als je de XSLT hebt geüpload kun je de rapportage ontsluiten op de Overview Presentation. Dit kun je doen door middel van een ‘HTMLFragment’. Voorbeeld:

04_ontsluiten_van_rapportage

Het eindresultaat

Als we op de Overview Presentation kijken dan zien we daar onze interactieve Google Maps viewer.

05_eindresultaat

Toepassing van het vorige artikel

Heb je de vorige keer het artikel gebruikt om het kaartje op de Detail pagina te ontsluiten? Dan kun je deze XSLT ook daarvoor gebruiken. De structuur van de rapportage is volledig gelijk gebleven, met alleen een enkele aanpassing in de ReportFields:

  • Bij Height moet je ‘px’ achter jouw waarde zetten
  • Zoom moet je veranderen in MinZoom

Downloaden

Upload onderstaand RCS-bestand in je Relatics environment om de voorbeelden van dit artikel zelf te bekijken. In de ZIP kun je ook het XSLT-bestand vinden, zodat je direct in jouw eigen workspace aan de slag kunt.

Over Tom Rupke

Na het afronden van de studie Civiele Techniek met een specialisatie in Constructieve Waterbouw werkte Tom als Specialist Risicoanalyse & Contractmanagement bij een ingenieursbureau. Sinds 2016 werkt hij bij Relatics als Business Information Consultant. Tom werkt het liefst aan nieuwe ideeën en innovaties om meer uit Relatics te kunnen halen. Hij draagt graag kennis over aan eindgebruikers en functioneel beheerders (zowel op projecten en bij klanten als door het geven verschillende trainingen en workshops).

Relatics Portret-127 (Small)

Contact

Heeft u hulp nodig bij het toepassen van de genoemde technieken in uw eigen casus? Of heeft u vragen, opmerkingen of suggesties over dit artikel? Laat het ons dan weten via onderstaand formulier.