@versatiles/style 5.2.6 → 5.2.7

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 (130) hide show
  1. package/dist/index.d.ts +274 -14
  2. package/dist/index.js +3650 -11
  3. package/dist/index.js.map +1 -1
  4. package/package.json +8 -8
  5. package/src/color/abstract.ts +83 -0
  6. package/src/color/hsl.test.ts +182 -0
  7. package/src/color/hsl.ts +122 -0
  8. package/src/color/hsv.test.ts +174 -0
  9. package/src/color/hsv.ts +100 -0
  10. package/src/color/index.test.ts +119 -0
  11. package/src/color/index.ts +38 -0
  12. package/src/color/random.test.ts +35 -0
  13. package/src/color/random.ts +165 -0
  14. package/src/color/rgb.test.ts +227 -0
  15. package/src/color/rgb.ts +248 -0
  16. package/src/color/utils.test.ts +86 -0
  17. package/src/color/utils.ts +13 -0
  18. package/src/guess_style/guess_style.test.ts +134 -0
  19. package/src/guess_style/guess_style.ts +166 -0
  20. package/{dist/guess_style/index.d.ts → src/guess_style/index.ts} +1 -0
  21. package/src/index.test.ts +77 -0
  22. package/src/index.ts +18 -0
  23. package/src/lib/utils.test.ts +197 -0
  24. package/src/lib/utils.ts +134 -0
  25. package/{dist/shortbread/index.d.ts → src/shortbread/index.ts} +1 -0
  26. package/src/shortbread/layers.test.ts +36 -0
  27. package/src/shortbread/layers.ts +564 -0
  28. package/src/shortbread/properties.test.ts +44 -0
  29. package/src/shortbread/properties.ts +142 -0
  30. package/src/shortbread/template.test.ts +43 -0
  31. package/src/shortbread/template.ts +343 -0
  32. package/src/style_builder/decorator.test.ts +67 -0
  33. package/src/style_builder/decorator.ts +135 -0
  34. package/src/style_builder/recolor.test.ts +306 -0
  35. package/src/style_builder/recolor.ts +110 -0
  36. package/src/style_builder/style_builder.test.ts +103 -0
  37. package/src/style_builder/style_builder.ts +134 -0
  38. package/src/style_builder/types.ts +141 -0
  39. package/src/styles/LICENSE.md +41 -0
  40. package/src/styles/colorful.ts +1041 -0
  41. package/src/styles/eclipse.ts +11 -0
  42. package/{dist/styles/empty.d.ts → src/styles/empty.ts} +7 -3
  43. package/src/styles/graybeard.ts +11 -0
  44. package/src/styles/index.ts +33 -0
  45. package/src/styles/neutrino.ts +429 -0
  46. package/{dist/types/index.d.ts → src/types/index.ts} +1 -0
  47. package/{dist/types/maplibre.d.ts → src/types/maplibre.ts} +3 -0
  48. package/src/types/tilejson.test.ts +94 -0
  49. package/src/types/tilejson.ts +125 -0
  50. package/src/types/vector_layer.test.ts +64 -0
  51. package/src/types/vector_layer.ts +69 -0
  52. package/dist/color/abstract.d.ts +0 -34
  53. package/dist/color/abstract.js +0 -53
  54. package/dist/color/abstract.js.map +0 -1
  55. package/dist/color/hsl.d.ts +0 -23
  56. package/dist/color/hsl.js +0 -98
  57. package/dist/color/hsl.js.map +0 -1
  58. package/dist/color/hsv.d.ts +0 -20
  59. package/dist/color/hsv.js +0 -100
  60. package/dist/color/hsv.js.map +0 -1
  61. package/dist/color/index.d.ts +0 -6
  62. package/dist/color/index.js +0 -29
  63. package/dist/color/index.js.map +0 -1
  64. package/dist/color/random.d.ts +0 -9
  65. package/dist/color/random.js +0 -134
  66. package/dist/color/random.js.map +0 -1
  67. package/dist/color/rgb.d.ts +0 -28
  68. package/dist/color/rgb.js +0 -195
  69. package/dist/color/rgb.js.map +0 -1
  70. package/dist/color/utils.d.ts +0 -3
  71. package/dist/color/utils.js +0 -10
  72. package/dist/color/utils.js.map +0 -1
  73. package/dist/guess_style/guess_style.d.ts +0 -8
  74. package/dist/guess_style/guess_style.js +0 -147
  75. package/dist/guess_style/guess_style.js.map +0 -1
  76. package/dist/guess_style/index.js +0 -2
  77. package/dist/guess_style/index.js.map +0 -1
  78. package/dist/lib/utils.d.ts +0 -6
  79. package/dist/lib/utils.js +0 -126
  80. package/dist/lib/utils.js.map +0 -1
  81. package/dist/shortbread/index.js +0 -3
  82. package/dist/shortbread/index.js.map +0 -1
  83. package/dist/shortbread/layers.d.ts +0 -5
  84. package/dist/shortbread/layers.js +0 -521
  85. package/dist/shortbread/layers.js.map +0 -1
  86. package/dist/shortbread/properties.d.ts +0 -7
  87. package/dist/shortbread/properties.js +0 -125
  88. package/dist/shortbread/properties.js.map +0 -1
  89. package/dist/shortbread/template.d.ts +0 -4
  90. package/dist/shortbread/template.js +0 -339
  91. package/dist/shortbread/template.js.map +0 -1
  92. package/dist/style_builder/decorator.d.ts +0 -4
  93. package/dist/style_builder/decorator.js +0 -127
  94. package/dist/style_builder/decorator.js.map +0 -1
  95. package/dist/style_builder/recolor.d.ts +0 -22
  96. package/dist/style_builder/recolor.js +0 -89
  97. package/dist/style_builder/recolor.js.map +0 -1
  98. package/dist/style_builder/style_builder.d.ts +0 -15
  99. package/dist/style_builder/style_builder.js +0 -106
  100. package/dist/style_builder/style_builder.js.map +0 -1
  101. package/dist/style_builder/types.d.ts +0 -122
  102. package/dist/style_builder/types.js +0 -3
  103. package/dist/style_builder/types.js.map +0 -1
  104. package/dist/styles/colorful.d.ts +0 -11
  105. package/dist/styles/colorful.js +0 -956
  106. package/dist/styles/colorful.js.map +0 -1
  107. package/dist/styles/eclipse.d.ts +0 -5
  108. package/dist/styles/eclipse.js +0 -9
  109. package/dist/styles/eclipse.js.map +0 -1
  110. package/dist/styles/empty.js +0 -8
  111. package/dist/styles/empty.js.map +0 -1
  112. package/dist/styles/graybeard.d.ts +0 -5
  113. package/dist/styles/graybeard.js +0 -9
  114. package/dist/styles/graybeard.js.map +0 -1
  115. package/dist/styles/index.d.ts +0 -11
  116. package/dist/styles/index.js +0 -20
  117. package/dist/styles/index.js.map +0 -1
  118. package/dist/styles/neutrino.d.ts +0 -11
  119. package/dist/styles/neutrino.js +0 -401
  120. package/dist/styles/neutrino.js.map +0 -1
  121. package/dist/types/index.js +0 -3
  122. package/dist/types/index.js.map +0 -1
  123. package/dist/types/maplibre.js +0 -2
  124. package/dist/types/maplibre.js.map +0 -1
  125. package/dist/types/tilejson.d.ts +0 -32
  126. package/dist/types/tilejson.js +0 -87
  127. package/dist/types/tilejson.js.map +0 -1
  128. package/dist/types/vector_layer.d.ts +0 -14
  129. package/dist/types/vector_layer.js +0 -51
  130. package/dist/types/vector_layer.js.map +0 -1
@@ -0,0 +1,86 @@
1
+ import { clamp, formatFloat, mod } from './utils.js';
2
+
3
+ describe('clamp function', () => {
4
+ test('returns the number itself if within the range', () => {
5
+ expect(clamp(5, 0, 10)).toBe(5);
6
+ expect(clamp(0, -10, 10)).toBe(0);
7
+ expect(clamp(-5, -10, 0)).toBe(-5);
8
+ });
9
+
10
+ test('returns the minimum value if number is below range', () => {
11
+ expect(clamp(-5, 0, 10)).toBe(0);
12
+ expect(clamp(-15, -10, 10)).toBe(-10);
13
+ });
14
+
15
+ test('returns the maximum value if number is above range', () => {
16
+ expect(clamp(15, 0, 10)).toBe(10);
17
+ expect(clamp(20, -10, 10)).toBe(10);
18
+ });
19
+
20
+ test('handles edge cases with boundaries', () => {
21
+ expect(clamp(0, 0, 10)).toBe(0);
22
+ expect(clamp(10, 0, 10)).toBe(10);
23
+ });
24
+ });
25
+
26
+ describe('mod function', () => {
27
+ test('returns the correct modulus for positive numbers', () => {
28
+ expect(mod(10, 3)).toBe(1);
29
+ expect(mod(15, 4)).toBe(3);
30
+ });
31
+
32
+ test('handles negative numbers correctly', () => {
33
+ expect(mod(-10, 3)).toBe(2);
34
+ expect(mod(-15, 4)).toBe(1);
35
+ });
36
+
37
+ test('returns 0 for numbers that are exact multiples of max', () => {
38
+ expect(mod(9, 3)).toBe(0);
39
+ expect(mod(20, 5)).toBe(0);
40
+ });
41
+
42
+ test('returns 0 for zero input with positive max', () => {
43
+ expect(mod(0, 5)).toBe(0);
44
+ });
45
+
46
+ test('handles edge cases with 1 as max', () => {
47
+ expect(mod(10, 1)).toBe(0);
48
+ expect(mod(-10, 1)).toBe(0);
49
+ });
50
+ });
51
+ describe('formatFloat function', () => {
52
+ test('formats numbers with specified precision correctly', () => {
53
+ expect(formatFloat(123.4567, 2)).toBe('123.46');
54
+ expect(formatFloat(123.4, 2)).toBe('123.4');
55
+ expect(formatFloat(123.0, 2)).toBe('123');
56
+ });
57
+
58
+ test('handles trailing zeros correctly', () => {
59
+ expect(formatFloat(0.000123, 6)).toBe('0.000123');
60
+ expect(formatFloat(0.000100, 6)).toBe('0.0001');
61
+ expect(formatFloat(10.0, 1)).toBe('10');
62
+ });
63
+
64
+ test('handles edge cases with small numbers and high precision', () => {
65
+ expect(formatFloat(0.0000001234, 10)).toBe('0.0000001234');
66
+ expect(formatFloat(0.0000001234, 5)).toBe('0');
67
+ });
68
+
69
+ test('handles large numbers correctly', () => {
70
+ expect(formatFloat(123456789.123456, 3)).toBe('123456789.123');
71
+ expect(formatFloat(123456789.0, 5)).toBe('123456789');
72
+ });
73
+
74
+ test('handles zero and negative numbers correctly', () => {
75
+ expect(formatFloat(0, 2)).toBe('0');
76
+ expect(formatFloat(-123.456, 1)).toBe('-123.5');
77
+ expect(formatFloat(-0.000123, 6)).toBe('-0.000123');
78
+ });
79
+
80
+ test('handles no unnecessary decimal points', () => {
81
+ expect(formatFloat(10.000, 3)).toBe('10');
82
+ expect(formatFloat(10.010, 3)).toBe('10.01');
83
+ });
84
+ })
85
+
86
+
@@ -0,0 +1,13 @@
1
+
2
+
3
+ export function clamp(num: number, min: number, max: number): number {
4
+ return Math.min(Math.max(min, num), max);
5
+ }
6
+
7
+ export function mod(num: number, max: number): number {
8
+ return ((num % max) + max) % max;
9
+ }
10
+
11
+ export function formatFloat(num: number, precision: number): string {
12
+ return num.toFixed(precision).replace(/0+$/, '').replace(/\.$/, '');
13
+ }
@@ -0,0 +1,134 @@
1
+
2
+ import type { TileJSONSpecification, VectorLayer } from '../types/index.js';
3
+ import { guessStyle } from './guess_style.js';
4
+ import { getShortbreadVectorLayers } from '../shortbread/template.js';
5
+ import { SourceSpecification, StyleSpecification, VectorSourceSpecification } from '@maplibre/maplibre-gl-style-spec';
6
+
7
+ describe('guessStyle', () => {
8
+ const tiles = ['https://example.com/tiles/{z}/{x}/{y}'];
9
+ const vectorLayersSomething: VectorLayer[] = [{ id: 'geometry', fields: { label: 'String', height: 'Number' } }];
10
+ const vectorLayersShortbread: VectorLayer[] = getShortbreadVectorLayers();
11
+
12
+ it('should build raster styles', () => {
13
+ expect(guessStyle({ tiles }))
14
+ .toStrictEqual({
15
+ version: 8,
16
+ sources: { rasterSource: { tiles, type: 'raster' } },
17
+ layers: [{ id: 'raster', source: 'rasterSource', type: 'raster' }],
18
+ });
19
+ });
20
+
21
+ it('should build vector inspector styles', () => {
22
+ expect(guessStyle({ tiles, vector_layers: vectorLayersSomething }))
23
+ .toStrictEqual({
24
+ version: 8,
25
+ sources: { vectorSource: { tiles, type: 'vector' } },
26
+ layers: [
27
+ {
28
+ id: 'background',
29
+ type: 'background',
30
+ paint: { 'background-color': '#fff' },
31
+ },
32
+ {
33
+ id: 'vectorSource-geometry-fill',
34
+ type: 'fill',
35
+ source: 'vectorSource',
36
+ 'source-layer': 'geometry',
37
+ filter: ['==', '$type', 'Polygon'],
38
+ paint: { 'fill-antialias': true, 'fill-color': 'hsla(7,57%,56%,0.6)', 'fill-opacity': 0.3, 'fill-outline-color': 'hsla(7,57%,56%,0.6)' },
39
+ },
40
+ {
41
+ id: 'vectorSource-geometry-line',
42
+ type: 'line',
43
+ source: 'vectorSource',
44
+ 'source-layer': 'geometry',
45
+ filter: ['==', '$type', 'LineString'],
46
+ layout: { 'line-cap': 'round', 'line-join': 'round' },
47
+ paint: { 'line-color': 'hsla(7,57%,56%,0.6)' },
48
+ },
49
+ {
50
+ id: 'vectorSource-geometry-circle',
51
+ type: 'circle',
52
+ source: 'vectorSource',
53
+ 'source-layer': 'geometry',
54
+ filter: ['==', '$type', 'Point'],
55
+ paint: { 'circle-color': 'hsla(7,57%,56%,0.6)', 'circle-radius': 2 },
56
+ },
57
+ ],
58
+ });
59
+ });
60
+
61
+ it('should build shortbread vector styles', () => {
62
+ const style = guessStyle({ tiles, vector_layers: vectorLayersShortbread }, { baseUrl: 'http://example.com' });
63
+
64
+ expect(style.layers.length).toBe(297);
65
+ style.layers = [];
66
+
67
+ expect(style).toStrictEqual({
68
+ glyphs: 'http://example.com/assets/glyphs/{fontstack}/{range}.pbf',
69
+ metadata: {
70
+ license: 'https://creativecommons.org/publicdomain/zero/1.0/',
71
+ },
72
+ name: 'versatiles-colorful',
73
+ sprite: [{ id: 'basics', url: 'http://example.com/assets/sprites/basics/sprites' }],
74
+ layers: [],
75
+ sources: {
76
+ 'versatiles-shortbread': {
77
+ attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
78
+ bounds: [-180, -85.0511287798066, 180, 85.0511287798066],
79
+ maxzoom: 14,
80
+ minzoom: 0,
81
+ scheme: 'xyz',
82
+ tiles,
83
+ type: 'vector',
84
+ },
85
+ },
86
+ version: 8,
87
+ });
88
+ });
89
+
90
+ const cases: { type: string; tilejson: TileJSONSpecification }[] = [
91
+ { type: 'image', tilejson: { tiles } },
92
+ { type: 'inspector', tilejson: { tiles, vector_layers: vectorLayersSomething } },
93
+ ];
94
+
95
+ function getSource(style: StyleSpecification): SourceSpecification {
96
+ return Object.values(style.sources)[0];
97
+ }
98
+
99
+ describe('minzoom sets minzoom', () => {
100
+ cases.forEach(({ type, tilejson }) => {
101
+ it(type, () => {
102
+ expect(getSource(guessStyle({ ...tilejson, minzoom: 5 }))).toHaveProperty('minzoom', 5);
103
+ });
104
+ });
105
+ });
106
+
107
+ describe('maxzoom sets maxzoom', () => {
108
+ cases.forEach(({ type, tilejson }) => {
109
+ it(type, () => {
110
+ expect(getSource(guessStyle({ ...tilejson, maxzoom: 5 }))).toHaveProperty('maxzoom', 5);
111
+ });
112
+ });
113
+ });
114
+
115
+ describe('absolute tile urls override baseUrl', () => {
116
+ cases.forEach(({ type, tilejson }) => {
117
+ it(type, () => {
118
+ const style = guessStyle({ ...tilejson, tiles: ['https://example1.org/tiles/{z}/{x}/{y}'] }, { baseUrl: 'https://example2.org/' });
119
+ const source = Object.values(style.sources)[0] as VectorSourceSpecification;
120
+ expect(source.tiles).toEqual(['https://example1.org/tiles/{z}/{x}/{y}']);
121
+ });
122
+ });
123
+ });
124
+
125
+ describe('relative tile urls are resolved with baseUrl', () => {
126
+ cases.forEach(({ type, tilejson }) => {
127
+ it(type, () => {
128
+ const style = guessStyle({ ...tilejson, tiles: ['./{z}/{x}/{y}'] }, { baseUrl: 'https://example2.org/tiles/' });
129
+ const source = Object.values(style.sources)[0] as VectorSourceSpecification;
130
+ expect(source.tiles).toEqual(['https://example2.org/tiles/{z}/{x}/{y}']);
131
+ });
132
+ });
133
+ });
134
+ });
@@ -0,0 +1,166 @@
1
+ import type { TileJSONSpecification, TileJSONSpecificationRaster, TileJSONSpecificationVector, VectorLayer } from '../types/index.js';
2
+ import { isTileJSONSpecification } from '../types/index.js';
3
+ import { deepClone, resolveUrl } from '../lib/utils.js';
4
+ import type { BackgroundLayerSpecification, CircleLayerSpecification, FillLayerSpecification, LineLayerSpecification, RasterSourceSpecification, SourceSpecification, SpriteSpecification, StyleSpecification, VectorSourceSpecification } from '@maplibre/maplibre-gl-style-spec';
5
+ import { colorful } from '../styles/index.js';
6
+ import { Color } from '../color/index.js';
7
+ import { isRasterTileJSONSpecification } from '../types/tilejson.js';
8
+
9
+ export interface GuessStyleOptions {
10
+ baseUrl?: string;
11
+ glyphs?: string;
12
+ sprite?: SpriteSpecification;
13
+ }
14
+
15
+ export function guessStyle(tileJSON: TileJSONSpecification, options?: GuessStyleOptions): StyleSpecification {
16
+ tileJSON = deepClone(tileJSON);
17
+
18
+ if (options && options.baseUrl) {
19
+ const { baseUrl } = options;
20
+ tileJSON.tiles = tileJSON.tiles.map(url => resolveUrl(baseUrl, url));
21
+ }
22
+
23
+ if (!isTileJSONSpecification(tileJSON)) throw Error('Invalid TileJSON specification');
24
+
25
+ let style: StyleSpecification;
26
+ if (isRasterTileJSONSpecification(tileJSON)) {
27
+ style = getRasterStyle(tileJSON);
28
+ } else {
29
+ if (isShortbread(tileJSON)) {
30
+ style = getShortbreadStyle(tileJSON, {
31
+ baseUrl: options?.baseUrl,
32
+ glyphs: options?.glyphs,
33
+ sprite: options?.sprite,
34
+ });
35
+ } else {
36
+ style = getInspectorStyle(tileJSON);
37
+ }
38
+ }
39
+
40
+ return style;
41
+ }
42
+
43
+ function isShortbread(spec: TileJSONSpecificationVector): boolean {
44
+ if (typeof spec !== 'object') return false;
45
+ if (!('vector_layers' in spec)) return false;
46
+ if (!Array.isArray(spec.vector_layers)) return false;
47
+
48
+
49
+ const layerIds = new Set(spec.vector_layers.map(l => String(l.id)));
50
+ const shortbreadIds = ['place_labels', 'boundaries', 'boundary_labels', 'addresses', 'water_lines', 'water_lines_labels', 'dam_lines', 'dam_polygons', 'pier_lines', 'pier_polygons', 'bridges', 'street_polygons', 'streets_polygons_labels', 'ferries', 'streets', 'street_labels', 'street_labels_points', 'aerialways', 'public_transport', 'buildings', 'water_polygons', 'ocean', 'water_polygons_labels', 'land', 'sites', 'pois'];
51
+ return shortbreadIds.every(id => layerIds.has(id));
52
+ }
53
+
54
+ function getShortbreadStyle(spec: TileJSONSpecificationVector, builderOption: { baseUrl?: string; glyphs?: string; sprite?: SpriteSpecification }): StyleSpecification {
55
+ return colorful({
56
+ tiles: spec.tiles,
57
+ baseUrl: builderOption.baseUrl,
58
+ glyphs: builderOption.glyphs,
59
+ sprite: builderOption.sprite,
60
+ });
61
+ }
62
+
63
+ function getInspectorStyle(spec: TileJSONSpecificationVector): StyleSpecification {
64
+ const sourceName = 'vectorSource';
65
+
66
+ const layers: {
67
+ background: BackgroundLayerSpecification[];
68
+ circle: CircleLayerSpecification[];
69
+ line: LineLayerSpecification[];
70
+ fill: FillLayerSpecification[];
71
+ } = { background: [], circle: [], line: [], fill: [] };
72
+
73
+ layers.background.push({ 'id': 'background', 'type': 'background', 'paint': { 'background-color': '#fff' } });
74
+
75
+ spec.vector_layers.forEach((vector_layer: VectorLayer) => {
76
+ let luminosity = 'bright', saturation, hue;
77
+
78
+ if (/water|ocean|lake|sea|river/.test(vector_layer.id)) hue = 'blue';
79
+ if (/state|country|place/.test(vector_layer.id)) hue = 'pink';
80
+ if (/road|highway|transport|streets/.test(vector_layer.id)) hue = 'orange';
81
+ if (/contour|building/.test(vector_layer.id)) hue = 'monochrome';
82
+ if (vector_layer.id.includes('building')) luminosity = 'dark';
83
+ if (/contour|landuse/.test(vector_layer.id)) hue = 'yellow';
84
+ if (/wood|forest|park|landcover|land/.test(vector_layer.id)) hue = 'green';
85
+
86
+ if (vector_layer.id.includes('point')) {
87
+ saturation = 'strong';
88
+ luminosity = 'light';
89
+ }
90
+
91
+ const color = Color.random({
92
+ hue,
93
+ luminosity,
94
+ saturation,
95
+ seed: vector_layer.id,
96
+ opacity: 0.6,
97
+ }).asString();
98
+
99
+ layers.circle.push({
100
+ id: `${sourceName}-${vector_layer.id}-circle`,
101
+ 'source-layer': vector_layer.id,
102
+ source: sourceName,
103
+ type: 'circle',
104
+ filter: ['==', '$type', 'Point'],
105
+ paint: { 'circle-color': color, 'circle-radius': 2 },
106
+ });
107
+
108
+ layers.line.push({
109
+ id: `${sourceName}-${vector_layer.id}-line`,
110
+ 'source-layer': vector_layer.id,
111
+ source: sourceName,
112
+ type: 'line',
113
+ filter: ['==', '$type', 'LineString'],
114
+ layout: { 'line-join': 'round', 'line-cap': 'round' },
115
+ paint: { 'line-color': color },
116
+ });
117
+
118
+ layers.fill.push({
119
+ id: `${sourceName}-${vector_layer.id}-fill`,
120
+ 'source-layer': vector_layer.id,
121
+ source: sourceName,
122
+ type: 'fill',
123
+ filter: ['==', '$type', 'Polygon'],
124
+ paint: { 'fill-color': color, 'fill-opacity': 0.3, 'fill-antialias': true, 'fill-outline-color': color },
125
+ });
126
+ });
127
+
128
+ return {
129
+ version: 8,
130
+ sources: {
131
+ [sourceName]: sourceFromSpec(spec, 'vector'),
132
+ },
133
+ layers: [
134
+ ...layers.background,
135
+ ...layers.fill,
136
+ ...layers.line,
137
+ ...layers.circle,
138
+ ],
139
+ };
140
+ }
141
+
142
+ function getRasterStyle(spec: TileJSONSpecificationRaster): StyleSpecification {
143
+ const sourceName = 'rasterSource';
144
+ return {
145
+ version: 8,
146
+ sources: {
147
+ [sourceName]: sourceFromSpec(spec, 'raster'),
148
+ },
149
+ layers: [{
150
+ id: 'raster',
151
+ type: 'raster',
152
+ source: sourceName,
153
+ }],
154
+ };
155
+ }
156
+
157
+ function sourceFromSpec(spec: TileJSONSpecification, type: 'raster' | 'vector'): SourceSpecification {
158
+ const source: RasterSourceSpecification | VectorSourceSpecification = { tiles: spec.tiles, type };
159
+
160
+ if (spec.minzoom != null) source.minzoom = spec.minzoom;
161
+ if (spec.maxzoom != null) source.maxzoom = spec.maxzoom;
162
+ if (spec.attribution != null) source.attribution = spec.attribution;
163
+ if (spec.scheme != null) source.scheme = spec.scheme;
164
+
165
+ return source;
166
+ }
@@ -1,2 +1,3 @@
1
+
1
2
  export type { GuessStyleOptions } from './guess_style.js';
2
3
  export { guessStyle } from './guess_style.js';
@@ -0,0 +1,77 @@
1
+
2
+ import { VectorSourceSpecification } from '@maplibre/maplibre-gl-style-spec';
3
+ import type { VectorLayer } from './index.js';
4
+ import { guessStyle, styles } from './index.js';
5
+
6
+ const { colorful, eclipse, graybeard, neutrino } = styles;
7
+
8
+ describe('styles', () => {
9
+ [
10
+ { name: 'colorful', builder: colorful },
11
+ { name: 'eclipse', builder: eclipse },
12
+ { name: 'graybeard', builder: graybeard },
13
+ { name: 'neutrino', builder: neutrino },
14
+ ].forEach(({ name, builder }) => {
15
+ it(`should create and test an instance of ${name}`, () => {
16
+ expect(typeof builder).toBe('function');
17
+
18
+ const style = builder({ baseUrl: 'https://example.org' });
19
+
20
+ const minSize = (name === 'empty') ? 4000 : 50000;
21
+ expect(JSON.stringify(style).length).toBeGreaterThan(minSize);
22
+
23
+ expect(style.name).toBe('versatiles-' + name);
24
+ expect(style.glyphs).toBe('https://example.org/assets/glyphs/{fontstack}/{range}.pbf');
25
+ expect(style.sprite).toStrictEqual([{ id: 'basics', url: 'https://example.org/assets/sprites/basics/sprites' }]);
26
+ expect(Object.keys(style.sources).join(',')).toBe('versatiles-shortbread');
27
+
28
+ const source = style.sources['versatiles-shortbread'] as VectorSourceSpecification;
29
+ expect(source.tiles).toEqual(['https://example.org/tiles/osm/{z}/{x}/{y}']);
30
+ });
31
+ });
32
+ });
33
+
34
+ describe('Colorful', () => {
35
+ const style = colorful({
36
+ baseUrl: 'https://dev.null',
37
+ colors: { commercial: '#f00' },
38
+ });
39
+ expect(style.glyphs).toBe('https://dev.null/assets/glyphs/{fontstack}/{range}.pbf');
40
+ const paint = style.layers.find(l => l.id === 'land-commercial')?.paint;
41
+
42
+ expect(paint).toBeDefined();
43
+ if (paint == null) throw Error();
44
+
45
+ expect(paint).toHaveProperty('fill-color');
46
+ if (!('fill-color' in paint)) throw Error();
47
+
48
+ expect(paint['fill-color']).toBe('rgb(255,0,0)');
49
+ });
50
+
51
+ describe('guessStyle', () => {
52
+ const tiles = ['https://fancy.map/tiles/{z}/{x}/{y}'];
53
+ const vector_layers: VectorLayer[] = [{ id: 'hallo', fields: { label: 'String' } }];
54
+
55
+ it('should build raster styles', () => {
56
+ const style = guessStyle({ tiles });
57
+ expect(style).toStrictEqual({
58
+ layers: [{ id: 'raster', source: 'rasterSource', type: 'raster' }],
59
+ sources: { rasterSource: { tiles, type: 'raster' } },
60
+ version: 8,
61
+ });
62
+ });
63
+
64
+ it('should build vector styles', () => {
65
+ const style = guessStyle({ tiles, vector_layers });
66
+ expect(style).toStrictEqual({
67
+ layers: [
68
+ { id: 'background', paint: { 'background-color': '#fff' }, type: 'background' },
69
+ { id: 'vectorSource-hallo-fill', filter: ['==', '$type', 'Polygon'], paint: { 'fill-antialias': true, 'fill-color': 'hsla(14,50%,52%,0.6)', 'fill-opacity': 0.3, 'fill-outline-color': 'hsla(14,50%,52%,0.6)' }, source: 'vectorSource', 'source-layer': 'hallo', type: 'fill' },
70
+ { id: 'vectorSource-hallo-line', filter: ['==', '$type', 'LineString'], layout: { 'line-cap': 'round', 'line-join': 'round' }, paint: { 'line-color': 'hsla(14,50%,52%,0.6)' }, source: 'vectorSource', 'source-layer': 'hallo', type: 'line' },
71
+ { id: 'vectorSource-hallo-circle', filter: ['==', '$type', 'Point'], paint: { 'circle-color': 'hsla(14,50%,52%,0.6)', 'circle-radius': 2 }, source: 'vectorSource', 'source-layer': 'hallo', type: 'circle' },
72
+ ],
73
+ sources: { vectorSource: { tiles, type: 'vector' } },
74
+ 'version': 8,
75
+ });
76
+ });
77
+ });
package/src/index.ts ADDED
@@ -0,0 +1,18 @@
1
+ export { colorful, eclipse, graybeard, neutrino, type StyleBuilderFunction } from './styles/index.js';
2
+ import { colorful, eclipse, graybeard, neutrino } from './styles/index.js';
3
+ export const styles = {
4
+ colorful,
5
+ eclipse,
6
+ graybeard,
7
+ neutrino,
8
+ };
9
+
10
+ export type { GuessStyleOptions } from './guess_style/index.js';
11
+ export type { RGB, HSL, HSV, RandomColorOptions } from './color/index.js';
12
+ export type { TileJSONSpecification, TileJSONSpecificationRaster, TileJSONSpecificationVector } from './types/tilejson.js';
13
+ export type { VectorLayer } from './types/index.js';
14
+ export type { StyleBuilderOptions, Language, StyleBuilderColors, StyleBuilderColorsEnsured, StyleBuilderFonts } from './style_builder/types.js';
15
+ export type { RecolorOptions } from './style_builder/recolor.js';
16
+
17
+ export { guessStyle } from './guess_style/index.js';
18
+ export { Color } from './color/index.js';