Developing with the API

2D Web Javascript API

API organisation

The first step for developping with the Geoportal API is to download it (See Download). The API project uses Maven for being compiled and installed. Python is also used for Javascript compression, as well as Perl for using a local CGI proxy.

The API must be uncompressed into a web published directory. The layout of the API is as follows :

trunkthe main directory containing sources, builds, ... the test files are located in the trunk/main/webapp/test directory
targetthe directory where the API is built. After compilation, it contains the API and the site. The API can be uncompressed when compiling with mvn -Penv-local, compressed when compiling with mvn -Penv-dev

The directory where the Javascript source codes reside is trunk/main/javascript. This directory is divided into several entries :

buildThis directory contains the ant scripts needed for various operations
geoportalThe API source code
openlayersThe source code of OpenLayers used by the API
proj4jsThe source code of PROJ4JS for reprojection handling

The openlayers and proj4js directories contain the original source codes. Any modifications made on these libraries are located into the geoportal/lib directory :

GeoportalContains the main source codes of the API. The overall structure is the same as OpenLayers.
OpenLayersContains the OverloadedOpenLayersMinimum.js, OverloadedOpenLayersStandard.js and OverloadedOpenLayersExtended.js files.
proj4jsContains the OverloadedProj4js.js file as well as the catalogues and projCode directories. The former holds a partial EPSG catalogue and the IGNF catalogue. These catalogues describes spatial reference systems used by the API. The latter directory contains new algorithms used in the API whenever necessary.

Developing with the API

The developer can use his/her license key in order to get datasets from the Geoportal. The first step is to tell the API not to load the Geoportal.js compressed code :

<script
  type="text/javascript"
  src="http://api.ign.fr/geoportail/api?key=KEY&amp;instance=VIEWER&amp;includeEngine=false&amp;">
<!--//--><![CDATA[//><!-- //--><!]]>
</script>

It may be interesting in debug mode to display messages through the use of OpenLayers.Console methods :

<script type="text/javascript" src="../js/VERSION/lib/openlayers/lib/Firebug/firebug.js">
<!--//--><![CDATA[//><!-- //--><!]]>
</script>

Then, you have to load your local compressed/uncompressed API. For the uncompressed API, the following code snippet shows how to do it (it is assumed that your web page is located into a directory at the same level as the API is) :

<script type="text/javascript" src="../js/VERSION/lib/geoportal/lib/Geoportal.js">
<!--//--><![CDATA[//><!-- //--><!]]>
</script>

the VERSION value is explained in the Integration page.

Your web page can be tested locally. There is no need to run it from the web site declared when obtaining the license key. This insures the developer to code its application locally before deploying it on his/her web site.

The following code shows a complete web page uncompressed_local.html) for local testing :

<!DOCTYPE html>
<html debug="true">
<head>
    <title>uncompressed_local.html</title>
    <!-- indicates UTF-8 to get proper display of API labels : -->
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <link rel="shortcut icon" type="image/x-icon" href="img/favicon.ico" />
    <!-- include CSS for easying overwriting of styles : -->
    <!-- OpenLayers styles : -->
    <link id="__OpenLayersCss__" rel="stylesheet" type="text/css" href="../js/VERSION/lib/openlayers/theme/default/style.css"/>
    <!--[if lte IE 6]>
    <link id="__IE6OpenLayersCss__" rel="stylesheet" type="text/css" href="../js/VERSION/lib/openlayers/theme/default/ie6-style.css"/>
    <![endif]-->
    <!-- if OpenLayer.Layer.Google is used : -->
    <!--
    <link id="__GoogleOpenLayersCss__" rel="stylesheet" type="text/css" href="../js/VERSION/lib/openlayers/theme/default/google.css"/>
      -->
    <!-- if OpenLayers.Popup.FramedCloud is used : -->
    <!--
    <link id="__FramedCloudOpenLayersCss__" rel="stylesheet" type="text/css" href="../js/VERSION/lib/openlayers/theme/default/framedCloud.css"/>
      -->
    <link id="__GeoportalCss__" rel="stylesheet" type="text/css" href="../js/VERSION/lib/geoportal/theme/geoportal/style.css"/>
    <!--[if lte IE 6]>
    <link id="__IE6GeoportalCss__" href="../js/VERSION/lib/geoportal/theme/geoportal/ie6-style.css" type="text/css" rel="stylesheet"/>
    <![endif]-->
    <!-- if Geoportal.Viewer.Standard is used : -->
    <!--
    <link id="__StandardCss__" rel="stylesheet" type="text/css" href="../js/VERSION/lib/geoportal/theme/geoportal/standard.css"/>
      -->
    <style type="text/css"><!--/*--><![CDATA[/*><!--*/
    /* overwritten styles or new styles : */
    div#footer {
        font-size:x-small;
        text-align:center;
        width:800px;
    }
    div#footer a, div#footer a:link, div#footer a:visited, div#footer a:hover {
        text-decoration:none;
        color:black;
    }
    /*]]>*/--></style>
</head>
<body>
    <div id="viewerDiv" style="width:800px;height:600px;"></div>    <!-- the map div -->
    <div id="footer"><a href="https://api.ign.fr/geoportail/document.do?doc=legal_mentions" target="_blank">Terms of Use</a> - &copy;IGN 2008-2012</div>
    <!-- get the API configuration, but without the API javascript : -->
    <script type="text/javascript" src="http://api.ign.fr/geoportail/api?key=YOUR_KEY&amp;includeEngine=false&amp;"><!--//--><![CDATA[//><!--
    //--><!]]></script>
    <!-- load local Firebug : -->
    <script type="text/javascript" src="../js/VERSION/lib/openlayers/lib/Firebug/firebug.js"><!--//--><![CDATA[//><!--
    //--><!]]></script>
    <!-- load local API : -->
    <script type="text/javascript" src="../js/VERSION/lib/geoportal/lib/Geoportal.js"><!--//--><![CDATA[//><!--
    //--><!]]></script>
    <!-- Application script : -->
    <script type="text/javascript"><!--//--><![CDATA[//><!--
    var viewer= null;                                   //the viewer instance
    if (window.__Geoportal$timer===undefined) {
        var __Geoportal$timer= null;
    }

    // onload event will call myOnLoad :
    function myOnLoad() {
        if (__Geoportal$timer!=null) {
            window.clearTimeout(__Geoportal$timer);
            __Geoportal$timer= null;
        }
        var f;
        var C= ['OpenLayers', 'Geoportal', 'Geoportal.Viewer', 'Geoportal.Viewer.Default'];
        for (var i= 0, l= C.length; i<l; i++) {
            try {
                f= eval(C[i]);
            } catch (e) {
                f= undefined;
            }
            if (typeof(f)==='undefined') {
                __Geoportal$timer= window.setTimeout('myOnLoad();', 300);
                return;
            }
        }
        // build a new viewer :
        viewer= new Geoportal.Viewer.Default(           // Default viewer (one could use Geoportal.Viewer.Standard)
                "viewerDiv",                            // div id where to display dataset
                OpenLayers.Util.extend({                // viewer parameters :
                    //mode:'normal',                      // default value
                    //territory:'FXX',                    // default value
                    //projection:'IGNF:GEOPORTALFXX',     // default value
                    displayProjection:'IGNF:RGF93G',      // default value is 'CRS:84'
                    //proxy:PROXY+'?url=',                // if deemed necessary (KML, etc ... not in the same domain)
                    nameInstance:'viewer'},
                    gGEOPORTALRIGHTSMANAGEMENT          // API configuration with regard to the API key
                )
        );
        if (!viewer) {
            alert('failed loading viewer');
            return;
        }
        viewer.addGeoportalLayers();                    // load all available layers
        // default center and zoom location :
        viewer.getMap().setCenter(viewer.viewerOptions.defaultCenter,viewer.viewerOptions.defaultZoom);
    }

    window.onload= myOnLoad;                            // call myOnLoad when onload event is fired
    //--><!]]></script>
</body>
</html>

The above example can be viewed via http://localhost/YOUR_CONTEXT/uncompress_local.html.

Note : we advise you to use ZazouMiniWebServer as web service (HTTP server) because of its simplicity of use.

Advanced development with the API (starting with 1.0beta4)

The above development model has been designed for people who want to rapidly show maps on the Web. For more advanced usages, the basic API limitations can be ignored by applying the following constructs.

The developer still needs to declare his/her license key, but this time without the VIEWER parameter :

<script
    type="text/javascript"
    src="http://api.ign.fr/geoportail/api?key=KEY&amp;includeEngine=false&amp;">
<!--//--><![CDATA[//><!-- //--><!]]>
</script>

Note : by using the includeEngine parameter set to "false", one asks not to receive the GeoportalMin.js (when VERSION equals "VERSION-m") Geoportal.js or GeoportalExtended.js (when VERSION equals "VERSION-e") Javascript API. This can be usefull for caching such a script.

The API will then sent the following JavaScript content back :

var window.gGEOPORTALRIGHTSMANAGEMENT= {};
gGEOPORTALRIGHTSMANAGEMENT.apiKey= 'KEY';
gGEOPORTALRIGHTSMANAGEMENT['KEY']= {
  tokenServer:{url:'TOKEN_SERVER',ttl:TTL},
  tokenTimeOut:TTO,
  bounds: [MINLON,MINLAT,MAXLON,MAXLAT],
  allowedGeoportalLayers:[],
  resources:{}
};
gGEOPORTALRIGHTSMANAGEMENT['KEY'].allowedGeoportalLayers.push('LAYER_NAME:SERVICE_TYPE');
gGEOPORTALRIGHTSMANAGEMENT['KEY'].resources['LAYER_NAME:SERVICETYPE']=
  {name:'LAYER_NAME',type:'SERVICE_TYPE',url:'http://wxs.ign.fr/geoportail/SERVICE'};
...

The content of the global variable gGEOPORTALRIGHTSMANAGEMENT can be now be used for creating the map :

...
my options= OpenLayers.Util.extend(
    {
        mode:"normal"
    },
    gGEOPORTALRIGHTSMANAGEMENT
);
...
VIEWER= new Geoportal.Viewer.Default("LocalDiv", options);
...

It is now up to the developer to insert this content in his/her application.

One can find templates here :

Default behavior of the API

This is deprecated and will be removed with API 2.0:

When the following code is inserted in the web page :

<script
    type="text/javascript"
    src="http://api.ign.fr/geoportail/api?v=VERSION&amp;key=KEY&amp;instance=VIEWER&amp;">
<!--//--><![CDATA[//><!-- //--><!]]>
</script>

the API send back the following Javascript code at the end of the head tag :

 var VIEWER= null;
function geoportalLoadVIEWER(idDivMap, mode, territory, crs, dispcrs, proxy){
  var options= {};
  if(mode) {options.mode= mode;}
  if(territory) {options.territory= territory;}
  if(crs) {options.projection= crs;}
  if(dispcrs) {options.displayProjection= dispcrs;}
  if(proxy) {options.proxy= proxy;}
  options.nameInstance= 'VIEWER';
  options.apiKey= [];
  options.apiKey.push('KEY');
  options['KEY']= {
    tokenServer:{url:'TOKEN_SERVER',ttl:600},
    tokenTimeOut:600,
    transport:'json',
    bounds: [MINLON,MINLAT,MAXLON,MAXLAT],/* the KEY contract extent */
    allowedGeoportalLayers:[],
    resources:{}
  }
  /* for each layer in your KEY contract : */
  options['KEY'].allowedGeoportalLayers.push('LAYER_NAME:SERVICE_TYPE');
  options['KEY'].resources['LAYER_NAME:SERVICE_TYPE']= {
    name:'LAYER_NAME',
    type:'SERVICE_TYPE',
    url:'http://wxs.ign.fr/geoportail/SERVICE'
  };
  /* end for each */
  VIEWER= new Geoportal.Viewer.Default(idDivMap, options);
  return VIEWER;
}
// Geoportal API version 1.0 (MODE)
var __Geoportal$listenerLoaded= false;
var __Geoportal$loadComplete= false;
var __Geoportal$onloadCallbacks= null;
var __Geoportal$ready= false;
var __Geoportal$nof= function(){};
var __Geoportal$timer= null;
var __Geoportal$ua= navigator.userAgent.toLowerCase();
var __Geoportal$browser= {" + this.newLine +
  version:(__Geoportal$ua.match(/.+(?:rv|it|ra|ie)[\\/: ]([\\d.]+)/) || [0,'0'])[1],
  safari:/webkit/.test(__Geoportal$ua) && !/chrome/.test(__Geoportal$ua),
  opera:/opera/.test(__Geoportal$ua),
  msie:/msie/.test(__Geoportal$ua) && !/opera/.test(__Geoportal$ua),
  mozilla:/mozilla/.test(__Geoportal$ua) && !/(compatible|webkit)/.test(__Geoportal$ua),
  chrome:/chrome/.test(__Geoportal$ua)
};

function __Geoportal$launch() {
  if (__Geoportal$timer!=null) {
    window.clearTimeout(__Geoportal$timer);
  }
  if (viewer==null && typeof(initGeoportalMap)=='function') {
    initGeoportalMap();
  }
}

function __Geoportal$init() {
  __Geoportal$loadListener();
  if (!__Geoportal$loadComplete) {
    __Geoportal$loadComplete= true;
  } else if (!__Geoportal$ready) {
    if (__Geoportal$timer!=null) {
      window.clearTimeout(__Geoportal$timer);
      __Geoportal$timer= null;
    }
    __Geoportal$ready= (typeof(Geoportal)!=='undefined' && typeof(Geoportal.Viewer)!=='undefined' && typeof(Geoportal.Viewer.Standard)!=='undefined');
    if (!__Geoportal$ready) {
      __Geoportal$timer= window.setTimeout('__Geoportal$init();',500);
      return;
    }
    if (typeof(__Geoportal$onloadCallbacks)=='function' && __Geoportal$onloadCallbacks!==__Geoportal$nof) {
      __Geoportal$onloadCallbacks();
    }
    __Geoportal$onloadCallbacks= __Geoportal$nof;
    if (__Geoportal$onloadCallbacks===__Geoportal$nof) {
      __Geoportal$launch();
    } else {
      __Geoportal$timer= window.setTimeout('__Geoportal$launch();',500);
    }
  }
}

function __Geoportal$loadListener() {
  if (__Geoportal$listenerLoaded) {return;}
    __Geoportal$listenerLoaded= true;
    /*Mozilla*/
    if (document.addEventListener && !/(webkit|opera)/.test(__Geoportal$ua)) {
      document.addEventListener("DOMContentLoaded", function() {
        document.removeEventListener("DOMContentLoaded", arguments.callee, false);
        __Geoportal$init();
      }, false);

    /*IE*/
    } else if (document.attachEvent && !/opera/.test(__Geoportal$ua)) {
      if (document.readyState==="complete"){
        __Geoportal$init();
      } else {
        document.attachEvent("onreadystatechange", function() {
          if (document.readyState==="complete") {
            document.detachEvent("onreadystatechange", arguments.callee);
            __Geoportal$init();
          }
        });
      }

      if (document.documentElement.doScroll && window==window.top) (function() {
        if (__Geoportal$loadComplete) {return;}
        try {
          document.documentElement.doScroll("left");
        } catch (error) {
          setTimeout(arguments.callee, 0);
          return;
        }
        __Geoportal$init(); })();

      /*Safari, Opera, Chrome*/
      } else if (/(webkit|opera)/.test(__Geoportal$ua)) {
        var __timer= setInterval(function() {
          if (/loaded|complete/.test(document.readyState)) {
            clearInterval(__timer);
            __Geoportal$init();
          }
        }, 10);
      }


   if (window.addEventListener) {
      window.addEventListener("load", function(e) {
        if (window.removeEventListener && e.eventPhase == 3) {
          window.removeEventListener("load", arguments.callee, false);
        }
        __Geoportal$init();
      },false);
   } else if (window.attachEvent) {
     window.attachEvent("onload", function() {
       if (window.detachEvent) {
         window.detachEvent("onload",arguments.callee);
       }
       __Geoportal$init();
     });
   }
}

/* When includeEngine is omitted or true : */
function __Geoportal$onloadcheck() {
  if (this.readyState=='loaded' || this.readyState=='complete') {
    this.onreadystatechange= null;
    this.onload();
    this.onload= null;
  }
}
/* end of when */

(function() {
  __Geoportal$onloadCallbacks= window.onload;
  window.onload= __Geoportal$nof;
  /* When includeEngine is omitted or true : */
  var _sGP= document.createElement('script');
  _sGP.type= 'text/javascript';
  _sGP.src= "http://api.ign.fr/geoportail/api/js" + VERSION + "GeoportalMODE.js';
  _sGP.charset= 'utf-8';
  _sGP.onload= __Geoportal$loadListener;
  _sGP.onerror= function(){//Useful only on FireFox (to have an error in case of a 404)
    throw ('The script ' + this.src + ' has not been found.');
  };
  if (/msie/.test(__Geoportal$ua) || /webkit/.test(__Geoportal$ua)) {
    _sGP.onload= __Geoportal$init;
    _sGP.onreadystatechange= __Geoportal$onloadcheck;
  }
  var nodes= document.getElementsByTagName('head');
  var head= nodes.length>0? nodes[0]: document.body;
  head.appendChild(_sGP);
  /* otherwise */
  __Geoportal$loadListener();
  /* end when */
})();

Minimum, Standard, Extended API (starting with 1.0beta4) and Mobile API (starting with 1.3)

The minimum API gives the developer the connectors for the WMS-C, WMS and WFS GeoRM protected services. The Geoportal permanent logo is also part of this API (See Terms Of Use). PROJ4JS library is part of this API while OpenLayers is not. The level of API allows web sites with an already existing OpenLayers based viewer to integrate Geoportal services (See the french metadata service web site).

The standard API gives the minimum API features and some feature of OpenLayers (KML, GPX, WMS access, Controls). It also embed a default viewer that was used for previous API releases. There is also another viewer based on the Geoportal web site as an example.

The extended API gives the standard API features and all OpenLayers features.

The mobile API gives access to mobile devices as standard API does.

Developing with the API under windows

Prerequisite Installations :
  • Maven : for compiling, installing the API into the local web repository and generating the documentation ;
  • Python : for compressing Javascript source codes ;
  • Perl or Php : for a local CGI proxies utilization ;
  • Zazou Mini Web Server or heavier web servers like IIS or Apache : for testing API web pages.
Steps :
  • Download the API's source codes and save into the API project's directory (say api_directory_path) ;
  • Copy ZazouMiniWebServer.exe into the directory api_directory_path\src\main\webapp ;
  • Open the Windows Command Line Interpreter, change directory to api_directory_path and type in the following command :
    mvn -e -Penv-local -Dpython_path="python_path\python.exe" \
        -Durl_site="api_directory_path\target" \
        clean compile site-deploy
  • Double click on ZazouMiniWebServer.exe : the examples are available at the following address http://localhost/test/index.html

Migration path between 1.x and upcoming 2.0

2D Web Javascript API

In order to be able to run current Geoportal API webapp with the next API 2.0 release one has to follow the following steps. More steps will appear on the road to 2.0 release.

Step 1 - Directly download the API :

The downloading of the API done through the API servlet is deprecated, the 2.0 release will give direct accesses to different flavors and versions of the API. The rational behind this is to simplify and make explicit the API downloading :

<html>
    <script type="text/javascript" src="http://api.ign.fr/geoportail/api?v=VERSION&amp;key=CLEF&amp;instance=VIEWER&amp;">
    <!--//--><![CDATA[//><!--
    //--><!]]>
    </script>

    <script type="text/javascript"><!--//--><![CDATA[//><!--
    // the VIEWER variable is declared by the API through the instance parameter
    VIEWER= null;

    function initGeoportalMap() {
        ...
        geoportalLoadVIEWER("viewerDiv", MODE, TERRITORY, CRS, DISPLAYCRS, PROXY);
        ...
    }
    ...
    //--><!]]></script>

    <body>
        ...
        <div id="viewerDiv"></div>
        ...
    </body>
</html>

It is then advised to write :

<html>
    <!-- SET the includeEngine parameter to false, REMOVE the v parameter : -->
    <script type="text/javascript" src="http://api.ign.fr/geoportail/api?key=CLEF&amp;instance=VIEWER&amp;includeEngine=false&amp;">
    <!--//--><![CDATA[//><!--
    //--><!]]>
    </script>

    <!-- DOWNLOAD explicitly the right flavor of the API based on the value of v : -->
    <!-- v=VERSION-m -->
    <script type="text/javascript" src="http://api.ign.fr/geoportail/api/js/VERSION/GeoportalMin.js" charset="utf-8">
    <!--//--><![CDATA[//><!--
    //--><!]]>
    </script>

    <!-- v=VERSION : -->
    <script type="text/javascript" src="http://api.ign.fr/geoportail/api/js/VERSION/Geoportal.js" charset="utf-8">
    <!--//--><![CDATA[//><!--
    //--><!]]>
    </script>

    <!-- v=VERSION-e -->
    <script type="text/javascript" src="http://api.ign.fr/geoportail/api/js/VERSION/GeoportalExtended.js" charset="utf-8">
    <!--//--><![CDATA[//><!--
    //--><!]]>
    </script>

    <script type="text/javascript"><!--//--><![CDATA[//><!--
    // the VIEWER variable is declared by the API through the instance parameter
    VIEWER= null;

    function initGeoportalMap() {
        ...
        geoportalLoadVIEWER("viewerDiv", MODE, TERRITORY, CRS, DISPLAYCRS, PROXY);
        ...
    }
    ...
    //--><!]]></script>

    <body>
        ...
        <div id="viewerDiv"></div>
        ...
    </body>
</html>

We will consider now that the API in used in the standard API for the following steps.

Step 2 - Change to way the API is launched :

The following method for downloading the API's launcher and executing it is deprecated, 2.0 release won't support it anymore. The rational behind this is to let the developer chose his/her strategy to start the API :

<html>
    <script type="text/javascript" src="http://api.ign.fr/geoportail/api?key=CLEF&amp;instance=VIEWER&amp;includeEngine=false&amp;">
    <!--//--><![CDATA[//><!--
    //--><!]]>
    </script>

    <script type="text/javascript" src="http://api.ign.fr/geoportail/api/js/VERSION/Geoportal.js" charset="utf-8">
    <!--//--><![CDATA[//><!--
    //--><!]]>
    </script>

    <script type="text/javascript"><!--//--><![CDATA[//><!--
    // the VIEWER variable is declared by the API through the instance parameter
    VIEWER= null;

    function initGeoportalMap() {
        ...
        geoportalLoadVIEWER("viewerDiv", MODE, TERRITORY, CRS, DISPLAYCRS, PROXY);
        ...
    }
    ...
    //--><!]]></script>

    <body>
        ...
        <div id="viewerDiv"></div>
        ...
    </body>
</html>

It is then advised to write :

<html>
    <!-- REMOVE the instance and includeEngine parameters : -->
    <script type="text/javascript" src="http://api.ign.fr/geoportail/api?key=KEY&amp;">
    <!--//--><![CDATA[//><!--
    //--><!]]>
    </script>

    <script type="text/javascript" src="http://api.ign.fr/geoportail/api/js/VERSION/Geoportal.js" charset="utf-8">
    <!--//--><![CDATA[//><!--
    //--><!]]>
    </script>

    <script type="text/javascript"><!--//--><![CDATA[//><!--
    // the VIEWER variable is not any more declared by the API
    VIEWER= null;

    function initGeoportalMap() {
        ...
        geoportalLoadVIEWER("viewerDiv", MODE, TERRITORY, CRS, DISPLAYCRS, PROXY);
        ...
    }
    ...
    //--><!]]></script>

    <!-- DEFINE geoportalLoadVIEWER : -->
    <script type="text/javascript"><!--//--><![CDATA[//><!--
    function geoportalLoadVIEWER(idDivMap, mode, territory, crs, dispcrs, proxy) {
        var options= {};
        if(mode) {options.mode= mode;}
        if(territory) {options.territory= territory;}
        if(crs) {options.projection= crs;}
        if(dispcrs) {options.displayProjection= dispcrs;}
        if(proxy) {options.proxy= proxy;}
        options.nameInstance= 'VIEWER';
        OpenLayers.Util.extend(options, gGEOPORTALRIGHTSMANAGEMENT || {});
        VIEWER= new Geoportal.Viewer.Default(idDivMap, options);

        return VIEWER;
    }
    //--><!]]></script>

    <!-- ADD onload callback : -->
    <body onload="initGeoportalMap()">
        ...
        <div id="viewerDiv"></div>
        ...
    </body>
</html>

One can use window.onload or any other means provided by other frameworks.

Step 3 - Get key's information explicitly :

The key's information is returned by the API servlet when the key parameter is in use, 2.0 release won't support it anymore. The rational behind this is to allow explicit access to the service in charge of delivering this information :

<html>
    <script type="text/javascript" src="http://api.ign.fr/geoportail/api?key=KEY&amp;">
    <!--//--><![CDATA[//><!--
    //--><!]]>
    </script>

    <script type="text/javascript" src="http://api.ign.fr/geoportail/api/js/VERSION/Geoportal.js" charset="utf-8">
    <!--//--><![CDATA[//><!--
    //--><!]]>
    </script>

    <script type="text/javascript"><!--//--><![CDATA[//><!--
    // the VIEWER variable is not any more declared by the API
    VIEWER= null;

    function initGeoportalMap() {
        ...
        geoportalLoadVIEWER("viewerDiv", MODE, TERRITORY, CRS, DISPLAYCRS, PROXY);
        ...
    }
    ...
    //--><!]]></script>

    <script type="text/javascript"><!--//--><![CDATA[//><!--
    function geoportalLoadVIEWER(idDivMap, mode, territory, crs, dispcrs, proxy) {
        var options= {};
        if(mode) {options.mode= mode;}
        if(territory) {options.territory= territory;}
        if(crs) {options.projection= crs;}
        if(dispcrs) {options.displayProjection= dispcrs;}
        if(proxy) {options.proxy= proxy;}
        options.nameInstance= 'VIEWER';
        OpenLayers.Util.extend(options, gGEOPORTALRIGHTSMANAGEMENT || {});
        VIEWER= new Geoportal.Viewer.Default(idDivMap, options);

        return VIEWER;
    }
    //--><!]]></script>

    <body onload="initGeoportalMap()">
        ...
        <div id="viewerDiv"></div>
        ...
    </body>
</html>

It is advised to write :

<html>
    <!-- REMOVE key parameter and therefore the call to the API servlet : -->

    <script type="text/javascript" src="http://api.ign.fr/geoportail/api/js/VERSION/Geoportal.js" charset="utf-8">
    <!--//--><![CDATA[//><!--
    //--><!]]>
    </script>

    <!-- DEFINE the contracts loader : -->
    <script type="text/javascript"><!--//--><![CDATA[//><!--
    if (window.__Geoportal$timer===undefined) {
        var __Geoportal$timer= null;
    }

    function checkApiLoading(retryClbk,clss) {
        if (__Geoportal$timer!=null) {
            //clearTimeout: cancels the timer "__Geoportal$timer" before its end
            window.clearTimeout(__Geoportal$timer);
            __Geoportal$timer= null;
        }
    
        /**
         * It may happen that the init function is executed before the API is loaded
         * Addition of a timer code that waits 300 ms before running the init function
         */
        var f;
        for (var i=0, l= clss.length; i<l; i++) {
            try {
                f= eval(clss[i]);
            } catch (e) {
                f= undefined;
            }
            if (typeof(f)==='undefined') {
                __Geoportal$timer= window.setTimeout(retryClbk, 300);
                return false;
            }
        }
        return true;
    }

    function loadAPI() {
        // wait for all classes to be loaded
        if (checkApiLoading(loadAPI,['OpenLayers','Geoportal','Geoportal.Viewer','Geoportal.Viewer.Default'])===false) {
            return;
        }

        // load API keys configuration, then load the interface
        Geoportal.GeoRMHandler.getConfig(['KEY'], null, null, {
            onContractsComplete: initGeoportalMap
        });
    }
    //--><!]]></script>

    <script type="text/javascript"><!--//--><![CDATA[//><!--
    // the VIEWER variable is not any more declared by the API
    VIEWER= null;

    function initGeoportalMap() {
        ...
        geoportalLoadVIEWER("viewerDiv", MODE, TERRITORY, CRS, DISPLAYCRS, PROXY);
        ...
    }
    ...
    //--><!]]></script>

    <script type="text/javascript"><!--//--><![CDATA[//><!--
    function geoportalLoadVIEWER(idDivMap, mode, territory, crs, dispcrs, proxy) {
        var options= {};
        if(mode) {options.mode= mode;}
        if(territory) {options.territory= territory;}
        if(crs) {options.projection= crs;}
        if(dispcrs) {options.displayProjection= dispcrs;}
        if(proxy) {options.proxy= proxy;}
        options.nameInstance= 'VIEWER';
        OpenLayers.Util.extend(options, gGEOPORTALRIGHTSMANAGEMENT || {});
        VIEWER= new Geoportal.Viewer.Default(idDivMap, options);

        return VIEWER;
    }
    //--><!]]></script>

    <!-- CHANGE onload callback : -->
    <body onload="loadAPI()">
        ...
        <div id="viewerDiv"></div>
        ...
    </body>
</html>

Now, the script is ready for a last improvement : put the scripts at the bottom of the page :

<html>
    <head>
        <title>...</title>
        ...
        <!-- put CSS here -->
        ...
    </head>
    <body>
        ...
        <div id="viewerDiv"></div>
        ...
        <script type="text/javascript" src="http://api.ign.fr/geoportail/api/js/VERSION/Geoportal.js" charset="utf-8">
        <!--//--><![CDATA[//><!--
        //--><!]]>
        </script>

        <script type="text/javascript"><!--//--><![CDATA[//><!--
        if (window.__Geoportal$timer===undefined) {
            var __Geoportal$timer= null;
        }

        function checkApiLoading(retryClbk,clss) {
            if (__Geoportal$timer!=null) {
                //clearTimeout: cancels the timer "__Geoportal$timer" before its end
                window.clearTimeout(__Geoportal$timer);
                __Geoportal$timer= null;
            }
    
            /**
             * It may happen that the init function is executed before the API is loaded
             * Addition of a timer code that waits 300 ms before running the init function
             */
            var f;
            for (var i=0, l= clss.length; i<l; i++) {
                try {
                    f= eval(clss[i]);
                } catch (e) {
                    f= undefined;
                }
                if (typeof(f)==='undefined') {
                    __Geoportal$timer= window.setTimeout(retryClbk, 300);
                    return false;
                }
            }
            return true;
        }

        function loadAPI() {
            // wait for all classes to be loaded
            if (checkApiLoading(loadAPI,['OpenLayers','Geoportal','Geoportal.Viewer','Geoportal.Viewer.Default'])===false) {
               return;
            }

            // load API keys configuration, then load the interface
            Geoportal.GeoRMHandler.getConfig(['KEY'], null, null, {
                onContractsComplete: initGeoportalMap
            });
        }

        VIEWER= null;

        function initGeoportalMap() {
            ...
            geoportalLoadVIEWER("viewerDiv", MODE, TERRITORY, CRS, DISPLAYCRS, PROXY);
            ...
        }
        ...
        function geoportalLoadVIEWER(idDivMap, mode, territory, crs, dispcrs, proxy) {
            var options= {};
            if(mode) {options.mode= mode;}
            if(territory) {options.territory= territory;}
            if(crs) {options.projection= crs;}
            if(dispcrs) {options.displayProjection= dispcrs;}
            if(proxy) {options.proxy= proxy;}
            options.nameInstance= 'VIEWER';
            OpenLayers.Util.extend(options, gGEOPORTALRIGHTSMANAGEMENT || {});
            VIEWER= new Geoportal.Viewer.Default(idDivMap, options);

            return VIEWER;
        }

        window.onload= loadAPI;
        //--><!]]></script>
    </body>
</html>

Finally, one get ride of geoportalLoadVIEWER() function to directly call the constructor enabling passing more options :

<html>
    <head>
        <title>...</title>
        ...
        <!-- put CSS here -->
        ...
    </head>
    <body>
        ...
        <div id="viewerDiv"></div>
        ...
        <script type="text/javascript" src="http://api.ign.fr/geoportail/api/js/VERSION/Geoportal.js" charset="utf-8">
        <!--//--><![CDATA[//><!--
        //--><!]]>
        </script>

        <script type="text/javascript"><!--//--><![CDATA[//><!--
        if (window.__Geoportal$timer===undefined) {
            var __Geoportal$timer= null;
        }

        function checkApiLoading(retryClbk,clss) {
            if (__Geoportal$timer!=null) {
                //clearTimeout: cancels the timer "__Geoportal$timer" before its end
                window.clearTimeout(__Geoportal$timer);
                __Geoportal$timer= null;
            }
    
            /**
             * It may happen that the init function is executed before the API is loaded
             * Addition of a timer code that waits 300 ms before running the init function
             */
            var f;
            for (var i=0, l= clss.length; i<l; i++) {
                try {
                    f= eval(clss[i]);
                } catch (e) {
                    f= undefined;
                }
                if (typeof(f)==='undefined') {
                    __Geoportal$timer= window.setTimeout(retryClbk, 300);
                    return false;
                }
            }
            return true;
        }

        function loadAPI() {
            // wait for all classes to be loaded
            if (checkApiLoading(loadAPI,['OpenLayers','Geoportal','Geoportal.Viewer','Geoportal.Viewer.Default'])===false) {
               return;
            }

            // load API keys configuration, then load the interface
            Geoportal.GeoRMHandler.getConfig(['KEY'], null, null, {
                onContractsComplete: initGeoportalMap
            });
        }

        VIEWER= null;

        // REPLACE geoportalLoadVIEWER call :
        function initGeoportalMap() {
            ... /* 1 */
            VIEWER= new Geoportal.Viewer.Default(
                "viewerDiv",
                OpenLayers.Util.extend({
                    mode:MODE,
                    territory:TERRITORY,
                    projection:CRS,
                    displayProjection:DISPLAYCRS,
                    proxy:PROXY
                }, gGEOPORTALRIGHTSMANAGEMENT || {})
            );
            ... /* 2 */
        }
        ...

        window.onload= loadAPI;
        //--><!]]></script>
    </body>
</html>
Step 4 (optional) - Loader utilisation

There is now an interface between various Geoportal's APIs (Javascript, Flash and 3D) whose aim is to allow a unique way for invoking these APIs ... It may be interesting to get prepared to using this interface by modifying the code's skeleton :

  • one gets ride of checkApiLoading() function as it is taken into account by the Geoportal.load loader ;
  • options given to the Geoportal.Viewer.Default constructor are now passed to the Geoportal.load loader ;
  • API's key is directly given to the Geoportal.load as it calls Geoportal.GeoRMHandler.getConfig ;
  • in order to get the same look and feel as above, one has to add the viewerClass to explicitly use Geoportal.Viewer.Default.

    The finalized code looks like :

    <html>
        <head>
            <title>...</title>
            ...
            <!-- put CSS here -->
            ...
        </head>
        <body>
            ...
            <div id="viewerDiv"></div>
            ...
            <script type="text/javascript" src="http://api.ign.fr/geoportail/api/js/VERSION/Geoportal.js" charset="utf-8">
            <!--//--><![CDATA[//><!--
            //--><!]]>
            </script>
    
            <script type="text/javascript"><!--//--><![CDATA[//><!--
    
            // ADDITION of a variable that will contain the visualisation interface (ease debugging) :
            var iVIEWER= null;
    
            // INSERTION of the loader :
            function loadAPI() {
                // MOVE lines before the call to Geoportal.Viewer.Default :
                ... /* 1 */
                // options are documented in the Geoportal.View.Default constructor :
                iVIEWER= new Geoportal.load(
                    "viewerDiv",
                    // the key or keys :
                    ['KEY'],
                    null,
                    null,
                    {
                        mode:MODE,
                        territory:TERRITORY,
                        projection:CRS,
                        displayProjection:DISPLAYCRS,
                        // WARNING, the option is called proxyUrl and not proxy :
                        proxyUrl:PROXY,
                        // KEEP the default viewer :
                        viewerClass:Geoportal.Viewer.Default,
                        // CALL initGeoportalMap in order to complete the work :
                        onView: initGeoportalMap,
                        // Every layer appearing in the first parameter of addGeoportalLayers() is now there :
                        layers:[
                            'LAYER_NAME'
                        ],
                        // Every options bound to layer appearing in the second parameter of addGeoportalLayers() is now there :
                        layersOptions:{
                            'LAYER_NAME':{ ... }
                        }
                    }
                );
            }
    
            // USE OF the interface viewer :
            function initGeoportalMap() {
                // RETRIEVE the viewer :
                var VIEWER= iVIEWER.getViewer();
                ... /* 2 */
            }
            ...
    
            window.onload= loadAPI;
            //--><!]]></script>
        </body>
    </html>
Best practices
CSSes

It is recommanded to insert directly the relevant API's CSSes instead of letting the API adds them to the DOM :

<!-- put CSS here -->
<!-- import OpenLayers/Geoportal CSS to ease overloading their styles : -->
<!-- OpenLayers :-->
<link id="__OpenLayersCss__" href="http://api.ign.fr/geoportail/api/js/VERSION/theme/default/style.css" type="text/css" rel="stylesheet"/>
<!--[if lte IE 6]>
<link id="__IE6OpenLayersCss__" href="http://api.ign.fr/geoportail/api/js/VERSION/theme/default/ie6-style.css" type="text/css" rel="stylesheet"/>
<![endif]-->
<!-- Geoportal :-->
<link id="__GeoportalCss__" href="http://api.ign.fr/geoportail/api/js/VERSION/theme/geoportal/style.css" type="text/css" rel="stylesheet"/>
<!--[if lte IE 6]>
<link id="__IE6GeoportalCss__" href="http://api.ign.fr/geoportail/api/js/VERSION/theme/geoportal/ie6-style.css" type="text/css" rel="stylesheet"/>
<![endif]-->

<!-- if Geoportal.Viewer.Standard is in use : -->
<link id="__StandardCss__" href="http://api.ign.fr/geoportail/api/js/VERSION/theme/black/standard.css" type="text/css" rel="stylesheet"/>        

<!-- if Geoportal.Viewer.Mobile is in use -->
<link id="__GeoportalMobileCss__" rel="stylesheet" type="text/css" href="http://api.ign.fr/geoportail/api/js/VERSION/theme/mobile/style.css"/>


<!-- if black theme is in use : replace the above CSS with those ones -->
<link id="__GeoportalBlackCss__" href="http://api.ign.fr/geoportail/api/js/VERSION/theme/black/style.css" type="text/css" rel="stylesheet"/>
<!--[if lte IE 6]>
<link id="__IE6GeoportalBlackCss__" href="http://api.ign.fr/geoportail/api/js/VERSION/theme/black/ie6-style.css" type="text/css" rel="stylesheet"/>
<![endif]-->

<!-- if Geoportal.Viewer.Standard is in use : -->
<link id="__StandardBlackCss__" href="http://api.ign.fr/geoportail/api/js/VERSION/theme/black/standard.css" type="text/css" rel="stylesheet"/>
Geoportal's Layer name

Whilst the Geoportal's layer name comprises the ressource name concatenated with the service type (colon separated), a good practice is to avoid using the serviceType in the layer's name to ease to migration. Therefore, it is better to write :

VIEWER.addGeoportalLayers(['LAYER_NAME'],{'LAYER_NAME':{/*properties*/}});

than :

VIEWER.addGeoportalLayers(['LAYER_NAME:WMSC'],{'LAYER_NAME:WMSC':{/*properties*/}});

This advice also applies when using the layers and layersOptions options of the loader.

The only exception is when using the Minimum API : in that case, the whole identification of the Geoportal's layer is needed.

Geoportal's default territory projection

Usually when defining the territory, one used to set up the default projection explicitly :

VIEWER= new Geoportal.Viewer.Default(
    "viewerDiv",
    OpenLayers.Util.extend({
        mode:MODE,
        territory:TERRITORY,
        projection:CRS,
        displayProjection:DISPLAYCRS,
        proxy:PROXY
    }, gGEOPORTALRIGHTSMANAGEMENT || {})
);

As the default territory's projection changed, it is better not to set up the projection when it is the territory's defaults :

VIEWER= new Geoportal.Viewer.Default(
    "viewerDiv",
    OpenLayers.Util.extend({
        mode:MODE,
        territory:TERRITORY,
        displayProjection:DISPLAYCRS,
        proxy:PROXY
    }, gGEOPORTALRIGHTSMANAGEMENT || {})
);

Territory's default projections are defined over there. With the upcoming Geoportal, the default projection will be EPSG:3857 for all territories.