@maptrip/map-tiles 1.1.1 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +2 -0
  2. package/dist/api-extensions/google/MapTripGoogleMapType.d.ts +28 -0
  3. package/dist/api-extensions/leaflet/MapTripLeafletGridLayer.d.ts +25 -0
  4. package/dist/api-extensions/openlayers/MapTripOpenLayersSource.d.ts +19 -0
  5. package/dist/core/CollisionDetector.d.ts +14 -0
  6. package/dist/core/VectorTileFactory.d.ts +64 -0
  7. package/dist/core/VectorTileLoader.d.ts +40 -0
  8. package/dist/core/VectorTileRenderer.d.ts +123 -0
  9. package/dist/core/constants.d.ts +10 -0
  10. package/dist/core/rendering_config_default.d.ts +658 -0
  11. package/dist/core/rendering_config_grayscale.d.ts +672 -0
  12. package/dist/core/rendering_config_traffic.d.ts +39 -0
  13. package/dist/map-tiles.d.ts +9 -0
  14. package/dist/map-tiles.js +22856 -9398
  15. package/dist/map-tiles.js.map +1 -0
  16. package/dist/types/interfaces.d.ts +134 -0
  17. package/lib/api-extensions/google/MapTripGoogleMapType.ts +43 -0
  18. package/lib/api-extensions/leaflet/MapTripLeafletGridLayer.ts +48 -0
  19. package/lib/api-extensions/openlayers/MapTripOpenLayersSource.ts +62 -0
  20. package/lib/core/CollisionDetector.ts +95 -0
  21. package/lib/core/VectorTileFactory.ts +331 -0
  22. package/lib/core/VectorTileLoader.ts +165 -0
  23. package/lib/core/VectorTileRenderer.ts +1220 -0
  24. package/lib/core/constants.ts +21 -0
  25. package/lib/core/rendering_config_grayscale.ts +1129 -0
  26. package/lib/types/interfaces.ts +147 -0
  27. package/package.json +22 -17
  28. package/lib/api-extensions/google/MapTripGoogleMapType.js +0 -25
  29. package/lib/api-extensions/leaflet/MapTripLeafletGridLayer.js +0 -24
  30. package/lib/api-extensions/openlayers/MapTripOpenLayersSource.js +0 -43
  31. package/lib/core/CollisionDetector.js +0 -65
  32. package/lib/core/VectorTileFactory.js +0 -245
  33. package/lib/core/VectorTileLoader.js +0 -132
  34. package/lib/core/VectorTileRenderer.js +0 -826
  35. package/lib/core/constants.js +0 -18
  36. package/lib/core/rendering_config_grayscale.js +0 -1107
  37. /package/lib/core/{rendering_config_default.js → rendering_config_default.ts} +0 -0
  38. /package/lib/core/{rendering_config_traffic.js → rendering_config_traffic.ts} +0 -0
  39. /package/lib/{main.js → main.ts} +0 -0
@@ -0,0 +1,134 @@
1
+ export interface MapTilesProperties {
2
+ provider?: string | "OpenStreetMap";
3
+ baseMap?: boolean;
4
+ traffic?: boolean;
5
+ timeout?: number;
6
+ parallelDownloads?: number;
7
+ detourProfile?: string;
8
+ renderingConfig?: RENDERING_CONFIG;
9
+ token?: string;
10
+ attribution?: string;
11
+ minZoom?: number;
12
+ maxZoom?: number;
13
+ name?: string;
14
+ NAME?: string;
15
+ }
16
+ export interface Renderer {
17
+ from: number;
18
+ to: number;
19
+ text?: {
20
+ size: number;
21
+ color: string;
22
+ font: string;
23
+ fontWeight?: string;
24
+ outlineColor?: string;
25
+ outlineWidth?: number;
26
+ fontStyle?: string;
27
+ };
28
+ polygon?: PolygonStyle;
29
+ line?: PolylineStyle;
30
+ image?: {
31
+ url: string;
32
+ width: number;
33
+ height: number;
34
+ dx: number;
35
+ dy: number;
36
+ };
37
+ filters?: Filter[];
38
+ }
39
+ export interface RENDERING_CONFIG {
40
+ background: {
41
+ from: number;
42
+ to: number;
43
+ color: string;
44
+ }[];
45
+ layers: {
46
+ [key: string]: string;
47
+ };
48
+ renderers: {
49
+ [key: string]: Renderer[];
50
+ };
51
+ }
52
+ export interface Filter {
53
+ interface: string;
54
+ key: string;
55
+ value?: any;
56
+ type: string;
57
+ }
58
+ export interface PolylineTextStyle {
59
+ size: number;
60
+ color: string;
61
+ font?: string | undefined;
62
+ fontWeight?: string | undefined;
63
+ outlineColor?: string | undefined;
64
+ outlineWidth?: number | undefined;
65
+ fontStyle?: string | undefined;
66
+ }
67
+ export interface PolylineStyle {
68
+ color?: string | undefined;
69
+ width?: number | undefined;
70
+ url?: string | undefined;
71
+ height?: number | undefined;
72
+ dx?: number | undefined;
73
+ dy?: number | undefined;
74
+ direction?: string | undefined;
75
+ }
76
+ export interface PolygonStyle {
77
+ color: string;
78
+ opacity?: number | undefined;
79
+ outlineColor?: string | undefined;
80
+ outlineWidth?: number | undefined;
81
+ url?: string | undefined;
82
+ font?: string | undefined;
83
+ fontStyle?: string | undefined;
84
+ fontWeight?: string | undefined;
85
+ size?: number | undefined;
86
+ }
87
+ export interface ImageStyle {
88
+ url: string;
89
+ width: number;
90
+ height: number;
91
+ dx: number;
92
+ dy: number;
93
+ }
94
+ export interface Tile {
95
+ x: number;
96
+ y: number;
97
+ z: number;
98
+ urls: string[];
99
+ token: string;
100
+ json?: JSON;
101
+ }
102
+ export interface TileQueueItem {
103
+ tile: Tile;
104
+ successCallback: SuccessCallback;
105
+ errorCallback: ErrorCallback;
106
+ }
107
+ export interface PointXY {
108
+ x: number;
109
+ y: number;
110
+ z?: number;
111
+ }
112
+ export interface Vertex {
113
+ x: number;
114
+ y: number;
115
+ }
116
+ export interface PositionXY {
117
+ x: number;
118
+ y: number;
119
+ angle: number;
120
+ }
121
+ export interface Coordinates {
122
+ lon: number;
123
+ lat: number;
124
+ }
125
+ export interface Boundaries {
126
+ min: Coordinates;
127
+ max: Coordinates;
128
+ }
129
+ export interface SuccessCallback {
130
+ (json: any): void;
131
+ }
132
+ export interface ErrorCallback {
133
+ (error: any): void;
134
+ }
@@ -0,0 +1,43 @@
1
+ import { VectorTileFactory } from "../../core/VectorTileFactory.js";
2
+ import { MIN_ZOOM, MAX_ZOOM } from "../../core/constants.js";
3
+ import {
4
+ RENDERING_CONFIG
5
+ } from "../../types/interfaces.js";
6
+ import { PointXY } from "../../types/interfaces.js";
7
+
8
+ class MapTripGoogleMapType {
9
+ tileSize = new google.maps.Size(256, 256);
10
+ alt = null;
11
+ maxZoom = MAX_ZOOM;
12
+ minZoom = MIN_ZOOM;
13
+ projection = null;
14
+ radius = 6378137;
15
+
16
+ name: string;
17
+ token: string;
18
+ factory: VectorTileFactory;
19
+
20
+ constructor(properties: {
21
+ provider?: string;
22
+ baseMap?: boolean;
23
+ traffic?: boolean;
24
+ timeout?: number;
25
+ parallelDownloads?: number;
26
+ detourProfile?: string;
27
+ renderingConfig?: RENDERING_CONFIG;
28
+ token?: string;
29
+ name?: string;
30
+ }) {
31
+ this.name = properties!.name ? properties!.name : "infoware";
32
+ this.token = properties!.token!;
33
+ this.factory = VectorTileFactory.createFactory(properties)!;
34
+ }
35
+
36
+ getTile(coord: PointXY, zoom: number) {
37
+ return this.factory.getJsonTile(zoom, coord.x, coord.y, this.token);
38
+ }
39
+
40
+ releaseTile() {}
41
+ }
42
+
43
+ export { MapTripGoogleMapType };
@@ -0,0 +1,48 @@
1
+ import L from "leaflet";
2
+ import { VectorTileFactory } from "../../core/VectorTileFactory.js";
3
+ import { MIN_ZOOM, MAX_ZOOM, ATTRIBUTION } from "../../core/constants.js";
4
+ import type { PointXY } from "../../types/interfaces.js";
5
+ import {
6
+ RENDERING_CONFIG
7
+ } from "../../types/interfaces.js";
8
+
9
+ class MapTripLeafletGridLayer extends L.GridLayer {
10
+ MIN_ZOOM = MIN_ZOOM;
11
+ MAX_ZOOM = MAX_ZOOM;
12
+ token: string;
13
+ factory: VectorTileFactory;
14
+ constructor(options: {
15
+ provider?: string;
16
+ baseMap?: boolean;
17
+ traffic?: boolean;
18
+ timeout?: number;
19
+ parallelDownloads?: number;
20
+ detourProfile?: string;
21
+ renderingConfig?: RENDERING_CONFIG;
22
+ token?: string;
23
+ attribution?: string;
24
+ minZoom?: number;
25
+ maxZoom?: number;
26
+ }) {
27
+ super(options as L.GridLayerOptions);
28
+ this.token = options.token!;
29
+ this.options.attribution = options.attribution
30
+ ? options.attribution
31
+ : ATTRIBUTION;
32
+ //@ts-expect-error picking up LayerOptions rather than GridLayerOptions
33
+ this.options.minZoom = options.minZoom
34
+ ? Math.max(this.MIN_ZOOM, options.minZoom)
35
+ : this.MIN_ZOOM;
36
+ //@ts-expect-error
37
+ this.options.maxZoom = options.maxZoom
38
+ ? Math.min(this.MAX_ZOOM, options.maxZoom)
39
+ : this.MAX_ZOOM;
40
+ this.factory = VectorTileFactory.createFactory(options);
41
+ }
42
+
43
+ createTile(coords: PointXY) {
44
+ return this.factory.getJsonTile(coords.z!, coords.x, coords.y, this.token);
45
+ }
46
+ }
47
+
48
+ export { MapTripLeafletGridLayer };
@@ -0,0 +1,62 @@
1
+ import XYZ from "ol/source/XYZ.js";
2
+ import { XYZOptions, createXYZ, extentFromProjection } from "ol/tilegrid.js";
3
+
4
+ import { VectorTileFactory } from "../../core/VectorTileFactory.js";
5
+ import { MIN_ZOOM, MAX_ZOOM, ATTRIBUTION } from "../../core/constants.js";
6
+ import { RENDERING_CONFIG } from "../../types/interfaces.js";
7
+
8
+ class MapTripOpenLayersSource extends XYZ {
9
+ token: string;
10
+ factory: VectorTileFactory;
11
+ constructor(properties: {
12
+ provider?: string;
13
+ baseMap?: boolean;
14
+ traffic?: boolean;
15
+ timeout?: number;
16
+ parallelDownloads?: number;
17
+ detourProfile?: string;
18
+ renderingConfig?: RENDERING_CONFIG;
19
+ token?: string;
20
+ }) {
21
+ super();
22
+ const options: XYZOptions = {};
23
+ const projection = "EPSG:3857";
24
+
25
+ const tileGrid = createXYZ({
26
+ extent: extentFromProjection(projection),
27
+ maxResolution: options.maxResolution,
28
+ minZoom: MIN_ZOOM,
29
+ maxZoom: MAX_ZOOM,
30
+ tileSize: [256, 256],
31
+ });
32
+
33
+ super({
34
+ opaque: true,
35
+ minZoom: MIN_ZOOM,
36
+ maxZoom: MAX_ZOOM,
37
+ projection: projection,
38
+ tileGrid: tileGrid,
39
+ wrapX: true,
40
+ url: "z:{z} x:{x} y:{y}",
41
+ tileLoadFunction: (tile) => {
42
+ let coord = tile.getTileCoord();
43
+ let canvas = this.factory.getJsonTile(
44
+ coord[0],
45
+ coord[1],
46
+ coord[2],
47
+ this.token!,
48
+ () => {
49
+ //@ts-expect-error: 'tile' is an OL ImageTile & .setImage() is available but not exported from types
50
+ tile.setImage(canvas);
51
+ }
52
+ );
53
+ },
54
+ attributions: ATTRIBUTION,
55
+ });
56
+
57
+ this.token = properties.token!;
58
+ this.factory = VectorTileFactory.createFactory(properties)!;
59
+ }
60
+ }
61
+
62
+ export { MapTripOpenLayersSource };
@@ -0,0 +1,95 @@
1
+ import RTree from "rtree";
2
+ import { PositionXY } from "../types/interfaces.js";
3
+
4
+ class CollisionDetector {
5
+ private _tree: any; //use 'any' type because rtree package does not have .d.ts file
6
+ constructor() {
7
+ this._tree = RTree(10);
8
+ }
9
+
10
+ insert(x: number, y: number, w: number, h: number) {
11
+ this._tree.insert({ x: x, y: y, w: w, h: h }, 0);
12
+ }
13
+
14
+ insertPolylineText(
15
+ context: CanvasRenderingContext2D,
16
+ text: string,
17
+ position: PositionXY
18
+ ) {
19
+ let widthUsed = 0;
20
+
21
+ for (let i = 0; i <= text.length; i++) {
22
+ let box = this.getCollisionParams(
23
+ context,
24
+ text.charAt(i),
25
+ position,
26
+ widthUsed
27
+ );
28
+ this.insert(box.x, box.y, box.w, box.h);
29
+
30
+ widthUsed += context.measureText(text.charAt(i)).width;
31
+ }
32
+ }
33
+
34
+ isCollision(x: number, y: number, w: number, h: number) {
35
+ return this._tree.search({ x: x, y: y, w: w, h: h }).length > 0;
36
+ }
37
+
38
+ isPolylineTextCollision(
39
+ context: CanvasRenderingContext2D,
40
+ text: string,
41
+ position: PositionXY
42
+ ): boolean {
43
+ let border = 5;
44
+ let widthUsed = 0;
45
+
46
+ for (let i = 0; i <= text.length; i++) {
47
+ var box = this.getCollisionParams(
48
+ context,
49
+ text.charAt(i),
50
+ position,
51
+ widthUsed
52
+ );
53
+
54
+ if (
55
+ box.x < border ||
56
+ box.y < border ||
57
+ box.x + box.w > 256 - border ||
58
+ box.y + box.h > 256 - border
59
+ ) {
60
+ return true;
61
+ }
62
+
63
+ if (this.isCollision(box.x, box.y, box.w, box.h)) {
64
+ return true;
65
+ }
66
+
67
+ widthUsed += context.measureText(text.charAt(i)).width;
68
+ }
69
+
70
+ return false;
71
+ }
72
+
73
+ getCollisionParams(
74
+ context: CanvasRenderingContext2D,
75
+ text: string,
76
+ position: PositionXY,
77
+ widthUsed: number
78
+ ): { [key: string]: number } {
79
+ let textWidth = context.measureText(text).width;
80
+ let textHeight = context.measureText(text.charAt(0)).width * 1.5;
81
+
82
+ return {
83
+ x: position.x + 0.5 * Math.cos(position.angle) * textWidth,
84
+ y: position.y + 0.5 * Math.sin(position.angle) * textWidth,
85
+ w:
86
+ Math.abs(Math.cos(position.angle) * textWidth) +
87
+ Math.abs(Math.sin(position.angle) * textHeight),
88
+ h:
89
+ Math.abs(Math.sin(position.angle) * textWidth) +
90
+ Math.abs(Math.cos(position.angle) * textHeight),
91
+ };
92
+ }
93
+ }
94
+
95
+ export { CollisionDetector };
@@ -0,0 +1,331 @@
1
+ import { VectorTileLoader } from "./VectorTileLoader.js";
2
+
3
+ import { VectorTileRenderer } from "./VectorTileRenderer.js";
4
+
5
+ import {
6
+ URL_TEMPLATE,
7
+ PROVIDER_PROJECTS,
8
+ PROVIDER_TRAFFIC,
9
+ } from "./constants.js";
10
+
11
+ import WebFont from "webfontloader";
12
+ import { RENDERING_CONFIG_DEFAULT } from "./rendering_config_default.js";
13
+ import { RENDERING_CONFIG_TRAFFIC } from "./rendering_config_traffic.js";
14
+
15
+ import {
16
+ Boundaries,
17
+ Coordinates,
18
+ SuccessCallback,
19
+ MapTilesProperties,
20
+ } from "../types/interfaces.js";
21
+
22
+ import { RENDERING_CONFIG } from "../types/interfaces.js"
23
+ /**
24
+ * Creates a factory to create tiles from the provided URL templates.
25
+ *
26
+ * The templates must have variables ${x}, ${y} and ${z} for the tile index.
27
+ * When multiple URLs are specified, they are used round robin.
28
+ */
29
+ class VectorTileFactory {
30
+ private _layers: string[];
31
+ private _tileLoader: VectorTileLoader;
32
+ private _renderer: VectorTileRenderer;
33
+ private _urls: string[];
34
+ private _additionalUrls: string[];
35
+
36
+ static _fonts: string | undefined = undefined;
37
+ static _properties: typeof VectorTileFactory.DEFAULT_PROPERTIES;
38
+ constructor(
39
+ urls: string[],
40
+ additionalUrls: string[],
41
+ renderingConfig: RENDERING_CONFIG,
42
+ properties: MapTilesProperties
43
+ ) {
44
+ this._urls = urls;
45
+ this._additionalUrls = additionalUrls;
46
+ this._layers = ["all"]; // could be used to load just a selection of layers from the data server
47
+
48
+ this._tileLoader = new VectorTileLoader(properties);
49
+ this._renderer = new VectorTileRenderer(renderingConfig);
50
+
51
+ if (!VectorTileFactory._fonts) {
52
+ WebFont.load({
53
+ custom: {
54
+ families: ["Open Sans:n4,n7,i4,i7"],
55
+ urls: ["https://maps.infoware.de/MapAPI-1.4/css/opensans.css"],
56
+ },
57
+ loading: function () {
58
+ VectorTileFactory._fonts = "loading";
59
+ },
60
+ active: () => {
61
+ VectorTileFactory._fonts = "active";
62
+ this._tileLoader.loadNext();
63
+ },
64
+ inactive: () => {
65
+ // font loading failed
66
+ VectorTileFactory._fonts = "active";
67
+ this._tileLoader.loadNext();
68
+ },
69
+ });
70
+ }
71
+ }
72
+
73
+ public static createFactory(properties: {
74
+ provider?: string;
75
+ baseMap?: boolean;
76
+ traffic?: boolean;
77
+ timeout?: number;
78
+ parallelDownloads?: number;
79
+ detourProfile?: string;
80
+ renderingConfig?: RENDERING_CONFIG;
81
+ }): VectorTileFactory {
82
+ // apply default properties
83
+ this._properties = properties
84
+ ? { ...VectorTileFactory.DEFAULT_PROPERTIES, ...properties }
85
+ : VectorTileFactory.DEFAULT_PROPERTIES;
86
+ this._properties.provider = this._properties.provider.toLowerCase();
87
+
88
+ // assert the provider is valid
89
+ if (!PROVIDER_PROJECTS[this._properties.provider]) {
90
+ throw new Error("Unknown provider");
91
+ }
92
+
93
+ // assert there is no traffic requested for a provider which does not provide traffic information
94
+ if (
95
+ this._properties.traffic &&
96
+ !PROVIDER_TRAFFIC[this._properties.provider]
97
+ ) {
98
+ throw new Error("There is now traffic information for this provider");
99
+ }
100
+
101
+ // assert there is either a base map or traffic (or both)
102
+ if (!this._properties.baseMap && !this._properties.traffic) {
103
+ throw new Error(
104
+ "You cannot create a factory with neither a base map nor traffic"
105
+ );
106
+ }
107
+ return new VectorTileFactory(
108
+ VectorTileFactory.getUrlTemplatesForBaseLayer(this._properties),
109
+ VectorTileFactory.getUrlTemplatesForTrafficLayer(this._properties),
110
+ VectorTileFactory.getRenderingConfig(this._properties),
111
+ this._properties
112
+ );
113
+ }
114
+
115
+ private static getUrlTemplatesForBaseLayer(
116
+ properties: GeoJSON.GeoJsonProperties
117
+ ): string[] | [] {
118
+ if (properties) {
119
+ if (properties.baseMap) {
120
+ let template = URL_TEMPLATE.replace(
121
+ "${project}",
122
+ PROVIDER_PROJECTS[properties.provider!]
123
+ );
124
+ return [0, 1, 2, 3].map((index) =>
125
+ template.replace("${index}", index.toString())
126
+ );
127
+ } else {
128
+ return [];
129
+ }
130
+ } else {
131
+ return [];
132
+ }
133
+ }
134
+
135
+ private static getUrlTemplatesForTrafficLayer(
136
+ properties: GeoJSON.GeoJsonProperties
137
+ ): string[] | [] {
138
+ if (properties) {
139
+ const trafficUrl = properties.traffic
140
+ ? PROVIDER_TRAFFIC[properties.provider!]
141
+ : null;
142
+ return trafficUrl ? [trafficUrl] : [];
143
+ } else {
144
+ return [];
145
+ }
146
+ }
147
+
148
+ private static getRenderingConfig(properties: {
149
+ provider?: string;
150
+ baseMap?: boolean;
151
+ traffic?: boolean;
152
+ timeout?: number;
153
+ parallelDownloads?: number;
154
+ detourProfile?: string;
155
+ renderingConfig?: RENDERING_CONFIG;
156
+ }) {
157
+ if (properties.renderingConfig) {
158
+ return properties.renderingConfig;
159
+ } else if (properties.baseMap) {
160
+ return RENDERING_CONFIG_DEFAULT;
161
+ } else {
162
+ return RENDERING_CONFIG_TRAFFIC;
163
+ }
164
+ }
165
+
166
+ public getJsonTile(
167
+ z: number,
168
+ x: number,
169
+ y: number,
170
+ token: string,
171
+ callback?: SuccessCallback
172
+ ): HTMLCanvasElement {
173
+ let maximumIndex = Math.pow(2, z);
174
+ x = (x + 16 * maximumIndex) % maximumIndex;
175
+ y = (y + 16 * maximumIndex) % maximumIndex;
176
+
177
+ let canvas = document.createElement("canvas");
178
+ canvas.width = 256;
179
+ canvas.height = 256;
180
+
181
+ let baseMapUrl = this.resolveTileUrl(z, x, y);
182
+ let urls = baseMapUrl ? [baseMapUrl] : [];
183
+
184
+ // add URLs for additional data like traffic flows
185
+ this._additionalUrls.forEach((it: string) => {
186
+ urls.push(
187
+ it
188
+ .replace("${x}", String(x))
189
+ .replace("${y}", String(y))
190
+ .replace(/\$\{z\}/g, String(z))
191
+ );
192
+ });
193
+
194
+ let tileLoadedSuccessfullyCallback = (json: GeoJSON.Feature) => {
195
+ this.drawTile(json, z, x, y, canvas);
196
+
197
+ if (callback) {
198
+ callback(canvas);
199
+ }
200
+ };
201
+
202
+ let tile_FailedCallback = () => {
203
+ this.drawErroredTile(canvas);
204
+
205
+ if (callback) {
206
+ callback(null);
207
+ }
208
+ };
209
+
210
+ this._tileLoader.queue(
211
+ { x, y, z, urls, token },
212
+ tileLoadedSuccessfullyCallback,
213
+ tile_FailedCallback
214
+ );
215
+
216
+ if (VectorTileFactory._fonts === "active") {
217
+ this._tileLoader.loadNext();
218
+ }
219
+
220
+ return canvas;
221
+ }
222
+
223
+ /**
224
+ * @private
225
+ */
226
+ private resolveTileUrl(z: number, x: number, y: number): string | null {
227
+ if (this._urls.length > 0) {
228
+ var index = (x + y + z) % this._urls.length;
229
+
230
+ return this._urls[index]
231
+ .replace("${x}", String(x))
232
+ .replace("${y}", String(y))
233
+ .replace(/\$\{z\}/g, String(z))
234
+ .replace("${layers}", this._layers.join(","));
235
+ } else {
236
+ // there is no base map layer
237
+ return null;
238
+ }
239
+ }
240
+
241
+ /**
242
+ * @private
243
+ */
244
+ private tileIndexToLatLong(z: number, x: number, y: number): Coordinates {
245
+ var n = Math.PI - (2 * Math.PI * y) / Math.pow(2, z);
246
+
247
+ return {
248
+ lat: (180 / Math.PI) * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n))),
249
+ lon: (x / Math.pow(2, z)) * 360 - 180,
250
+ };
251
+ }
252
+
253
+ /**
254
+ * @private
255
+ */
256
+ private getTileBoundaries(z: number, x: number, y: number): Boundaries {
257
+ return {
258
+ min: this.tileIndexToLatLong(z, x, y),
259
+ max: this.tileIndexToLatLong(z, x + 1, y + 1),
260
+ };
261
+ }
262
+
263
+ /**
264
+ * @private
265
+ */
266
+ private drawTile(
267
+ json: GeoJSON.GeoJsonObject,
268
+ z: number,
269
+ x: number,
270
+ y: number,
271
+ canvas: HTMLCanvasElement
272
+ ): void {
273
+ var features = this.getFeatures(json)!.sort(function (a: any, b: any) {
274
+ if (a.properties && a.properties.sort_rank) {
275
+ if (b.properties && b.properties.sort_rank) {
276
+ return a.properties.sort_rank - b.properties.sort_rank;
277
+ } else {
278
+ return -1;
279
+ }
280
+ } else {
281
+ if (b.properties && b.properties.sort_rank) {
282
+ return 1;
283
+ } else {
284
+ return 0;
285
+ }
286
+ }
287
+ });
288
+
289
+ const context = canvas.getContext("2d");
290
+ if (context) {
291
+ this._renderer.drawTile(
292
+ features,
293
+ z,
294
+ this.getTileBoundaries(z, x, y),
295
+ context
296
+ );
297
+ } else {
298
+ console.error("Failed to create canvas context");
299
+ }
300
+ }
301
+
302
+ /**
303
+ * Draws an error message on the tile.
304
+ * @private
305
+ *
306
+ * @param canvas
307
+ */
308
+ private drawErroredTile(canvas: HTMLCanvasElement): void {
309
+ this._renderer.drawErroredTile(canvas);
310
+ }
311
+
312
+ /**
313
+ * @private
314
+ */
315
+ private getFeatures(json: GeoJSON.GeoJsonObject): GeoJSON.Feature[] | void {
316
+ if (json.type && json.type == "FeatureCollection") {
317
+ const featureCollection = json as GeoJSON.FeatureCollection;
318
+ return featureCollection.features;
319
+ } else {
320
+ return;
321
+ }
322
+ }
323
+
324
+ static DEFAULT_PROPERTIES = {
325
+ provider: "OpenStreetmap",
326
+ baseMap: true,
327
+ traffic: false,
328
+ };
329
+ }
330
+
331
+ export { VectorTileFactory };