Starting from the LuciadRIA V2020.0 release, the LuciadRIA API is provided as ES6 modules. To remain backward compatible, the API is still available as AMD modules as well. We recommend switching to using ES6 modules. Switching from AMD to ES6 modules is explained in Migrating from AMD to ES6 modules.

The LuciadRIA V2020.0 release includes some incompatible changes, which may require you to update some of your code. Those changes are described in Incompatible changes

Migrating from AMD to ES6 modules

Change import statements

Previously, you had to import LuciadRIA modules using the AMD syntax shown in this code block.

define(["luciad/view/Map"], function(Map) {
    //your code
}

The LuciadRIA ES6 API uses named ES6 exports to export classes and static functions. To import those from the LuciadRIA ES6 API, you must use the following syntax.

import {Map} from "@luciad/ria/view/Map";
//your code

AMD module loading does not force you to use a specific name for an imported module. ES6 named imports, however, require you to import modules with the name that they are exported with. Note that you can change this by importing a module under an alias, for example import {Map as LuciadMap} from "@luciad/ria/view/Map".

Change imports of static functions

Before V2020.0, each file could export only one variable. Now that the LuciadRIA API is provided as ES6 modules, you can export and import static functions separately. This implies that you must import some static functions separately from the main class of that module.

For example:

define(["luciad/shape/ShapeFactory"], function(ShapeFactory) {
    var point = ShapeFactory.createPoint(reference, [x,y]);
}

or, if you were using CommonJS imports:

var ShapeFactory = require("luciad/shape/ShapeFactory");
var point = ShapeFactory.createPoint(reference, [x,y]);

now becomes:

import {createPoint} from "@luciad/shape/ShapeFactory";

var point = createPoint(reference, [x,y]);

You can also choose to import all named exports from ShapeFactory with import * as ShapeFactory from "@luciad/shape/ShapeFactory". Note that this will work only for files that exclusively export static functions.

These files have multiple module exports

  • ShapeFactory

  • FilterFactory

  • ReferenceProvider

  • SymbologyProvider

  • TransformationFactory

  • QuantityKindRegistry

  • UnitOfMeasureRegistry

  • ColorMap

  • License

  • LightEffect

  • GeodesyFactory

  • TopologyFactory

  • MeshFactory

  • SEPainterFactory

  • FeaturePainterUtil

  • TileSetScaleUtil

  • ExpressionFactory

  • HandleEventResult

  • PatternFactory

Upgrading an existing TypeScript project

The LuciadRIA 2020.0 release now has improved support for integrating it in a TypeScript project. This improved support does however require you to make some small changes for existing TypeScript projects using LuciadRIA.

Previously the LuciadRIA release contained a single TypeScript definition file (luciad.d.ts). Starting from the LuciadRIA 2020.0 release, each module has its own definition file. The TypeScript Hello World tutorial demonstrates how you can set up a TypeScript project with LuciadRIA.

Before version 2020.0, the LuciadRIA typescript definition file was maintained manually. Now the definition files are generated automatically. As a consequence, a lot of mistakes in the definition files have been corrected. The new definition files may hence contain some incompatible changes. The following incompatibilities might affect your existing TypeScript project:

  • Namespaces are no longer used to differentiate our modules. To handle this change you will need to update your type imports.

  • Names of several interfaces have changed to have a more consistent naming across the LuciadRIA API. Interfaces for option objects used in constructors have the following naming scheme: {ClassName}ConstructorOptions. For example the object literal that you can pass to a FeatureModel constructor is of type FeatureModelConstructorOptions. For other option objects, the interface name will always end with Options.

  • Some class and interface properties are now optional. This implies that you might need to add an undefined check before you can use these properties.

  • Our definition files are generated with non-nullable types, as a result of this our typing now explicitly contains null and undefined.

Upgrading to LuciadRIA 2020.0 AMD modules

Although we do recommend updating your project to use the ES6 modules, it is still possible to update an existing project to use LuciadRIA 2020.0 while still using AMD module loading. The AMD modules can be found in the LuciadRIA distribution in the packages/amd directory.

When your existing project does not use TypeScript, you will only need to take the incompatible changes documented in the release notes into account when updating to LuciadRIA 2020.0. Otherwise you must take the changes described in Upgrading an existing TypeScript project into account as well, so that your project correctly picks up the new TypeScript definition files.

Incompatible changes

Polyfills for IE11

Starting with the LuciadRIA V2020.0 release, polyfills for Promise, Map, Set, Object and performance are no longer provided in the API. All recent browsers have native support for these constructs.

If you want to keep using LuciadRIA with IE11, however, you need to provide polyfills for those constructs. One way to do this, is by importing core-js. The webpack dev-server configuration included in the LuciadRIA distribution polyfills these constructs by defining core-js as an additional entry point. See samples/common/webpack.config.js for more information.

LuciadRIA Evented API

The Evented API allows you to emit and listen to specific events in LuciadRIA. By defining listeners for specific events, you can define what your application needs to do when events are emitted.

Evented is an interface. It includes an on method for defining what to do in case of a specific event. Using the on method, you can define the callback function that must be triggered if an event is emitted. Program: Adding a listener shows how you can use the ModelChanged event to fit the map to an object added to the FeatureModel.

Program: Adding a listener
featureModel.on("ModelChanged", (eventType, feature, id) => {
  this.map.mapNavigator.fit({
    bounds: feature.shape.bounds
  });
});

Before the LuciadRIA V2020.0 release, Evented could be be used in a prototype chain of a class to wire in the event notification system. Starting with the LuciadRIA V2020.0 release, this is no longer possible because Evented is now an interface. If you are using Evented in the prototype chain in one of your classes, you will need to change your code to use a delegate pattern instead. LuciadRIA 2020.0 provides EventedSupport as a default implementation for the Evented interface, which can be used as a delegate.

The EventedSupport class also provides an emit function for emitting an event in addition to the on method of the Evented interface. Most classes in the LuciadRIA API do not have an emit function. You should not emit any event in those classes. LuciadRIA will emit the corresponding event when needed. For example, you cannot emit a ModelChanged event in the FeatureModel. It is automatically emitted by LuciadRIA when an object is added to the model.

Using the Evented API with TypeScript

You can write a custom class that uses the Evented API in TypeScript. This class must implement the Evented class.

When implementing the Evented interface, you can delegate the on method to EventedSupport. Program: Creating a custom class that implements Evented in TypeScript shows how you can implement the Evented class.

Program: Creating a custom class that implements Evented in TypeScript
import {Evented, Handle} from "@luciad/ria/util/Evented";
import {EventedSupport} from "@luciad/ria/util/EventedSupport";

class CustomClass implements Evented {
    private _eventedSupport: EventedSupport;

    constructor() {
        this._eventedSupport = new EventedSupport();
    }

    on(event: string, callback: (...args: any[]) => void, context?: any, options?: any): Handle {
        return this._eventedSupport.on(event, callback, context, options);
    }

    foo(): void{
      let value = 5;
      this._eventedSupport.emit("EventType", value);
    }
}

Using the Evented API with ES6

Program: Creating a custom store that delegates to EventedSupport in ES6 shows how to write a class using the Evented API in the LuciadRIA ES6 API.

Program: Creating a custom store that extends EventedSupport in ES6
class CustomStore {

  constructor(options) {
    this._eventedSupport = new EventedSupport();
  }

  add(feature, options) {
    this._eventedSupport.emit("StoreChanged", "add", feature, feature.id);
    return feature.id;
  }

  put(feature, options) {
    this._eventedSupport.emit("StoreChanged", "put", feature, feature.id);
    return feature.id;
  }

  remove(id) {
    this._eventedSupport.emit("StoreChanged", "remove", id);
    return true;
  }

  on(event, callback, context, options) {
    return this._eventedSupport.on(event, callback, context, options);
  }
}

Using the Evented API with AMD

Program: Creating a custom store that delegates to EventedSupport in AMD shows how to write a custom class using the Evented API in LuciadRIA AMD API.

Program: Creating a custom store that delegates to EventedSupport in AMD
function CustomStore() {
  this._eventedSupport = new EventedSupport();
}

CustomStore.prototype.add =  function(feature, options){
  this._eventedSupport.emit("StoreChanged", "add", feature, feature.id);
    return feature.id;
}

CustomStore.prototype.put =  function(feature, options){
  this._eventedSupport.emit("StoreChanged", "put", feature, feature.id);
    return feature.id;
}

CustomStore.prototype.remove =  function(id){
  this._eventedSupport.emit("StoreChanged", "remove", feature, feature.id);
  return true;
}

CustomStore.prototype.on = function(event, callback, context, options) {
  return this._eventedSupport.on(event, callback, context, options);
}

Extending from EventedSupport

As an alternative to implementing the Evented interface, you can still extend the EventedSupport class, as demonstrated by Program: Creating a custom store that extends EventedSupport in TypeScript. It is however recommended to use the delegate pattern.

Program: Creating a custom store that extends EventedSupport in TypeScript
import {EventedSupport} from "@luciad/ria/util/EventedSupport";
import {Store} from "@luciad/ria/model/store/Store";
import {Feature} from "@luciad/ria/model/feature/Feature";
export class CustomStore extends EventedSupport implements Store {
  constructor() {
    super();
  }

  add(feature: Feature, options?: any): number | string | Promise<number> | Promise<string> {
    this.emit("StoreChanged", "add", feature, feature.id);
    return feature.id;
  }

  put(feature: Feature, options?: any): number | string | Promise<number> | Promise<string> {
    this.emit("StoreChanged", "put", feature, feature.id);
    return feature.id;
  }

  remove(id: number | string): boolean | Promise<boolean> {
    this.emit("StoreChanged", "remove", id);
    return true;
  }
}