Starting from the LuciadRIA 2020.0 release, the LuciadRIA API comes as ES6 modules. In versions 2020.0 and 2020.1, the API is still available as Asynchronous Module Definition (AMD) modules as well. As of LuciadRIA 2021.0, AMD modules are no longer included, so you must switch to ES6 modules. Migrating from AMD to ES6 modules explains how to refactor your code.

The LuciadRIA 2020.0 release includes some incompatible changes, which may require you to update some of your code. See Incompatible changes for an overview of those changes.

Migrating from AMD to ES6 modules

Change import statements

Before 2020.0, 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.js";
//your code

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

Change imports of static functions

Before 2020.0, each file could export only one variable. Now that the LuciadRIA API comes 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.js";

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 only works for files that only export static functions.

These files have many module exports

  • ShapeFactory

  • FilterFactory

  • ReferenceProvider

  • SymbologyProvider

  • TransformationFactory

  • QuantityKindRegistry

  • UnitOfMeasureRegistry

  • ColorMap

  • License

  • LightEffect

  • GeodesyFactory

  • TopologyFactory

  • MeshFactory

  • SEPainterFactory

  • FeaturePainterUtil

  • TileSetScaleUtil

  • ExpressionFactory

  • HandleEventResult

  • PatternFactory

Use a bundler

Not all modern browsers support our LuciadRIA ES6 modules natively because of the following reasons:

  1. LuciadRIA imports do not contain file extensions

  2. Optional modules reference LuciadRIA as @luciad/ria, which is not a file path

  3. Not all browsers support import maps, which could fix the previous reasons

This means that if you didn’t use a bundler before, like webpack, you will now need to add this to your build process. How to do this can be seen in our samples setup or the Hello World tutorial.

Upgrading an existing TypeScript project

The LuciadRIA 2020.0 release has improved support for integrating LuciadRIA in a TypeScript project. To make use of that support, you must make small changes to your existing TypeScript projects that use LuciadRIA.

Before 2020.0, 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 2020.0, we maintained the LuciadRIA TypeScript definition file manually. Now, the definition files are generated automatically. As a consequence, many mistakes in the definition files are now gone. The new definition files may hence contain incompatible changes. These incompatibilities might affect your existing TypeScript project:

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

  • The names of several interfaces have changed to have 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 always ends with Options.

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

  • The definition files are generated with non-nullable types. As a result, the typing now explicitly has null and undefined.

Upgrading to LuciadRIA 2020.0 AMD modules

As of v2021.0, AMD modules are no longer included in LuciadRIA. You must switch to ES Modules.

Although we recommend updating your project to use the ES6 modules, it’s possible to update an existing project to use LuciadRIA 2020.0 and still use AMD module loading. You can find the AMD modules in the packages/amd directory of the LuciadRIA distribution.

When your existing project doesn’t use TypeScript, you 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 2020.0 release, the API no longer offers polyfills for Promise, Map, Set, Object, and performance. All recent browsers have native support for these constructs.

If you want to keep using LuciadRIA with Internet Explorer 11 , 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.

As of LuciadRIA 2021.0, Internet Explorer is no longer supported.

LuciadRIA Evented API

You can use the Evented API 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 2020.0 release, you could use Evented in a prototype chain of a class to wire in the event notification system. Starting with the LuciadRIA 2020.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 must change your code to use a delegate pattern instead. LuciadRIA 2020.0 provides EventedSupport as a default implementation for the Evented interface, which you can use as a delegate.

The EventedSupport class also provides an emit function for emitting an event aside from the on method of the Evented interface. Most classes in the LuciadRIA API don’t have an emit function. You shouldn’t emit any event in those classes. LuciadRIA emits the corresponding event when needed. For example, you can’t emit a ModelChanged event in the FeatureModel. LuciadRIA automatically emits it 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.js";
import {EventedSupport} from "@luciad/ria/util/EventedSupport.js";

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’s recommended to use the delegate pattern, though.

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

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

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

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