Creating Map Modules

Creating Map Modules

Creating a map source module allows you to setup custom data sources and layers that you can then add to your InteractiveMapApp and InteractiveMap instances. You can also share the modules you create by publicly releasing them as a pre-compiled/packaged Javascript file (opens in a new tab) or public NPM module (opens in a new tab) to allow other users to include your modules in their own applications.

Getting Started

We've setup a map module starter project (opens in a new tab) to help you get started with your custom modules quickly. Just follow the following steps:

  1. Download (opens in a new tab) and unzip the map module starter project source or clone the repo (opens in a new tab).

  2. Run the following commands to setup your project:

    cd aeris-js-module-starter; sh setup.sh

    This script will prompt you for information about your module project and setup the project's files with the necessary information. This will also run yarn install to install the required dependencies.

  3. Install any other dependencies your module may require using yarn add or npm install.

  4. If you didn't provide your Xweather account keys during setup, you will need to add your Xweather account access keys to the project environment file at /.env to use while developing and testing locally:

    # Account ID and secret for interacting with the Xweather Weather API
    AERIS_CLIENT_ID=
    AERIS_CLIENT_SECRET=

    Note that this environment file containing your Xweather access keys will not be included with your package or Git repository if you choose to publish an NPM module.

  5. Start up the local development server to start building your module:

    yarn dev-server

Setting up a MapSourceModule

Custom map modules should be subclasses of the MapSourceModule class that's included in the SDK and override the required configuration methods. This class is already setup for you when using the starter project above:

import ModuleGroup from '@aerisweather/javascript-sdk/dist/modules/MapSourceModule';
 
class MyModule extends MapSourceModule {
 
    get id() {
        return 'MODULE_ID';
    }
 
    constructor(opts = null) {
        super(opts);
    }
 
    source() {
 
    }
 
    controls() {
 
    }
 
    legend() {
 
    }
 
    infopanel() {
 
    }
}

The following sections will go into more detail regarding configuration and setup of the various components of a map module.

Creating a Module Using the Precompiled SDK

If you want to quickly create a custom map source module in your map applications but don't want to setup a separate Javascript project or external dependencies, you can instead create a module directly using the public interface provided by the modules library of the SDK.

You have access to both MapSourceModule and ModuleGroup classes from this interface. Using this method, you also don't have to worry about creating a subclass for your module if you're adding it directly into your map application. You can provide the necessary module configuration in the constructor when creating an instance.

The following would create a new custom module and add it to the map application:

aeris.apps().then((apps) => {
 
    // create a map app instance
    const app = new apps.InteractiveMapApp('#app');
 
    // load the Modules library from the SDK
    aeris.modules().then((modules) => {
 
        // create and configure a custom module
        const customModule = new modules.MapSourceModule({
            id: 'MODULE_ID',
            source: {
 
            },
            controls: {
 
            },
            legend: {
 
            },
            infopanel: {
 
            }
        });
 
        // add the module to the map app
        app.modules.add(customModule);
    });
 
});

The configurations for each component of your module are the same as if you were creating your module using the starter project and are outlined below.

Setting Up a Map Data Source

Every map module must provide a valid map data source, which is used to configure any data requests and/or styling options for the module's data when rendered on an interactive map.

The map data source can be one of the following types supported by the SDK:

TypeCodeDescription
TileSourcetileUsed to display raster map tiles, such as Xweather Raster Maps imagery. Read more about setting up a tile source.
VectorSourcevectorUsed to display vector data on a map, such as markers, polygons, and polylines. Data can be provided in a variety of formats. Read more about setting up a vector source.
GeoJsonSourcegeojsonSimilar to VectorSource except that the data must be provided in a valid GeoJSON format. Read more about setting up a GeoJSON source.
TextSourcetextA subclass of VectorSource that renders text markers on the map based on the source's configuration. Text values can also be animated across time. Read more about setting up a text source.

Setting Up Layer Controls

If you want your users to be able to toggle your map source on and off on their maps, you'll need to provide a button configuration for the layers panel that pertains to your module. Refer to the Button Configuration section of the layers panel documentation for additional information on how to configure your module's layer controls.

In most cases, you'll just need to return an object that contains a value for both value and title for your control, where this.id refers to the unique identifier you provide in your module's class:

controls() {
    return {
        value: this.id,
        title: 'My Module'
    }
}

The above example would include a button in the map application's layers panel with the label of “My Module”.

If your module is a vector source type, you may also need to include options for segments, filter, and multiselect to control any remote data requests for data depending on the functional requirements of your module.

Setting Up Legends

Each map data source can display its own legend within a map application's legend panel if desired. This functionality is built into the SDK for the standard Xweather weather layers. However, you may want to override the default legends for Xweather layers if you're using custom styling, especially for vector sources, or if your dataset requires a legend.

Configuring your custom legend is simple. You just need to provide a URL to the legend image to display and an optional title:

legend() {
    return {
        title: 'Flight Status',
        url: 'https://www.mydomain.com/assets/flightstatus-legend.png'
    }
}

Your legend will appear in the map application's legend panel when the map source associated with your module is added to the map.

Setting Up Info Panel Views

Your module can also configure the views that are displayed within a map application's info panel, which is used to display detailed information associated with a point on the map or a marker, polyline or polygon when clicked. This configuration is optional and should only be provided based on your module's functional requirements.

The following options are supported when configuring the info panel content view for your module:

OptionTypeDescription
viewsany[]An array of view configurations or section view keys to render as part of this content view. The order in which they appear in the array is the order in which they will be rendered in the info panel.
requestApiRequest or FunctionRequest to use when loading data for the content view. This request should load all data that is required by each section view. For API requests, this will often be a batch request. This value can either be a request instance or a function that returns a request instance.

At a minimum, you must provide a valid array of view configurations for the views property. This should be an array of section view configurations in the order in which you want the views to be rendered.

Each view within an info panel's content view is considered a section view and should be configured using the following options:

OptionTypeDescription
titlestringView title. If provided, the title will be rendered at the top of the section view's container as a header DOM element.
dataobject or FunctionThe data to use when rendering the section view. If a function is provided, the full data set from the parent content view will be passed as an argument and the function must return the specific data required for rendering this section view.
rendererstring or FunctionThe section renderer, which can either be an HTML string or a function that receives the view's data as an argument and returns the final HTML for the view.

The following example will render two static views for the module's info panel content view:

infopanel() {
    return {
        views: [{
            renderer: (data) => {
                return '<div>This is the first view</div>';
            }
        },{
            renderer: (data) => {
                return '<div>This is the second view</div>';
            }
        }]
    }
}

Usually your info panel content view will need access to data or request additional data from a remote source. For this you can provide the ApiRequest request to use. Each section view can access the data returned by the request using the data parameter passed to each view's renderer function:

infopanel() {
    return {
        request: () => {
            const request = this.account.api();
            request.addRequest(this.account.api().endpoint('forecasts').filter('3hr').limit(7));
            request.addRequest(this.account.api().endpoint('lightning').action(ApiAction.CLOSEST).radius('60mi').limit(100));
 
            return request;
        },
        views: [{
            renderer: (data) => {
                if (!data) return;
                const forecast = data.forecasts;   // access the forecast data returned by the result
                return '<div>This is the first view. Total forecast periods: ' + forecast.periods.length + '</div>';
            }
        },{
            renderer: (data) => {
                if (!data) return;
                const lightning = data.lightning;   // access the lightning data returned by the request
                return '<div>This is the second view. Total strikes: ' + lightning.length + '</div>';
            }
        }]
    }
}

Refer to the View Section Configuration documentation for additional information on configuring section views for an info panel view.

Showing the Info Panel

The base MapSourceModule class that your custom module subclasses provides a convenient method for showing your module's info panel view. Use the showInfoPanel(:title, :data) method from within your module's class to present the info panel, such as on a marker or polygon click.

This method is a convenience method that calls showInfo(:view, :title, :data) on the map application and passes in the info panel content view to display that's configured by your module.

Additional Configuration

Your module can perform additional configuration and setup using one or more event hooks that are registered with a module when it's added to a map application. These hooks are already declared in the base MapSourceModule group, so you just need to override them in your own subclass to perform any additional setup.

The following hooks are supported and triggered at the appropriate times:

onInit() {
    // Called when the module has been initialized with an application.
}
 
onAdd() {
    // Called when the module's map data source has been added to the map.
}
 
onRemove() {
    // Called when the module's map data source is removed from the map.
}
 
onMarkerClick(marker, data) {
    // Called when a marker associated with the module's map data source
    // is clicked on the map.
}
 
onShapeClick(shape, data) {
    // Called when a polygon or polyline associated with the module's map
    // data source is clicked on the map.
}

Additionally, you have access to the interactive map app, interactive map, and account instances from within the context of your module's class that the module was registered with when added to the map. Use the app, map and account properties on your MapSourceModule class respectively.