@versatiles/style 5.5.2 → 5.6.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 CHANGED
@@ -139,6 +139,10 @@ A local server will be available at <http://localhost:8080>. Use it to select a
139
139
  <!--- This chapter is generated automatically --->
140
140
 
141
141
  ```mermaid
142
+ ---
143
+ config:
144
+ layout: elk
145
+ ---
142
146
  flowchart TB
143
147
 
144
148
  subgraph 0["src"]
@@ -239,14 +243,8 @@ Y-->7
239
243
  Y-->X
240
244
  Y-->E
241
245
 
242
- style 0 fill-opacity:0.2
243
- style 1 fill-opacity:0.2
244
- style 9 fill-opacity:0.2
245
- style B fill-opacity:0.2
246
- style D fill-opacity:0.2
247
- style G fill-opacity:0.2
248
- style I fill-opacity:0.2
249
- style T fill-opacity:0.2
246
+ class 0,1,9,B,D,G,I,T subgraphs;
247
+ classDef subgraphs fill-opacity:0.1, fill:#888, color:#888, stroke:#888;
250
248
  ```
251
249
 
252
250
  ## Licenses
package/dist/index.d.ts CHANGED
@@ -21,6 +21,7 @@ declare class RGB extends Color {
21
21
  contrast(value: number): RGB;
22
22
  brightness(value: number): RGB;
23
23
  tint(value: number, tintColor: Color): RGB;
24
+ blend(value: number, blendColor: Color): RGB;
24
25
  lighten(ratio: number): RGB;
25
26
  darken(ratio: number): RGB;
26
27
  fade(value: number): RGB;
@@ -100,19 +101,115 @@ declare abstract class Color {
100
101
  lighten(value: number): RGB;
101
102
  darken(value: number): RGB;
102
103
  tint(value: number, tintColor: Color): RGB;
104
+ blend(value: number, blendColor: Color): RGB;
103
105
  setHue(value: number): HSV;
104
106
  abstract fade(value: number): Color;
105
107
  }
106
108
 
109
+ /**
110
+ * Module for applying various color transformations such as hue rotation, saturation, contrast, brightness,
111
+ * tinting, and blending. These transformations are defined through the `RecolorOptions` interface.
112
+ */
113
+
114
+ /**
115
+ * Configuration options for recoloring all map colors.
116
+ *
117
+ * The transformations (if specified) are done in the following order:
118
+ * 1. [Invert brightness](#invertbrightness)
119
+ * 2. [Rotate hue](#rotate)
120
+ * 3. [Saturate](#saturate)
121
+ * 4. [Gamma correction](#gamma)
122
+ * 5. [Contrast adjustment](#contrast)
123
+ * 6. [Brightness adjustment](#brightness)
124
+ * 7. [Tinting](#tint)
125
+ * 8. [Blending](#blend)
126
+ *
127
+ * Usage Examples
128
+ *
129
+ * ```typescript
130
+ * const style = VersaTilesStyle.colorful({
131
+ * recolor: {
132
+ * rotate: 180,
133
+ * saturate: 0.5,
134
+ * brightness: 0.2,
135
+ * }
136
+ * };
137
+ * ```
138
+ *
139
+ * If you want do make you map simply brighter or darker, you can use the `blend` option:
140
+ * ```typescript
141
+ * const style = VersaTilesStyle.colorful({
142
+ * recolor: {
143
+ * blend: 0.5,
144
+ * blendColor: '#000000', // to blend all colors with black
145
+ * // or blendColor: '#FFFFFF', // to blend all colors with white
146
+ * }
147
+ * };
148
+ * ```
149
+ *
150
+ */
107
151
  interface RecolorOptions {
152
+ /**
153
+ * If true, inverts all colors' brightness.
154
+ * See also {@link HSL.invertLuminosity}
155
+ */
108
156
  invertBrightness?: boolean;
157
+ /**
158
+ * Rotate the hue of all colors in degrees (0-360).
159
+ * See also {@link HSL.rotateHue}
160
+ */
109
161
  rotate?: number;
162
+ /**
163
+ * Adjust the saturation level. Positive values increase, negative values decrease saturation.
164
+ * |value|effect |
165
+ * |----:|-----------------|
166
+ * | -1|grayscale |
167
+ * | 0|no effect |
168
+ * | 1|double saturation|
169
+ *
170
+ * See also {@link HSL.saturate}
171
+ */
110
172
  saturate?: number;
173
+ /**
174
+ * Adjust the gamma (non-linear brightness adjustment).
175
+ * Defaults to 1.
176
+ * See also {@link RGB.gamma}
177
+ */
111
178
  gamma?: number;
179
+ /**
180
+ * Adjust the contrast level.
181
+ * Values > 1 increase contrast, values < 1 decrease it.
182
+ * Defaults to 1.
183
+ * See also {@link RGB.contrast}
184
+ */
112
185
  contrast?: number;
186
+ /**
187
+ * Adjust the brightness level.
188
+ * Positive values make it brighter, negative values make it darker.
189
+ * Defaults to 0.
190
+ * See also {@link RGB.brightness}
191
+ */
113
192
  brightness?: number;
193
+ /**
194
+ * Intensity of the tinting effect (0 = none, 1 = full effect).
195
+ * See also {@link RGB.tint}
196
+ */
114
197
  tint?: number;
198
+ /**
199
+ * The tinting color in hex format (default: '#FF0000').
200
+ * See also {@link RGB.tint}
201
+ */
115
202
  tintColor?: string;
203
+ /**
204
+ * Intensity of the blending effect (0 = none, 1 = full effect).
205
+ * See also {@link RGB.blend}
206
+ */
207
+ blend?: number;
208
+ /**
209
+ * The blending color in hex format (default: '#000000').
210
+ * See also {@link RGB.blend}
211
+ */
212
+ blendColor?: string;
116
213
  }
117
214
 
118
215
  /** Represents language suffixes used in map styles. */
package/dist/index.js CHANGED
@@ -46,16 +46,30 @@ class Color {
46
46
  tint(value, tintColor) {
47
47
  return this.toRGB().tint(value, tintColor);
48
48
  }
49
+ blend(value, blendColor) {
50
+ return this.toRGB().blend(value, blendColor);
51
+ }
49
52
  setHue(value) {
50
53
  return this.toHSV().setHue(value);
51
54
  }
52
55
  }
53
56
 
54
- function clamp(num, min, max) {
55
- return Math.min(Math.max(min, num), max);
57
+ function clamp(value, min, max) {
58
+ if (value == null || isNaN(value))
59
+ return min;
60
+ if (value < min)
61
+ return min;
62
+ if (value > max)
63
+ return max;
64
+ return value;
56
65
  }
57
- function mod(num, max) {
58
- return ((num % max) + max) % max;
66
+ function mod(value, max) {
67
+ value = value % max;
68
+ if (value < 0)
69
+ value += max;
70
+ if (value == 0)
71
+ return 0;
72
+ return value;
59
73
  }
60
74
  function formatFloat(num, precision) {
61
75
  return num.toFixed(precision).replace(/0+$/, '').replace(/\.$/, '');
@@ -240,6 +254,11 @@ class RGB extends Color {
240
254
  const rgbNew = this.setHue(tintColor.toHSV().h).toRGB();
241
255
  return new RGB(this.r * (1 - value) + value * rgbNew.r, this.g * (1 - value) + value * rgbNew.g, this.b * (1 - value) + value * rgbNew.b, this.a);
242
256
  }
257
+ blend(value, blendColor) {
258
+ value = clamp(value ?? 0, 0, 1);
259
+ const rgbNew = blendColor.toRGB();
260
+ return new RGB(this.r * (1 - value) + value * rgbNew.r, this.g * (1 - value) + value * rgbNew.g, this.b * (1 - value) + value * rgbNew.b, this.a);
261
+ }
243
262
  lighten(ratio) {
244
263
  return new RGB(clamp(255 - (255 - this.r) * (1 - ratio), 0, 255), clamp(255 - (255 - this.g) * (1 - ratio), 0, 255), clamp(255 - (255 - this.b) * (1 - ratio), 0, 255), this.a);
245
264
  }
@@ -796,7 +815,6 @@ function getShortbreadLayers(option) {
796
815
  });
797
816
  });
798
817
  // no links
799
- const noDrivewayExpression = ['!=', 'service', 'driveway'];
800
818
  ['track', 'pedestrian', 'service', 'living_street', 'residential', 'unclassified'].forEach(t => {
801
819
  results.push({
802
820
  id: prefix + 'street-' + t.replace(/_/g, '') + suffix,
@@ -805,7 +823,6 @@ function getShortbreadLayers(option) {
805
823
  filter: ['all',
806
824
  ['==', 'kind', t],
807
825
  ...filter,
808
- ...(t === 'service') ? [noDrivewayExpression] : [], // ignore driveways
809
826
  ],
810
827
  });
811
828
  });
@@ -820,7 +837,6 @@ function getShortbreadLayers(option) {
820
837
  ['==', 'kind', t],
821
838
  ['==', 'bicycle', 'designated'],
822
839
  ...filter,
823
- ...(t === 'service') ? [noDrivewayExpression] : [], // ignore driveways
824
840
  ],
825
841
  });
826
842
  });
@@ -853,8 +869,9 @@ function getShortbreadLayers(option) {
853
869
  });
854
870
  // separate outline for trains
855
871
  [':outline', ''].forEach(suffix => {
856
- // transport
857
- ['rail', 'light_rail', 'subway', 'narrow_gauge', 'tram', 'funicular', 'monorail', 'bus_guideway', 'busway'].reverse().forEach((t) => {
872
+ // with service distinction
873
+ ['rail', 'light_rail', 'subway', 'narrow_gauge', 'tram'].reverse().forEach((t) => {
874
+ // main rail
858
875
  results.push({
859
876
  id: prefix + 'transport-' + t.replace(/_/g, '') + suffix,
860
877
  type: 'line',
@@ -865,6 +882,29 @@ function getShortbreadLayers(option) {
865
882
  ...filter,
866
883
  ],
867
884
  });
885
+ // service rail (crossover, siding, spur, yard)
886
+ results.push({
887
+ id: prefix + 'transport-' + t.replace(/_/g, '') + '-service' + suffix,
888
+ type: 'line',
889
+ 'source-layer': 'streets',
890
+ filter: ['all',
891
+ ['in', 'kind', t],
892
+ ['has', 'service'],
893
+ ...filter,
894
+ ],
895
+ });
896
+ });
897
+ // other transport
898
+ ['funicular', 'monorail', 'bus_guideway', 'busway'].reverse().forEach((t) => {
899
+ results.push({
900
+ id: prefix + 'transport-' + t.replace(/_/g, '') + suffix,
901
+ type: 'line',
902
+ 'source-layer': 'streets',
903
+ filter: ['all',
904
+ ['in', 'kind', t],
905
+ ...filter,
906
+ ],
907
+ });
868
908
  });
869
909
  if (c === 'street') {
870
910
  // aerialway, no bridges, above street evel
@@ -1828,6 +1868,13 @@ function decorate(layers, rules, recolor) {
1828
1868
  }
1829
1869
  }
1830
1870
 
1871
+ /**
1872
+ * Module for applying various color transformations such as hue rotation, saturation, contrast, brightness,
1873
+ * tinting, and blending. These transformations are defined through the `RecolorOptions` interface.
1874
+ */
1875
+ /**
1876
+ * Returns the default recolor settings.
1877
+ */
1831
1878
  function getDefaultRecolorFlags() {
1832
1879
  return {
1833
1880
  invertBrightness: false,
@@ -1838,67 +1885,85 @@ function getDefaultRecolorFlags() {
1838
1885
  brightness: 0,
1839
1886
  tint: 0,
1840
1887
  tintColor: '#FF0000',
1888
+ blend: 0,
1889
+ blendColor: '#000000',
1841
1890
  };
1842
1891
  }
1892
+ /**
1893
+ * Checks if the given options object contains any active recolor transformations.
1894
+ * @param opt The recolor options to validate.
1895
+ */
1843
1896
  function isValidRecolorOptions(opt) {
1844
1897
  if (!opt)
1845
1898
  return false;
1846
- if ((opt.invertBrightness != null) && opt.invertBrightness)
1847
- return true;
1848
- if ((opt.rotate != null) && (opt.rotate !== 0))
1849
- return true;
1850
- if ((opt.saturate != null) && (opt.saturate !== 0))
1851
- return true;
1852
- if ((opt.gamma != null) && (opt.gamma !== 1))
1853
- return true;
1854
- if ((opt.contrast != null) && (opt.contrast !== 1))
1855
- return true;
1856
- if ((opt.brightness != null) && (opt.brightness !== 0))
1857
- return true;
1858
- if ((opt.tint != null) && (opt.tint !== 0))
1859
- return true;
1860
- if ((opt.tintColor != null) && (opt.tintColor !== '#FF0000'))
1861
- return true;
1862
- return false;
1899
+ return (opt.invertBrightness ||
1900
+ (opt.rotate != null && opt.rotate !== 0) ||
1901
+ (opt.saturate != null && opt.saturate !== 0) ||
1902
+ (opt.gamma != null && opt.gamma !== 1) ||
1903
+ (opt.contrast != null && opt.contrast !== 1) ||
1904
+ (opt.brightness != null && opt.brightness !== 0) ||
1905
+ (opt.tint != null && opt.tint !== 0) ||
1906
+ (opt.tintColor != null && opt.tintColor !== '#FF0000') ||
1907
+ (opt.blend != null && opt.blend !== 0) ||
1908
+ (opt.blendColor != null && opt.blendColor !== '#000000'));
1863
1909
  }
1910
+ /**
1911
+ * Caches recolored colors to optimize performance.
1912
+ */
1864
1913
  class CachedRecolor {
1865
1914
  skip;
1866
1915
  opt;
1867
1916
  cache;
1917
+ /**
1918
+ * Creates a cached recolor instance.
1919
+ * @param opt Optional recolor options.
1920
+ */
1868
1921
  constructor(opt) {
1869
1922
  this.skip = !isValidRecolorOptions(opt);
1870
1923
  this.cache = new Map();
1871
1924
  this.opt = opt;
1872
1925
  }
1926
+ /**
1927
+ * Applies cached recoloring to a given color.
1928
+ * @param color The color to recolor.
1929
+ * @returns The recolored color, either from cache or newly computed.
1930
+ */
1873
1931
  do(color) {
1874
1932
  if (this.skip)
1875
1933
  return color;
1876
1934
  const key = color.asHex();
1877
- const result = this.cache.get(key);
1878
- if (result)
1879
- return result;
1880
- color = recolor(color, this.opt);
1881
- this.cache.set(key, color);
1882
- return color;
1935
+ if (this.cache.has(key))
1936
+ return this.cache.get(key);
1937
+ const recolored = recolor(color, this.opt);
1938
+ this.cache.set(key, recolored);
1939
+ return recolored;
1883
1940
  }
1884
1941
  }
1942
+ /**
1943
+ * Applies the specified recoloring transformations to a single color.
1944
+ * @param color The original color.
1945
+ * @param opt Optional recolor options.
1946
+ * @returns A new `Color` instance with applied transformations.
1947
+ */
1885
1948
  function recolor(color, opt) {
1886
1949
  if (!isValidRecolorOptions(opt))
1887
1950
  return color;
1888
- if (opt.invertBrightness ?? false)
1951
+ if (opt.invertBrightness)
1889
1952
  color = color.invertLuminosity();
1890
- if ((opt.rotate !== undefined) && (opt.rotate !== 0))
1953
+ if (opt.rotate)
1891
1954
  color = color.rotateHue(opt.rotate);
1892
- if ((opt.saturate !== undefined) && (opt.saturate !== 0))
1955
+ if (opt.saturate)
1893
1956
  color = color.saturate(opt.saturate);
1894
- if ((opt.gamma !== undefined) && (opt.gamma !== 1))
1957
+ if (opt.gamma != null && opt.gamma != 1)
1895
1958
  color = color.gamma(opt.gamma);
1896
- if ((opt.contrast !== undefined) && (opt.contrast !== 1))
1959
+ if (opt.contrast != null && opt.contrast != 1)
1897
1960
  color = color.contrast(opt.contrast);
1898
- if ((opt.brightness !== undefined) && (opt.brightness !== 0))
1961
+ if (opt.brightness)
1899
1962
  color = color.brightness(opt.brightness);
1900
- if ((opt.tint !== undefined) && (opt.tintColor !== undefined) && (opt.tint !== 0))
1963
+ if (opt.tint && opt.tintColor != null)
1901
1964
  color = color.tint(opt.tint, Color.parse(opt.tintColor));
1965
+ if (opt.blend && opt.blendColor != null)
1966
+ color = color.blend(opt.blend, Color.parse(opt.blendColor));
1902
1967
  return color;
1903
1968
  }
1904
1969
 
@@ -2463,15 +2528,26 @@ class Colorful extends StyleBuilder {
2463
2528
  size: { 12: 1, 14: 2, 16: 5, 18: 24, 19: 60, 20: 120 },
2464
2529
  opacity: { 12: 0, 13: 1 },
2465
2530
  },
2466
- // service and tracks
2467
- '{bridge-,tunnel-,}street-{service,track}:outline': {
2531
+ // tracks
2532
+ '{bridge-,tunnel-,}street-track:outline': {
2468
2533
  size: { 14: 2, 16: 4, 18: 18, 19: 48, 20: 96 },
2469
2534
  opacity: { 14: 0, 15: 1 },
2470
2535
  },
2471
- '{bridge-,tunnel-,}street-{service,track}': {
2536
+ '{bridge-,tunnel-,}street-track': {
2472
2537
  size: { 14: 1, 16: 3, 18: 16, 19: 44, 20: 88 },
2473
2538
  opacity: { 14: 0, 15: 1 },
2474
2539
  },
2540
+ // service
2541
+ '{bridge-,tunnel-,}street-service:outline': {
2542
+ size: { 14: 1, 16: 3, 18: 12, 19: 32, 20: 48 },
2543
+ opacity: { 15: 0, 16: 1 },
2544
+ color: colors.streetbg.lighten(0.3),
2545
+ },
2546
+ '{bridge-,tunnel-,}street-service': {
2547
+ size: { 14: 1, 16: 2, 18: 10, 19: 28, 20: 40 },
2548
+ opacity: { 15: 0, 16: 1 },
2549
+ color: colors.street.darken(0.03),
2550
+ },
2475
2551
  // ways
2476
2552
  '{bridge-,tunnel-,}way-*:outline': {
2477
2553
  size: { 15: 0, 16: 5, 18: 7, 19: 12, 20: 22 },
@@ -2511,7 +2587,8 @@ class Colorful extends StyleBuilder {
2511
2587
  },
2512
2588
  // cycle streets overlay
2513
2589
  '{bridge-,tunnel-,}street-{tertiary,tertiary-link,unclassified,residential,livingstreet,pedestrian}-bicycle': {
2514
- lineCap: 'butt',
2590
+ lineJoin: 'round',
2591
+ lineCap: 'round',
2515
2592
  color: colors.cycle,
2516
2593
  },
2517
2594
  // pedestrian
@@ -2527,11 +2604,25 @@ class Colorful extends StyleBuilder {
2527
2604
  // rail, lightrail
2528
2605
  '{tunnel-,bridge-,}transport-{rail,lightrail}:outline': {
2529
2606
  color: colors.rail,
2530
- size: { 8: 1, 13: 1, 15: 3, 16: 4, 18: 8, 19: 11, 20: 14 },
2607
+ minzoom: 8,
2608
+ size: { 8: 1, 13: 1, 15: 1, 20: 14 },
2531
2609
  },
2532
2610
  '{tunnel-,bridge-,}transport-{rail,lightrail}': {
2533
2611
  color: colors.rail.lighten(0.25),
2534
- size: { 8: 1, 13: 1, 15: 2, 16: 3, 18: 6, 19: 8, 20: 10 },
2612
+ minzoom: 14,
2613
+ size: { 14: 0, 15: 1, 20: 10 },
2614
+ lineDasharray: [2, 2],
2615
+ },
2616
+ // rail-service, lightrail-service
2617
+ '{tunnel-,bridge-,}transport-{rail,lightrail}-service:outline': {
2618
+ color: colors.rail,
2619
+ minzoom: 14,
2620
+ size: { 14: 0, 15: 1, 16: 1, 20: 14 },
2621
+ },
2622
+ '{tunnel-,bridge-,}transport-{rail,lightrail}-service': {
2623
+ color: colors.rail.lighten(0.25),
2624
+ minzoom: 15,
2625
+ size: { 15: 0, 16: 1, 20: 10 },
2535
2626
  lineDasharray: [2, 2],
2536
2627
  },
2537
2628
  // subway
@@ -2707,7 +2798,7 @@ class Colorful extends StyleBuilder {
2707
2798
  'marking-oneway{-reverse,}': {
2708
2799
  minzoom: 16,
2709
2800
  image: 'basics:marking-arrow',
2710
- opacity: { 16: 0, 17: 0.7 },
2801
+ opacity: { 16: 0, 17: 0.4, 20: 0.4 },
2711
2802
  font: fonts.regular,
2712
2803
  },
2713
2804
  // TODO: bicycle and pedestrian