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.
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";