Getting started with Mapspace API

Introduction

This is a basic developer documentation to start creating a basic web app with Mapspace API. In this tutorial we will learn what is a workspace, how can layouts be used to arrange an array of viewers, and how to set up viewers for a first time. We will end with a web page with two viewers, a 2D map viewer and a Street image viewer shown in a dual side-by-side page. Let's start.

Initial steps

Create a new empty directory for your project and create an file index.html inside it with the following content:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Mapspace API basic sample</title>
    <link rel="stylesheet" href="http://your.mapspace.com/css/bootstrap.min.css" type="text/css"/>
    <link rel="stylesheet" href="http://your.mapspace.com/css/ol.css" type="text/css"/>
    <link rel="stylesheet" href="http://your.mapspace.com/css/widgets.css" type="text/css"/>
    <link rel="stylesheet" href="http://your.mapspace.com/css/mapspace.css" type="text/css"/>
    <link rel="stylesheet" href="http://your.mapspace.com/css/animate.min.css" type="text/css"/>
    <script src="http://your.mapspace.com/js/mapspace.js"></script>
    <style>
      #viewer {
        width: 960px;
        height: 540px;
      }
      .mapspace-zoom {
        top: .75em;
      }
    </style>
    <script type="text/javascript">
      $(function() {
          Mapspace.USERKEY = 'Set your own user token here';
          //Code to initialize the app goes here
      });
    </script>
  </head>
  <body>
    <div id="viewer"></div>
  </body>
</html>

The snippet above is the minimum HTML content to add to a web page to link with Mapspace API. That includes five CSS files for styling controls and one JS file that bundles all the API with its dependencies. mapspace.js includes JQuery, Bootstrap, Openlayers, CesiumJS and Three.js, among others libs, so if you are going to use them there is no need to include any more. As we have Jquery we can use the Jquery syntax to initialize our code after loaded of the page is completed.

Now the first line to set in the initialize function is the one that saves the userkey in the Mapspace object. Replace the string with your user token provided by Field Group.

Workspaces and viewers

A workspace is a collection of set-up rules to configure the way several viewers are initiated and are related together. It is possible to use it for initialize only one viewer, or several.

Let´s start doing the most basic set up initializing a workspace with only one 2D viewer.

Modify the index.html to have now this code:

$(function() {
    var mapViewer, mapViewerControls;
    var streetViewer, streetViewerControls;
    var workspace;

    Mapspace.USERKEY = 'Set your own user token here';

    mapViewerControls = [
        Mapspace.controldef.noAction(new Mapspace.control.StatusBar({
            controls: [
                Mapspace.global.controldef.ViewerInfo(),
                Mapspace.global.controldef.ScaleLine()
            ]
        })),
        Mapspace.global.controldef.Zoom(undefined, {duration: 1000}),
        Mapspace.global.controldef.Attribution()
    ];

    mapViewer = new Mapspace.global.Viewer({
        center: [10.743704, 59.911299],
        resolution: 2.38,
        layers: [
            new Mapspace.layer.Tile({
                name: 'Ortho WMTS',
                source: new Mapspace.ortho.source.WMTS({
                    userLayerName : "-Default-"
                })
            })
        ]
    });
    
    workspace = new Mapspace.Workspace({
        layout: {
            name: 'Map layout',
            views: [
                {
                    column: 0,
                    viewer: mapViewer,
                    controls: mapViewerControls
                }
            ]
        },
        target: 'viewer'
    });
});

Try the code copying it to Codepen or check this example: Viewer with map & controls.

You will see one viewer, showing 2D imagery centered at Oslo, with a few basic controls.

This basic app has some functionality already done. You can pan (by dragging), zoom (with the mouse wheel or using the buttons), and rotate the view (by Ctrl + dragging). As you move the mouse you will se the coordinates in the status bar. Map rotation, scale and dates of the visible imagery is also shown there.

Let's explain how this works.

A workspace is contained of one or several viewers. The collection of viewers can be passed to the workspace constructor using a Mapspace.WorkspaceOptions object. This object has two optional properties:

  • layout, to define the collection of viewers and their arrangement
  • target, to define the HTML element where the workspace will be rendered.

The layout is defined using a Mapspace.Layout object. This object has two optional properties:

  • name, to give a name to the layout (useful if you need in the future to change between different layouts)
  • views, that define the collection of viewers, and their arrangement. This collection is an array of Mapspace.LayoutView objects.

A Mapspace.LayoutView object has two required properties and optional properties:

  • column with the column index (starting at zero) where the viewer will be added
  • viewer with the viewer object
  • controls an optional array of Control Definitions that define a collection of controls.

Now check again out previous code and notice that we have created a valid Mapspace.Layout object named "Map layout" and with only one valid Mapspace.LayoutView object. This is defined to be in a first column (column: 0) and will contain a 2D viewer (Mapspace.global.Viewer).

The layout system is pretty straightforward. Each viewer is added to a column, and if several viewers share the same column, they are stacked below the previous one in a vertical stack. For example, to create a dual view with two viewers in horizontal layout, you should use this:

    workspace = new Mapspace.Workspace({
        layout: {
            name: 'Map & Street layout',
            views: [
                {
                    column: 0,
                    viewer: mapViewer
                },
                {
                    column: 1,
                    viewer: streetViewer
                }
            ]
        },
        target: 'viewer'
    });

For a dual view with two viewers in vertical layout, you should use this:

    workspace = new Mapspace.Workspace({
        layout: {
            name: 'Map & Street layout',
            views: [
                {
                    column: 0,
                    viewer: mapViewer
                },
                {
                    column: 0,
                    viewer: streetViewer
                }
            ]
        },
        target: 'viewer'
    });

A triple view with two viewers in first column and one in the second could be defined as:

    workspace = new Mapspace.Workspace({
        layout: {
            name: 'Map & Street layout',
            views: [
                {
                    column: 0,
                    viewer: mapViewer
                },
                {
                    column: 0,
                    viewer: mapViewer2
                },
                {
                    column: 1,
                    viewer: streetViewer
                }
            ]
        },
        target: 'viewer'
    });

This system has some limitations but for the purposing of making a layout of viewers is quite flexible, and just by setting a column index for each viewer.

Setting up a dual viewer

Now we know how to use workspaces and layouts. Let's end our first example with a dual viewer showing both a 2D and a Street viewer side-by-side, and also define some syncing properties. Please uptate the index.html as follows:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Mapspace API basic sample</title>
    <link rel="stylesheet" href="http://your.mapspace.com/css/bootstrap.min.css" type="text/css"/>
    <link rel="stylesheet" href="http://your.mapspace.com/css/ol.css" type="text/css"/>
    <link rel="stylesheet" href="http://your.mapspace.com/css/widgets.css" type="text/css"/>
    <link rel="stylesheet" href="http://your.mapspace.com/css/mapspace.css" type="text/css"/>
    <link rel="stylesheet" href="http://your.mapspace.com/css/animate.min.css" type="text/css"/>
    <script src="http://your.mapspace.com/maps/js/mapspace.js"></script>
    <style>
      #viewer {
        width: 960px;
        height: 540px;
      }
      .mapspace-zoom {
        top: .75em;
      }
      .openstreet_button {
          top: .75em;
          right: 3em;
      }
    </style>
    <script type="text/javascript">
    $(function() {
        var workspace, mapViewer, mapViewerControls;
        var streetViewer, streetViewerControls;
        var openStreetAction, openStreetButton;
        var buttonActive = false;

        Mapspace.USERKEY = 'Set your own user token here';

        mapViewerControls = [
            Mapspace.controldef.noAction(new Mapspace.control.StatusBar({
                controls: [
                    Mapspace.global.controldef.ViewerInfo(),
                    Mapspace.global.controldef.ScaleLine()
                ]
            })),
            Mapspace.global.controldef.Zoom(undefined, {duration: 1000}),
            Mapspace.global.controldef.Attribution()
        ];

        mapViewer = new Mapspace.global.Viewer({
            center: [10.743704, 59.911299],
            resolution: 2.38,
            layers: [
                new Mapspace.layer.Tile({
                    name: 'Ortho WMTS',
                    source: new Mapspace.ortho.source.WMTS({
                        userLayerName : "-Default-"
                    })
                })
            ]
        });

        openStreetAction = new Mapspace.street.action.OpenStreetImage();

        openStreetButton = new Mapspace.control.Button({
            iconSVG: 'view_street',
            label: 'Open Street image',
            classNames: 'btn-light no-shadow openstreet_button',
            handler: function(evt) {
                buttonActive = !buttonActive;
                this.setSelected(buttonActive); //this refers to the Button
                openStreetAction.toolActive = buttonActive;
            }
        });

        streetViewerControls = [
            {
                control: openStreetButton,
                actions: [openStreetAction]
            },
            Mapspace.controldef.noAction(new Mapspace.control.StatusBar({
                controls: [Mapspace.street.controldef.ViewerInfo()]
            })),
            Mapspace.street.controldef.Zoom(undefined, {duration: 1000}),
            Mapspace.controldef.Attribution()
        ];
        
        streetViewer = new Mapspace.street.Viewer({
            center: [10.743704, 59.911299]
        });
        
        workspace = new Mapspace.Workspace({
            layout: {
                name: 'Map & Street layout',
                views: [
                    {
                        column: 0,
                        viewer: mapViewer,
                        controls: mapViewerControls
                    },
                    {
                        column: 1,
                        viewer: streetViewer,
                        controls: streetViewerControls,
                        syncOptions: [
                            {
                                syncedViewIndex: 0,
                                center: true,
                                FOV: true
                            }
                        ]
                    }
                ]
            },
            target: 'viewer'
        });
    });
    </script>
  </head>
  <body>
    <div id="viewer"></div>
  </body>
</html>

Some new elements we have added here are these:

  • A Mapspace.street.Viewer and an array of Mapspace.ControlDefinition objects for it.
  • A Mapspace.LayoutView object in the options of the workspace and we have set it to a new column in the layout.
  • A Mapspace.control.Button that is added to the Street viewer to open Street images near the point clicked in the Street viewer.
  • A Mapspace.SyncProperties object added to the Mapspace.LayoutView. This object has a syncedViewIndex to reference the viewer that will be synced (the one in the array of viewers with the index given), and several properties that modify the behaviour when a synchronization is executed. In this case, using center the 2D viewer will update its center each time the Street viewer changes (and not viceversa), and also using FOV each time the street viewer changes its FOV (field of View) the 2D will update an icon.

You can observe that Zoom buttons are automatically hidden or shown when the active viewer changes. To make a viewer the active one you must click inside it once. Then it is highlighted with a grey border.