The content of this article applies to LuciadRIA 2019 and older versions only. LuciadRIA 2020.0 has been migrated to TypeScript and is released as a JavaScript library with TypeScript definition files generated from the source TypeScript files. The separate TypeScript declaration file discussed in this article is no longer required.

For more information about TypeScript, and how it is used as of LuciadRIA 2020, see:

You can integrate LuciadRIA modules in TypeScript projects. To make this as easy as possible, we developed the LuciadRIA TypeScript declaration file, which you can add to your application development project. As a result, the TypeScript compiler can verify that your application uses the LuciadRIA API correctly.

The TypeScript declaration is included in the LuciadRIA release as of version 2017.0. You can find it in the web/luciad/ folder.

Keep in mind that the declaration file in the release distribution is maintained with each version.

This article explains how to write LuciadRIA TypeScript code in LuciadRIA versions prior to 2020.0. It illustrates two project setup options that integrate the required support for the AMD module format into a TypeScript development project.

Developing LuciadRIA applications with TypeScript

What’s the purpose of the LuciadRIA TypeScript declaration file?

Starting from version 2017.0, LuciadRIA is released with a TypeScript declaration file. You can find the luciad.d.ts file in the web/luciad/ directory of a LuciadRIA release. With this declaration file, the TypeScript compiler can verify the correctness of any LuciadRIA API call you that you make in your application.

The LuciadRIA declaration file contains the complete API, including support for optional components such as Defense Symbology and Advanced GIS Engine. Because LuciadRIA is shipped as an AMD library, the declaration file also contains the mapping of TypeScript classes to AMD modules. This allows you to import only the required LuciadRIA modules in your TypeScript project, while the TypeScript compiler will pick up the types that are exported by that module.

Writing LuciadRIA TypeScript code

Importing modules

Once you have the LuciadRIA TypeScript declaration file, you can start writing TypeScript code that imports LuciadRIA AMD modules and uses the LuciadRIA API. Just like in any other LuciadRIA project, you must import the corresponding module before you can use a component.

TypeScript uses both the ES6 syntax and the CommonJS syntax to import modules, because the export semantics of ES6, CommonJS and AMD aren’t compatible. See the TypeScript module documentation for more details. Therefore, you must use the CommonJS syntax in your TypeScript code to import LuciadRIA AMD modules. For example, you import the WebGLMap LuciadRIA module as follows:

Importing LuciadRIA modules in TypeScript
import WebGLMap = require("luciad/view/WebGLMap");

The LuciadRIA declaration file declares the luciad/view/webGLMap module and associates it with the WebGLMap class. As a result, the compiler and your IDE can perform static analysis and make suggestions when you use the WebGLMap import. In addition, the import statement will be translated to the module standard that was configured in tsconfig.json. In the case of AMD, the earlier import statement is transpiled to the following:

TypeScript import statements after transpilation to AMD
define(["require", "exports", "luciad/view/WebGLMap"], function(require, exports, WebGLMap) {
});

Example code

This is an example of how to create a WebGL Map and add a WMS layer in TypeScript:

LuciadRIA example
import WebGLMap = require("luciad/view/WebGLMap");
import WMSTileSetModel = require("luciad/model/tileset/WMSTileSetModel");
import ReferenceProvider = require("luciad/reference/ReferenceProvider");
import ShapeFactory = require("luciad/shape/ShapeFactory");
import RasterTileSetLayer = require("luciad/view/tileset/RasterTileSetLayer");
import $ = require("jquery");

$("document").ready(() => {
  let map: WebGLMap = new WebGLMap("mapNode", {
    reference: ReferenceProvider.getReference("EPSG:4978")
  });

  let ref = ReferenceProvider.getReference("CRS:84");
  let wmsBounds = ShapeFactory.createBounds(ref, [-180, 360, -90, 180]);

  let model = new WMSTileSetModel({
    getMapRoot: "http://fusion.3d.luciad.com/wms",
    version: "1.3.0",
    bounds: wmsBounds,
    layers: ["4ceea49c-3e7c-4e2d-973d-c608fb2fb07e"],
    transparent: true
  });

  let layer = new RasterTileSetLayer(model);

  map.layerTree.addChild(layer);
});

After the code is transpiled to ES5 code with AMD, it looks as follows:

LuciadRIA example after transpilation
define([
  "require",
  "exports",
  "luciad/view/WebGLMap",
  "luciad/model/tileset/WMSTileSetModel",
  "luciad/reference/ReferenceProvider",
  "luciad/shape/ShapeFactory",
  "luciad/view/tileset/RasterTileSetLayer",
  "jquery"
], function(require, exports, WebGLMap, WMSTileSetModel, ReferenceProvider, ShapeFactory, RasterTileSetLayer, $) {
  "use strict";
  $("document").ready(function() {
    var map = new WebGLMap("mapNode", {
      reference: ReferenceProvider.getReference("EPSG:4978")
    });
    var ref = ReferenceProvider.getReference("CRS:84");
    var wmsBounds = ShapeFactory.createBounds(ref, [-180, 360, -90, 180]);
    var model = new WMSTileSetModel({
      getMapRoot: "http://fusion.3d.luciad.com/wms",
      version: "1.3.0",
      bounds: wmsBounds,
      layers: ["4ceea49c-3e7c-4e2d-973d-c608fb2fb07e"],
      transparent: true
    });
    var layer = new RasterTileSetLayer(model);
    map.layerTree.addChild(layer);
  });
});

Setting up a LuciadRIA project with TypeScript

LuciadRIA is shipped as a modular AMD library. Therefore, to embed LuciadRIA in your application, your TypeScript development tool chain must support the AMD module format. Possible options are:

  • Option A. Using AMD module loaders and optimizers, such as RequireJS and R.js or SystemJS and jspm.

  • Option B. Using a module bundler that collects multiple modules into a single bundle before the code is loaded to the browser, such as webpack, jspm or browserify.

Both options are described in detail below. For each approach, we provide a template project that you can download and run yourself.

These two options are provided as an illustration, to help you understand the basics. You have other options to perform the same task. For instance, your could use an IDE such as Visual Studio or WebStorm to create and compile your project. To keep this article concise, we won’t cover IDEs here.

Option A. Setting up a project with an AMD tool chain

If you use an AMD module loader, you can keep using your AMD tool chain by configuring the TypeScript compiler to compile TypeScript modules to AMD modules. Consider the following project structure:

AMDProjectStructure

The project is created in the web/samples directory of a LuciadRIA release. It consists of a ts directory, which contains the TypeScript source code for our web application, the AMD loader configuration in amdload.js, and the TypeScript compiler options in tsconfig.json. The TypeScript configuration file contains the following directives:

tsconfig.json
{
  "compilerOptions": {
    "module": "amd",
    "outDir": "../js",
    "allowJs": true,
    "noResolve": true,
    "sourceMap": true
  },
  "include": ["**/*", "../../../luciad/**/*.d.ts", "../typings/**/*"]
}

These settings give the following instructions to the TypeScript compiler:

module

Instructs the TypeScript compiler to output AMD modules. Those can then be loaded with an AMD module loader, or built into a deployment bundle using an AMD module optimizer.

outDir

Instructs the TypeScript compiler to put the compiled files in the js directory next to the ts directory.

noResolve

Tells the compiler not to copy module imports other than the application-specific code to the js directory. More specifically, this instructs the compiler not to copy LuciadRIA AMD modules. We will configure the AMD loader with the location of those modules instead.

allowJS

Allows you to mix JavaScript code with TypeScript code. This makes the TypeScript compiler pick up the amdconfig.js file.

sourceMap

Tells the compiler to generate source map files, which makes it easier to debug the compiled code in the web browser.

include

Tells the compiler to pick up all the files in the current directory, and the LuciadRIA TypeScript declaration file located in the <LUCIADRIA_INSTALLATION_ROOT>/web/luciad directory next to the samples. Other TypeScript declaration files can be placed in the typings directory.

When the TypeScript compiler has finished, you can load the application in the browser by loading RequireJS in the web page and instructing it to load amdconfig.js.

Loading RequireJS into your web page
<script type="text/javascript" data-main="js/amdconfig" src="node_modules/requirejs/require.js"></script>

The contents of amdconfig are:

amdconfig.js
require.config({
  paths:
  {
    "jquery": "../node_modules/jquery/dist/jquery"
  },
  packages:
  [
    {
      name: "luciad", location: "../../../luciad"
    }
  ]
});

require(['main']);

It configures the AMD loader with the location of jquery and LuciadRIA, and boots the application by loading the main module.

Try it out

You can download the the project template. You can try it out as follows:

  1. Unzip the file in the samples directory

  2. Run npm install to download all necessary dependencies

  3. Run npm run build to compile the TypeScript files to JavaScript

  4. Start the sample server and navigate your web browser to http://localhost:8072/web/samples/TypeScriptAMDTemplate/

Option B. Setting up a project with WebPack

Module bundlers allow you to mix and match different module standards. Typically they support ES6, AMD, CommonJS, and UMD. Aside from module bundling, they also allow for additional processing of the JavaScript code. For example, you can transpile ES6 to ES5 by integrating with Babel, or transpile TypeScript code to ES5 by invoking the TypeScript compiler. We’ll show you how you can set up a webpack project with LuciadRIA and TypeScript.

This image illustrates a possible webpack project setup:

WebpackProjectStructure

The project-specific HTML, CSS, and TypeScript code resides in the src directory. LuciadRIA, with the TypeScript declaration file, is located in the libs directory. The node_modules directory contains the necessary development dependencies such as webpack, webpack loaders and the TypeScript compiler.

The project structure is defined in webpack.config.js. The following file shows only the relevant snippets required by webpack to compile TypeScript code and package LuciadRIA code:

webpack.config.js
module.exports = {
  entry: './src/index.ts',

  output: {
    path: './dist',
    filename: '[name].js'
  },

  resolve: {
    modulesDirectories: ['node_modules', 'libs'],
    extensions: ['', '.ts', '.js', '.json']
  },

  module: {
    loaders: [
      {
        test: /\.ts?$/,
        loader: 'awesome-typescript-loader',
        exclude: /node_modules/
      },
        ...
    ]
  },

  //configure NodeJS's fs module to be absent, otherwise LuciadRIA WebGL will refuse to function
  node: {
    fs: "empty"
  }
};

The configuration file exports a configuration object in which the following keys are defined:

entry

Defines the application entry point. Starting from this point, webpack will calculate all module dependencies and collect them in a bundle.

output

Defines where to put the bundle and how to name it.

resolve

Defines the locations of the bundling resources. By default, webpack looks for resources in node_modules. However, we must instruct webpack to look in the libs directory as well, because LuciadRIA is located there. To accomplish this, we add libs to modulesDirectories. We also need to define .ts as an extension to prevent that webpack disregards TypeScript files as a bundling resource.

module

Defines how to treat particular modules before they are bundled. You do so by defining a loader for those module types. The preceding example shows a loader for TypeScript files only. Other loaders have been omitted from the example. The TypeScript loader is applied to files with the .ts extension only. The module loader to be applied to those files is called awesome-typescript-loader. This loader is added as a development dependency in the package.json file in the project. The loader is also instructed to disregard TypeScript modules in node_modules, so that only application code will be considered.

node

The WebGL rendering engine in LuciadRIA code checks if the NodeJS fs module is available. To be able to bundle LuciadRIA for a web application with webpack, you must configure the fs module to be empty.

With this configuration file, webpack picks up your TypeScript code, transpiles it to JavaScript, resolves the dependencies to the required LuciadRIA modules, and creates a bundle. tsconfig.json defines how webpack transpiles the TypeScript code:

tsconfig.json
{
  "compilerOptions": {
    "module": "amd",
    "target": "es5"
  },
  "exclude": [
    "node_modules",
    "dist"
  ]
}

This tells the TypeScript compiler to output AMD modules, and use ES5 as a compilation target. The exclude setting is there to speed up the TypeScript compiler. If you leave it out, webpack even suggests this setting to you. The TypeScript compiler output is picked up by webpack and bundled into a single JavaScript file called main.js in the dist directory.

Try it out

You can download this setup by downloading and unpacking this zip file. Then perform the following actions:

  1. Verify that you have included your LuciadRIA license file in your LuciadRIA installation.

  2. Copy the LuciadRIA javascript files from <LUCIADRIA_INSTALLATION_ROOT>/web/luciad/* to <WEBPACKSETUP>/libs/luciad>.

  3. Execute npm install in the webpack project root.

  4. Execute npm run dev:webpackserver in the webpack project.

  5. When the compilation and packaging has finished, navigate to http://localhost:8080/ in your web browser.