@versatiles/style 5.0.0 → 5.2.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.
@@ -0,0 +1,213 @@
1
+ import { HSL } from './hsl.js';
2
+ import { HSV } from './hsv.js';
3
+ import { Color } from './abstract.js';
4
+ import { clamp, formatFloat } from './utils.js';
5
+ export class RGB extends Color {
6
+ r = 0; // between 0 and 255
7
+ g = 0; // between 0 and 255
8
+ b = 0; // between 0 and 255
9
+ a = 1; // between 0 and 1
10
+ constructor(r, g, b, a = 1) {
11
+ super();
12
+ this.r = clamp(r, 0, 255);
13
+ this.g = clamp(g, 0, 255);
14
+ this.b = clamp(b, 0, 255);
15
+ this.a = clamp(a, 0, 1);
16
+ }
17
+ clone() {
18
+ return new RGB(this.r, this.g, this.b, this.a);
19
+ }
20
+ asArray() {
21
+ return [this.r, this.g, this.b, this.a];
22
+ }
23
+ asString() {
24
+ if (this.a === 1) {
25
+ return `rgb(${this.r.toFixed(0)},${this.g.toFixed(0)},${this.b.toFixed(0)})`;
26
+ }
27
+ else {
28
+ return `rgba(${this.r.toFixed(0)},${this.g.toFixed(0)},${this.b.toFixed(0)},${formatFloat(this.a, 3)})`;
29
+ }
30
+ }
31
+ asHex() {
32
+ const r = Math.round(this.r).toString(16).padStart(2, '0');
33
+ const g = Math.round(this.g).toString(16).padStart(2, '0');
34
+ const b = Math.round(this.b).toString(16).padStart(2, '0');
35
+ if (this.a === 1) {
36
+ return `#${r}${g}${b}`.toUpperCase();
37
+ }
38
+ else {
39
+ const a = Math.round(this.a * 255).toString(16).padStart(2, '0');
40
+ return `#${r}${g}${b}${a}`.toUpperCase();
41
+ }
42
+ }
43
+ asHSL() {
44
+ const r = this.r / 255;
45
+ const g = this.g / 255;
46
+ const b = this.b / 255;
47
+ const min = Math.min(r, g, b);
48
+ const max = Math.max(r, g, b);
49
+ const delta = max - min;
50
+ let h = 0;
51
+ let s = 0;
52
+ if (max === min)
53
+ h = 0;
54
+ else if (r === max)
55
+ h = (g - b) / delta;
56
+ else if (g === max)
57
+ h = 2 + (b - r) / delta;
58
+ else if (b === max)
59
+ h = 4 + (r - g) / delta;
60
+ h = Math.min(h * 60, 360);
61
+ if (h < 0)
62
+ h += 360;
63
+ const l = (min + max) / 2;
64
+ if (max === min)
65
+ s = 0;
66
+ else if (l <= 0.5)
67
+ s = delta / (max + min);
68
+ else
69
+ s = delta / (2 - max - min);
70
+ return new HSL(h, s * 100, l * 100, this.a);
71
+ }
72
+ ;
73
+ asHSV() {
74
+ const r = this.r / 255;
75
+ const g = this.g / 255;
76
+ const b = this.b / 255;
77
+ const v = Math.max(r, g, b);
78
+ const diff = v - Math.min(r, g, b);
79
+ let h = 0;
80
+ let s = 0;
81
+ if (diff !== 0) {
82
+ function diffc(c) {
83
+ return (v - c) / 6 / diff + 1 / 2;
84
+ }
85
+ ;
86
+ s = diff / v;
87
+ const rdif = diffc(r);
88
+ const gdif = diffc(g);
89
+ const bdif = diffc(b);
90
+ if (r === v)
91
+ h = bdif - gdif;
92
+ else if (g === v)
93
+ h = (1 / 3) + rdif - bdif;
94
+ else if (b === v)
95
+ h = (2 / 3) + gdif - rdif;
96
+ if (h < 0)
97
+ h += 1;
98
+ else if (h > 1)
99
+ h -= 1;
100
+ }
101
+ return new HSV(h * 360, s * 100, v * 100, this.a);
102
+ }
103
+ asRGB() {
104
+ return this.clone();
105
+ }
106
+ toRGB() {
107
+ return this;
108
+ }
109
+ static parse(str) {
110
+ str = str.toLowerCase().replaceAll(/[^0-9a-z.#,()]/g, '');
111
+ let match;
112
+ match = str.match(/^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})?$/);
113
+ if (match) {
114
+ const r = parseInt(match[1], 16);
115
+ const g = parseInt(match[2], 16);
116
+ const b = parseInt(match[3], 16);
117
+ const a = match[4] ? parseInt(match[4], 16) / 255 : 1;
118
+ return new RGB(r, g, b, a);
119
+ }
120
+ match = str.match(/^#([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])?$/);
121
+ if (match) {
122
+ const r = parseInt(match[1], 16) * 17;
123
+ const g = parseInt(match[2], 16) * 17;
124
+ const b = parseInt(match[3], 16) * 17;
125
+ const a = match[4] ? parseInt(match[4], 16) / 15 : 1;
126
+ return new RGB(r, g, b, a);
127
+ }
128
+ str = str.trim().toLowerCase().replaceAll(' ', '');
129
+ match = str.match(/^rgb\((\d+),(\d+),(\d+)\)$/);
130
+ if (match) {
131
+ const r = parseInt(match[1]);
132
+ const g = parseInt(match[2]);
133
+ const b = parseInt(match[3]);
134
+ return new RGB(r, g, b);
135
+ }
136
+ match = str.match(/^rgba\((\d+),(\d+),(\d+),([.\d]+)\)$/);
137
+ if (match) {
138
+ const r = parseInt(match[1]);
139
+ const g = parseInt(match[2]);
140
+ const b = parseInt(match[3]);
141
+ const a = parseFloat(match[4]);
142
+ return new RGB(r, g, b, a);
143
+ }
144
+ throw new Error(`Invalid RGB color string: "${str}"`);
145
+ }
146
+ gamma(value) {
147
+ if (value < 1e-3)
148
+ value = 1e-3;
149
+ if (value > 1e3)
150
+ value = 1e3;
151
+ this.r = Math.pow(this.r / 255, value) * 255;
152
+ this.g = Math.pow(this.g / 255, value) * 255;
153
+ this.b = Math.pow(this.b / 255, value) * 255;
154
+ return this;
155
+ }
156
+ invert() {
157
+ this.r = 255 - this.r;
158
+ this.g = 255 - this.g;
159
+ this.b = 255 - this.b;
160
+ return this;
161
+ }
162
+ contrast(value) {
163
+ if (value < 0)
164
+ value = 0;
165
+ if (value > 1e6)
166
+ value = 1e6;
167
+ this.r = clamp((this.r - 127.5) * value + 127.5, 0, 255);
168
+ this.g = clamp((this.g - 127.5) * value + 127.5, 0, 255);
169
+ this.b = clamp((this.b - 127.5) * value + 127.5, 0, 255);
170
+ return this;
171
+ }
172
+ brightness(value) {
173
+ if (value < -1)
174
+ value = -1;
175
+ if (value > 1)
176
+ value = 1;
177
+ const a = 1 - Math.abs(value);
178
+ const b = (value < 0) ? 0 : 255 * value;
179
+ this.r = this.r * a + b;
180
+ this.g = this.g * a + b;
181
+ this.b = this.b * a + b;
182
+ return this;
183
+ }
184
+ tint(value, tintColor) {
185
+ if (value < 0)
186
+ value = 0;
187
+ if (value > 1)
188
+ value = 1;
189
+ const hsv = this.asHSV();
190
+ hsv.h = tintColor.toHSV().h;
191
+ const rgbNew = hsv.toRGB();
192
+ rgbNew.r = this.r * (1 - value) + value * rgbNew.r;
193
+ rgbNew.g = this.g * (1 - value) + value * rgbNew.g;
194
+ rgbNew.b = this.b * (1 - value) + value * rgbNew.b;
195
+ return rgbNew;
196
+ }
197
+ lighten(ratio) {
198
+ this.r = clamp(255 - (255 - this.r) * (1 - ratio), 0, 255);
199
+ this.g = clamp(255 - (255 - this.g) * (1 - ratio), 0, 255);
200
+ this.b = clamp(255 - (255 - this.b) * (1 - ratio), 0, 255);
201
+ return this;
202
+ }
203
+ darken(ratio) {
204
+ this.r = clamp(this.r * (1 - ratio), 0, 255);
205
+ this.g = clamp(this.g * (1 - ratio), 0, 255);
206
+ this.b = clamp(this.b * (1 - ratio), 0, 255);
207
+ return this;
208
+ }
209
+ fade(value) {
210
+ this.a *= 1 - value;
211
+ return this;
212
+ }
213
+ }
@@ -0,0 +1,3 @@
1
+ export declare function clamp(num: number, min: number, max: number): number;
2
+ export declare function mod(num: number, max: number): number;
3
+ export declare function formatFloat(num: number, precision: number): string;
@@ -0,0 +1,9 @@
1
+ export function clamp(num, min, max) {
2
+ return Math.min(Math.max(min, num), max);
3
+ }
4
+ export function mod(num, max) {
5
+ return ((num % max) + max) % max;
6
+ }
7
+ export function formatFloat(num, precision) {
8
+ return num.toFixed(precision).replace(/0+$/, '').replace(/\.$/, '');
9
+ }
@@ -1,7 +1,7 @@
1
1
  import { isTileJSONSpecification, isVectorLayers } from '../types/index.js';
2
2
  import { resolveUrl } from '../lib/utils.js';
3
- import randomColorGenerator from './random_color.js';
4
3
  import { colorful } from '../styles/index.js';
4
+ import { Color } from '../color/index.js';
5
5
  export function guessStyle(opt) {
6
6
  const { format } = opt;
7
7
  const tilejsonBasic = {
@@ -131,7 +131,6 @@ function getInspectorStyle(spec) {
131
131
  const sourceName = 'vectorSource';
132
132
  const layers = { background: [], circle: [], line: [], fill: [] };
133
133
  layers.background.push({ 'id': 'background', 'type': 'background', 'paint': { 'background-color': '#fff' } });
134
- const randomColor = randomColorGenerator();
135
134
  spec.vector_layers.forEach((vector_layer) => {
136
135
  let luminosity = 'bright', saturation, hue;
137
136
  if (/water|ocean|lake|sea|river/.test(vector_layer.id))
@@ -152,13 +151,13 @@ function getInspectorStyle(spec) {
152
151
  saturation = 'strong';
153
152
  luminosity = 'light';
154
153
  }
155
- const color = randomColor({
154
+ const color = Color.random({
156
155
  hue,
157
156
  luminosity,
158
157
  saturation,
159
158
  seed: vector_layer.id,
160
159
  opacity: 0.6,
161
- });
160
+ }).asString();
162
161
  layers.circle.push({
163
162
  id: `${sourceName}-${vector_layer.id}-circle`,
164
163
  'source-layer': vector_layer.id,
package/dist/index.d.ts CHANGED
@@ -3,3 +3,4 @@ export * from './styles/index.js';
3
3
  export { guessStyle, guessStyleFromContainer } from './guess_style/index.js';
4
4
  export type { GuessStyleOptions, GuessContainerOptions } from './guess_style/index.js';
5
5
  export type { VectorLayer } from './types/index.js';
6
+ export { default as Color } from './color/index.js';
package/dist/index.js CHANGED
@@ -1,2 +1,3 @@
1
1
  export * from './styles/index.js';
2
2
  export { guessStyle, guessStyleFromContainer } from './guess_style/index.js';
3
+ export { default as Color } from './color/index.js';
package/dist/lib/utils.js CHANGED
@@ -1,4 +1,4 @@
1
- import Color from 'color';
1
+ import Color from '../color/index.js';
2
2
  // Utility function to deep clone an object
3
3
  export function deepClone(obj) {
4
4
  const type = typeof obj;
@@ -21,8 +21,7 @@ export function deepClone(obj) {
21
21
  return obj.map((e) => deepClone(e));
22
22
  }
23
23
  if (obj instanceof Color) {
24
- // @ts-expect-error: Too complicated to handle
25
- return Color(obj);
24
+ return obj.clone();
26
25
  }
27
26
  if (obj == null)
28
27
  return obj;
@@ -83,7 +82,7 @@ export function deepMerge(source0, ...sources) {
83
82
  }
84
83
  if (sourceValue instanceof Color) {
85
84
  // @ts-expect-error: Too complicated to handle
86
- target[key] = Color(sourceValue);
85
+ target[key] = sourceValue.clone();
87
86
  continue;
88
87
  }
89
88
  if (isSimpleObject(target[key]) && isSimpleObject(sourceValue)) {
@@ -110,29 +110,40 @@ export function getShortbreadLayers(option) {
110
110
  ...['tunnel', 'street', 'bridge'].flatMap((c) => {
111
111
  let filter;
112
112
  let prefix;
113
+ let suffixes = [];
113
114
  const results = [];
114
115
  switch (c) {
115
116
  case 'tunnel':
116
117
  filter = [['==', 'tunnel', true]];
117
118
  prefix = 'tunnel-';
119
+ suffixes = [':outline', ''];
118
120
  break;
119
121
  case 'street':
120
122
  filter = [['!=', 'bridge', true], ['!=', 'tunnel', true]];
121
123
  prefix = '';
124
+ suffixes = [':outline', ''];
122
125
  break;
123
126
  case 'bridge':
124
127
  filter = [['==', 'bridge', true]];
125
128
  prefix = 'bridge-';
129
+ suffixes = [':bridge', ':outline', ''];
126
130
  break;
127
131
  }
128
- // bridges, above street, below bridge
129
- if (c === 'bridge')
132
+ // in osm data streets on bridges are often not tagged as such
133
+ // to be able to have multiple levels of bridges cross over each
134
+ // other in the right order without using a secondary property.
135
+ // this results in bridge-polygons being rendered above streets.
136
+ // therefore bridge polygons are *under* surface streets here.
137
+ // this workaround is also wrong, but everyone is using it since
138
+ // it's simpler than removing all these tagging hacks from osm.
139
+ // bridges, above tunnel, below street
140
+ if (c === 'street')
130
141
  results.push({
131
142
  id: 'bridge',
132
143
  type: 'fill',
133
144
  'source-layer': 'bridges',
134
145
  });
135
- [':outline', ''].forEach(suffix => {
146
+ suffixes.forEach(suffix => {
136
147
  // pedestrian zone — no outline
137
148
  if (suffix === ':outline')
138
149
  results.push({
@@ -1,4 +1,4 @@
1
1
  import type { MaplibreLayer } from '../types/index.js';
2
2
  import type { StyleRules } from './types.js';
3
- import type { CachedRecolor } from './recolor.ts';
3
+ import type { CachedRecolor } from './recolor.js';
4
4
  export declare function decorate(layers: MaplibreLayer[], rules: StyleRules, recolor: CachedRecolor): MaplibreLayer[];
@@ -1,4 +1,4 @@
1
- import Color from 'color';
1
+ import Color from '../color/index.js';
2
2
  import expandBraces from 'brace-expansion';
3
3
  import maplibreProperties from '../shortbread/properties.js';
4
4
  import { deepMerge } from '../lib/utils.js';
@@ -93,11 +93,10 @@ export function decorate(layers, rules, recolor) {
93
93
  }
94
94
  function processColor(value) {
95
95
  if (typeof value === 'string')
96
- value = Color(value);
96
+ value = Color.parse(value);
97
97
  if (value instanceof Color) {
98
98
  const color = recolor.do(value);
99
- const text = (color.alpha() === 1) ? color.hex() : color.string();
100
- return text.toLowerCase();
99
+ return color.asString();
101
100
  }
102
101
  throw new Error(`unknown color type "${typeof value}"`);
103
102
  }
@@ -1,4 +1,4 @@
1
- import Color from 'color';
1
+ import Color from '../color/index.js';
2
2
  export interface RecolorOptions {
3
3
  invertBrightness?: boolean;
4
4
  rotate?: number;
@@ -11,6 +11,7 @@ export interface RecolorOptions {
11
11
  }
12
12
  export declare function getDefaultRecolorFlags(): RecolorOptions;
13
13
  export declare function recolorObject(colors: Record<string, Color>, opt?: RecolorOptions): void;
14
+ export declare function recolorArray(colors: Color[], opt?: RecolorOptions): void;
14
15
  export declare class CachedRecolor {
15
16
  private readonly skip;
16
17
  private readonly opt?;
@@ -1,4 +1,4 @@
1
- import Color from 'color';
1
+ import Color from '../color/index.js';
2
2
  export function getDefaultRecolorFlags() {
3
3
  return {
4
4
  invertBrightness: false,
@@ -39,6 +39,13 @@ export function recolorObject(colors, opt) {
39
39
  colors[k] = recolor(c, opt);
40
40
  }
41
41
  }
42
+ export function recolorArray(colors, opt) {
43
+ if (!isValidRecolorOptions(opt))
44
+ return;
45
+ for (let i = 0; i < colors.length; i++) {
46
+ colors[i] = recolor(colors[i], opt);
47
+ }
48
+ }
42
49
  export class CachedRecolor {
43
50
  skip;
44
51
  opt;
@@ -51,7 +58,7 @@ export class CachedRecolor {
51
58
  do(color) {
52
59
  if (this.skip)
53
60
  return color;
54
- const key = color.string();
61
+ const key = color.asHex();
55
62
  const result = this.cache.get(key);
56
63
  if (result)
57
64
  return result;
@@ -64,59 +71,18 @@ export function recolor(color, opt) {
64
71
  if (!isValidRecolorOptions(opt))
65
72
  return color;
66
73
  if (opt.invertBrightness ?? false)
67
- color = invert(color);
74
+ color = color.invertLuminosity();
68
75
  if ((opt.rotate !== undefined) && (opt.rotate !== 0))
69
- color = color.rotate(opt.rotate);
76
+ color = color.rotateHue(opt.rotate);
70
77
  if ((opt.saturate !== undefined) && (opt.saturate !== 0))
71
78
  color = color.saturate(opt.saturate);
72
79
  if ((opt.gamma !== undefined) && (opt.gamma !== 1))
73
- color = gamma(color, opt.gamma);
80
+ color = color.gamma(opt.gamma);
74
81
  if ((opt.contrast !== undefined) && (opt.contrast !== 1))
75
- color = contrast(color, opt.contrast);
82
+ color = color.contrast(opt.contrast);
76
83
  if ((opt.brightness !== undefined) && (opt.brightness !== 0))
77
- color = brightness(color, opt.brightness);
84
+ color = color.brightness(opt.brightness);
78
85
  if ((opt.tint !== undefined) && (opt.tintColor !== undefined) && (opt.tint !== 0))
79
- color = tint(color, opt.tint, Color(opt.tintColor));
86
+ color = color.tint(opt.tint, Color.parse(opt.tintColor));
80
87
  return color;
81
- function invert(c) {
82
- c = c.hsl();
83
- return c.lightness(100 - c.lightness()).rgb();
84
- }
85
- function gamma(c, value) {
86
- if (value < 1e-3)
87
- value = 1e-3;
88
- if (value > 1e3)
89
- value = 1e3;
90
- const rgb = c.rgb().array();
91
- return Color.rgb(Math.pow(rgb[0] / 255, value) * 255, Math.pow(rgb[1] / 255, value) * 255, Math.pow(rgb[2] / 255, value) * 255, c.alpha());
92
- }
93
- function contrast(c, value) {
94
- if (value < 0)
95
- value = 0;
96
- if (value > 1e6)
97
- value = 1e6;
98
- const rgb = c.rgb().array();
99
- return Color.rgb((rgb[0] - 127.5) * value + 127.5, (rgb[1] - 127.5) * value + 127.5, (rgb[2] - 127.5) * value + 127.5, c.alpha());
100
- }
101
- function brightness(c, value) {
102
- if (value < -1e6)
103
- value = -1e6;
104
- if (value > 1e6)
105
- value = 1e6;
106
- const a = 1 - Math.abs(value);
107
- const b = (value < 0) ? 0 : 255 * value;
108
- const rgb = c.rgb().array();
109
- return Color.rgb(rgb[0] * a + b, rgb[1] * a + b, rgb[2] * a + b, c.alpha());
110
- }
111
- function tint(c, value, tintColor) {
112
- if (value < 0)
113
- value = 0;
114
- if (value > 1)
115
- value = 1;
116
- const rgb0 = c.rgb().array();
117
- const hsv = c.hsv().array();
118
- hsv[0] = tintColor.hue();
119
- const rgbNew = Color.hsv(hsv).rgb().array();
120
- return Color.rgb(rgb0[0] * (1 - value) + value * rgbNew[0], rgb0[1] * (1 - value) + value * rgbNew[1], rgb0[2] * (1 - value) + value * rgbNew[2], c.alpha());
121
- }
122
88
  }
@@ -1,4 +1,4 @@
1
- import Color from 'color';
1
+ import Color from '../color/index.js';
2
2
  import type { MaplibreStyle } from '../types/maplibre.js';
3
3
  import type { StyleBuilderColorStrings, StyleBuilderColors, StyleBuilderFontStrings, StyleBuilderOptions } from './types.js';
4
4
  import type { StyleRules, StyleRulesOptions } from './types.js';
@@ -1,4 +1,4 @@
1
- import Color from 'color';
1
+ import Color from '../color/index.js';
2
2
  import { getShortbreadTemplate, getShortbreadLayers } from '../shortbread/index.js';
3
3
  import { decorate } from './decorator.js';
4
4
  import { CachedRecolor, getDefaultRecolorFlags } from './recolor.js';
@@ -17,8 +17,11 @@ export default class StyleBuilder {
17
17
  const recolorOptions = options.recolor ?? getDefaultRecolorFlags();
18
18
  const colors = this.getColors(this.defaultColors);
19
19
  if (options.colors) {
20
- for (const key in options.colors)
21
- colors[key] = Color(options.colors[key]);
20
+ for (const key in options.colors) {
21
+ const value = options.colors[key];
22
+ if (value != null)
23
+ colors[key] = Color.parse(value);
24
+ }
22
25
  }
23
26
  const fonts = deepClone(this.defaultFonts);
24
27
  if (options.fonts) {
@@ -74,7 +77,7 @@ export default class StyleBuilder {
74
77
  }
75
78
  getColors(colors) {
76
79
  const entriesString = Object.entries(colors);
77
- const entriesColor = entriesString.map(([key, value]) => [key, Color(value)]);
80
+ const entriesColor = entriesString.map(([key, value]) => [key, Color.parse(value)]);
78
81
  const result = Object.fromEntries(entriesColor);
79
82
  return result;
80
83
  }
@@ -94,7 +97,7 @@ export default class StyleBuilder {
94
97
  transformDefaultColors(callback) {
95
98
  const colors = this.getColors(this.defaultColors);
96
99
  for (const key in colors) {
97
- this.defaultColors[key] = callback(colors[key]).hexa();
100
+ this.defaultColors[key] = callback(colors[key]).asHex();
98
101
  }
99
102
  }
100
103
  }
@@ -1,4 +1,4 @@
1
- import type Color from 'color';
1
+ import type Color from '../color/index.js';
2
2
  import type StyleBuilder from './style_builder.js';
3
3
  import type { RecolorOptions } from './recolor.js';
4
4
  /** Represents language suffixes used in map styles. */
@@ -317,6 +317,47 @@ export default class Colorful extends StyleBuilder {
317
317
  'bridge-{street,way}-*:outline': {
318
318
  lineCap: 'butt',
319
319
  },
320
+ // faux bridges
321
+ 'bridge-{street,way}-*:bridge': {
322
+ lineCap: 'butt',
323
+ lineJoin: 'round',
324
+ color: colors.land.darken(0.02),
325
+ fillAntialias: true,
326
+ opacity: 0.5,
327
+ },
328
+ 'bridge-street-motorway:bridge': {
329
+ size: { '5': 0, '6': 3, '10': 7, '14': 7, '16': 20, '18': 53, '19': 118, '20': 235 }
330
+ },
331
+ 'bridge-street-trunk:bridge': {
332
+ size: { '7': 0, '8': 3, '10': 6, '14': 8, '16': 17, '18': 50, '19': 104, '20': 202 }
333
+ },
334
+ 'bridge-street-primary:bridge': {
335
+ size: { '8': 0, '9': 1, '10': 6, '14': 8, '16': 17, '18': 50, '19': 104, '20': 202 }
336
+ },
337
+ 'bridge-street-secondary:bridge': {
338
+ size: { '11': 3, '14': 7, '16': 11, '18': 42, '19': 95, '20': 193 },
339
+ opacity: { '11': 0, '12': 1 }
340
+ },
341
+ 'bridge-street-motorway-link:bridge': {
342
+ minzoom: 12,
343
+ size: { '12': 3, '14': 4, '16': 10, '18': 20, '20': 56 }
344
+ },
345
+ 'bridge-street-{trunk,primary,secondary}-link:bridge': {
346
+ minzoom: 13,
347
+ size: { '12': 3, '14': 4, '16': 10, '18': 20, '20': 56 }
348
+ },
349
+ 'bridge-street-{tertiary,tertiary-link,unclassified,residential,livingstreet,pedestrian}*:bridge': {
350
+ size: { '12': 3, '14': 4, '16': 8, '18': 36, '19': 90, '20': 179 },
351
+ opacity: { '12': 0, '13': 1 }
352
+ },
353
+ 'bridge-street-{service,track}:bridge': {
354
+ size: { '14': 3, '16': 6, '18': 25, '19': 67, '20': 134 },
355
+ opacity: { '14': 0, '15': 1 }
356
+ },
357
+ 'bridge-way-*:bridge': {
358
+ size: { '15': 0, '16': 7, '18': 10, '19': 17, '20': 31 },
359
+ minzoom: 15
360
+ },
320
361
  // special color: motorway
321
362
  '{bridge-,}street-motorway{-link,}:outline': {
322
363
  color: colors.motorwaybg,
@@ -435,10 +476,10 @@ export default class Colorful extends StyleBuilder {
435
476
  color: colors.foot.lighten(0.02),
436
477
  },
437
478
  'tunnel-way-{footway,path,steps}:outline': {
438
- color: colors.foot.darken(0.1).desaturate(0.5),
479
+ color: colors.foot.darken(0.1).saturate(-0.5),
439
480
  },
440
481
  'tunnel-way-{footway,path,steps}': {
441
- color: colors.foot.darken(0.02).desaturate(0.5),
482
+ color: colors.foot.darken(0.02).saturate(-0.5),
442
483
  lineDasharray: [1, 0.2],
443
484
  },
444
485
  // cycleway
@@ -449,10 +490,10 @@ export default class Colorful extends StyleBuilder {
449
490
  color: colors.cycle,
450
491
  },
451
492
  'tunnel-way-cycleway:outline': {
452
- color: colors.cycle.darken(0.1).desaturate(0.5),
493
+ color: colors.cycle.darken(0.1).saturate(-0.5),
453
494
  },
454
495
  'tunnel-way-cycleway': {
455
- color: colors.cycle.darken(0.02).desaturate(0.5),
496
+ color: colors.cycle.darken(0.02).saturate(-0.5),
456
497
  lineDasharray: [1, 0.2],
457
498
  },
458
499
  // cycle streets overlay
@@ -567,7 +608,7 @@ export default class Colorful extends StyleBuilder {
567
608
  size: { 5: 8, 8: 12 },
568
609
  },
569
610
  'label-place-*': {
570
- color: colors.label.rotate(-15).saturate(1).darken(0.05),
611
+ color: colors.label.rotateHue(-15).saturate(1).darken(0.05),
571
612
  font: fonts.regular,
572
613
  textHaloColor: colors.labelHalo,
573
614
  textHaloWidth: 2,
@@ -602,19 +643,19 @@ export default class Colorful extends StyleBuilder {
602
643
  minzoom: 11,
603
644
  size: { 11: 11, 13: 14 },
604
645
  textTransform: 'uppercase',
605
- color: colors.label.rotate(-30).saturate(1).darken(0.05),
646
+ color: colors.label.rotateHue(-30).saturate(1).darken(0.05),
606
647
  },
607
648
  'label-place-quarter': {
608
649
  minzoom: 13,
609
650
  size: { 13: 13 },
610
651
  textTransform: 'uppercase',
611
- color: colors.label.rotate(-40).saturate(1).darken(0.05),
652
+ color: colors.label.rotateHue(-40).saturate(1).darken(0.05),
612
653
  },
613
654
  'label-place-neighbourhood': {
614
655
  minzoom: 14,
615
656
  size: { 14: 12 },
616
657
  textTransform: 'uppercase',
617
- color: colors.label.rotate(-50).saturate(1).darken(0.05),
658
+ color: colors.label.rotateHue(-50).saturate(1).darken(0.05),
618
659
  },
619
660
  'label-motorway-shield': {
620
661
  color: colors.shield,
@@ -3,9 +3,6 @@ export default class Eclipse extends Colorful {
3
3
  name = 'Eclipse';
4
4
  constructor() {
5
5
  super();
6
- this.transformDefaultColors(color => {
7
- color = color.hsl();
8
- return color.lightness(100 - color.lightness()).rgb();
9
- });
6
+ this.transformDefaultColors(color => color.invertLuminosity());
10
7
  }
11
8
  }
@@ -3,6 +3,6 @@ export default class Graybeard extends Colorful {
3
3
  name = 'Graybeard';
4
4
  constructor() {
5
5
  super();
6
- this.transformDefaultColors(color => color.desaturate(1));
6
+ this.transformDefaultColors(color => color.saturate(-1));
7
7
  }
8
8
  }