@mapwhit/tilerenderer 0.50.0 → 0.51.1
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/build/min/package.json +1 -1
- package/build/min/src/shaders/.dir +0 -0
- package/build/min/src/shaders/{_prelude.fragment.glsl.txt → _prelude.fragment.glsl.js} +2 -1
- package/build/min/src/shaders/{_prelude.vertex.glsl.txt → _prelude.vertex.glsl.js} +2 -2
- package/build/min/src/shaders/background.fragment.glsl.js +5 -0
- package/build/min/src/shaders/background.vertex.glsl.js +1 -0
- package/build/min/src/shaders/background_pattern.fragment.glsl.js +5 -0
- package/build/min/src/shaders/background_pattern.vertex.glsl.js +1 -0
- package/build/min/src/shaders/{circle.fragment.glsl.txt → circle.fragment.glsl.js} +2 -2
- package/build/min/src/shaders/{circle.vertex.glsl.txt → circle.vertex.glsl.js} +2 -2
- package/build/min/src/shaders/clipping_mask.fragment.glsl.js +1 -0
- package/build/min/src/shaders/clipping_mask.vertex.glsl.js +1 -0
- package/build/min/src/shaders/collision_box.fragment.glsl.js +1 -0
- package/build/min/src/shaders/collision_box.vertex.glsl.js +1 -0
- package/build/min/src/shaders/collision_circle.fragment.glsl.js +1 -0
- package/build/min/src/shaders/collision_circle.vertex.glsl.js +1 -0
- package/build/min/src/shaders/debug.fragment.glsl.js +1 -0
- package/build/min/src/shaders/debug.vertex.glsl.js +1 -0
- package/build/min/src/shaders/{fill.fragment.glsl.txt → fill.fragment.glsl.js} +2 -2
- package/build/min/src/shaders/{fill.vertex.glsl.txt → fill.vertex.glsl.js} +2 -2
- package/build/min/src/shaders/fill_extrusion.fragment.glsl.js +5 -0
- package/build/min/src/shaders/{fill_extrusion.vertex.glsl.txt → fill_extrusion.vertex.glsl.js} +2 -2
- package/build/min/src/shaders/{fill_extrusion_pattern.fragment.glsl.txt → fill_extrusion_pattern.fragment.glsl.js} +2 -2
- package/build/min/src/shaders/{fill_extrusion_pattern.vertex.glsl.txt → fill_extrusion_pattern.vertex.glsl.js} +2 -2
- package/build/min/src/shaders/{fill_outline.fragment.glsl.txt → fill_outline.fragment.glsl.js} +2 -2
- package/build/min/src/shaders/{fill_outline.vertex.glsl.txt → fill_outline.vertex.glsl.js} +2 -2
- package/build/min/src/shaders/{fill_outline_pattern.fragment.glsl.txt → fill_outline_pattern.fragment.glsl.js} +2 -2
- package/build/min/src/shaders/{fill_outline_pattern.vertex.glsl.txt → fill_outline_pattern.vertex.glsl.js} +2 -2
- package/build/min/src/shaders/{fill_pattern.fragment.glsl.txt → fill_pattern.fragment.glsl.js} +2 -2
- package/build/min/src/shaders/{fill_pattern.vertex.glsl.txt → fill_pattern.vertex.glsl.js} +2 -2
- package/build/min/src/shaders/{heatmap.fragment.glsl.txt → heatmap.fragment.glsl.js} +2 -2
- package/build/min/src/shaders/{heatmap.vertex.glsl.txt → heatmap.vertex.glsl.js} +2 -2
- package/build/min/src/shaders/heatmap_texture.fragment.glsl.js +5 -0
- package/build/min/src/shaders/heatmap_texture.vertex.glsl.js +1 -0
- package/build/min/src/shaders/{hillshade.fragment.glsl.txt → hillshade.fragment.glsl.js} +2 -2
- package/build/min/src/shaders/hillshade.vertex.glsl.js +1 -0
- package/build/min/src/shaders/{hillshade_prepare.fragment.glsl.txt → hillshade_prepare.fragment.glsl.js} +2 -2
- package/build/min/src/shaders/hillshade_prepare.vertex.glsl.js +1 -0
- package/build/min/src/shaders/{line.fragment.glsl.txt → line.fragment.glsl.js} +2 -2
- package/build/min/src/shaders/{line.vertex.glsl.txt → line.vertex.glsl.js} +2 -2
- package/build/min/src/shaders/{line_gradient.fragment.glsl.txt → line_gradient.fragment.glsl.js} +2 -2
- package/build/min/src/shaders/{line_gradient.vertex.glsl.txt → line_gradient.vertex.glsl.js} +2 -2
- package/build/min/src/shaders/{line_pattern.fragment.glsl.txt → line_pattern.fragment.glsl.js} +2 -2
- package/build/min/src/shaders/{line_pattern.vertex.glsl.txt → line_pattern.vertex.glsl.js} +2 -2
- package/build/min/src/shaders/{line_sdf.fragment.glsl.txt → line_sdf.fragment.glsl.js} +2 -2
- package/build/min/src/shaders/{line_sdf.vertex.glsl.txt → line_sdf.vertex.glsl.js} +2 -2
- package/build/min/src/shaders/raster.fragment.glsl.js +5 -0
- package/build/min/src/shaders/raster.vertex.glsl.js +1 -0
- package/build/min/src/shaders/{symbol_icon.fragment.glsl.txt → symbol_icon.fragment.glsl.js} +2 -2
- package/build/min/src/shaders/{symbol_icon.vertex.glsl.txt → symbol_icon.vertex.glsl.js} +2 -2
- package/build/min/src/shaders/{symbol_sdf.fragment.glsl.txt → symbol_sdf.fragment.glsl.js} +2 -2
- package/build/min/src/shaders/{symbol_sdf.vertex.glsl.txt → symbol_sdf.vertex.glsl.js} +2 -2
- package/package.json +14 -10
- package/src/data/array_types.js +1 -1
- package/src/data/bucket/fill_bucket.js +1 -1
- package/src/data/bucket/fill_extrusion_bucket.js +2 -2
- package/src/data/bucket/line_bucket.js +1 -1
- package/src/data/bucket/symbol_bucket.js +3 -3
- package/src/data/feature_index.js +1 -1
- package/src/data/program_configuration.js +1 -1
- package/src/geo/transform.js +1 -1
- package/src/gl/color_mode.js +1 -1
- package/src/gl/value.js +1 -1
- package/src/index.js +2 -2
- package/src/render/draw_debug.js +1 -1
- package/src/render/draw_fill.js +1 -1
- package/src/render/draw_heatmap.js +1 -1
- package/src/render/glyph_manager.js +6 -130
- package/src/render/painter.js +1 -1
- package/src/render/uniform_binding.js +1 -1
- package/src/shaders/index.js +50 -50
- package/src/source/geojson_source.js +1 -1
- package/src/source/geojson_worker_source.js +4 -4
- package/src/source/geojson_wrapper.js +35 -27
- package/src/source/image_source.js +2 -2
- package/src/source/raster_tile_source.js +1 -1
- package/src/source/resources/glyphs.js +73 -0
- package/src/source/resources/images.js +68 -0
- package/src/source/resources/index.js +22 -0
- package/src/source/rtl_text_plugin.js +1 -1
- package/src/source/source_cache.js +2 -2
- package/src/source/tile.js +1 -1
- package/src/source/vector_tile_source.js +1 -1
- package/src/source/vector_tile_worker_source.js +5 -5
- package/src/source/worker.js +6 -5
- package/src/source/worker_tile.js +4 -4
- package/src/style/light.js +1 -1
- package/src/style/properties.js +1 -2
- package/src/style/query_utils.js +1 -1
- package/src/style/style.js +4 -4
- package/src/style/style_layer/circle_style_layer.js +1 -1
- package/src/style/style_layer/fill_extrusion_style_layer.js +1 -1
- package/src/style/style_layer/line_style_layer.js +1 -1
- package/src/style/style_layer/symbol_style_layer.js +1 -1
- package/src/style/style_layer.js +2 -2
- package/src/style-spec/feature_filter/index.js +43 -34
- package/src/style-spec/group_by_layout.js +10 -32
- package/src/symbol/anchor.js +1 -1
- package/src/symbol/clip_line.js +1 -1
- package/src/symbol/collision_feature.js +1 -1
- package/src/symbol/collision_index.js +1 -1
- package/src/symbol/mergelines.js +0 -2
- package/src/symbol/projection.js +1 -1
- package/src/symbol/quads.js +1 -1
- package/src/symbol/symbol_layout.js +0 -1
- package/src/symbol/symbol_size.js +1 -1
- package/src/symbol/transform_text.js +0 -1
- package/src/ui/camera.js +2 -2
- package/src/ui/map.js +11 -41
- package/src/util/browser.js +3 -18
- package/src/util/classify_rings.js +1 -1
- package/src/util/config.js +1 -1
- package/src/util/dom.js +0 -88
- package/src/util/find_pole_of_inaccessibility.js +3 -3
- package/src/util/intersection_tests.js +1 -1
- package/src/util/web_worker_transfer.js +4 -4
- package/src/worker.js +4 -0
- package/build/min/src/shaders/background.fragment.glsl.txt +0 -5
- package/build/min/src/shaders/background.vertex.glsl.txt +0 -1
- package/build/min/src/shaders/background_pattern.fragment.glsl.txt +0 -5
- package/build/min/src/shaders/background_pattern.vertex.glsl.txt +0 -1
- package/build/min/src/shaders/clipping_mask.fragment.glsl.txt +0 -1
- package/build/min/src/shaders/clipping_mask.vertex.glsl.txt +0 -1
- package/build/min/src/shaders/collision_box.fragment.glsl.txt +0 -1
- package/build/min/src/shaders/collision_box.vertex.glsl.txt +0 -1
- package/build/min/src/shaders/collision_circle.fragment.glsl.txt +0 -1
- package/build/min/src/shaders/collision_circle.vertex.glsl.txt +0 -1
- package/build/min/src/shaders/debug.fragment.glsl.txt +0 -1
- package/build/min/src/shaders/debug.vertex.glsl.txt +0 -1
- package/build/min/src/shaders/fill_extrusion.fragment.glsl.txt +0 -5
- package/build/min/src/shaders/heatmap_texture.fragment.glsl.txt +0 -5
- package/build/min/src/shaders/heatmap_texture.vertex.glsl.txt +0 -1
- package/build/min/src/shaders/hillshade.vertex.glsl.txt +0 -1
- package/build/min/src/shaders/hillshade_prepare.vertex.glsl.txt +0 -1
- package/build/min/src/shaders/raster.fragment.glsl.txt +0 -5
- package/build/min/src/shaders/raster.vertex.glsl.txt +0 -1
- package/src/style/load_glyph_range.js +0 -17
- package/src/style-spec/expression/compound_expression.js +0 -132
- package/src/style-spec/expression/definitions/assertion.js +0 -116
- package/src/style-spec/expression/definitions/at.js +0 -57
- package/src/style-spec/expression/definitions/case.js +0 -73
- package/src/style-spec/expression/definitions/coalesce.js +0 -66
- package/src/style-spec/expression/definitions/coercion.js +0 -120
- package/src/style-spec/expression/definitions/collator.js +0 -80
- package/src/style-spec/expression/definitions/comparison.js +0 -193
- package/src/style-spec/expression/definitions/format.js +0 -97
- package/src/style-spec/expression/definitions/index.js +0 -339
- package/src/style-spec/expression/definitions/interpolate.js +0 -245
- package/src/style-spec/expression/definitions/length.js +0 -54
- package/src/style-spec/expression/definitions/let.js +0 -60
- package/src/style-spec/expression/definitions/literal.js +0 -69
- package/src/style-spec/expression/definitions/match.js +0 -142
- package/src/style-spec/expression/definitions/step.js +0 -116
- package/src/style-spec/expression/definitions/var.js +0 -38
- package/src/style-spec/expression/evaluation_context.js +0 -38
- package/src/style-spec/expression/index.js +0 -330
- package/src/style-spec/expression/is_constant.js +0 -63
- package/src/style-spec/expression/parsing_context.js +0 -221
- package/src/style-spec/expression/parsing_error.js +0 -9
- package/src/style-spec/expression/runtime_error.js +0 -12
- package/src/style-spec/expression/scope.js +0 -34
- package/src/style-spec/expression/stops.js +0 -37
- package/src/style-spec/expression/types/collator.js +0 -24
- package/src/style-spec/expression/types/formatted.js +0 -39
- package/src/style-spec/expression/types.js +0 -88
- package/src/style-spec/expression/values.js +0 -149
- package/src/style-spec/function/convert.js +0 -240
- package/src/style-spec/function/index.js +0 -303
- package/src/style-spec/util/color.js +0 -73
- package/src/style-spec/util/color_spaces.js +0 -128
- package/src/style-spec/util/get_type.js +0 -18
- package/src/style-spec/util/interpolate.js +0 -21
- package/src/style-spec/util/properties.js +0 -17
- package/src/style-spec/util/result.js +0 -19
- package/src/ui/anchor.js +0 -24
- package/src/ui/bind_handlers.js +0 -199
- package/src/ui/events.js +0 -210
- package/src/ui/handler/box_zoom.js +0 -151
- package/src/ui/handler/dblclick_zoom.js +0 -91
- package/src/ui/handler/drag_pan.js +0 -285
- package/src/ui/handler/drag_rotate.js +0 -290
- package/src/ui/handler/frame.js +0 -28
- package/src/ui/handler/inertia.js +0 -45
- package/src/ui/handler/keyboard.js +0 -148
- package/src/ui/handler/scroll_zoom.js +0 -284
- package/src/ui/handler/touch_zoom_rotate.js +0 -263
- package/src/util/evented.js +0 -182
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
const { NumberType, ValueType, FormattedType, array, StringType } = require('../types');
|
|
2
|
-
const { Formatted, FormattedSection } = require('../types/formatted');
|
|
3
|
-
const { toString } = require('../values');
|
|
4
|
-
|
|
5
|
-
class FormatExpression {
|
|
6
|
-
constructor(sections) {
|
|
7
|
-
this.type = FormattedType;
|
|
8
|
-
this.sections = sections;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
static parse(args, context) {
|
|
12
|
-
if (args.length < 3) {
|
|
13
|
-
return context.error('Expected at least two arguments.');
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
if ((args.length - 1) % 2 !== 0) {
|
|
17
|
-
return context.error('Expected an even number of arguments.');
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const sections = [];
|
|
21
|
-
for (let i = 1; i < args.length - 1; i += 2) {
|
|
22
|
-
const text = context.parse(args[i], 1, ValueType);
|
|
23
|
-
if (!text) return null;
|
|
24
|
-
const kind = text.type.kind;
|
|
25
|
-
if (kind !== 'string' && kind !== 'value' && kind !== 'null')
|
|
26
|
-
return context.error("Formatted text type must be 'string', 'value', or 'null'.");
|
|
27
|
-
|
|
28
|
-
const options = args[i + 1];
|
|
29
|
-
if (typeof options !== 'object' || Array.isArray(options))
|
|
30
|
-
return context.error('Format options argument must be an object.');
|
|
31
|
-
|
|
32
|
-
let scale = null;
|
|
33
|
-
if (options['font-scale']) {
|
|
34
|
-
scale = context.parse(options['font-scale'], 1, NumberType);
|
|
35
|
-
if (!scale) return null;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
let font = null;
|
|
39
|
-
if (options['text-font']) {
|
|
40
|
-
font = context.parse(options['text-font'], 1, array(StringType));
|
|
41
|
-
if (!font) return null;
|
|
42
|
-
}
|
|
43
|
-
sections.push({ text, scale, font });
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return new FormatExpression(sections);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
evaluate(ctx) {
|
|
50
|
-
return new Formatted(
|
|
51
|
-
this.sections.map(
|
|
52
|
-
section =>
|
|
53
|
-
new FormattedSection(
|
|
54
|
-
toString(section.text.evaluate(ctx)),
|
|
55
|
-
section.scale ? section.scale.evaluate(ctx) : null,
|
|
56
|
-
section.font ? section.font.evaluate(ctx).join(',') : null
|
|
57
|
-
)
|
|
58
|
-
)
|
|
59
|
-
);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
eachChild(fn) {
|
|
63
|
-
for (const section of this.sections) {
|
|
64
|
-
fn(section.text);
|
|
65
|
-
if (section.scale) {
|
|
66
|
-
fn(section.scale);
|
|
67
|
-
}
|
|
68
|
-
if (section.font) {
|
|
69
|
-
fn(section.font);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
possibleOutputs() {
|
|
75
|
-
// Technically the combinatoric set of all children
|
|
76
|
-
// Usually, this.text will be undefined anyway
|
|
77
|
-
return [undefined];
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
serialize() {
|
|
81
|
-
const serialized = ['format'];
|
|
82
|
-
for (const section of this.sections) {
|
|
83
|
-
serialized.push(section.text.serialize());
|
|
84
|
-
const options = {};
|
|
85
|
-
if (section.scale) {
|
|
86
|
-
options['font-scale'] = section.scale.serialize();
|
|
87
|
-
}
|
|
88
|
-
if (section.font) {
|
|
89
|
-
options['text-font'] = section.font.serialize();
|
|
90
|
-
}
|
|
91
|
-
serialized.push(options);
|
|
92
|
-
}
|
|
93
|
-
return serialized;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
module.exports = { Formatted, FormatExpression };
|
|
@@ -1,339 +0,0 @@
|
|
|
1
|
-
const {
|
|
2
|
-
NumberType,
|
|
3
|
-
StringType,
|
|
4
|
-
BooleanType,
|
|
5
|
-
ColorType,
|
|
6
|
-
ObjectType,
|
|
7
|
-
ValueType,
|
|
8
|
-
ErrorType,
|
|
9
|
-
CollatorType,
|
|
10
|
-
array,
|
|
11
|
-
toString: typeToString
|
|
12
|
-
} = require('../types');
|
|
13
|
-
|
|
14
|
-
const { typeOf, Color, validateRGBA, toString: valueToString } = require('../values');
|
|
15
|
-
const CompoundExpression = require('../compound_expression');
|
|
16
|
-
const RuntimeError = require('../runtime_error');
|
|
17
|
-
const Let = require('./let');
|
|
18
|
-
const Var = require('./var');
|
|
19
|
-
const Literal = require('./literal');
|
|
20
|
-
const Assertion = require('./assertion');
|
|
21
|
-
const Coercion = require('./coercion');
|
|
22
|
-
const At = require('./at');
|
|
23
|
-
const Match = require('./match');
|
|
24
|
-
const Case = require('./case');
|
|
25
|
-
const Step = require('./step');
|
|
26
|
-
const Interpolate = require('./interpolate');
|
|
27
|
-
const Coalesce = require('./coalesce');
|
|
28
|
-
const { Equals, NotEquals, LessThan, GreaterThan, LessThanOrEqual, GreaterThanOrEqual } = require('./comparison');
|
|
29
|
-
const { CollatorExpression } = require('./collator');
|
|
30
|
-
const { FormatExpression } = require('./format');
|
|
31
|
-
const Length = require('./length');
|
|
32
|
-
|
|
33
|
-
const expressions = {
|
|
34
|
-
// special forms
|
|
35
|
-
'==': Equals,
|
|
36
|
-
'!=': NotEquals,
|
|
37
|
-
'>': GreaterThan,
|
|
38
|
-
'<': LessThan,
|
|
39
|
-
'>=': GreaterThanOrEqual,
|
|
40
|
-
'<=': LessThanOrEqual,
|
|
41
|
-
array: Assertion,
|
|
42
|
-
at: At,
|
|
43
|
-
boolean: Assertion,
|
|
44
|
-
case: Case,
|
|
45
|
-
coalesce: Coalesce,
|
|
46
|
-
collator: CollatorExpression,
|
|
47
|
-
format: FormatExpression,
|
|
48
|
-
interpolate: Interpolate,
|
|
49
|
-
'interpolate-hcl': Interpolate,
|
|
50
|
-
'interpolate-lab': Interpolate,
|
|
51
|
-
length: Length,
|
|
52
|
-
let: Let,
|
|
53
|
-
literal: Literal,
|
|
54
|
-
match: Match,
|
|
55
|
-
number: Assertion,
|
|
56
|
-
object: Assertion,
|
|
57
|
-
step: Step,
|
|
58
|
-
string: Assertion,
|
|
59
|
-
'to-boolean': Coercion,
|
|
60
|
-
'to-color': Coercion,
|
|
61
|
-
'to-number': Coercion,
|
|
62
|
-
'to-string': Coercion,
|
|
63
|
-
var: Var
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
function rgba(ctx, [r, g, b, a]) {
|
|
67
|
-
r = r.evaluate(ctx);
|
|
68
|
-
g = g.evaluate(ctx);
|
|
69
|
-
b = b.evaluate(ctx);
|
|
70
|
-
const alpha = a ? a.evaluate(ctx) : 1;
|
|
71
|
-
const error = validateRGBA(r, g, b, alpha);
|
|
72
|
-
if (error) throw new RuntimeError(error);
|
|
73
|
-
return new Color((r / 255) * alpha, (g / 255) * alpha, (b / 255) * alpha, alpha);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function has(key, obj) {
|
|
77
|
-
return key in obj;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function get(key, obj) {
|
|
81
|
-
const v = obj[key];
|
|
82
|
-
return typeof v === 'undefined' ? null : v;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function binarySearch(v, a, i, j) {
|
|
86
|
-
while (i <= j) {
|
|
87
|
-
const m = (i + j) >> 1;
|
|
88
|
-
if (a[m] === v) return true;
|
|
89
|
-
if (a[m] > v) j = m - 1;
|
|
90
|
-
else i = m + 1;
|
|
91
|
-
}
|
|
92
|
-
return false;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function varargs(type) {
|
|
96
|
-
return { type };
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
CompoundExpression.register(expressions, {
|
|
100
|
-
error: [
|
|
101
|
-
ErrorType,
|
|
102
|
-
[StringType],
|
|
103
|
-
(ctx, [v]) => {
|
|
104
|
-
throw new RuntimeError(v.evaluate(ctx));
|
|
105
|
-
}
|
|
106
|
-
],
|
|
107
|
-
typeof: [StringType, [ValueType], (ctx, [v]) => typeToString(typeOf(v.evaluate(ctx)))],
|
|
108
|
-
'to-rgba': [
|
|
109
|
-
array(NumberType, 4),
|
|
110
|
-
[ColorType],
|
|
111
|
-
(ctx, [v]) => {
|
|
112
|
-
return v.evaluate(ctx).toArray();
|
|
113
|
-
}
|
|
114
|
-
],
|
|
115
|
-
rgb: [ColorType, [NumberType, NumberType, NumberType], rgba],
|
|
116
|
-
rgba: [ColorType, [NumberType, NumberType, NumberType, NumberType], rgba],
|
|
117
|
-
has: {
|
|
118
|
-
type: BooleanType,
|
|
119
|
-
overloads: [
|
|
120
|
-
[[StringType], (ctx, [key]) => has(key.evaluate(ctx), ctx.properties())],
|
|
121
|
-
[[StringType, ObjectType], (ctx, [key, obj]) => has(key.evaluate(ctx), obj.evaluate(ctx))]
|
|
122
|
-
]
|
|
123
|
-
},
|
|
124
|
-
get: {
|
|
125
|
-
type: ValueType,
|
|
126
|
-
overloads: [
|
|
127
|
-
[[StringType], (ctx, [key]) => get(key.evaluate(ctx), ctx.properties())],
|
|
128
|
-
[[StringType, ObjectType], (ctx, [key, obj]) => get(key.evaluate(ctx), obj.evaluate(ctx))]
|
|
129
|
-
]
|
|
130
|
-
},
|
|
131
|
-
'feature-state': [ValueType, [StringType], (ctx, [key]) => get(key.evaluate(ctx), ctx.featureState || {})],
|
|
132
|
-
properties: [ObjectType, [], ctx => ctx.properties()],
|
|
133
|
-
'geometry-type': [StringType, [], ctx => ctx.geometryType()],
|
|
134
|
-
id: [ValueType, [], ctx => ctx.id()],
|
|
135
|
-
zoom: [NumberType, [], ctx => ctx.globals.zoom],
|
|
136
|
-
'heatmap-density': [NumberType, [], ctx => ctx.globals.heatmapDensity || 0],
|
|
137
|
-
'line-progress': [NumberType, [], ctx => ctx.globals.lineProgress || 0],
|
|
138
|
-
'+': [
|
|
139
|
-
NumberType,
|
|
140
|
-
varargs(NumberType),
|
|
141
|
-
(ctx, args) => {
|
|
142
|
-
let result = 0;
|
|
143
|
-
for (const arg of args) {
|
|
144
|
-
result += arg.evaluate(ctx);
|
|
145
|
-
}
|
|
146
|
-
return result;
|
|
147
|
-
}
|
|
148
|
-
],
|
|
149
|
-
'*': [
|
|
150
|
-
NumberType,
|
|
151
|
-
varargs(NumberType),
|
|
152
|
-
(ctx, args) => {
|
|
153
|
-
let result = 1;
|
|
154
|
-
for (const arg of args) {
|
|
155
|
-
result *= arg.evaluate(ctx);
|
|
156
|
-
}
|
|
157
|
-
return result;
|
|
158
|
-
}
|
|
159
|
-
],
|
|
160
|
-
'-': {
|
|
161
|
-
type: NumberType,
|
|
162
|
-
overloads: [
|
|
163
|
-
[[NumberType, NumberType], (ctx, [a, b]) => a.evaluate(ctx) - b.evaluate(ctx)],
|
|
164
|
-
[[NumberType], (ctx, [a]) => -a.evaluate(ctx)]
|
|
165
|
-
]
|
|
166
|
-
},
|
|
167
|
-
'/': [NumberType, [NumberType, NumberType], (ctx, [a, b]) => a.evaluate(ctx) / b.evaluate(ctx)],
|
|
168
|
-
'%': [NumberType, [NumberType, NumberType], (ctx, [a, b]) => a.evaluate(ctx) % b.evaluate(ctx)],
|
|
169
|
-
ln2: [NumberType, [], () => Math.LN2],
|
|
170
|
-
pi: [NumberType, [], () => Math.PI],
|
|
171
|
-
e: [NumberType, [], () => Math.E],
|
|
172
|
-
'^': [NumberType, [NumberType, NumberType], (ctx, [b, e]) => b.evaluate(ctx) ** e.evaluate(ctx)],
|
|
173
|
-
sqrt: [NumberType, [NumberType], (ctx, [x]) => Math.sqrt(x.evaluate(ctx))],
|
|
174
|
-
log10: [NumberType, [NumberType], (ctx, [n]) => Math.log10(n.evaluate(ctx))],
|
|
175
|
-
ln: [NumberType, [NumberType], (ctx, [n]) => Math.log(n.evaluate(ctx))],
|
|
176
|
-
log2: [NumberType, [NumberType], (ctx, [n]) => Math.log2(n.evaluate(ctx))],
|
|
177
|
-
sin: [NumberType, [NumberType], (ctx, [n]) => Math.sin(n.evaluate(ctx))],
|
|
178
|
-
cos: [NumberType, [NumberType], (ctx, [n]) => Math.cos(n.evaluate(ctx))],
|
|
179
|
-
tan: [NumberType, [NumberType], (ctx, [n]) => Math.tan(n.evaluate(ctx))],
|
|
180
|
-
asin: [NumberType, [NumberType], (ctx, [n]) => Math.asin(n.evaluate(ctx))],
|
|
181
|
-
acos: [NumberType, [NumberType], (ctx, [n]) => Math.acos(n.evaluate(ctx))],
|
|
182
|
-
atan: [NumberType, [NumberType], (ctx, [n]) => Math.atan(n.evaluate(ctx))],
|
|
183
|
-
min: [NumberType, varargs(NumberType), (ctx, args) => Math.min(...args.map(arg => arg.evaluate(ctx)))],
|
|
184
|
-
max: [NumberType, varargs(NumberType), (ctx, args) => Math.max(...args.map(arg => arg.evaluate(ctx)))],
|
|
185
|
-
abs: [NumberType, [NumberType], (ctx, [n]) => Math.abs(n.evaluate(ctx))],
|
|
186
|
-
round: [
|
|
187
|
-
NumberType,
|
|
188
|
-
[NumberType],
|
|
189
|
-
(ctx, [n]) => {
|
|
190
|
-
const v = n.evaluate(ctx);
|
|
191
|
-
// Javascript's Math.round() rounds towards +Infinity for halfway
|
|
192
|
-
// values, even when they're negative. It's more common to round
|
|
193
|
-
// away from 0 (e.g., this is what python and C++ do)
|
|
194
|
-
return v < 0 ? -Math.round(-v) : Math.round(v);
|
|
195
|
-
}
|
|
196
|
-
],
|
|
197
|
-
floor: [NumberType, [NumberType], (ctx, [n]) => Math.floor(n.evaluate(ctx))],
|
|
198
|
-
ceil: [NumberType, [NumberType], (ctx, [n]) => Math.ceil(n.evaluate(ctx))],
|
|
199
|
-
'filter-==': [BooleanType, [StringType, ValueType], (ctx, [k, v]) => ctx.properties()[k.value] === v.value],
|
|
200
|
-
'filter-id-==': [BooleanType, [ValueType], (ctx, [v]) => ctx.id() === v.value],
|
|
201
|
-
'filter-type-==': [BooleanType, [StringType], (ctx, [v]) => ctx.geometryType() === v.value],
|
|
202
|
-
'filter-<': [
|
|
203
|
-
BooleanType,
|
|
204
|
-
[StringType, ValueType],
|
|
205
|
-
(ctx, [k, v]) => {
|
|
206
|
-
const a = ctx.properties()[k.value];
|
|
207
|
-
const b = v.value;
|
|
208
|
-
return typeof a === typeof b && a < b;
|
|
209
|
-
}
|
|
210
|
-
],
|
|
211
|
-
'filter-id-<': [
|
|
212
|
-
BooleanType,
|
|
213
|
-
[ValueType],
|
|
214
|
-
(ctx, [v]) => {
|
|
215
|
-
const a = ctx.id();
|
|
216
|
-
const b = v.value;
|
|
217
|
-
return typeof a === typeof b && a < b;
|
|
218
|
-
}
|
|
219
|
-
],
|
|
220
|
-
'filter->': [
|
|
221
|
-
BooleanType,
|
|
222
|
-
[StringType, ValueType],
|
|
223
|
-
(ctx, [k, v]) => {
|
|
224
|
-
const a = ctx.properties()[k.value];
|
|
225
|
-
const b = v.value;
|
|
226
|
-
return typeof a === typeof b && a > b;
|
|
227
|
-
}
|
|
228
|
-
],
|
|
229
|
-
'filter-id->': [
|
|
230
|
-
BooleanType,
|
|
231
|
-
[ValueType],
|
|
232
|
-
(ctx, [v]) => {
|
|
233
|
-
const a = ctx.id();
|
|
234
|
-
const b = v.value;
|
|
235
|
-
return typeof a === typeof b && a > b;
|
|
236
|
-
}
|
|
237
|
-
],
|
|
238
|
-
'filter-<=': [
|
|
239
|
-
BooleanType,
|
|
240
|
-
[StringType, ValueType],
|
|
241
|
-
(ctx, [k, v]) => {
|
|
242
|
-
const a = ctx.properties()[k.value];
|
|
243
|
-
const b = v.value;
|
|
244
|
-
return typeof a === typeof b && a <= b;
|
|
245
|
-
}
|
|
246
|
-
],
|
|
247
|
-
'filter-id-<=': [
|
|
248
|
-
BooleanType,
|
|
249
|
-
[ValueType],
|
|
250
|
-
(ctx, [v]) => {
|
|
251
|
-
const a = ctx.id();
|
|
252
|
-
const b = v.value;
|
|
253
|
-
return typeof a === typeof b && a <= b;
|
|
254
|
-
}
|
|
255
|
-
],
|
|
256
|
-
'filter->=': [
|
|
257
|
-
BooleanType,
|
|
258
|
-
[StringType, ValueType],
|
|
259
|
-
(ctx, [k, v]) => {
|
|
260
|
-
const a = ctx.properties()[k.value];
|
|
261
|
-
const b = v.value;
|
|
262
|
-
return typeof a === typeof b && a >= b;
|
|
263
|
-
}
|
|
264
|
-
],
|
|
265
|
-
'filter-id->=': [
|
|
266
|
-
BooleanType,
|
|
267
|
-
[ValueType],
|
|
268
|
-
(ctx, [v]) => {
|
|
269
|
-
const a = ctx.id();
|
|
270
|
-
const b = v.value;
|
|
271
|
-
return typeof a === typeof b && a >= b;
|
|
272
|
-
}
|
|
273
|
-
],
|
|
274
|
-
'filter-has': [BooleanType, [ValueType], (ctx, [k]) => k.value in ctx.properties()],
|
|
275
|
-
'filter-has-id': [BooleanType, [], ctx => ctx.id() !== null],
|
|
276
|
-
'filter-type-in': [BooleanType, [array(StringType)], (ctx, [v]) => v.value.indexOf(ctx.geometryType()) >= 0],
|
|
277
|
-
'filter-id-in': [BooleanType, [array(ValueType)], (ctx, [v]) => v.value.indexOf(ctx.id()) >= 0],
|
|
278
|
-
'filter-in-small': [
|
|
279
|
-
BooleanType,
|
|
280
|
-
[StringType, array(ValueType)],
|
|
281
|
-
// assumes v is an array literal
|
|
282
|
-
(ctx, [k, v]) => v.value.indexOf(ctx.properties()[k.value]) >= 0
|
|
283
|
-
],
|
|
284
|
-
'filter-in-large': [
|
|
285
|
-
BooleanType,
|
|
286
|
-
[StringType, array(ValueType)],
|
|
287
|
-
// assumes v is a array literal with values sorted in ascending order and of a single type
|
|
288
|
-
(ctx, [k, v]) => binarySearch(ctx.properties()[k.value], v.value, 0, v.value.length - 1)
|
|
289
|
-
],
|
|
290
|
-
all: {
|
|
291
|
-
type: BooleanType,
|
|
292
|
-
overloads: [
|
|
293
|
-
[[BooleanType, BooleanType], (ctx, [a, b]) => a.evaluate(ctx) && b.evaluate(ctx)],
|
|
294
|
-
[
|
|
295
|
-
varargs(BooleanType),
|
|
296
|
-
(ctx, args) => {
|
|
297
|
-
for (const arg of args) {
|
|
298
|
-
if (!arg.evaluate(ctx)) return false;
|
|
299
|
-
}
|
|
300
|
-
return true;
|
|
301
|
-
}
|
|
302
|
-
]
|
|
303
|
-
]
|
|
304
|
-
},
|
|
305
|
-
any: {
|
|
306
|
-
type: BooleanType,
|
|
307
|
-
overloads: [
|
|
308
|
-
[[BooleanType, BooleanType], (ctx, [a, b]) => a.evaluate(ctx) || b.evaluate(ctx)],
|
|
309
|
-
[
|
|
310
|
-
varargs(BooleanType),
|
|
311
|
-
(ctx, args) => {
|
|
312
|
-
for (const arg of args) {
|
|
313
|
-
if (arg.evaluate(ctx)) return true;
|
|
314
|
-
}
|
|
315
|
-
return false;
|
|
316
|
-
}
|
|
317
|
-
]
|
|
318
|
-
]
|
|
319
|
-
},
|
|
320
|
-
'!': [BooleanType, [BooleanType], (ctx, [b]) => !b.evaluate(ctx)],
|
|
321
|
-
'is-supported-script': [
|
|
322
|
-
BooleanType,
|
|
323
|
-
[StringType],
|
|
324
|
-
// At parse time this will always return true, so we need to exclude this expression with isGlobalPropertyConstant
|
|
325
|
-
(ctx, [s]) => {
|
|
326
|
-
const isSupportedScript = ctx.globals?.isSupportedScript;
|
|
327
|
-
if (isSupportedScript) {
|
|
328
|
-
return isSupportedScript(s.evaluate(ctx));
|
|
329
|
-
}
|
|
330
|
-
return true;
|
|
331
|
-
}
|
|
332
|
-
],
|
|
333
|
-
upcase: [StringType, [StringType], (ctx, [s]) => s.evaluate(ctx).toUpperCase()],
|
|
334
|
-
downcase: [StringType, [StringType], (ctx, [s]) => s.evaluate(ctx).toLowerCase()],
|
|
335
|
-
concat: [StringType, varargs(ValueType), (ctx, args) => args.map(arg => valueToString(arg.evaluate(ctx))).join('')],
|
|
336
|
-
'resolved-locale': [StringType, [CollatorType], (ctx, [collator]) => collator.evaluate(ctx).resolvedLocale()]
|
|
337
|
-
});
|
|
338
|
-
|
|
339
|
-
module.exports = expressions;
|
|
@@ -1,245 +0,0 @@
|
|
|
1
|
-
const UnitBezier = require('@mapbox/unitbezier');
|
|
2
|
-
|
|
3
|
-
const interpolate = require('../../util/interpolate');
|
|
4
|
-
const { toString, ColorType, NumberType } = require('../types');
|
|
5
|
-
const { findStopLessThanOrEqualTo } = require('../stops');
|
|
6
|
-
const { hcl, lab } = require('../../util/color_spaces');
|
|
7
|
-
|
|
8
|
-
class Interpolate {
|
|
9
|
-
constructor(type, operator, interpolation, input, stops) {
|
|
10
|
-
this.type = type;
|
|
11
|
-
this.operator = operator;
|
|
12
|
-
this.interpolation = interpolation;
|
|
13
|
-
this.input = input;
|
|
14
|
-
|
|
15
|
-
this.labels = [];
|
|
16
|
-
this.outputs = [];
|
|
17
|
-
for (const [label, expression] of stops) {
|
|
18
|
-
this.labels.push(label);
|
|
19
|
-
this.outputs.push(expression);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
static interpolationFactor(interpolation, input, lower, upper) {
|
|
24
|
-
let t = 0;
|
|
25
|
-
if (interpolation.name === 'exponential') {
|
|
26
|
-
t = exponentialInterpolation(input, interpolation.base, lower, upper);
|
|
27
|
-
} else if (interpolation.name === 'linear') {
|
|
28
|
-
t = exponentialInterpolation(input, 1, lower, upper);
|
|
29
|
-
} else if (interpolation.name === 'cubic-bezier') {
|
|
30
|
-
const c = interpolation.controlPoints;
|
|
31
|
-
const ub = new UnitBezier(c[0], c[1], c[2], c[3]);
|
|
32
|
-
t = ub.solve(exponentialInterpolation(input, 1, lower, upper));
|
|
33
|
-
}
|
|
34
|
-
return t;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
static parse(args, context) {
|
|
38
|
-
let [operator, interpolation, input, ...rest] = args;
|
|
39
|
-
|
|
40
|
-
if (!Array.isArray(interpolation) || interpolation.length === 0) {
|
|
41
|
-
return context.error('Expected an interpolation type expression.', 1);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (interpolation[0] === 'linear') {
|
|
45
|
-
interpolation = { name: 'linear' };
|
|
46
|
-
} else if (interpolation[0] === 'exponential') {
|
|
47
|
-
const base = interpolation[1];
|
|
48
|
-
if (typeof base !== 'number') return context.error('Exponential interpolation requires a numeric base.', 1, 1);
|
|
49
|
-
interpolation = {
|
|
50
|
-
name: 'exponential',
|
|
51
|
-
base
|
|
52
|
-
};
|
|
53
|
-
} else if (interpolation[0] === 'cubic-bezier') {
|
|
54
|
-
const controlPoints = interpolation.slice(1);
|
|
55
|
-
if (controlPoints.length !== 4 || controlPoints.some(t => typeof t !== 'number' || t < 0 || t > 1)) {
|
|
56
|
-
return context.error(
|
|
57
|
-
'Cubic bezier interpolation requires four numeric arguments with values between 0 and 1.',
|
|
58
|
-
1
|
|
59
|
-
);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
interpolation = {
|
|
63
|
-
name: 'cubic-bezier',
|
|
64
|
-
controlPoints: controlPoints
|
|
65
|
-
};
|
|
66
|
-
} else {
|
|
67
|
-
return context.error(`Unknown interpolation type ${String(interpolation[0])}`, 1, 0);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
if (args.length - 1 < 4) {
|
|
71
|
-
return context.error(`Expected at least 4 arguments, but found only ${args.length - 1}.`);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
if ((args.length - 1) % 2 !== 0) {
|
|
75
|
-
return context.error('Expected an even number of arguments.');
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
input = context.parse(input, 2, NumberType);
|
|
79
|
-
if (!input) return null;
|
|
80
|
-
|
|
81
|
-
const stops = [];
|
|
82
|
-
|
|
83
|
-
let outputType = null;
|
|
84
|
-
if (operator === 'interpolate-hcl' || operator === 'interpolate-lab') {
|
|
85
|
-
outputType = ColorType;
|
|
86
|
-
} else if (context.expectedType && context.expectedType.kind !== 'value') {
|
|
87
|
-
outputType = context.expectedType;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
for (let i = 0; i < rest.length; i += 2) {
|
|
91
|
-
const label = rest[i];
|
|
92
|
-
const value = rest[i + 1];
|
|
93
|
-
|
|
94
|
-
const labelKey = i + 3;
|
|
95
|
-
const valueKey = i + 4;
|
|
96
|
-
|
|
97
|
-
if (typeof label !== 'number') {
|
|
98
|
-
return context.error(
|
|
99
|
-
'Input/output pairs for "interpolate" expressions must be defined using literal numeric values (not computed expressions) for the input values.',
|
|
100
|
-
labelKey
|
|
101
|
-
);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (stops.length && stops[stops.length - 1][0] >= label) {
|
|
105
|
-
return context.error(
|
|
106
|
-
'Input/output pairs for "interpolate" expressions must be arranged with input values in strictly ascending order.',
|
|
107
|
-
labelKey
|
|
108
|
-
);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const parsed = context.parse(value, valueKey, outputType);
|
|
112
|
-
if (!parsed) return null;
|
|
113
|
-
outputType = outputType || parsed.type;
|
|
114
|
-
stops.push([label, parsed]);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
if (
|
|
118
|
-
outputType.kind !== 'number' &&
|
|
119
|
-
outputType.kind !== 'color' &&
|
|
120
|
-
!(outputType.kind === 'array' && outputType.itemType.kind === 'number' && typeof outputType.N === 'number')
|
|
121
|
-
) {
|
|
122
|
-
return context.error(`Type ${toString(outputType)} is not interpolatable.`);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
return new Interpolate(outputType, operator, interpolation, input, stops);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
evaluate(ctx) {
|
|
129
|
-
const labels = this.labels;
|
|
130
|
-
const outputs = this.outputs;
|
|
131
|
-
|
|
132
|
-
if (labels.length === 1) {
|
|
133
|
-
return outputs[0].evaluate(ctx);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
const value = this.input.evaluate(ctx);
|
|
137
|
-
if (value <= labels[0]) {
|
|
138
|
-
return outputs[0].evaluate(ctx);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
const stopCount = labels.length;
|
|
142
|
-
if (value >= labels[stopCount - 1]) {
|
|
143
|
-
return outputs[stopCount - 1].evaluate(ctx);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const index = findStopLessThanOrEqualTo(labels, value);
|
|
147
|
-
const lower = labels[index];
|
|
148
|
-
const upper = labels[index + 1];
|
|
149
|
-
const t = Interpolate.interpolationFactor(this.interpolation, value, lower, upper);
|
|
150
|
-
|
|
151
|
-
const outputLower = outputs[index].evaluate(ctx);
|
|
152
|
-
const outputUpper = outputs[index + 1].evaluate(ctx);
|
|
153
|
-
|
|
154
|
-
if (this.operator === 'interpolate') {
|
|
155
|
-
return interpolate[this.type.kind.toLowerCase()](outputLower, outputUpper, t);
|
|
156
|
-
}
|
|
157
|
-
if (this.operator === 'interpolate-hcl') {
|
|
158
|
-
return hcl.reverse(hcl.interpolate(hcl.forward(outputLower), hcl.forward(outputUpper), t));
|
|
159
|
-
}
|
|
160
|
-
return lab.reverse(lab.interpolate(lab.forward(outputLower), lab.forward(outputUpper), t));
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
eachChild(fn) {
|
|
164
|
-
fn(this.input);
|
|
165
|
-
for (const expression of this.outputs) {
|
|
166
|
-
fn(expression);
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
possibleOutputs() {
|
|
171
|
-
return [].concat(...this.outputs.map(output => output.possibleOutputs()));
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
serialize() {
|
|
175
|
-
let interpolation;
|
|
176
|
-
if (this.interpolation.name === 'linear') {
|
|
177
|
-
interpolation = ['linear'];
|
|
178
|
-
} else if (this.interpolation.name === 'exponential') {
|
|
179
|
-
if (this.interpolation.base === 1) {
|
|
180
|
-
interpolation = ['linear'];
|
|
181
|
-
} else {
|
|
182
|
-
interpolation = ['exponential', this.interpolation.base];
|
|
183
|
-
}
|
|
184
|
-
} else {
|
|
185
|
-
interpolation = ['cubic-bezier'].concat(this.interpolation.controlPoints);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
const serialized = [this.operator, interpolation, this.input.serialize()];
|
|
189
|
-
|
|
190
|
-
for (let i = 0; i < this.labels.length; i++) {
|
|
191
|
-
serialized.push(this.labels[i], this.outputs[i].serialize());
|
|
192
|
-
}
|
|
193
|
-
return serialized;
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* Returns a ratio that can be used to interpolate between exponential function
|
|
199
|
-
* stops.
|
|
200
|
-
* How it works: Two consecutive stop values define a (scaled and shifted) exponential function `f(x) = a * base^x + b`, where `base` is the user-specified base,
|
|
201
|
-
* and `a` and `b` are constants affording sufficient degrees of freedom to fit
|
|
202
|
-
* the function to the given stops.
|
|
203
|
-
*
|
|
204
|
-
* Here's a bit of algebra that lets us compute `f(x)` directly from the stop
|
|
205
|
-
* values without explicitly solving for `a` and `b`:
|
|
206
|
-
*
|
|
207
|
-
* First stop value: `f(x0) = y0 = a * base^x0 + b`
|
|
208
|
-
* Second stop value: `f(x1) = y1 = a * base^x1 + b`
|
|
209
|
-
* => `y1 - y0 = a(base^x1 - base^x0)`
|
|
210
|
-
* => `a = (y1 - y0)/(base^x1 - base^x0)`
|
|
211
|
-
*
|
|
212
|
-
* Desired value: `f(x) = y = a * base^x + b`
|
|
213
|
-
* => `f(x) = y0 + a * (base^x - base^x0)`
|
|
214
|
-
*
|
|
215
|
-
* From the above, we can replace the `a` in `a * (base^x - base^x0)` and do a
|
|
216
|
-
* little algebra:
|
|
217
|
-
* ```
|
|
218
|
-
* a * (base^x - base^x0) = (y1 - y0)/(base^x1 - base^x0) * (base^x - base^x0)
|
|
219
|
-
* = (y1 - y0) * (base^x - base^x0) / (base^x1 - base^x0)
|
|
220
|
-
* ```
|
|
221
|
-
*
|
|
222
|
-
* If we let `(base^x - base^x0) / (base^x1 base^x0)`, then we have
|
|
223
|
-
* `f(x) = y0 + (y1 - y0) * ratio`. In other words, `ratio` may be treated as
|
|
224
|
-
* an interpolation factor between the two stops' output values.
|
|
225
|
-
*
|
|
226
|
-
* (Note: a slightly different form for `ratio`,
|
|
227
|
-
* `(base^(x-x0) - 1) / (base^(x1-x0) - 1) `, is equivalent, but requires fewer
|
|
228
|
-
* expensive `Math.pow()` operations.)
|
|
229
|
-
*
|
|
230
|
-
* @private
|
|
231
|
-
*/
|
|
232
|
-
function exponentialInterpolation(input, base, lowerValue, upperValue) {
|
|
233
|
-
const difference = upperValue - lowerValue;
|
|
234
|
-
const progress = input - lowerValue;
|
|
235
|
-
|
|
236
|
-
if (difference === 0) {
|
|
237
|
-
return 0;
|
|
238
|
-
}
|
|
239
|
-
if (base === 1) {
|
|
240
|
-
return progress / difference;
|
|
241
|
-
}
|
|
242
|
-
return (base ** progress - 1) / (base ** difference - 1);
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
module.exports = Interpolate;
|