@maptrip/map-tiles 1.3.3 → 1.5.0
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.
- package/README.md +15 -2
- package/dist/core/VectorTileFactory.d.ts +2 -0
- package/dist/core/constants.d.ts +5 -0
- package/dist/core/rendering_config_default.d.ts +45 -32
- package/dist/core/rendering_config_grayscale.d.ts +45 -32
- package/dist/map-tiles.js +241 -143
- package/dist/map-tiles.js.map +1 -1
- package/dist/util/MapReleaseFetcher.d.ts +2 -1
- package/lib/api-extensions/leaflet/MapTripLeafletGridLayer.ts +3 -1
- package/lib/core/VectorTileFactory.ts +52 -7
- package/lib/core/VectorTileRenderer.ts +129 -129
- package/lib/core/constants.ts +12 -1
- package/lib/core/rendering_config_default.ts +32 -27
- package/lib/core/rendering_config_grayscale.ts +31 -26
- package/lib/util/MapReleaseFetcher.ts +15 -5
- package/package.json +4 -4
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
export declare class MapReleaseFetcher {
|
|
2
2
|
private _token;
|
|
3
3
|
private _tomtom;
|
|
4
|
+
private _orbis;
|
|
4
5
|
private _osm;
|
|
5
6
|
private _here;
|
|
6
7
|
constructor(token: string);
|
|
7
8
|
getRelease(provider: string): Promise<string | null | undefined>;
|
|
8
|
-
fetchAndExtractRelease(url: string): Promise<string | null>;
|
|
9
|
+
fetchAndExtractRelease(provider: string, url: string): Promise<string | null>;
|
|
9
10
|
private extractTargetString;
|
|
10
11
|
}
|
|
@@ -119,10 +119,12 @@ class MapTripLeafletGridLayer extends L.GridLayer {
|
|
|
119
119
|
const eventProvider = event.layer.options.provider;
|
|
120
120
|
let newProvider: string;
|
|
121
121
|
if (eventProvider) {
|
|
122
|
-
if (eventProvider.toLowerCase() === "
|
|
122
|
+
if (eventProvider.toLowerCase() === "openstreetmap") {
|
|
123
123
|
newProvider = "openstreetmap";
|
|
124
124
|
} else if (eventProvider.toLowerCase() === "tomtom") {
|
|
125
125
|
newProvider = "tomtom";
|
|
126
|
+
} else if (eventProvider.toLowerCase() === "orbis") {
|
|
127
|
+
newProvider = "orbis";
|
|
126
128
|
} else if (eventProvider.toLowerCase() === "here") {
|
|
127
129
|
newProvider = "here";
|
|
128
130
|
} else {
|
|
@@ -6,6 +6,8 @@ import {
|
|
|
6
6
|
URL_TEMPLATE,
|
|
7
7
|
PROVIDER_PROJECTS,
|
|
8
8
|
PROVIDER_TRAFFIC,
|
|
9
|
+
VECTOR_TILE_SIZE,
|
|
10
|
+
VECTOR_TILE_RENDER_PADDING
|
|
9
11
|
} from "./constants.js";
|
|
10
12
|
|
|
11
13
|
import WebFont from "webfontloader";
|
|
@@ -163,6 +165,49 @@ class VectorTileFactory {
|
|
|
163
165
|
}
|
|
164
166
|
}
|
|
165
167
|
|
|
168
|
+
private createCanvas(size: number, padding: number): HTMLCanvasElement {
|
|
169
|
+
let canvas = document.createElement("canvas");
|
|
170
|
+
|
|
171
|
+
const paddedTileSize = size + 2 * padding;
|
|
172
|
+
|
|
173
|
+
canvas.width = paddedTileSize;
|
|
174
|
+
canvas.height = paddedTileSize;
|
|
175
|
+
canvas.style.width = paddedTileSize + 'px';
|
|
176
|
+
canvas.style.height = paddedTileSize + 'px';
|
|
177
|
+
canvas.style.maxWidth = paddedTileSize + 'px';
|
|
178
|
+
canvas.style.maxHeight = paddedTileSize + 'px';
|
|
179
|
+
canvas.style.left = -padding + 'px';
|
|
180
|
+
canvas.style.top = -padding + 'px';
|
|
181
|
+
|
|
182
|
+
const context = canvas.getContext('2d');
|
|
183
|
+
if (!context) {
|
|
184
|
+
throw new Error("Failed to create canvas");
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (typeof context.setTransform === 'function') {
|
|
188
|
+
context.setTransform(1, 0, 0, 1, padding, padding);
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
context.translate(padding, padding);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return canvas;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
private cropCanvas(source: HTMLCanvasElement, target: HTMLCanvasElement): void {
|
|
198
|
+
const ctx = target.getContext("2d");
|
|
199
|
+
|
|
200
|
+
if (ctx) {
|
|
201
|
+
ctx.drawImage(
|
|
202
|
+
source,
|
|
203
|
+
VECTOR_TILE_RENDER_PADDING, VECTOR_TILE_RENDER_PADDING, // position in source
|
|
204
|
+
VECTOR_TILE_SIZE, VECTOR_TILE_SIZE, // size in source
|
|
205
|
+
0, 0, // position in target
|
|
206
|
+
VECTOR_TILE_SIZE, VECTOR_TILE_SIZE // size in target
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
166
211
|
public getJsonTile(
|
|
167
212
|
z: number,
|
|
168
213
|
x: number,
|
|
@@ -174,9 +219,8 @@ class VectorTileFactory {
|
|
|
174
219
|
x = (x + 16 * maximumIndex) % maximumIndex;
|
|
175
220
|
y = (y + 16 * maximumIndex) % maximumIndex;
|
|
176
221
|
|
|
177
|
-
let
|
|
178
|
-
|
|
179
|
-
canvas.height = 256;
|
|
222
|
+
let resultCanvas = this.createCanvas(VECTOR_TILE_SIZE, 0);
|
|
223
|
+
let tempCanvas = this.createCanvas(VECTOR_TILE_SIZE, VECTOR_TILE_RENDER_PADDING);
|
|
180
224
|
|
|
181
225
|
let baseMapUrl = this.resolveTileUrl(z, x, y);
|
|
182
226
|
let urls = baseMapUrl ? [baseMapUrl] : [];
|
|
@@ -192,15 +236,16 @@ class VectorTileFactory {
|
|
|
192
236
|
});
|
|
193
237
|
|
|
194
238
|
let tileLoadedSuccessfullyCallback = (json: GeoJSON.Feature) => {
|
|
195
|
-
this.drawTile(json, z, x, y,
|
|
239
|
+
this.drawTile(json, z, x, y, tempCanvas);
|
|
240
|
+
this.cropCanvas(tempCanvas, resultCanvas);
|
|
196
241
|
|
|
197
242
|
if (callback) {
|
|
198
|
-
callback(
|
|
243
|
+
callback(resultCanvas);
|
|
199
244
|
}
|
|
200
245
|
};
|
|
201
246
|
|
|
202
247
|
let tile_FailedCallback = () => {
|
|
203
|
-
this.drawErroredTile(
|
|
248
|
+
this.drawErroredTile(resultCanvas);
|
|
204
249
|
|
|
205
250
|
if (callback) {
|
|
206
251
|
callback(null);
|
|
@@ -217,7 +262,7 @@ class VectorTileFactory {
|
|
|
217
262
|
this._tileLoader.loadNext();
|
|
218
263
|
}
|
|
219
264
|
|
|
220
|
-
return
|
|
265
|
+
return resultCanvas;
|
|
221
266
|
}
|
|
222
267
|
|
|
223
268
|
/**
|
|
@@ -6,7 +6,9 @@ import {
|
|
|
6
6
|
MultiPolygon,
|
|
7
7
|
GeoJsonProperties,
|
|
8
8
|
} from "geojson";
|
|
9
|
+
|
|
9
10
|
import { CollisionDetector } from "./CollisionDetector.js";
|
|
11
|
+
|
|
10
12
|
import {
|
|
11
13
|
Boundaries,
|
|
12
14
|
ImageStyle,
|
|
@@ -19,7 +21,11 @@ import {
|
|
|
19
21
|
Vertex,
|
|
20
22
|
} from "../types/interfaces.js";
|
|
21
23
|
|
|
22
|
-
import {
|
|
24
|
+
import {
|
|
25
|
+
VECTOR_TILE_SIZE
|
|
26
|
+
} from "./constants.js"
|
|
27
|
+
|
|
28
|
+
import { RENDERING_CONFIG } from "../types/interfaces.js"
|
|
23
29
|
|
|
24
30
|
class VectorTileRenderer {
|
|
25
31
|
private _styles: RENDERING_CONFIG;
|
|
@@ -38,7 +44,7 @@ class VectorTileRenderer {
|
|
|
38
44
|
context: CanvasRenderingContext2D
|
|
39
45
|
): void {
|
|
40
46
|
context.fillStyle = this.getBackgroundColor(z);
|
|
41
|
-
context.fillRect(0, 0,
|
|
47
|
+
context.fillRect(0, 0, VECTOR_TILE_SIZE, VECTOR_TILE_SIZE);
|
|
42
48
|
|
|
43
49
|
var collisions = new CollisionDetector();
|
|
44
50
|
let polygons = layer
|
|
@@ -73,6 +79,7 @@ class VectorTileRenderer {
|
|
|
73
79
|
);
|
|
74
80
|
|
|
75
81
|
this.drawTilePhase(polygons, z, boundaries, context, "areas", collisions);
|
|
82
|
+
// add phase areasOutline here if polygon outlines should be rendered
|
|
76
83
|
this.drawPolylineLayers(lines, z, boundaries, context, "", collisions);
|
|
77
84
|
this.drawTilePhase(points, z, boundaries, context, "texts", collisions);
|
|
78
85
|
this.drawTilePhase(lines, z, boundaries, context, "lineTexts", collisions);
|
|
@@ -113,6 +120,14 @@ class VectorTileRenderer {
|
|
|
113
120
|
"linesOutline",
|
|
114
121
|
collisions
|
|
115
122
|
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
for (let i = 0; i < rank.length; i++) {
|
|
126
|
+
// select all lines with this sort rank
|
|
127
|
+
let currentRank = lines.filter(
|
|
128
|
+
(it) => parseInt(it.properties!.sort_rank) === rank[i]
|
|
129
|
+
);
|
|
130
|
+
|
|
116
131
|
this.drawTilePhase(
|
|
117
132
|
currentRank,
|
|
118
133
|
z,
|
|
@@ -123,12 +138,12 @@ class VectorTileRenderer {
|
|
|
123
138
|
);
|
|
124
139
|
}
|
|
125
140
|
}
|
|
126
|
-
|
|
141
|
+
|
|
127
142
|
drawErroredTile(canvas: HTMLCanvasElement): void {
|
|
128
143
|
var context = canvas.getContext("2d");
|
|
129
144
|
if (context != null) {
|
|
130
145
|
context.fillStyle = "#C8C8C8";
|
|
131
|
-
context.fillRect(0, 0,
|
|
146
|
+
context.fillRect(0, 0, VECTOR_TILE_SIZE, VECTOR_TILE_SIZE);
|
|
132
147
|
context.fillStyle = "#AAA";
|
|
133
148
|
context.font = "15px Arial";
|
|
134
149
|
context.textAlign = "center";
|
|
@@ -164,7 +179,7 @@ class VectorTileRenderer {
|
|
|
164
179
|
const rendererName = this._styles.layers[kind];
|
|
165
180
|
const renderer = rendererName
|
|
166
181
|
? //@ts-ignore
|
|
167
|
-
|
|
182
|
+
this._styles?.renderers[rendererName]
|
|
168
183
|
: undefined;
|
|
169
184
|
|
|
170
185
|
if (renderer) {
|
|
@@ -179,10 +194,7 @@ class VectorTileRenderer {
|
|
|
179
194
|
if (geometry.type === "Polygon") {
|
|
180
195
|
const polygonGeometry = geometry as Polygon;
|
|
181
196
|
const coordinates = polygonGeometry.coordinates;
|
|
182
|
-
if (
|
|
183
|
-
(phase === "areasOutline" || phase === "areas") &&
|
|
184
|
-
renderer[j].polygon
|
|
185
|
-
) {
|
|
197
|
+
if ((phase === "areasOutline" || phase === "areas") && renderer[j].polygon) {
|
|
186
198
|
this.drawPolygon(
|
|
187
199
|
coordinates,
|
|
188
200
|
layer[i].properties,
|
|
@@ -192,10 +204,7 @@ class VectorTileRenderer {
|
|
|
192
204
|
context,
|
|
193
205
|
phase
|
|
194
206
|
);
|
|
195
|
-
} else if (
|
|
196
|
-
phase === "areaTexts" &&
|
|
197
|
-
renderer[j].text !== undefined
|
|
198
|
-
) {
|
|
207
|
+
} else if (phase === "areaTexts" && renderer[j].text !== undefined) {
|
|
199
208
|
this.drawPolygon(
|
|
200
209
|
coordinates,
|
|
201
210
|
layer[i].properties,
|
|
@@ -211,10 +220,7 @@ class VectorTileRenderer {
|
|
|
211
220
|
} else if (geometry.type === "MultiPolygon") {
|
|
212
221
|
const multiPolygonGeometry = geometry as MultiPolygon;
|
|
213
222
|
const coordinates = multiPolygonGeometry.coordinates;
|
|
214
|
-
if (
|
|
215
|
-
(phase === "areasOutline" || phase === "areas") &&
|
|
216
|
-
renderer[j].polygon
|
|
217
|
-
) {
|
|
223
|
+
if ((phase === "areasOutline" || phase === "areas") && renderer[j].polygon) {
|
|
218
224
|
for (let k = 0; k < coordinates.length; k++) {
|
|
219
225
|
this.drawPolygon(
|
|
220
226
|
coordinates[k],
|
|
@@ -244,10 +250,7 @@ class VectorTileRenderer {
|
|
|
244
250
|
} else if (geometry.type === "LineString") {
|
|
245
251
|
const lineStringGeometry = geometry as LineString;
|
|
246
252
|
const coordinates = lineStringGeometry.coordinates;
|
|
247
|
-
if (
|
|
248
|
-
(phase === "linesOutline" || phase === "lines") &&
|
|
249
|
-
renderer[j].line
|
|
250
|
-
) {
|
|
253
|
+
if ((phase === "linesOutline" || phase === "lines") && renderer[j].line) {
|
|
251
254
|
this.drawPolyline(
|
|
252
255
|
coordinates,
|
|
253
256
|
layer[i].properties,
|
|
@@ -270,10 +273,7 @@ class VectorTileRenderer {
|
|
|
270
273
|
} else if (geometry.type === "MultiLineString") {
|
|
271
274
|
const multiLineStringGeometry = geometry as MultiLineString;
|
|
272
275
|
const coordinates = multiLineStringGeometry.coordinates;
|
|
273
|
-
if (
|
|
274
|
-
(phase === "linesOutline" || phase === "lines") &&
|
|
275
|
-
renderer[j].line
|
|
276
|
-
) {
|
|
276
|
+
if ((phase === "linesOutline" || phase === "lines") && renderer[j].line) {
|
|
277
277
|
for (let k = 0; k < coordinates.length; k++) {
|
|
278
278
|
this.drawPolyline(
|
|
279
279
|
coordinates[k],
|
|
@@ -315,12 +315,18 @@ class VectorTileRenderer {
|
|
|
315
315
|
collisions
|
|
316
316
|
)
|
|
317
317
|
) {
|
|
318
|
-
const match = text.match(/([
|
|
318
|
+
const match = text.match(/([a-zA-Z])\s?([0-9]+[a-z]*).*/);
|
|
319
319
|
if (match) {
|
|
320
320
|
const letter = match[1];
|
|
321
321
|
const number = match[2];
|
|
322
|
-
|
|
323
|
-
|
|
322
|
+
|
|
323
|
+
// Stadsroutes are major roads in some cities in the Netherlands and start with s.
|
|
324
|
+
// Adding them here will render them like Bundesstraßen in Germany.
|
|
325
|
+
// If country-dependent rendering is added, it should be a white box with black border and text.
|
|
326
|
+
|
|
327
|
+
if (letter === "A" || letter === "B" || letter === "s") {
|
|
328
|
+
text = letter === "A" || letter === "B" ? number : letter + number;
|
|
329
|
+
|
|
324
330
|
this.drawImage(
|
|
325
331
|
coordinates,
|
|
326
332
|
boundaries,
|
|
@@ -360,6 +366,9 @@ class VectorTileRenderer {
|
|
|
360
366
|
}
|
|
361
367
|
}
|
|
362
368
|
}
|
|
369
|
+
else {
|
|
370
|
+
console.log("no renderer for kind " + kind);
|
|
371
|
+
}
|
|
363
372
|
}
|
|
364
373
|
}
|
|
365
374
|
|
|
@@ -435,17 +444,24 @@ class VectorTileRenderer {
|
|
|
435
444
|
var part = coordinates[j];
|
|
436
445
|
|
|
437
446
|
context.globalAlpha = merged.opacity;
|
|
438
|
-
context.beginPath();
|
|
439
447
|
|
|
448
|
+
if ('areas' !== phase || j === 0) {
|
|
449
|
+
// when rendering areas, only the first part of a polygon should begin a path
|
|
450
|
+
// (otherwise especially islands are clipped on some zoom levels)
|
|
451
|
+
context.beginPath();
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
const width = boundaries.max.lon - boundaries.min.lon;
|
|
455
|
+
const height = boundaries.max.lat - boundaries.min.lat;
|
|
456
|
+
if (width === 0 || height === 0) {
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
|
|
440
460
|
var points: { x: number; y: number }[] = [];
|
|
441
461
|
|
|
442
462
|
for (let k = 0; k < part.length; k++) {
|
|
443
|
-
let x =
|
|
444
|
-
|
|
445
|
-
(boundaries.max.lon! - boundaries.min.lon!);
|
|
446
|
-
let y =
|
|
447
|
-
(256 * (part[k][1] - boundaries.min.lat!)) /
|
|
448
|
-
(boundaries.max.lat! - boundaries.min.lat!);
|
|
463
|
+
let x = (VECTOR_TILE_SIZE * (part[k][0] - boundaries.min.lon!)) / width;
|
|
464
|
+
let y = (VECTOR_TILE_SIZE * (part[k][1] - boundaries.min.lat!)) / height;
|
|
449
465
|
|
|
450
466
|
points.push({ x: x, y: y });
|
|
451
467
|
|
|
@@ -466,7 +482,7 @@ class VectorTileRenderer {
|
|
|
466
482
|
}
|
|
467
483
|
|
|
468
484
|
return;
|
|
469
|
-
} else if ("areas" === phase) {
|
|
485
|
+
} else if ("areas" === phase && j === coordinates.length - 1) {
|
|
470
486
|
if (merged.url) {
|
|
471
487
|
if (this._images[merged.url]) {
|
|
472
488
|
var pattern = context.createPattern(
|
|
@@ -486,7 +502,7 @@ class VectorTileRenderer {
|
|
|
486
502
|
context.fillStyle = merged.color;
|
|
487
503
|
}
|
|
488
504
|
|
|
489
|
-
context.fill();
|
|
505
|
+
context.fill('evenodd');
|
|
490
506
|
} else if ("areaTexts" === phase) {
|
|
491
507
|
if (geoJsonProperties && geoJsonProperties.NAME) {
|
|
492
508
|
// skip texts which already are in this tile
|
|
@@ -497,14 +513,8 @@ class VectorTileRenderer {
|
|
|
497
513
|
let merged = { ...VectorTileRenderer.DEFAULT_STYLE.TEXT, ...style };
|
|
498
514
|
|
|
499
515
|
context.globalAlpha = merged.opacity;
|
|
500
|
-
context.font =
|
|
501
|
-
|
|
502
|
-
" " +
|
|
503
|
-
merged.fontWeight +
|
|
504
|
-
" " +
|
|
505
|
-
merged.size +
|
|
506
|
-
"px " +
|
|
507
|
-
merged.font;
|
|
516
|
+
context.font = `${merged.fontStyle} ${merged.fontWeight} ${merged.size}px ${merged.font}`;
|
|
517
|
+
|
|
508
518
|
context.textAlign = "left";
|
|
509
519
|
context.textBaseline = "top";
|
|
510
520
|
|
|
@@ -518,7 +528,7 @@ class VectorTileRenderer {
|
|
|
518
528
|
let h = merged.size!;
|
|
519
529
|
|
|
520
530
|
// skip texts outside a tile
|
|
521
|
-
if (x < 0 || x + w >
|
|
531
|
+
if (x < 0 || x + w > VECTOR_TILE_SIZE || y < 0 || y + h > VECTOR_TILE_SIZE) {
|
|
522
532
|
return;
|
|
523
533
|
}
|
|
524
534
|
|
|
@@ -622,15 +632,12 @@ class VectorTileRenderer {
|
|
|
622
632
|
var lastX, lastY;
|
|
623
633
|
var points = [];
|
|
624
634
|
|
|
635
|
+
const width = boundaries.max.lon - boundaries.min.lon;
|
|
636
|
+
const height = boundaries.max.lat - boundaries.min.lat;
|
|
637
|
+
|
|
625
638
|
for (var j = 0; j < coordinates.length; j++) {
|
|
626
|
-
var x = Math.round(
|
|
627
|
-
|
|
628
|
-
(boundaries.max.lon! - boundaries.min.lon!)
|
|
629
|
-
);
|
|
630
|
-
var y = Math.round(
|
|
631
|
-
(256 * (coordinates[j][1] - boundaries.min.lat!)) /
|
|
632
|
-
(boundaries.max.lat! - boundaries.min.lat!)
|
|
633
|
-
);
|
|
639
|
+
var x = Math.round((VECTOR_TILE_SIZE * (coordinates[j][0] - boundaries.min.lon!)) / width);
|
|
640
|
+
var y = Math.round((VECTOR_TILE_SIZE * (coordinates[j][1] - boundaries.min.lat!)) / height);
|
|
634
641
|
|
|
635
642
|
if (x != lastX || y != lastY) {
|
|
636
643
|
points.push({ x: x, y: y });
|
|
@@ -682,48 +689,69 @@ class VectorTileRenderer {
|
|
|
682
689
|
|
|
683
690
|
// draw images on the line (e.g. arrows for one-way roads)
|
|
684
691
|
if (merged.url && this._images[merged.url]) {
|
|
685
|
-
|
|
686
|
-
|
|
692
|
+
const desiredDistance: number = 40;
|
|
693
|
+
const margin: number = Math.round(desiredDistance / 2);
|
|
694
|
+
|
|
695
|
+
let totalLength = 0;
|
|
696
|
+
for (let i = 0; i < points.length - 1; i++) {
|
|
697
|
+
totalLength += Math.hypot(
|
|
698
|
+
points[i + 1].x - points[i].x,
|
|
699
|
+
points[i + 1].y - points[i].y
|
|
700
|
+
);
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
let distance: number = margin;
|
|
704
|
+
let traveled: number = 0;
|
|
687
705
|
|
|
688
706
|
for (var i = 0; i < points.length - 1; i++) {
|
|
689
707
|
// calculate angle of this section of the line
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
708
|
+
const dx: number = points[i + 1].x - points[i].x;
|
|
709
|
+
const dy: number = points[i + 1].y - points[i].y;
|
|
710
|
+
let angle: number = Math.atan2(dy, dx);
|
|
693
711
|
|
|
694
712
|
if (merged.direction != "reverse") {
|
|
695
713
|
angle = angle + Math.PI;
|
|
696
714
|
}
|
|
697
715
|
|
|
698
716
|
// now calculate equidistant points on the polyline
|
|
699
|
-
|
|
717
|
+
const distanceToNext: number = Math.sqrt(dx * dx + dy * dy);
|
|
700
718
|
while (distance < distanceToNext) {
|
|
701
719
|
// there are more points on this section of the line
|
|
702
|
-
var f = distance / distanceToNext;
|
|
703
720
|
|
|
704
|
-
|
|
705
|
-
var y = points[i].y + f * dy;
|
|
721
|
+
if (traveled + distance <= totalLength - margin) {
|
|
706
722
|
|
|
707
|
-
|
|
723
|
+
const f: number = distance / distanceToNext;
|
|
708
724
|
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
725
|
+
const x: number = points[i].x + f * dx;
|
|
726
|
+
const y: number = points[i].y + f * dy;
|
|
727
|
+
|
|
728
|
+
const size: number = Math.max(12, 1.5 * merged.width);
|
|
712
729
|
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
730
|
+
if (x > size && y > size && x < VECTOR_TILE_SIZE - size && y < VECTOR_TILE_SIZE - size) {
|
|
731
|
+
context.save();
|
|
732
|
+
|
|
733
|
+
context.translate(x, y);
|
|
734
|
+
context.rotate(angle);
|
|
735
|
+
context.translate(-x, -y);
|
|
736
|
+
|
|
737
|
+
context.drawImage(
|
|
738
|
+
this._images[merged.url],
|
|
739
|
+
x - size / 2,
|
|
740
|
+
y - size / 2,
|
|
741
|
+
size,
|
|
742
|
+
size,
|
|
743
|
+
);
|
|
720
744
|
|
|
721
|
-
|
|
745
|
+
context.restore();
|
|
746
|
+
}
|
|
722
747
|
|
|
723
|
-
|
|
748
|
+
}
|
|
749
|
+
distance += desiredDistance;
|
|
724
750
|
}
|
|
725
751
|
|
|
726
|
-
|
|
752
|
+
traveled += distanceToNext;
|
|
753
|
+
distance -= distanceToNext;
|
|
754
|
+
// distance = (desiredDistance - (distanceToNext - distance)) % desiredDistance;
|
|
727
755
|
}
|
|
728
756
|
}
|
|
729
757
|
}
|
|
@@ -755,14 +783,7 @@ class VectorTileRenderer {
|
|
|
755
783
|
var merged = { ...VectorTileRenderer.DEFAULT_STYLE.TEXT, ...style };
|
|
756
784
|
|
|
757
785
|
context.globalAlpha = merged.opacity;
|
|
758
|
-
context.font =
|
|
759
|
-
merged.fontStyle +
|
|
760
|
-
" " +
|
|
761
|
-
merged.fontWeight +
|
|
762
|
-
" " +
|
|
763
|
-
merged.size +
|
|
764
|
-
"px " +
|
|
765
|
-
merged.font;
|
|
786
|
+
context.font = `${merged.fontStyle} ${merged.fontWeight} ${merged.size}px ${merged.font}`;
|
|
766
787
|
|
|
767
788
|
var points = this.projectCoordinates(coordinates, boundaries);
|
|
768
789
|
if (points.length < 2) {
|
|
@@ -909,8 +930,8 @@ class VectorTileRenderer {
|
|
|
909
930
|
positions.length == 0
|
|
910
931
|
? 0
|
|
911
932
|
: Math.abs(
|
|
912
|
-
|
|
913
|
-
|
|
933
|
+
positions[positions.length - 1].angle - position.angle
|
|
934
|
+
);
|
|
914
935
|
|
|
915
936
|
if (!collision && deltaAngle < Math.PI / 6) {
|
|
916
937
|
widthUsed += letterWidth;
|
|
@@ -957,7 +978,7 @@ class VectorTileRenderer {
|
|
|
957
978
|
outline: number,
|
|
958
979
|
context: CanvasRenderingContext2D
|
|
959
980
|
): void {
|
|
960
|
-
var width = context.measureText(letter).width + outline;
|
|
981
|
+
var width = context.measureText(letter).width + outline;
|
|
961
982
|
|
|
962
983
|
var x = position.x + 0.5 * Math.cos(position.angle) * width;
|
|
963
984
|
var y = position.y + 0.5 * Math.sin(position.angle) * width;
|
|
@@ -1010,12 +1031,12 @@ class VectorTileRenderer {
|
|
|
1010
1031
|
if (merged.url) {
|
|
1011
1032
|
if (this._images[merged.url]) {
|
|
1012
1033
|
var x = Math.round(
|
|
1013
|
-
(
|
|
1014
|
-
|
|
1034
|
+
(VECTOR_TILE_SIZE * (coordinate[0] - boundaries.min.lon!)) /
|
|
1035
|
+
(boundaries.max.lon! - boundaries.min.lon!)
|
|
1015
1036
|
);
|
|
1016
1037
|
var y = Math.round(
|
|
1017
|
-
(
|
|
1018
|
-
|
|
1038
|
+
(VECTOR_TILE_SIZE * (coordinate[1] - boundaries.min.lat!)) /
|
|
1039
|
+
(boundaries.max.lat! - boundaries.min.lat!)
|
|
1019
1040
|
);
|
|
1020
1041
|
if (merged.width && merged.height) {
|
|
1021
1042
|
merged.width = Number(merged.width);
|
|
@@ -1045,26 +1066,19 @@ class VectorTileRenderer {
|
|
|
1045
1066
|
): boolean {
|
|
1046
1067
|
var merged = { ...VectorTileRenderer.DEFAULT_STYLE.TEXT, ...style };
|
|
1047
1068
|
|
|
1048
|
-
|
|
1049
|
-
(
|
|
1050
|
-
|
|
1069
|
+
let x = Math.round(
|
|
1070
|
+
(VECTOR_TILE_SIZE * (coordinate[0] - boundaries.min.lon)) /
|
|
1071
|
+
(boundaries.max.lon - boundaries.min.lon)
|
|
1051
1072
|
);
|
|
1052
|
-
|
|
1053
|
-
(
|
|
1054
|
-
|
|
1073
|
+
let y = Math.round(
|
|
1074
|
+
(VECTOR_TILE_SIZE * (coordinate[1] - boundaries.min.lat)) /
|
|
1075
|
+
(boundaries.max.lat - boundaries.min.lat)
|
|
1055
1076
|
);
|
|
1056
1077
|
|
|
1057
|
-
context.font =
|
|
1058
|
-
merged.fontStyle +
|
|
1059
|
-
" " +
|
|
1060
|
-
merged.fontWeight +
|
|
1061
|
-
" " +
|
|
1062
|
-
merged.size +
|
|
1063
|
-
"px " +
|
|
1064
|
-
merged.font;
|
|
1078
|
+
context.font = `${merged.fontStyle} ${merged.fontWeight} ${merged.size}px ${merged.font}`;
|
|
1065
1079
|
|
|
1066
|
-
|
|
1067
|
-
|
|
1080
|
+
const w = context.measureText(name).width;
|
|
1081
|
+
const h = merged.size; // XXX ???
|
|
1068
1082
|
|
|
1069
1083
|
x = x - w / 2; // center on x
|
|
1070
1084
|
|
|
@@ -1085,23 +1099,16 @@ class VectorTileRenderer {
|
|
|
1085
1099
|
var merged = { ...VectorTileRenderer.DEFAULT_STYLE.TEXT, ...style };
|
|
1086
1100
|
|
|
1087
1101
|
var x = Math.round(
|
|
1088
|
-
(
|
|
1089
|
-
|
|
1102
|
+
(VECTOR_TILE_SIZE * (coordinate[0] - boundaries.min.lon)) /
|
|
1103
|
+
(boundaries.max.lon - boundaries.min.lon)
|
|
1090
1104
|
);
|
|
1091
1105
|
var y = Math.round(
|
|
1092
|
-
(
|
|
1093
|
-
|
|
1106
|
+
(VECTOR_TILE_SIZE * (coordinate[1] - boundaries.min.lat)) /
|
|
1107
|
+
(boundaries.max.lat - boundaries.min.lat)
|
|
1094
1108
|
);
|
|
1095
1109
|
|
|
1096
1110
|
context.globalAlpha = merged.opacity;
|
|
1097
|
-
context.font =
|
|
1098
|
-
merged.fontStyle +
|
|
1099
|
-
" " +
|
|
1100
|
-
merged.fontWeight +
|
|
1101
|
-
" " +
|
|
1102
|
-
merged.size +
|
|
1103
|
-
"px " +
|
|
1104
|
-
merged.font;
|
|
1111
|
+
context.font = `${merged.fontStyle} ${merged.fontWeight} ${merged.size}px ${merged.font}`;
|
|
1105
1112
|
|
|
1106
1113
|
var w = context.measureText(name).width;
|
|
1107
1114
|
var h = merged.size; // XXX ???
|
|
@@ -1158,15 +1165,8 @@ class VectorTileRenderer {
|
|
|
1158
1165
|
let text = this._styles.renderers[renderer][i].text;
|
|
1159
1166
|
if (text) {
|
|
1160
1167
|
let merged = { ...VectorTileRenderer.DEFAULT_STYLE.TEXT, ...text };
|
|
1161
|
-
let font = (
|
|
1162
|
-
|
|
1163
|
-
" " +
|
|
1164
|
-
merged.fontWeight +
|
|
1165
|
-
" " +
|
|
1166
|
-
merged.size +
|
|
1167
|
-
"px " +
|
|
1168
|
-
merged.font
|
|
1169
|
-
).trim();
|
|
1168
|
+
let font = `${merged.fontStyle} ${merged.fontWeight} ${merged.size}px ${merged.font}`.trim();
|
|
1169
|
+
|
|
1170
1170
|
result.push(font);
|
|
1171
1171
|
}
|
|
1172
1172
|
}
|
package/lib/core/constants.ts
CHANGED
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
export const URL_TEMPLATE =
|
|
2
2
|
"https://v${index}.maptrip.de/?tilex=${x}&tiley=${y}&acao=true&context=tomtom${z}&project=${project}&projection=wgs84";
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
|
|
5
5
|
export const PROVIDER_PROJECTS: { [key: string]: string } = {
|
|
6
6
|
tomtom: "TomTom_latest",
|
|
7
|
+
orbis: "Orbis_latest",
|
|
7
8
|
here: "HERE_latest",
|
|
8
9
|
openstreetmap: "OSM_latest",
|
|
9
10
|
};
|
|
10
11
|
|
|
12
|
+
export const PROVIDER_NAMES: { [key: string]: string } = {
|
|
13
|
+
tomtom: "TomTom",
|
|
14
|
+
orbis: "TomTom Orbis",
|
|
15
|
+
here: "HERE",
|
|
16
|
+
openstreetmap: "OpenStreetMap",
|
|
17
|
+
};
|
|
18
|
+
|
|
11
19
|
export const PROVIDER_TRAFFIC: { [key: string]: string | null } = {
|
|
12
20
|
tomtom:
|
|
13
21
|
"https://v0.maptrip.de/tiles?project=TrafficMobileTomTom_EUROPE&tilex=${x}&tiley=${y}&acao=true&context=traffic${z}&projection=wgs84",
|
|
@@ -20,3 +28,6 @@ export const MAX_ZOOM = 18;
|
|
|
20
28
|
|
|
21
29
|
export const ATTRIBUTION =
|
|
22
30
|
'© <a href="https://maptrip.de/" target="_blank">infoware GmbH</a>';
|
|
31
|
+
|
|
32
|
+
export const VECTOR_TILE_SIZE = 256;
|
|
33
|
+
export const VECTOR_TILE_RENDER_PADDING = 32;
|