Adding a Google Map to a FoxInCloud Form
FoxInCloud supports Google Map in both desktop and Web mode, with a high level of progam and/or user interaction. This post shows how, with very simple code, your application can provide a great map user experience on any device: desktop, browser on desktop or hand-held device.
(installed with V 2.21.1 scheduled 2016-05-01).
1- Add an Internet Explorer activeX object to the form
ADD OBJECT oleIE AS ficOLEIE WITH ; && ficOLEIE as awOLEIE of aw.vcx
    Top = 5, ;
    Left = 10, ;
    Height = 315, ;
    Width = 745, ;
    ZOrderSet = 11, ;
    Anchor = 15, ;
    Name = "oleIE"
  PROCEDURE oleIE.Init
    && 2016-04-20 thn -- {en} desktop mode: to use Google Maps in this control, you need to set Internet Explorer Compatibility:
    && 2016-04-20 thn -- {fr} mode desktop : pour utiliser Google Maps dans ce contrôle, vous devez régler la compatibilité Internet Explorer :
    && https://weblog.west-wind.com/posts/2011/May/21/Web-Browser-Control-Specifying-the-IE-Version
  ENDPROC2- Implement a Google Map in Web mode
When generating HTML, this objects instructs the HTML/CSS/JS generator to add JavaScript that creates a Google Map in Web mode:
PROCEDURE oleIE.wcHTMLgen
    LPARAMETERS toHTMLgen AS awHTMLgen OF awHTML.prg, tlInnerHTML && {en} doc in Parent Code {fr} doc dans le code parent
    local cScript as String
    && {en} The following JavaScript:
    && {en} - instantiates a Google Maps API object and stores a reference in a property added to the form's HTML element
    && {en} - implements the 'center_changed' event that fires when user moves the map using the mouse:
    && {en}   event handler writes the new lattitude and longitude to the spinners in the page
    && {en} notes:
    && {en} - $() is a shortcut to document.getElementById()
    && {en} - cLitteralJS() (modify command abTxt) turns any VFP value into a JavaScript literal
    && {en} - [test ? valueTrue : valueFalse] is the JavaScript equivalent for Iif()
    && {fr} Ce JavaScript :
    && {fr} - instancie un objet Google Maps API et stocke sa référence dans une propriété ajoutée à l'élément HTML du formulaire
    && {fr} - implémente l'événement 'center_changed' déclenché lorsque l'utilisateur déplace la carte avec la souris
    && {fr}   ce code écrit les nouvelles latitude et longitude dans les toupies présentes sur la page HTML
    && {fr} notes :
    && {fr} - $() est un raccourci (alias) de document.getElementById()
    && {fr} - cLitteralJS() (modify command abTxt) convertit toute valeur VFP en un littéral JavaScript
    && {fr} - [test ? valueTrue : valueFalse] est l'équivalent JavaScript de Iif()
    && https://developers.google.com/maps/documentation/javascript/reference
    text to cScript noshow textmerge flags 1 pretext 15
      $('<<m.thisForm.wcID>>').googleMap = new google.maps.Map(
        $('<<m.this.wcID>>')
      , {
          center: {lat: <<cLitteralJS(thisForm.spnLat.Value)>>, lng: <<cLitteralJS(thisForm.spnLng.Value)>>}
        , zoom: 8
        }
      );
      $('<<m.thisForm.wcID>>').googleMap.addListener('center_changed', function(){
        var googleMap = $('<<m.thisForm.wcID>>').googleMap
        , LatLng = googleMap.getCenter()
        , zoom = googleMap.getZoom()
        , dec = zoom > 12
          ? 5
          : (zoom > 10
            ? 4
            : (zoom > 8
              ? 3
              : (zoom > 6
                ? 2
                : (zoom > 4
                  ? 1
                  : 0
                )
              )
            )
          )
        ;
        $('<<thisForm.spnLat.wcID>>').valueSet(LatLng.lat().toFixed(dec) + '°');
        $('<<thisForm.spnLng.wcID>>').valueSet(LatLng.lng().toFixed(dec) + '°');
      });
    endtext
    m.toHTMLgen.cScriptJSadd(m.cScript)
  ENDPROC3- Load the Google Map JavaScript resource
Of course, we need to instruct the server, namely the process object, to generate a HTML instruction that loads the Google Map JavaScript whenever necessary:
* -------------------------------------------
PROTECTED FUNCTION cawJSinc && of xxxProcess
LPARAMETERS ;
  tcJSAdd; && [''] {en} Application, current form[, and custom] {fr} JS files URLs (UTF-8 encoded) {fr} URL des fichiers JS de l'application et du formulaire courant (encodés en UTF-8)
, toForm as awFrm of aw.vcx; && {en} Reference to form && {fr} Référence au formulaire && 2016-04-20 thn -- {en} {FiC V 2.21.1-beta.0} added paramter
, tcForm; && {en} .Name of form {fr} Nom du formulaire && 2016-04-20 thn -- {en} {FiC V 2.21.1-beta.0} added parameter
local result
result = DoDefault(m.tcJSAdd)
if InList(Lower(m.tcForm), Lower('index.scx'), Lower('googleMap.scx'))
  result = '<script src="https://maps.googleapis.com/maps/api/js"></script>' + m.result
endif
return m.result
endfunc4- Add control over the map location
We also add 2 spinners and a commandButton to control where the map is centered:
ADD OBJECT spnLat AS ficSpn WITH ; && ficSpn as awSpn of aw.vcx
    Anchor = 12, ;
    Height = 24, ;
    InputMask = "999.99°", ;
    KeyboardHighValue = 180, ;
    KeyboardLowValue = -180, ;
    Left = 680, ;
    SpinnerHighValue = 180.00, ;
    SpinnerLowValue = -180.00, ;
    Top = 345, ;
    Width = 75, ;
    ZOrderSet = 6, ;
    Value = 48.79, ; && initial map lattitude
    Name = "spnLat"
  ADD OBJECT spnLng AS ficSpn WITH ; && ficSpn as awSpn of aw.vcx
    Anchor = 12, ;
    Height = 24, ;
    InputMask = "999.99°", ;
    KeyboardHighValue = 180, ;
    KeyboardLowValue = -180, ;
    Left = 680, ;
    SpinnerHighValue = 180.00, ;
    SpinnerLowValue = -180.00, ;
    Top = 398, ;
    Width = 75, ;
    ZOrderSet = 8, ;
    Value = 2.21, ; && initial map longitude
    Name = "spnLng"
  ADD OBJECT cmdSet AS ficCmd WITH ; && ficCmd as awCmd of aw.vcx
    Top = 430, ;
    Left = 680, ;
    Height = 24, ;
    Width = 75, ;
    Anchor = 12, ;
    Caption = "Set", ;
    ZOrderSet = 10, ;
    Name = "cmdSet"As usual, the .click() method of the button is implemented for both desktop and web mode, all code (VFP and JavaScript) in the same method:
PROCEDURE cmdSet.Click
    if thisForm.wlHTMLgen && FoxInCloud adaptation
      return
    endif
    local oAJAX as awAJAX of awServer.prg;
    , cURL as String;
    * ==============================
    if wlAJAX(@m.oAJAX) && Web mode
    * ==============================
      && tutoServer.prg > tutoProcess.cawJSinc() {en} loads the Google Map Script {fr} charge le script Google Map
      && https://developers.google.com/maps/documentation/javascript/reference
      && {en} act upon Google Maps API object stored in form HTML element
      && {en} notes:
      && {en} - FoxInCloud Application Server executes this code when user clicks this button in the browser
      && {en} - oAJAX is a reference to the FoxInCloud AJAX object processing the request
      && {en} - oAJAX.cScriptJSadd_() adds some JavaScript instruction to the AJAX response
      && {en} - $() is a shortcut to document.getElementById()
      && {en} - cLitteralJS() (modify command abTxt) turns any VFP value into a JavaScript literal
      && {fr} agir sur l'objet Google Maps API dont l'élément HTML du formulaire garde une référence
      && {fr} notes :
      && {fr} - Le serveur d'application FoxInCloud exécute ce code lorsque l'utilisateur clique le bouton dans le navigateur
      && {fr} - oAJAX est une référence à l'Objet AJAX FoxInCloud traitant la requête
      && {fr} - oAJAX.cScriptJSadd_() ajoute des instructions JavaScript à la réponse AJAX
      && {fr} - $() est un raccourci (alias) de document.getElementById()
      && {fr} - cLitteralJS() (modify command abTxt) convertit toute valeur VFP en un littéral JavaScript
      m.oAJAX.cScriptJSadd_(Textmerge([$('<<wcID(thisForm)>>').googleMap.setCenter({lat:<<cLitteralJS(Cast(m.thisForm.spnLat.Value as N(6,2)))>>, lng:<<cLitteralJS(Cast(thisForm.spnLng.Value as N(6,2)))>>});]))
    * ==============================
    else && LAN / desktop mode
    * ==============================
      && {en} change URL on Internet Explorer activeX
      && {fr} mettre à jour l'URL de l'Internet Explorer activeX
      cURL = Evl(thisForm.oleIE.object.LocationURL, 'https://www.google.com/maps/@48.8000,2.2000,10z')
      cURL = GetWordNum(m.cURL, 1, '@');
        + '@' + cL(thisForm.spnLat.Value); && {en} Cast() depends on Set("Point"), cL() works around this {fr} Cast() dépend de Set("Point"), cL() s'en affranchit
        + ',' + cL(thisForm.spnLng.Value); && modify command abTxt
        + ',' + GetWordNum(GetWordNum(m.cURL, 2, '@'), 3, ',');
        + ''
      thisForm.oleIE.object.navigate2(m.cURL) && <==
    endif
  ENDPROC5- Initialize map location at form.Init()
We make sure that form inits to some location (default or parameter)
PROCEDURE Init
    lparameters lat, lng
    DoDefault()
    if thisForm.wlInitFirst && FoxInCloud adaptation
      return
    endif
    if Pcount() > 0
      this.spnLat.Value = Cast(m.lat as N(4,1))
      this.spnLng.Value = Cast(m.lng as N(4,1))
    endif
    this.cmdSet.Click6- Update spinners with the current map location
Whenever user moves the map using the mouse, the lattitude and longitude spinners reflect where map is currently centered
PROCEDURE oleIE.NavigateComplete2
    *** ActiveX Control Event ***
    LPARAMETERS pdisp, url
    && {en} fires in desktop mode only
    && {fr} ne se déclenche qu'en mode desktop
    url = GetWordNum(m.url, 2, '@') && eg 'https://www.google.com/maps/@48.8000,2.2000,10z' > '48.8000,2.2000,10z'
    thisform.spnLat.Value = Cast(GetWordNum(m.url, 1, ',') as N(6,2))
    thisform.spnLng.Value = Cast(GetWordNum(m.url, 2, ',') as N(6,2))
  PROCEDURE oleIE.wcHTMLgen
    LPARAMETERS toHTMLgen AS awHTMLgen OF awHTML.prg, tlInnerHTML && {en} doc in Parent Code {fr} doc dans le code parent
    text to cScript noshow textmerge flags 1 pretext 15 && for Web mode
      $('<<m.thisForm.wcID>>').googleMap.addListener('center_changed', function(){
        var googleMap = $('<<m.thisForm.wcID>>').googleMap
        , LatLng = googleMap.getCenter()
        , zoom = googleMap.getZoom()
        , dec = zoom > 12
          ? 5
          : (zoom > 10
            ? 4
            : (zoom > 8
              ? 3
              : (zoom > 6
                ? 2
                : (zoom > 4
                  ? 1
                  : 0
                )
              )
            )
          )
        ;
        $('<<thisForm.spnLat.wcID>>').valueSet(LatLng.lat().toFixed(dec) + '°');
        $('<<thisForm.spnLng.wcID>>').valueSet(LatLng.lng().toFixed(dec) + '°');
      });
    endtext
    m.toHTMLgen.cScriptJSadd(m.cScript)
  ENDPROC7- Test!
tags: JavaScript user experience
Watch FoxInCloud Marketing Videos :: Watch FoxInCloud Technical Videos :: Stay tuned on FoxInCloud Roadmap :: Learn how to use FoxInCloud :: Download FoxInCloud Adaptation Assistant for free :: Download FoxInCloud Web Application Studio for free