0

I tried to redo this Azure Maps Animations sample with TypeScript: https://samples.azuremaps.com/animations/animate-marker-along-path

I have several issues and would need some help. I'll explain and provide my code below.

When running in Chrome, the console shows two errors:

Ucaught TypeError: Cannot read properties of undefined (reading 'EventEmitter')
    at azure-maps-animations.js:1101:23
    at azure-maps-animations.js:3424:2

Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'moveAlongRoute')
    at main.ts:96:41

I wanted to use VSCode and RequireJs, I used these options in tsconfig.json:

  "compilerOptions": {
    "module": "AMD",
    "target": "ES6",
    "moduleResolution": "node",
    "esModuleInterop": true,

    "strict": true,
    "jsx": "preserve",
    "sourceMap": true,
    "declaration": false,
    "lib": ["ES6", "DOM"],
    "resolveJsonModule": true,
    "downlevelIteration": true,

    "outDir": "./js",
    "rootDir": "./ts",
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "typeRoots": [
      "./node_modules/@types",
      "./types"
    ],
    "baseUrl": "./",
    "paths": {
      "azure-maps-control": ["node_modules/azure-maps-control/dist/atlas.min"]
    },
  }

I used this config.js file to setup RequireJS:

require.config({
  baseUrl: './js',
  paths: {
    'azure-maps-control': 'https://atlas.microsoft.com/sdk/javascript/mapcontrol/3/atlas'
    ,'azure-maps-animations': '../lib/azure-maps/azure-maps-animations'
  }
});

require(['main'], function(main) {
});

My html page only has:

<head>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js" defer></script>
    <script src="./node_modules/requirejs/require.js" defer></script>
    <script src="./config.js" defer></script>
    <link href="https://atlas.microsoft.com/sdk/javascript/mapcontrol/3/atlas.min.css" rel="stylesheet" />
</head>
<body>
    <div id="myMap"></div>
</body>

Here is the main.ts file:

import * as azmaps from 'azure-maps-control'
import * as atlas from 'azure-maps-animations'

var anim: atlas.RoutePathAnimation;
var map: azmaps.Map;

function main() {

    try {
        map = new azmaps.Map("myMap", {
            center: [-122.345, 47.615],
            zoom: 14,
            view: 'Auto',
            authOptions: {...}
        });

        map.events.add('click', function () {
            //anim.play();
        });

        map.events.add('ready', function () {

            map.imageSprite.createFromTemplate('arrow-icon', 'marker-arrow', 'teal', '#fff').then(function () {

                //Create data sources and add them to the map.
                var lineSource = new azmaps.source.DataSource();
                var pinSource = new azmaps.source.DataSource();
                map.sources.add([lineSource, pinSource]);

                //Create a layer to render the path.
                map.layers.add(new azmaps.layer.LineLayer(lineSource, undefined, {
                    strokeColor: 'DodgerBlue',
                    strokeWidth: 3
                }));

                //Extract the positions to highlight the full route on the map as a line.
                var path: azmaps.data.Position[] = [];

                var routePoints = [
                    new azmaps.data.Feature(new azmaps.data.Point([-122.34758, 47.62155]), { _timestamp: new Date('Tue, 18 Aug 2020 00:53:53 GMT').getTime() }),
                    new azmaps.data.Feature(new azmaps.data.Point([-122.34764, 47.61859]), { _timestamp: new Date('Tue, 18 Aug 2020 00:54:53 GMT').getTime() }),
                    new azmaps.data.Feature(new azmaps.data.Point([-122.33787, 47.61295]), { _timestamp: new Date('Tue, 18 Aug 2020 00:56:53 GMT').getTime() }),
                    new azmaps.data.Feature(new azmaps.data.Point([-122.34217, 47.60964]), { _timestamp: new Date('Tue, 18 Aug 2020 00:59:53 GMT').getTime() })
                ];

                routePoints.forEach(f => {
                    path.push(f.geometry.coordinates);
                });

                lineSource.add(new azmaps.data.LineString(path));

                //Create a layer to render a symbol which we will animate.
                map.layers.add(new azmaps.layer.SymbolLayer(pinSource, undefined, {
                    iconOptions: {
                        //Pass in the id of the custom icon that was loaded into the map resources.
                        image: 'arrow-icon',

                        //Anchor the icon to the center of the image.
                        anchor: 'center',

                        //Rotate the icon based on the rotation property on the point data.
                        //The arrow icon being used in this case points down, so we have to rotate it 180 degrees.
                        rotation: ['+', 180, ['get', 'heading']],

                        //Have the rotation align with the map.
                        rotationAlignment: 'map',

                        //For smoother animation, ignore the placement of the icon. This skips the label collision calculations and allows the icon to overlap map labels. 
                        ignorePlacement: true,

                        //For smoother animation, allow symbol to overlap all other symbols on the map.
                        allowOverlap: true
                    },
                    textOptions: {
                        //For smoother animation, ignore the placement of the text. This skips the label collision calculations and allows the text to overlap map labels.
                        ignorePlacement: true,

                        //For smoother animation, allow text to overlap all other symbols on the map.
                        allowOverlap: true
                    }
                }));

                //Create a pin and wrap with the shape class and add to data source.
                var pin = new azmaps.Shape(routePoints[0]);
                pinSource.add(pin);

                //Create the animation.
                anim = atlas.animations.moveAlongRoute(routePoints, pin, { 
                    //Specify the property that contains the timestamp.
                    //timestampProperty: 'timestamp',

                    captureMetadata: true,
                    loop: false,
                    reverse: false,
                    rotationOffset: 0,
                    
                    speedMultiplier: 60,
                    map: undefined,
                    zoom: 15,
                    pitch: 45,
                    rotate: true
                });
            });
        });
    } catch (error) {
        console.error('Error initializing game:', error);
    }
}

function ready(fn: () => void) {
    if (document.readyState !== 'loading') {
        fn();
    } else {
        document.addEventListener('DOMContentLoaded', fn);
    }
}

ready(() => {
    console.log("addEventListener");
    main();
});

If I uncomment //anim.play(); I get: Property 'play' does not exist on type 'RoutePathAnimation'.

If I uncomment //timestampProperty: 'timestamp', I get: 'timestampProperty' does not exist in type 'RoutePathAnimationOptions'

I noticed that the sample uses atlas namespace for both control and animations imports, I don't know how to do this, could it be the issue ?

The file ../lib/azure-maps/azure-maps-animations.js comes from https://github.com/Azure-Samples/azure-maps-animations/blob/main/dist/azure-maps-animations.js

The file /types/azure-maps-animations.d.ts comes from https://github.com/Azure-Samples/azure-maps-animations/blob/main/typings/index.d.ts

I really love the idea of "timestampProperty" and wish to use it, could you please help me understand the issues ?

Thanks.

1 Answer 1

0

The options for the moveAlongRoute don't have a timestampProperty option, so that is a bug and commenting that out (or deleting) is the right thing to do. This is a bug in the sample that doesn't cause any issues in JavaScript as it's simply ignored.

Note that moveAlongRoute function requires all your points to have a property called _timestamp. If you have timestamp information in another property, pass your points through the extractRoutePoints function first. The has a timestampProperty option.

This library does require access to the atlas namespace used by Azure Maps.

In your code you can provide this like follows:

import * as atlas from "azure-maps-control";
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks a lot !!!! I will try this tonight, it seems that both imports has to be under atlas namespace, I will try to merge them tonight with namespace atlas { export * from 'azure-maps-control'; export * from 'azure-maps-animations'; }, I never did that before, thanks again !
I merged the maps control and the maps animation with this code: namespace atlas { export const AuthenticationType = azmaps.AuthenticationType; export const Map = azmaps.Map; export const source = azmaps.source; export const layer = azmaps.layer; export const data = azmaps.data; export const Shape = azmaps.Shape; export const animations = azanimations.animations; } and I have now three errors at runtime: TypeError: Cannot read properties of undefined (reading 'EventEmitter') , (reading 'moveAlongRoute') and (reading 'play') is there a better way for merging ?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.