Web App Development Overview

Part 2: Creating a Map App with Pascal and "Canned" JavaScript


Contents

Introduction
The 10 Steps
The Pascal Server App
OpenLayers and Map Tile Servers


Introduction

This article takes a simple JavaScript app, QxMap, and shows how to add a Pascal server app to it. QxMap can be customized to use your own locations on the map via a simple JSON file rather than modifying the JavaScript code. These locations will be passed to the server app, which returns data for the locations to be displayed on the map.

The key here is to focus on the Pascal server part and ignore for now the client-side JavaScript that might seem strange to Pascal developers. A side benefit of this approach is to minimize the potential frustration with something new by doing one step at a time:

You can play with the QxMap app below. Or click here to launch it in its own browser window (for example, to test on a mobile device).


The 10 Steps

  1. Download the qooxdoo SDK. Unzip this anywhere you want.

  2. On Windows, make sure you have Python 2.7 installed. Mac and Linux systems will already have Python installed.

  3. Download the QxMap app's source. Unzip this anywhere you want.

  4. Create your own JSON file of location data. Substitute this file for the example locations.json included with QxMap (in source/resource/qxmap).

    The locations.json file included with QxMap looks like this:

    [{"name":"Ouray",     "lat":38.02, "lon":-107.67, "display":"Data goes here"},
     {"name":"Silverton", "lat":37.81, "lon":-107.66, "display":"Data goes here"},
     {"name":"Telluride", "lat":37.94, "lon":-107.81, "display":"Data goes here"}]
    The "display" strings are just placeholders for what will be ultimately be supplied by the server app. You can put anything you want there for use in testing QxMap without a server app.

  5. Edit QxMap's config.json file and customize it for your own needs:

    The default app-settings look like this:

        "app-settings" :
        {
          "environment" : {
            "appName"      : "QxMap",
            "appVersion"   : "0.1",
            "copyright"    : "",
            "description"  : "",
            "mapCenterLat" : 37.92, 
            "mapCenterLon" : -107.74,
            "mapZoomLevel" : 10,
            "locsJsonUrl"  : "resource/qxmap/locations.json",
          }
        },
    Note that you can edit the config.json file in Lazarus by opening the qxmap.lpi project file (in source/class/qxmap).

  6. Generate your own QxMap app by entering this at the command line in the folder where config.json is located:

    python generate.py source-noserver
    This will generate a version of QxMap that doesn't call a server app. This type of simple app can be posted anywhere on the Web.

    Note that if you have the Qx_Proj package installed in Lazarus, you can open the qxmap.lpi project in Lazarus and choose Run | Compile to run the generate.py script.

  7. To test QxMap, double-click the index.html file in QxMap's source folder to open it in your browser.

  8. Write your Pascal server app. See below for what this server app needs to do.

  9. Create a version of QxMap that calls your Pascal server app by running generate.py with the source-cgi job. You can test this version locally against your server app.

  10. Create a version of QxMap for deployment by running generate.py with the build-cgi job.

    You can zip up the QxMap files that need to be deployed by entering this at the command line in the folder where config.json is located:

    zip -r build build
    Once unzipped on your server, you can rename the build folder to your app's name.

The Pascal Server App

QxMap will call the server app and pass the latitude and longitude of your locations as named query parameters. For example, with the example locations, the query string passed to the server app would look like this:

lat1=38.02&lon1=-107.67&lat2=37.81&lon2=-107.66&lat3=37.94&lon3=-107.81
All your server app has to do is return data in JSON format for the specified locations. For example, here is what the Pascal for GIS getforecast app might return for these locations (with line breaks inserted for readability):
[{"point":"1","high":"67","low":"36","display":"High: 67 Low: 36"},
 {"point":"2","high":"52","low":"34","display":"High: 52 Low: 34"},
 {"point":"3","high":"53","low":"37","display":"High: 53 Low: 37"}]
The "display" field is the only required data; that's what QxMap will look for in the returned JSON and what it will display on the map for each location.

A slight complication

In order to make cross-domain calls, QxMap actually makes a JSONP request, passing along an extra "callback" parameter that the server app needs to look for. If present, the server app "wraps" the returned data with this parameter. For example, here is what the JSONP request might look like:

lat1=38.02&lon1=-107.67&lat2=37.81&lon2=-107.66&lat3=37.94&lon3=-107.81&callback=qx.bom.request.Jsonp.qx1474502452269303.callback
And here's what the returned data would look like (again, with line breaks inserted for readability):

qx.bom.request.Jsonp.qx1474502452269303.callback(
[{"point":"1","high":"67","low":"36","display":"High: 67 Low: 36"},
 {"point":"2","high":"52","low":"34","display":"High: 52 Low: 34"},
 {"point":"3","high":"53","low":"37","display":"High: 53 Low: 37"}]);

Pascal CGI units, etc.

You can write your Pascal server app using whatever CGI or other units you want, as long as it does what is outlined above.

For example, the Pascal for GIS getforecast app uses Free Pascal's simple ezcgi unit. The source for getforecast is here if you want to look at it.

You can compile getforecast as follows:

lazbuild ndfd_pkg.lpk
lazbuild getforecast.lpi
Note that your Pascal app does not need to return weather forecast data the way getforecast does. Any data associated with specific locations that changes regularly would probably be a good candidate for displaying with QxMap.

Deploying

QxMap's config.json file exports four "jobs" that you use with generate.py to specify which version of QxMap you want to generate. Here's what they look like:

    "source-noserver" :
    {
      "extend" : ["source", "app-settings", "ol-debug", "osm-stamen"],
      "environment" : {
        "getDataUrl" : ""
      }
    },

    "build-noserver" :
    {
      "extend" : ["build", "app-settings", "ol-deploy", "osm-stamen"],
      "environment" : {
        "getDataUrl" : ""
      }
    },

    "source-cgi" :
    {
      "extend" : ["source", "app-settings", "ol-debug", "osm-stamen"],
      "environment" : {
        "getDataUrl" : "http://yourdomain.com/getforecast/getforecast.cgi"
      }
    },

    "build-cgi" :
    {
      "extend" : ["build", "app-settings", "ol-deploy", "osm-stamen"],
      "environment" : {
        "getDataUrl" : "../../getforecast/getforecast.cgi"
      }
    }
Use the source-noserver job to generate a version of QxMap for testing locally without calling a server. Use the build-noserver job to generate a version of QxMap to deploy to a Web site.

Note that the noserver jobs don't specify a server app URL in the getDataUrl setting. To deploy QxMap that was generated with one of the server jobs to an https site, you must also communicate with the server app over https, not http. For a more in-depth explanation, see this.

Use the source-cgi job to generate a version of QxMap for testing locally that calls the server app. Use the build-cgi job to generate a version of QxMap to deploy.

For the source-cgi and build-cgi jobs, adjust the getDataUrl setting as needed. With build-cgi's default getDataUrl, the assumption is that the server app will be on the same server, relative to QxMap's directory. With source-cgi, the full URL is needed.


OpenLayers and Map Tile Servers

QxMap uses the OpenLayers JavaScript library to draw the map. The config.json file includes settings for OpenLayers as well:

    "ol" :
    {
      "environment" : {
        "olVersion"   : "3.18.2",
        "olCssUrl"    : "https://cdnjs.cloudflare.com/ajax/libs/ol3/3.18.2/ol.css",
        "olMarkerUrl" : "https://openlayers.org/api/img/marker.png",
      }
    },

    "ol-debug" :
    {
      "extend" : ["ol"],
      "environment" : {
        "olJsUrl" : "https://cdnjs.cloudflare.com/ajax/libs/ol3/3.18.2/ol-debug.js",
      }
    },

    "ol-deploy" :
    {
      "extend" : ["ol"],
      "environment" : {
        "olJsUrl" : "https://cdnjs.cloudflare.com/ajax/libs/ol3/3.18.2/ol.js",
      }
    },
You can change these settings as needed, for example to use a newer version of OpenLayers or to deploy the OpenLayers CSS and JavaScript files on your own server. Note that the ol-debug.js file is somewhat larger than the ol.js file because its whitespace has not been stripped out to minimize its size. Normally when you deploy an app you would use the smaller ol.js to minimize download time.

OpenLayers can download map tiles from a variety of servers. By default, QxMap uses Stamen's terrain map tiles. Stamen's map tile server is free to use.

OpenStreetMap also provides map tile servers, but there are restrictions on their use. However, you can test your QxMap with OpenStreetMap (and see how different the map looks) by changing osm-stamen to osm-mapnik in the appropriate job (for example, source-noserver) and regenerating QxMap.

To add a map tile server to config.json, just add a new job similar to osm-stamen, which looks like this:

    "osm-stamen" :
    {
      "environment" : {
        "osmUrl" : "https://stamen-tiles.a.ssl.fastly.net/terrain/{z}/{x}/{y}.jpg",
        "osmAttribution" : "Map tiles by Stamen Design, under CC BY 3.0. Data by OpenStreetMap, under ODbL."
      }
    },
Map tile servers typically support URL templates, where {z} is zoom level, {x} is horizontal position, and {y} is vertical position of the desired tile.


Copyright 2016 by Phil Hess.

macpgmr (at) icloud (dot) com

First posted Sept. 24, 2016; last edited June 10, 2017.

Code syntax highlighting done with highlight.js.