ol 7.5.1 → 8.0.0-dev.1692053484481

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 (135) hide show
  1. package/DataTile.d.ts +2 -2
  2. package/DataTile.d.ts.map +1 -1
  3. package/DataTile.js +3 -2
  4. package/Image.d.ts +139 -40
  5. package/Image.d.ts.map +1 -1
  6. package/Image.js +194 -96
  7. package/ImageCanvas.d.ts +2 -2
  8. package/ImageCanvas.d.ts.map +1 -1
  9. package/ImageCanvas.js +2 -2
  10. package/Object.d.ts +7 -0
  11. package/Object.d.ts.map +1 -1
  12. package/Object.js +8 -0
  13. package/dist/ol.js +2 -2
  14. package/dist/ol.js.map +1 -1
  15. package/expr/cpu.d.ts +71 -0
  16. package/expr/cpu.d.ts.map +1 -0
  17. package/expr/cpu.js +312 -0
  18. package/expr/expression.d.ts +97 -0
  19. package/expr/expression.d.ts.map +1 -0
  20. package/expr/expression.js +373 -0
  21. package/has.d.ts +5 -0
  22. package/has.d.ts.map +1 -1
  23. package/has.js +6 -0
  24. package/index.d.ts +1 -2
  25. package/index.js +1 -1
  26. package/layer/Base.d.ts +12 -8
  27. package/layer/Base.d.ts.map +1 -1
  28. package/layer/Base.js +12 -8
  29. package/layer/BaseVector.d.ts.map +1 -1
  30. package/layer/BaseVector.js +67 -33
  31. package/layer/Heatmap.d.ts.map +1 -1
  32. package/layer/Heatmap.js +16 -55
  33. package/layer/Layer.d.ts +2 -2
  34. package/layer/Layer.d.ts.map +1 -1
  35. package/layer/Layer.js +1 -1
  36. package/layer/WebGLPoints.d.ts +7 -12
  37. package/layer/WebGLPoints.d.ts.map +1 -1
  38. package/layer/WebGLPoints.js +7 -12
  39. package/package.json +1 -1
  40. package/render/Feature.d.ts +8 -0
  41. package/render/Feature.d.ts.map +1 -1
  42. package/render/Feature.js +9 -0
  43. package/render/canvas/Immediate.d.ts.map +1 -1
  44. package/render/canvas/Immediate.js +5 -3
  45. package/render/canvas/TextBuilder.js +2 -2
  46. package/render/canvas/style.d.ts +69 -0
  47. package/render/canvas/style.d.ts.map +1 -0
  48. package/render/canvas/style.js +1192 -0
  49. package/render/canvas.js +1 -1
  50. package/render/webgl/VectorStyleRenderer.d.ts.map +1 -1
  51. package/render/webgl/VectorStyleRenderer.js +4 -0
  52. package/renderer/Layer.d.ts +2 -2
  53. package/renderer/Layer.d.ts.map +1 -1
  54. package/renderer/Layer.js +1 -1
  55. package/renderer/canvas/ImageLayer.d.ts +4 -4
  56. package/renderer/canvas/ImageLayer.d.ts.map +1 -1
  57. package/renderer/canvas/ImageLayer.js +17 -12
  58. package/renderer/canvas/Layer.d.ts +2 -2
  59. package/renderer/canvas/Layer.d.ts.map +1 -1
  60. package/renderer/canvas/Layer.js +1 -1
  61. package/renderer/canvas/VectorImageLayer.d.ts.map +1 -1
  62. package/renderer/canvas/VectorImageLayer.js +3 -2
  63. package/renderer/webgl/VectorLayer.d.ts +1 -2
  64. package/renderer/webgl/VectorLayer.d.ts.map +1 -1
  65. package/reproj/Image.d.ts +5 -5
  66. package/reproj/Image.d.ts.map +1 -1
  67. package/reproj/Image.js +6 -6
  68. package/reproj.d.ts +2 -2
  69. package/reproj.d.ts.map +1 -1
  70. package/reproj.js +1 -1
  71. package/resolution.d.ts +13 -0
  72. package/resolution.d.ts.map +1 -0
  73. package/resolution.js +18 -0
  74. package/source/Image.d.ts +44 -7
  75. package/source/Image.d.ts.map +1 -1
  76. package/source/Image.js +97 -8
  77. package/source/ImageArcGISRest.d.ts +0 -23
  78. package/source/ImageArcGISRest.d.ts.map +1 -1
  79. package/source/ImageArcGISRest.js +18 -120
  80. package/source/ImageMapGuide.d.ts +0 -24
  81. package/source/ImageMapGuide.d.ts.map +1 -1
  82. package/source/ImageMapGuide.js +21 -113
  83. package/source/ImageStatic.d.ts +2 -27
  84. package/source/ImageStatic.d.ts.map +1 -1
  85. package/source/ImageStatic.js +20 -70
  86. package/source/ImageWMS.d.ts +2 -46
  87. package/source/ImageWMS.d.ts.map +1 -1
  88. package/source/ImageWMS.js +43 -201
  89. package/source/{Stamen.d.ts → StadiaMaps.d.ts} +17 -7
  90. package/source/StadiaMaps.d.ts.map +1 -0
  91. package/source/{Stamen.js → StadiaMaps.js} +85 -38
  92. package/source/TileArcGISRest.d.ts.map +1 -1
  93. package/source/TileArcGISRest.js +11 -22
  94. package/source/TileWMS.d.ts +0 -1
  95. package/source/TileWMS.d.ts.map +1 -1
  96. package/source/TileWMS.js +43 -106
  97. package/source/arcgisRest.d.ts +88 -0
  98. package/source/arcgisRest.d.ts.map +1 -0
  99. package/source/arcgisRest.js +131 -0
  100. package/source/common.d.ts +5 -0
  101. package/source/common.d.ts.map +1 -1
  102. package/source/common.js +6 -0
  103. package/source/mapguide.d.ts +52 -0
  104. package/source/mapguide.d.ts.map +1 -0
  105. package/source/mapguide.js +116 -0
  106. package/source/static.d.ts +45 -0
  107. package/source/static.d.ts.map +1 -0
  108. package/source/static.js +44 -0
  109. package/source/wms.d.ts +109 -1
  110. package/source/wms.d.ts.map +1 -1
  111. package/source/wms.js +170 -0
  112. package/source.d.ts +5 -1
  113. package/source.d.ts.map +1 -1
  114. package/source.js +5 -1
  115. package/style/flat.d.ts +332 -173
  116. package/style/flat.d.ts.map +1 -1
  117. package/style/flat.js +176 -248
  118. package/style/literal.d.ts +27 -72
  119. package/style/literal.d.ts.map +1 -1
  120. package/style/literal.js +14 -35
  121. package/util.d.ts.map +1 -1
  122. package/util.js +1 -1
  123. package/webgl/Helper.d.ts +7 -2
  124. package/webgl/Helper.d.ts.map +1 -1
  125. package/webgl/Helper.js +16 -27
  126. package/webgl/ShaderBuilder.d.ts +4 -14
  127. package/webgl/ShaderBuilder.d.ts.map +1 -1
  128. package/webgl/ShaderBuilder.js +72 -72
  129. package/webgl/styleparser.d.ts +3 -9
  130. package/webgl/styleparser.d.ts.map +1 -1
  131. package/webgl/styleparser.js +503 -88
  132. package/ImageBase.d.ts +0 -65
  133. package/ImageBase.d.ts.map +0 -1
  134. package/ImageBase.js +0 -98
  135. package/source/Stamen.d.ts.map +0 -1
@@ -0,0 +1,1192 @@
1
+ /**
2
+ * @module ol/render/canvas/style
3
+ */
4
+
5
+ import Circle from '../../style/Circle.js';
6
+ import Fill from '../../style/Fill.js';
7
+ import Icon from '../../style/Icon.js';
8
+ import RegularShape from '../../style/RegularShape.js';
9
+ import Stroke from '../../style/Stroke.js';
10
+ import Style from '../../style/Style.js';
11
+ import Text from '../../style/Text.js';
12
+ import {
13
+ BooleanType,
14
+ ColorType,
15
+ NumberArrayType,
16
+ NumberType,
17
+ StringType,
18
+ newParsingContext,
19
+ } from '../../expr/expression.js';
20
+ import {buildExpression, newEvaluationContext} from '../../expr/cpu.js';
21
+ import {toSize} from '../../size.js';
22
+
23
+ /**
24
+ * @fileoverview This module includes functions to build styles for the canvas renderer. Building
25
+ * is composed of two steps: parsing and compiling. The parsing step takes an encoded expression
26
+ * and returns an instance of one of the expression classes. The compiling step takes the
27
+ * expression instance and returns a function that can be evaluated to return a literal value. The
28
+ * evaluator function should do as little allocation and work as possible.
29
+ */
30
+
31
+ /**
32
+ * @typedef {import("../../style/flat.js").FlatStyle} FlatStyle
33
+ */
34
+
35
+ /**
36
+ * @typedef {import("../../expr/expression.js").EncodedExpression} EncodedExpression
37
+ */
38
+
39
+ /**
40
+ * @typedef {import("../../expr/expression.js").ParsingContext} ParsingContext
41
+ */
42
+
43
+ /**
44
+ * @typedef {import("../../expr/expression.js").CallExpression} CallExpression
45
+ */
46
+
47
+ /**
48
+ * @typedef {import("../../expr/cpu.js").EvaluationContext} EvaluationContext
49
+ */
50
+
51
+ /**
52
+ * @typedef {import("../../expr/cpu.js").ExpressionEvaluator} ExpressionEvaluator
53
+ */
54
+
55
+ /**
56
+ * @param {EvaluationContext} context The evaluation context.
57
+ * @return {boolean} Always true.
58
+ */
59
+ function always(context) {
60
+ return true;
61
+ }
62
+
63
+ /**
64
+ * This function adapts a rule evaluator to the existing style function interface.
65
+ * After we have deprecated the style function, we can use the compiled rules directly
66
+ * and pass a more complete evaluation context (variables, zoom, time, etc.).
67
+ *
68
+ * @param {Array<import('../../style/flat.js').Rule>} rules The rules.
69
+ * @return {import('../../style/Style.js').StyleFunction} A style function.
70
+ */
71
+ export function rulesToStyleFunction(rules) {
72
+ const parsingContext = newParsingContext();
73
+ const evaluator = buildRuleSet(rules, parsingContext);
74
+ const evaluationContext = newEvaluationContext();
75
+ return function (feature, resolution) {
76
+ evaluationContext.properties = feature.getPropertiesInternal();
77
+ evaluationContext.resolution = resolution;
78
+ return evaluator(evaluationContext);
79
+ };
80
+ }
81
+
82
+ /**
83
+ * This function adapts a style evaluator to the existing style function interface.
84
+ * After we have deprecated the style function, we can use the compiled rules directly
85
+ * and pass a more complete evaluation context (variables, zoom, time, etc.).
86
+ *
87
+ * @param {Array<import('../../style/flat.js').FlatStyle>} flatStyles The flat styles.
88
+ * @return {import('../../style/Style.js').StyleFunction} A style function.
89
+ */
90
+ export function flatStylesToStyleFunction(flatStyles) {
91
+ const parsingContext = newParsingContext();
92
+ const length = flatStyles.length;
93
+
94
+ /**
95
+ * @type {Array<StyleEvaluator>}
96
+ */
97
+ const evaluators = new Array(length);
98
+ for (let i = 0; i < length; ++i) {
99
+ evaluators[i] = buildStyle(flatStyles[i], parsingContext);
100
+ }
101
+ const evaluationContext = newEvaluationContext();
102
+
103
+ /**
104
+ * @type {Array<Style>}
105
+ */
106
+ const styles = new Array(length);
107
+
108
+ return function (feature, resolution) {
109
+ evaluationContext.properties = feature.getPropertiesInternal();
110
+ evaluationContext.resolution = resolution;
111
+ for (let i = 0; i < length; ++i) {
112
+ styles[i] = evaluators[i](evaluationContext);
113
+ }
114
+ return styles;
115
+ };
116
+ }
117
+
118
+ /**
119
+ * @typedef {function(EvaluationContext):Array<Style>} RuleSetEvaluator
120
+ */
121
+
122
+ /**
123
+ * @typedef {Object} CompiledRule
124
+ * @property {ExpressionEvaluator} filter The compiled filter evaluator.
125
+ * @property {Array<StyleEvaluator>} styles The list of compiled style evaluators.
126
+ */
127
+
128
+ /**
129
+ * @param {Array<import('../../style/flat.js').Rule>} rules The rules.
130
+ * @param {ParsingContext} context The parsing context.
131
+ * @return {RuleSetEvaluator} The evaluator function.
132
+ */
133
+ export function buildRuleSet(rules, context) {
134
+ const length = rules.length;
135
+
136
+ /**
137
+ * @type {Array<CompiledRule>}
138
+ */
139
+ const compiledRules = new Array(length);
140
+
141
+ for (let i = 0; i < length; ++i) {
142
+ const rule = rules[i];
143
+ const filter =
144
+ 'filter' in rule
145
+ ? buildExpression(rule.filter, BooleanType, context)
146
+ : always;
147
+
148
+ /**
149
+ * @type {Array<StyleEvaluator>}
150
+ */
151
+ let styles;
152
+ if (Array.isArray(rule.style)) {
153
+ const styleLength = rule.style.length;
154
+ styles = new Array(styleLength);
155
+ for (let j = 0; j < styleLength; ++j) {
156
+ styles[j] = buildStyle(rule.style[j], context);
157
+ }
158
+ } else {
159
+ styles = [buildStyle(rule.style, context)];
160
+ }
161
+
162
+ compiledRules[i] = {filter, styles};
163
+ }
164
+
165
+ return function (context) {
166
+ /**
167
+ * @type {Array<Style>}
168
+ */
169
+ const styles = [];
170
+
171
+ let someMatched = false;
172
+ for (let i = 0; i < length; ++i) {
173
+ const filterEvaluator = compiledRules[i].filter;
174
+ if (!filterEvaluator(context)) {
175
+ continue;
176
+ }
177
+ if (rules[i].else && someMatched) {
178
+ continue;
179
+ }
180
+ someMatched = true;
181
+ for (const styleEvaluator of compiledRules[i].styles) {
182
+ styles.push(styleEvaluator(context));
183
+ }
184
+ }
185
+
186
+ return styles;
187
+ };
188
+ }
189
+
190
+ /**
191
+ * @typedef {function(EvaluationContext):Style} StyleEvaluator
192
+ */
193
+
194
+ /**
195
+ * @param {FlatStyle} flatStyle A flat style literal.
196
+ * @param {ParsingContext} context The parsing context.
197
+ * @return {StyleEvaluator} A function that evaluates to a style. The style returned by
198
+ * this function will be reused between invocations.
199
+ */
200
+ export function buildStyle(flatStyle, context) {
201
+ const evaluateFill = buildFill(flatStyle, '', context);
202
+ const evaluateStroke = buildStroke(flatStyle, '', context);
203
+ const evaluateText = buildText(flatStyle, context);
204
+ const evaluateImage = buildImage(flatStyle, context);
205
+ const evaluateZIndex = numberEvaluator(flatStyle, 'z-index', context);
206
+
207
+ const style = new Style();
208
+ return function (context) {
209
+ if (evaluateFill) {
210
+ style.setFill(evaluateFill(context));
211
+ }
212
+ if (evaluateStroke) {
213
+ style.setStroke(evaluateStroke(context));
214
+ }
215
+ if (evaluateText) {
216
+ style.setText(evaluateText(context));
217
+ }
218
+ if (evaluateImage) {
219
+ style.setImage(evaluateImage(context));
220
+ }
221
+ if (evaluateZIndex) {
222
+ style.setZIndex(evaluateZIndex(context));
223
+ }
224
+ return style;
225
+ };
226
+ }
227
+
228
+ /**
229
+ * @typedef {function(EvaluationContext):Fill} FillEvaluator
230
+ */
231
+
232
+ /**
233
+ * @param {FlatStyle} flatStyle The flat style.
234
+ * @param {string} prefix The property prefix.
235
+ * @param {ParsingContext} context The parsing context.
236
+ * @return {FillEvaluator?} A function that evaluates to a fill.
237
+ */
238
+ function buildFill(flatStyle, prefix, context) {
239
+ const evaluateColor = colorLikeEvaluator(
240
+ flatStyle,
241
+ prefix + 'fill-color',
242
+ context
243
+ );
244
+ if (!evaluateColor) {
245
+ return null;
246
+ }
247
+
248
+ const fill = new Fill();
249
+ return function (context) {
250
+ const color = evaluateColor(context);
251
+ if (color === 'none') {
252
+ return null;
253
+ }
254
+ fill.setColor(color);
255
+ return fill;
256
+ };
257
+ }
258
+
259
+ /**
260
+ * @typedef {function(EvaluationContext):Stroke} StrokeEvaluator
261
+ */
262
+
263
+ /**
264
+ * @param {FlatStyle} flatStyle The flat style.
265
+ * @param {string} prefix The property prefix.
266
+ * @param {ParsingContext} context The parsing context.
267
+ * @return {StrokeEvaluator?} A function the evaluates to a stroke.
268
+ */
269
+ function buildStroke(flatStyle, prefix, context) {
270
+ const evaluateWidth = numberEvaluator(
271
+ flatStyle,
272
+ prefix + 'stroke-width',
273
+ context
274
+ );
275
+
276
+ const evaluateColor = colorLikeEvaluator(
277
+ flatStyle,
278
+ prefix + 'stroke-color',
279
+ context
280
+ );
281
+
282
+ if (!evaluateWidth && !evaluateColor) {
283
+ return null;
284
+ }
285
+
286
+ const evaluateLineCap = stringEvaluator(
287
+ flatStyle,
288
+ prefix + 'stroke-line-cap',
289
+ context
290
+ );
291
+
292
+ const evaluateLineJoin = stringEvaluator(
293
+ flatStyle,
294
+ prefix + 'stroke-line-join',
295
+ context
296
+ );
297
+
298
+ const evaluateLineDash = numberArrayEvaluator(
299
+ flatStyle,
300
+ prefix + 'stroke-line-dash',
301
+ context
302
+ );
303
+
304
+ const evaluateLineDashOffset = numberEvaluator(
305
+ flatStyle,
306
+ prefix + 'stroke-line-dash-offset',
307
+ context
308
+ );
309
+
310
+ const evaluateMiterLimit = numberEvaluator(
311
+ flatStyle,
312
+ prefix + 'stroke-miter-limit',
313
+ context
314
+ );
315
+
316
+ const stroke = new Stroke();
317
+ return function (context) {
318
+ if (evaluateWidth) {
319
+ stroke.setWidth(evaluateWidth(context));
320
+ }
321
+
322
+ if (evaluateColor) {
323
+ stroke.setColor(evaluateColor(context));
324
+ }
325
+
326
+ if (evaluateLineCap) {
327
+ const lineCap = evaluateLineCap(context);
328
+ if (lineCap !== 'butt' && lineCap !== 'round' && lineCap !== 'square') {
329
+ throw new Error('Expected butt, round, or square line cap');
330
+ }
331
+ stroke.setLineCap(lineCap);
332
+ }
333
+
334
+ if (evaluateLineJoin) {
335
+ const lineJoin = evaluateLineJoin(context);
336
+ if (
337
+ lineJoin !== 'bevel' &&
338
+ lineJoin !== 'round' &&
339
+ lineJoin !== 'miter'
340
+ ) {
341
+ throw new Error('Expected bevel, round, or miter line join');
342
+ }
343
+ stroke.setLineJoin(lineJoin);
344
+ }
345
+
346
+ if (evaluateLineDash) {
347
+ stroke.setLineDash(evaluateLineDash(context));
348
+ }
349
+
350
+ if (evaluateLineDashOffset) {
351
+ stroke.setLineDashOffset(evaluateLineDashOffset(context));
352
+ }
353
+
354
+ if (evaluateMiterLimit) {
355
+ stroke.setMiterLimit(evaluateMiterLimit(context));
356
+ }
357
+
358
+ return stroke;
359
+ };
360
+ }
361
+
362
+ /**
363
+ * @typedef {function(EvaluationContext):Text} TextEvaluator
364
+ */
365
+
366
+ /**
367
+ * @param {FlatStyle} flatStyle The flat style.
368
+ * @param {ParsingContext} context The parsing context.
369
+ * @return {TextEvaluator?} A function that evaluates to a text symbolizer.
370
+ */
371
+ function buildText(flatStyle, context) {
372
+ const prefix = 'text-';
373
+
374
+ // Currently, an Array<string> may be used for rich text support. This doesn't
375
+ // work with our expression syntax where arrays of strings are interpreted as
376
+ // call expressions. To support rich text, we could add a 'strings' operator
377
+ // where all the following arguments would be string values.
378
+ const evaluateValue = stringEvaluator(flatStyle, prefix + 'value', context);
379
+ if (!evaluateValue) {
380
+ return null;
381
+ }
382
+
383
+ const evaluateFill = buildFill(flatStyle, prefix, context);
384
+
385
+ const evaluateBackgroundFill = buildFill(
386
+ flatStyle,
387
+ prefix + 'background-',
388
+ context
389
+ );
390
+
391
+ const evaluateStroke = buildStroke(flatStyle, prefix, context);
392
+
393
+ const evaluateBackgroundStroke = buildStroke(
394
+ flatStyle,
395
+ prefix + 'background-',
396
+ context
397
+ );
398
+
399
+ const evaluateFont = stringEvaluator(flatStyle, prefix + 'font', context);
400
+
401
+ const evaluateMaxAngle = numberEvaluator(
402
+ flatStyle,
403
+ prefix + 'max-angle',
404
+ context
405
+ );
406
+
407
+ const evaluateOffsetX = numberEvaluator(
408
+ flatStyle,
409
+ prefix + 'offset-x',
410
+ context
411
+ );
412
+
413
+ const evaluateOffsetY = numberEvaluator(
414
+ flatStyle,
415
+ prefix + 'offset-y',
416
+ context
417
+ );
418
+
419
+ const evaluateOverflow = booleanEvaluator(
420
+ flatStyle,
421
+ prefix + 'overflow',
422
+ context
423
+ );
424
+
425
+ const evaluatePlacement = stringEvaluator(
426
+ flatStyle,
427
+ prefix + 'placement',
428
+ context
429
+ );
430
+
431
+ const evaluateRepeat = numberEvaluator(flatStyle, prefix + 'repeat', context);
432
+
433
+ const evaluateScale = sizeLikeEvaluator(flatStyle, prefix + 'scale', context);
434
+
435
+ const evaluateRotateWithView = booleanEvaluator(
436
+ flatStyle,
437
+ prefix + 'rotate-with-view',
438
+ context
439
+ );
440
+
441
+ const evaluateRotation = numberEvaluator(
442
+ flatStyle,
443
+ prefix + 'rotation',
444
+ context
445
+ );
446
+
447
+ const evaluateAlign = stringEvaluator(flatStyle, prefix + 'align', context);
448
+
449
+ const evaluateJustify = stringEvaluator(
450
+ flatStyle,
451
+ prefix + 'justify',
452
+ context
453
+ );
454
+
455
+ const evaluateBaseline = stringEvaluator(
456
+ flatStyle,
457
+ prefix + 'baseline',
458
+ context
459
+ );
460
+
461
+ const evaluatePadding = numberArrayEvaluator(
462
+ flatStyle,
463
+ prefix + 'padding',
464
+ context
465
+ );
466
+
467
+ const text = new Text({});
468
+ return function (context) {
469
+ text.setText(evaluateValue(context));
470
+
471
+ if (evaluateFill) {
472
+ text.setFill(evaluateFill(context));
473
+ }
474
+
475
+ if (evaluateBackgroundFill) {
476
+ text.setBackgroundFill(evaluateBackgroundFill(context));
477
+ }
478
+
479
+ if (evaluateStroke) {
480
+ text.setStroke(evaluateStroke(context));
481
+ }
482
+
483
+ if (evaluateBackgroundStroke) {
484
+ text.setBackgroundStroke(evaluateBackgroundStroke(context));
485
+ }
486
+
487
+ if (evaluateFont) {
488
+ text.setFont(evaluateFont(context));
489
+ }
490
+
491
+ if (evaluateMaxAngle) {
492
+ text.setMaxAngle(evaluateMaxAngle(context));
493
+ }
494
+
495
+ if (evaluateOffsetX) {
496
+ text.setOffsetX(evaluateOffsetX(context));
497
+ }
498
+
499
+ if (evaluateOffsetY) {
500
+ text.setOffsetY(evaluateOffsetY(context));
501
+ }
502
+
503
+ if (evaluateOverflow) {
504
+ text.setOverflow(evaluateOverflow(context));
505
+ }
506
+
507
+ if (evaluatePlacement) {
508
+ const placement = evaluatePlacement(context);
509
+ if (placement !== 'point' && placement !== 'line') {
510
+ throw new Error('Expected point or line for text-placement');
511
+ }
512
+ text.setPlacement(placement);
513
+ }
514
+
515
+ if (evaluateRepeat) {
516
+ text.setRepeat(evaluateRepeat(context));
517
+ }
518
+
519
+ if (evaluateScale) {
520
+ text.setScale(evaluateScale(context));
521
+ }
522
+
523
+ if (evaluateRotateWithView) {
524
+ text.setRotateWithView(evaluateRotateWithView(context));
525
+ }
526
+
527
+ if (evaluateRotation) {
528
+ text.setRotation(evaluateRotation(context));
529
+ }
530
+
531
+ if (evaluateAlign) {
532
+ const textAlign = evaluateAlign(context);
533
+ if (
534
+ textAlign !== 'left' &&
535
+ textAlign !== 'center' &&
536
+ textAlign !== 'right' &&
537
+ textAlign !== 'end' &&
538
+ textAlign !== 'start'
539
+ ) {
540
+ throw new Error(
541
+ 'Expected left, right, center, start, or end for text-align'
542
+ );
543
+ }
544
+ text.setTextAlign(textAlign);
545
+ }
546
+
547
+ if (evaluateJustify) {
548
+ const justify = evaluateJustify(context);
549
+ if (justify !== 'left' && justify !== 'right' && justify !== 'center') {
550
+ throw new Error('Expected left, right, or center for text-justify');
551
+ }
552
+ text.setJustify(justify);
553
+ }
554
+
555
+ if (evaluateBaseline) {
556
+ const textBaseline = evaluateBaseline(context);
557
+ if (
558
+ textBaseline !== 'bottom' &&
559
+ textBaseline !== 'top' &&
560
+ textBaseline !== 'middle' &&
561
+ textBaseline !== 'alphabetic' &&
562
+ textBaseline !== 'hanging'
563
+ ) {
564
+ throw new Error(
565
+ 'Expected bottom, top, middle, alphabetic, or hanging for text-baseline'
566
+ );
567
+ }
568
+ text.setTextBaseline(textBaseline);
569
+ }
570
+
571
+ if (evaluatePadding) {
572
+ text.setPadding(evaluatePadding(context));
573
+ }
574
+
575
+ return text;
576
+ };
577
+ }
578
+
579
+ /**
580
+ * @typedef {function(EvaluationContext):import("../../style/Image.js").default} ImageEvaluator
581
+ */
582
+
583
+ /**
584
+ * @param {FlatStyle} flatStyle The flat style.
585
+ * @param {ParsingContext} context The parsing context.
586
+ * @return {ImageEvaluator?} A function that evaluates to an image symbolizer.
587
+ */
588
+ function buildImage(flatStyle, context) {
589
+ if ('icon-src' in flatStyle) {
590
+ return buildIcon(flatStyle, context);
591
+ }
592
+
593
+ if ('shape-points' in flatStyle) {
594
+ return buildShape(flatStyle, context);
595
+ }
596
+
597
+ if ('circle-radius' in flatStyle) {
598
+ return buildCircle(flatStyle, context);
599
+ }
600
+
601
+ return null;
602
+ }
603
+
604
+ /**
605
+ * @param {FlatStyle} flatStyle The flat style.
606
+ * @param {ParsingContext} context The parsing context.
607
+ * @return {ImageEvaluator} A function that evaluates to an image symbolizer.
608
+ */
609
+ function buildIcon(flatStyle, context) {
610
+ const prefix = 'icon-';
611
+
612
+ // required property
613
+ const srcName = prefix + 'src';
614
+ const src = requireString(flatStyle[srcName], srcName);
615
+
616
+ // settable properties
617
+ const evaluateAnchor = coordinateEvaluator(
618
+ flatStyle,
619
+ prefix + 'anchor',
620
+ context
621
+ );
622
+
623
+ const evaluateScale = sizeLikeEvaluator(flatStyle, prefix + 'scale', context);
624
+
625
+ const evaluateOpacity = numberEvaluator(
626
+ flatStyle,
627
+ prefix + 'opacity',
628
+ context
629
+ );
630
+
631
+ const evaluateDisplacement = coordinateEvaluator(
632
+ flatStyle,
633
+ prefix + 'displacement',
634
+ context
635
+ );
636
+
637
+ const evaluateRotation = numberEvaluator(
638
+ flatStyle,
639
+ prefix + 'rotation',
640
+ context
641
+ );
642
+
643
+ const evaluateRotateWithView = booleanEvaluator(
644
+ flatStyle,
645
+ prefix + 'rotate-with-view',
646
+ context
647
+ );
648
+
649
+ // the remaining symbolizer properties are not currently settable
650
+ const anchorOrigin = optionalIconOrigin(flatStyle, prefix + 'anchor-origin');
651
+ const anchorXUnits = optionalIconAnchorUnits(
652
+ flatStyle,
653
+ prefix + 'anchor-x-units'
654
+ );
655
+ const anchorYUnits = optionalIconAnchorUnits(
656
+ flatStyle,
657
+ prefix + 'anchor-y-units'
658
+ );
659
+ const color = optionalColorLike(flatStyle, prefix + 'color');
660
+ const crossOrigin = optionalString(flatStyle, prefix + 'cross-origin');
661
+ const offset = optionalNumberArray(flatStyle, prefix + 'offset');
662
+ const offsetOrigin = optionalIconOrigin(flatStyle, prefix + 'offset-origin');
663
+ const width = optionalNumber(flatStyle, prefix + 'width');
664
+ const height = optionalNumber(flatStyle, prefix + 'height');
665
+ const size = optionalSize(flatStyle, prefix + 'size');
666
+ const declutterMode = optionalDeclutterMode(flatStyle, prefix + 'declutter');
667
+
668
+ const icon = new Icon({
669
+ src,
670
+ anchorOrigin,
671
+ anchorXUnits,
672
+ anchorYUnits,
673
+ color,
674
+ crossOrigin,
675
+ offset,
676
+ offsetOrigin,
677
+ height,
678
+ width,
679
+ size,
680
+ declutterMode,
681
+ });
682
+
683
+ return function (context) {
684
+ if (evaluateOpacity) {
685
+ icon.setOpacity(evaluateOpacity(context));
686
+ }
687
+
688
+ if (evaluateDisplacement) {
689
+ icon.setDisplacement(evaluateDisplacement(context));
690
+ }
691
+
692
+ if (evaluateRotation) {
693
+ icon.setRotation(evaluateRotation(context));
694
+ }
695
+
696
+ if (evaluateRotateWithView) {
697
+ icon.setRotateWithView(evaluateRotateWithView(context));
698
+ }
699
+
700
+ if (evaluateScale) {
701
+ icon.setScale(evaluateScale(context));
702
+ }
703
+
704
+ if (evaluateAnchor) {
705
+ icon.setAnchor(evaluateAnchor(context));
706
+ }
707
+ return icon;
708
+ };
709
+ }
710
+
711
+ /**
712
+ * @param {FlatStyle} flatStyle The flat style.
713
+ * @param {ParsingContext} context The parsing context.
714
+ * @return {ImageEvaluator} A function that evaluates to an icon symbolizer.
715
+ */
716
+ function buildShape(flatStyle, context) {
717
+ const prefix = 'shape-';
718
+
719
+ // required property
720
+ const pointsName = prefix + 'points';
721
+ const points = requireNumber(flatStyle[pointsName], pointsName);
722
+
723
+ // settable properties
724
+ const evaluateFill = buildFill(flatStyle, prefix, context);
725
+ const evaluateStroke = buildStroke(flatStyle, prefix, context);
726
+ const evaluateScale = sizeLikeEvaluator(flatStyle, prefix + 'scale', context);
727
+ const evaluateDisplacement = coordinateEvaluator(
728
+ flatStyle,
729
+ prefix + 'displacement',
730
+ context
731
+ );
732
+ const evaluateRotation = numberEvaluator(
733
+ flatStyle,
734
+ prefix + 'rotation',
735
+ context
736
+ );
737
+ const evaluateRotateWithView = booleanEvaluator(
738
+ flatStyle,
739
+ prefix + 'rotate-with-view',
740
+ context
741
+ );
742
+
743
+ // the remaining properties are not currently settable
744
+ const radius = optionalNumber(flatStyle, prefix + 'radius');
745
+ const radius1 = optionalNumber(flatStyle, prefix + 'radius1');
746
+ const radius2 = optionalNumber(flatStyle, prefix + 'radius2');
747
+ const angle = optionalNumber(flatStyle, prefix + 'angle');
748
+ const declutterMode = optionalDeclutterMode(
749
+ flatStyle,
750
+ prefix + 'declutter-mode'
751
+ );
752
+
753
+ const shape = new RegularShape({
754
+ points,
755
+ radius,
756
+ radius1,
757
+ radius2,
758
+ angle,
759
+ declutterMode,
760
+ });
761
+
762
+ return function (context) {
763
+ if (evaluateFill) {
764
+ shape.setFill(evaluateFill(context));
765
+ }
766
+ if (evaluateStroke) {
767
+ shape.setStroke(evaluateStroke(context));
768
+ }
769
+ if (evaluateDisplacement) {
770
+ shape.setDisplacement(evaluateDisplacement(context));
771
+ }
772
+ if (evaluateRotation) {
773
+ shape.setRotation(evaluateRotation(context));
774
+ }
775
+ if (evaluateRotateWithView) {
776
+ shape.setRotateWithView(evaluateRotateWithView(context));
777
+ }
778
+ if (evaluateScale) {
779
+ shape.setScale(evaluateScale(context));
780
+ }
781
+
782
+ return shape;
783
+ };
784
+ }
785
+
786
+ /**
787
+ * @param {FlatStyle} flatStyle The flat style.
788
+ * @param {ParsingContext} context The parsing context.
789
+ * @return {ImageEvaluator} A function that evaluates to a circle symbolizer.
790
+ */
791
+ function buildCircle(flatStyle, context) {
792
+ const prefix = 'circle-';
793
+
794
+ // settable properties
795
+ const evaluateFill = buildFill(flatStyle, prefix, context);
796
+ const evaluateStroke = buildStroke(flatStyle, prefix, context);
797
+ const evaluateRadius = numberEvaluator(flatStyle, prefix + 'radius', context);
798
+ const evaluateScale = sizeLikeEvaluator(flatStyle, prefix + 'scale', context);
799
+ const evaluateDisplacement = coordinateEvaluator(
800
+ flatStyle,
801
+ prefix + 'displacement',
802
+ context
803
+ );
804
+ const evaluateRotation = numberEvaluator(
805
+ flatStyle,
806
+ prefix + 'rotation',
807
+ context
808
+ );
809
+ const evaluateRotateWithView = booleanEvaluator(
810
+ flatStyle,
811
+ prefix + 'rotate-with-view',
812
+ context
813
+ );
814
+
815
+ // the remaining properties are not currently settable
816
+ const declutterMode = optionalDeclutterMode(
817
+ flatStyle,
818
+ prefix + 'declutter-mode'
819
+ );
820
+
821
+ const circle = new Circle({
822
+ radius: 5, // this is arbitrary, but required - the evaluated radius is used below
823
+ declutterMode,
824
+ });
825
+
826
+ return function (context) {
827
+ if (evaluateRadius) {
828
+ circle.setRadius(evaluateRadius(context));
829
+ }
830
+ if (evaluateFill) {
831
+ circle.setFill(evaluateFill(context));
832
+ }
833
+ if (evaluateStroke) {
834
+ circle.setStroke(evaluateStroke(context));
835
+ }
836
+ if (evaluateDisplacement) {
837
+ circle.setDisplacement(evaluateDisplacement(context));
838
+ }
839
+ if (evaluateRotation) {
840
+ circle.setRotation(evaluateRotation(context));
841
+ }
842
+ if (evaluateRotateWithView) {
843
+ circle.setRotateWithView(evaluateRotateWithView(context));
844
+ }
845
+ if (evaluateScale) {
846
+ circle.setScale(evaluateScale(context));
847
+ }
848
+
849
+ return circle;
850
+ };
851
+ }
852
+
853
+ /**
854
+ * @param {FlatStyle} flatStyle The flat style.
855
+ * @param {string} name The property name.
856
+ * @param {ParsingContext} context The parsing context.
857
+ * @return {import('../../expr/cpu.js').NumberEvaluator|undefined} The expression evaluator or undefined.
858
+ */
859
+ function numberEvaluator(flatStyle, name, context) {
860
+ if (!(name in flatStyle)) {
861
+ return undefined;
862
+ }
863
+ const evaluator = buildExpression(flatStyle[name], NumberType, context);
864
+ return function (context) {
865
+ return requireNumber(evaluator(context), name);
866
+ };
867
+ }
868
+
869
+ /**
870
+ * @param {FlatStyle} flatStyle The flat style.
871
+ * @param {string} name The property name.
872
+ * @param {ParsingContext} context The parsing context.
873
+ * @return {import('../../expr/cpu.js').StringEvaluator?} The expression evaluator.
874
+ */
875
+ function stringEvaluator(flatStyle, name, context) {
876
+ if (!(name in flatStyle)) {
877
+ return null;
878
+ }
879
+ const evaluator = buildExpression(flatStyle[name], StringType, context);
880
+ return function (context) {
881
+ return requireString(evaluator(context), name);
882
+ };
883
+ }
884
+
885
+ /**
886
+ * @param {FlatStyle} flatStyle The flat style.
887
+ * @param {string} name The property name.
888
+ * @param {ParsingContext} context The parsing context.
889
+ * @return {import('../../expr/cpu.js').BooleanEvaluator?} The expression evaluator.
890
+ */
891
+ function booleanEvaluator(flatStyle, name, context) {
892
+ if (!(name in flatStyle)) {
893
+ return null;
894
+ }
895
+ const evaluator = buildExpression(flatStyle[name], BooleanType, context);
896
+ return function (context) {
897
+ const value = evaluator(context);
898
+ if (typeof value !== 'boolean') {
899
+ throw new Error(`Expected a boolean for ${name}`);
900
+ }
901
+ return value;
902
+ };
903
+ }
904
+
905
+ /**
906
+ * @param {FlatStyle} flatStyle The flat style.
907
+ * @param {string} name The property name.
908
+ * @param {ParsingContext} context The parsing context.
909
+ * @return {import('../../expr/cpu.js').ColorLikeEvaluator?} The expression evaluator.
910
+ */
911
+ function colorLikeEvaluator(flatStyle, name, context) {
912
+ if (!(name in flatStyle)) {
913
+ return null;
914
+ }
915
+ const evaluator = buildExpression(
916
+ flatStyle[name],
917
+ ColorType | StringType,
918
+ context
919
+ );
920
+ return function (context) {
921
+ return requireColorLike(evaluator(context), name);
922
+ };
923
+ }
924
+
925
+ /**
926
+ * @param {FlatStyle} flatStyle The flat style.
927
+ * @param {string} name The property name.
928
+ * @param {ParsingContext} context The parsing context.
929
+ * @return {import('../../expr/cpu.js').NumberArrayEvaluator?} The expression evaluator.
930
+ */
931
+ function numberArrayEvaluator(flatStyle, name, context) {
932
+ if (!(name in flatStyle)) {
933
+ return null;
934
+ }
935
+ const evaluator = buildExpression(flatStyle[name], NumberArrayType, context);
936
+ return function (context) {
937
+ return requireNumberArray(evaluator(context), name);
938
+ };
939
+ }
940
+
941
+ /**
942
+ * @param {FlatStyle} flatStyle The flat style.
943
+ * @param {string} name The property name.
944
+ * @param {ParsingContext} context The parsing context.
945
+ * @return {import('../../expr/cpu.js').CoordinateEvaluator?} The expression evaluator.
946
+ */
947
+ function coordinateEvaluator(flatStyle, name, context) {
948
+ if (!(name in flatStyle)) {
949
+ return null;
950
+ }
951
+ const evaluator = buildExpression(flatStyle[name], NumberArrayType, context);
952
+ return function (context) {
953
+ const array = requireNumberArray(evaluator(context), name);
954
+ if (array.length !== 2) {
955
+ throw new Error(`Expected two numbers for ${name}`);
956
+ }
957
+ return array;
958
+ };
959
+ }
960
+
961
+ /**
962
+ * @param {FlatStyle} flatStyle The flat style.
963
+ * @param {string} name The property name.
964
+ * @param {ParsingContext} context The parsing context.
965
+ * @return {import('../../expr/cpu.js').SizeLikeEvaluator?} The expression evaluator.
966
+ */
967
+ function sizeLikeEvaluator(flatStyle, name, context) {
968
+ if (!(name in flatStyle)) {
969
+ return null;
970
+ }
971
+ const evaluator = buildExpression(flatStyle[name], NumberArrayType, context);
972
+ return function (context) {
973
+ return requireSizeLike(evaluator(context), name);
974
+ };
975
+ }
976
+
977
+ /**
978
+ * @param {FlatStyle} flatStyle The flat style.
979
+ * @param {string} property The symbolizer property.
980
+ * @return {number|undefined} A number or undefined.
981
+ */
982
+ function optionalNumber(flatStyle, property) {
983
+ const value = flatStyle[property];
984
+ if (value === undefined) {
985
+ return undefined;
986
+ }
987
+ if (typeof value !== 'number') {
988
+ throw new Error(`Expected a number for ${property}`);
989
+ }
990
+ return value;
991
+ }
992
+
993
+ /**
994
+ * @param {FlatStyle} flatStyle The flat style.
995
+ * @param {string} property The symbolizer property.
996
+ * @return {import("../../size.js").Size|undefined} A size or undefined.
997
+ */
998
+ function optionalSize(flatStyle, property) {
999
+ const encoded = flatStyle[property];
1000
+ if (encoded === undefined) {
1001
+ return undefined;
1002
+ }
1003
+ if (typeof encoded === 'number') {
1004
+ return toSize(encoded);
1005
+ }
1006
+ if (!Array.isArray(encoded)) {
1007
+ throw new Error(`Expected a number or size array for ${property}`);
1008
+ }
1009
+ if (
1010
+ encoded.length !== 2 ||
1011
+ typeof encoded[0] !== 'number' ||
1012
+ typeof encoded[1] !== 'number'
1013
+ ) {
1014
+ throw new Error(`Expected a number or size array for ${property}`);
1015
+ }
1016
+ return encoded;
1017
+ }
1018
+
1019
+ /**
1020
+ * @param {FlatStyle} flatStyle The flat style.
1021
+ * @param {string} property The symbolizer property.
1022
+ * @return {string|undefined} A string or undefined.
1023
+ */
1024
+ function optionalString(flatStyle, property) {
1025
+ const encoded = flatStyle[property];
1026
+ if (encoded === undefined) {
1027
+ return undefined;
1028
+ }
1029
+ if (typeof encoded !== 'string') {
1030
+ throw new Error(`Expected a string for ${property}`);
1031
+ }
1032
+ return encoded;
1033
+ }
1034
+
1035
+ /**
1036
+ * @param {FlatStyle} flatStyle The flat style.
1037
+ * @param {string} property The symbolizer property.
1038
+ * @return {import("../../style/Icon.js").IconOrigin|undefined} An icon origin or undefined.
1039
+ */
1040
+ function optionalIconOrigin(flatStyle, property) {
1041
+ const encoded = flatStyle[property];
1042
+ if (encoded === undefined) {
1043
+ return undefined;
1044
+ }
1045
+ if (
1046
+ encoded !== 'bottom-left' &&
1047
+ encoded !== 'bottom-right' &&
1048
+ encoded !== 'top-left' &&
1049
+ encoded !== 'top-right'
1050
+ ) {
1051
+ throw new Error(
1052
+ `Expected bottom-left, bottom-right, top-left, or top-right for ${property}`
1053
+ );
1054
+ }
1055
+ return encoded;
1056
+ }
1057
+
1058
+ /**
1059
+ * @param {FlatStyle} flatStyle The flat style.
1060
+ * @param {string} property The symbolizer property.
1061
+ * @return {import("../../style/Icon.js").IconAnchorUnits|undefined} Icon anchor units or undefined.
1062
+ */
1063
+ function optionalIconAnchorUnits(flatStyle, property) {
1064
+ const encoded = flatStyle[property];
1065
+ if (encoded === undefined) {
1066
+ return undefined;
1067
+ }
1068
+ if (encoded !== 'pixels' && encoded !== 'fraction') {
1069
+ throw new Error(`Expected pixels or fraction for ${property}`);
1070
+ }
1071
+ return encoded;
1072
+ }
1073
+
1074
+ /**
1075
+ * @param {FlatStyle} flatStyle The flat style.
1076
+ * @param {string} property The symbolizer property.
1077
+ * @return {Array<number>|undefined} An array of numbers or undefined.
1078
+ */
1079
+ function optionalNumberArray(flatStyle, property) {
1080
+ const encoded = flatStyle[property];
1081
+ if (encoded === undefined) {
1082
+ return undefined;
1083
+ }
1084
+ return requireNumberArray(encoded, property);
1085
+ }
1086
+
1087
+ /**
1088
+ * @param {FlatStyle} flatStyle The flat style.
1089
+ * @param {string} property The symbolizer property.
1090
+ * @return {"declutter"|"obstacle"|"none"|undefined} Icon declutter mode.
1091
+ */
1092
+ function optionalDeclutterMode(flatStyle, property) {
1093
+ const encoded = flatStyle[property];
1094
+ if (encoded === undefined) {
1095
+ return undefined;
1096
+ }
1097
+ if (typeof encoded !== 'string') {
1098
+ throw new Error(`Expected a string for ${property}`);
1099
+ }
1100
+ if (encoded !== 'declutter' && encoded !== 'obstacle' && encoded !== 'none') {
1101
+ throw new Error(`Expected declutter, obstacle, or none for ${property}`);
1102
+ }
1103
+ return encoded;
1104
+ }
1105
+
1106
+ /**
1107
+ * @param {FlatStyle} flatStyle The flat style.
1108
+ * @param {string} property The symbolizer property.
1109
+ * @return {string|Array<number>|undefined} A string or an array of color values or undefined.
1110
+ */
1111
+ function optionalColorLike(flatStyle, property) {
1112
+ const encoded = flatStyle[property];
1113
+ if (encoded === undefined) {
1114
+ return undefined;
1115
+ }
1116
+ return requireColorLike(encoded, property);
1117
+ }
1118
+
1119
+ /**
1120
+ * @param {any} value The value.
1121
+ * @param {string} property The property.
1122
+ * @return {Array<number>} An array of numbers.
1123
+ */
1124
+ function requireNumberArray(value, property) {
1125
+ if (!Array.isArray(value)) {
1126
+ throw new Error(`Expected an array for ${property}`);
1127
+ }
1128
+ const length = value.length;
1129
+ for (let i = 0; i < length; ++i) {
1130
+ if (typeof value[i] !== 'number') {
1131
+ throw new Error(`Expected an array of numbers for ${property}`);
1132
+ }
1133
+ }
1134
+ return value;
1135
+ }
1136
+
1137
+ /**
1138
+ * @param {any} value The value.
1139
+ * @param {string} property The property.
1140
+ * @return {string} A string.
1141
+ */
1142
+ function requireString(value, property) {
1143
+ if (typeof value !== 'string') {
1144
+ throw new Error(`Expected a string for ${property}`);
1145
+ }
1146
+ return value;
1147
+ }
1148
+
1149
+ /**
1150
+ * @param {any} value The value.
1151
+ * @param {string} property The property.
1152
+ * @return {number} A number.
1153
+ */
1154
+ function requireNumber(value, property) {
1155
+ if (typeof value !== 'number') {
1156
+ throw new Error(`Expected a number for ${property}`);
1157
+ }
1158
+ return value;
1159
+ }
1160
+
1161
+ /**
1162
+ * @param {any} value The value.
1163
+ * @param {string} property The property.
1164
+ * @return {Array<number>|string} A color.
1165
+ */
1166
+ function requireColorLike(value, property) {
1167
+ if (typeof value === 'string') {
1168
+ return value;
1169
+ }
1170
+ const array = requireNumberArray(value, property);
1171
+ const length = array.length;
1172
+ if (length < 3 || length > 4) {
1173
+ throw new Error(`Expected a color with 3 or 4 values for ${property}`);
1174
+ }
1175
+ return array;
1176
+ }
1177
+
1178
+ /**
1179
+ * @param {any} value The value.
1180
+ * @param {string} property The property.
1181
+ * @return {number|Array<number>} A number or an array of two numbers.
1182
+ */
1183
+ function requireSizeLike(value, property) {
1184
+ if (typeof value === 'number') {
1185
+ return value;
1186
+ }
1187
+ const size = requireNumberArray(value, property);
1188
+ if (size.length !== 2) {
1189
+ throw new Error(`Expected an array of two numbers for ${property}`);
1190
+ }
1191
+ return size;
1192
+ }