diff --git a/build/generate-style-spec.ts b/build/generate-style-spec.ts
index 303d8de49..d0e3170e2 100644
--- a/build/generate-style-spec.ts
+++ b/build/generate-style-spec.ts
@@ -207,9 +207,7 @@ export type ExpressionSpecification =
| ['distance', unknown | ExpressionSpecification]
// Ramps, scales, curves
| ['interpolate', InterpolationSpecification, number | ExpressionSpecification,
- ...(number | number[] | ColorSpecification | ExpressionSpecification)[]] // alternating number and number | number[] | ColorSpecification
- | ['interpolate-projection', InterpolationSpecification, number | ExpressionSpecification,
- ...(number | string)[]] // alternating Projection
+ ...(number | number[] | ColorSpecification | ExpressionSpecification | ProjectionSpecification )[]] // alternating number and number | number[] | ColorSpecification
| ['interpolate-hcl', InterpolationSpecification, number | ExpressionSpecification,
...(number | ColorSpecification)[]] // alternating number and ColorSpecificaton
| ['interpolate-lab', InterpolationSpecification, number | ExpressionSpecification,
diff --git a/docs/types.md b/docs/types.md
index 659514271..3de9171f8 100644
--- a/docs/types.md
+++ b/docs/types.md
@@ -176,10 +176,10 @@ output at zoom 11.1: "mercator"
#### Animate between different projections based on zoom level**
-Use a [`camera expression`](./expressions.md#camera-expressions), to animate between projections based on zoom, using [`interpolate-projection`](./expressions.md#interpolate-projection) function. The example below will yield an adaptive globe that interpolates from `vertical-perspective` to `mercator` between zoom 10 and 12.
+Use a [`camera expression`](./expressions.md#camera-expressions), to animate between projections based on zoom, using [`interpolate`](./expressions.md#interpolate) function. The example below will yield an adaptive globe that interpolates from `vertical-perspective` to `mercator` between zoom 10 and 12.
```ts
-type: ["interpolate-projection", ["linear"], ["zoom"],
+type: ["interpolate", ["linear"], ["zoom"],
10,"vertical-perspective",
12,"mercator"
]
@@ -205,4 +205,4 @@ There are also additional presets that yield commonly used expressions:
| Preset | Full value | Description |
|--------|------------|-------------|
-| `globe` | `["interpolate-projection", ["linear"], ["zoom"],`
`10, "vertical-perspective", 12, "mercator"]` | Adaptive globe: interpolates from vertical-perspective to mercator projection between zoom levels 10 and 12. |
+| `globe` | `["interpolate", ["linear"], ["zoom"],`
`10, "vertical-perspective", 12, "mercator"]` | Adaptive globe: interpolates from vertical-perspective to mercator projection between zoom levels 10 and 12. |
diff --git a/src/expression/definitions/coercion.ts b/src/expression/definitions/coercion.ts
index c38d1f998..e4b27c7a4 100644
--- a/src/expression/definitions/coercion.ts
+++ b/src/expression/definitions/coercion.ts
@@ -123,6 +123,8 @@ class Coercion implements Expression {
return Formatted.fromString(valueToString(this.args[0].evaluate(ctx)));
case 'resolvedImage':
return ResolvedImage.fromString(valueToString(this.args[0].evaluate(ctx)));
+ case 'projection':
+ return this.args[0].evaluate(ctx);
default:
return valueToString(this.args[0].evaluate(ctx));
}
diff --git a/src/expression/definitions/index.ts b/src/expression/definitions/index.ts
index b32766659..8832a0a90 100644
--- a/src/expression/definitions/index.ts
+++ b/src/expression/definitions/index.ts
@@ -52,7 +52,6 @@ export const expressions: ExpressionRegistry = {
'interpolate': Interpolate,
'interpolate-hcl': Interpolate,
'interpolate-lab': Interpolate,
- 'interpolate-projection': Interpolate,
'length': Length,
'let': Let,
'literal': Literal,
diff --git a/src/expression/definitions/interpolate.ts b/src/expression/definitions/interpolate.ts
index ec0b13760..585f721e6 100644
--- a/src/expression/definitions/interpolate.ts
+++ b/src/expression/definitions/interpolate.ts
@@ -20,7 +20,7 @@ export type InterpolationType = {
controlPoints: [number, number, number, number];
};
type InterpolatedValueType = NumberTypeT | ColorTypeT | ProjectionTypeT | PaddingTypeT | VariableAnchorOffsetCollectionTypeT | ArrayType;
-type InterpolationOperator = 'interpolate' | 'interpolate-hcl' | 'interpolate-lab' | 'interpolate-projection';
+type InterpolationOperator = 'interpolate' | 'interpolate-hcl' | 'interpolate-lab';
class Interpolate implements Expression {
type: InterpolatedValueType;
@@ -108,8 +108,6 @@ class Interpolate implements Expression {
let outputType: Type = null;
if (operator === 'interpolate-hcl' || operator === 'interpolate-lab') {
outputType = ColorType;
- } else if (operator === 'interpolate-projection') {
- outputType = ProjectionType;
} else if (context.expectedType && context.expectedType.kind !== 'value') {
outputType = context.expectedType;
}
@@ -128,7 +126,6 @@ class Interpolate implements Expression {
if (stops.length && stops[stops.length - 1][0] >= label) {
return context.error('Input/output pairs for "interpolate" expressions must be arranged with input values in strictly ascending order.', labelKey) as null;
}
-
const parsed = context.parse(value, valueKey, outputType);
if (!parsed) return null;
outputType = outputType || parsed.type;
@@ -187,14 +184,13 @@ class Interpolate implements Expression {
return interpolate.padding(outputLower, outputUpper, t);
case 'variableAnchorOffsetCollection':
return interpolate.variableAnchorOffsetCollection(outputLower, outputUpper, t);
+ case 'projection':
+ return interpolate.projection(outputLower, outputUpper, t);
}
case 'interpolate-hcl':
return interpolate.color(outputLower, outputUpper, t, 'hcl');
case 'interpolate-lab':
return interpolate.color(outputLower, outputUpper, t, 'lab');
- case 'interpolate-projection': {
- return interpolate.projection(outputLower, outputUpper, t);
- }
}
}
diff --git a/src/expression/index.ts b/src/expression/index.ts
index 8df563433..1253baa90 100644
--- a/src/expression/index.ts
+++ b/src/expression/index.ts
@@ -334,7 +334,7 @@ export function createPropertyExpression(expressionInput: unknown, propertySpec:
}
import {isFunction, createFunction} from '../function';
-import {Color, VariableAnchorOffsetCollection} from './values';
+import {Color, Projection, VariableAnchorOffsetCollection} from './values';
// serialization wrapper for old-style stop functions normalized to the
// expression interface
@@ -391,6 +391,8 @@ export function normalizePropertyExpression(
constant = Padding.parse(value as (number | number[]));
} else if (specification.type === 'variableAnchorOffsetCollection' && Array.isArray(value)) {
constant = VariableAnchorOffsetCollection.parse(value as VariableAnchorOffsetCollectionSpecification);
+ } else if (specification.type === 'projection' && typeof value === 'string') {
+ constant = value;
}
return {
kind: 'constant',
@@ -477,6 +479,8 @@ function getDefaultValue(spec: StylePropertySpecification): Value {
return Padding.parse(spec.default) || null;
} else if (spec.type === 'variableAnchorOffsetCollection') {
return VariableAnchorOffsetCollection.parse(spec.default) || null;
+ } else if (spec.type === 'projection') {
+ return Projection.parse(spec.default) || null;
} else if (spec.default === undefined) {
return null;
} else {
diff --git a/src/expression/parsing_context.ts b/src/expression/parsing_context.ts
index 03d6564f4..335dfd4eb 100644
--- a/src/expression/parsing_context.ts
+++ b/src/expression/parsing_context.ts
@@ -120,7 +120,7 @@ class ParsingContext {
//
if ((expected.kind === 'string' || expected.kind === 'number' || expected.kind === 'boolean' || expected.kind === 'object' || expected.kind === 'array') && actual.kind === 'value') {
parsed = annotate(parsed, expected, options.typeAnnotation || 'assert');
- } else if ((expected.kind === 'projection') && (actual.kind === 'string')) {
+ } else if ((expected.kind === 'projection') && (actual.kind === 'string' || actual.kind === 'array')) {
parsed = annotate(parsed, expected, options.typeAnnotation || 'coerce');
} else if ((expected.kind === 'color' || expected.kind === 'formatted' || expected.kind === 'resolvedImage') && (actual.kind === 'value' || actual.kind === 'string')) {
parsed = annotate(parsed, expected, options.typeAnnotation || 'coerce');
diff --git a/src/index.ts b/src/index.ts
index a15cc7648..ca439a3b4 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -67,6 +67,12 @@ export type StylePropertySpecification = {
expression?: ExpressionSpecificationDefinition;
transition: boolean;
default?: VariableAnchorOffsetCollectionSpecification;
+} | {
+ type: 'projection';
+ 'property-type': ExpressionType;
+ expression?: ExpressionSpecificationDefinition;
+ transition: boolean;
+ default?: ProjectionSpecification;
};
import v8Spec from './reference/v8.json' with {type: 'json'};
@@ -107,7 +113,7 @@ import {typeOf} from './expression/values';
import FormatExpression from './expression/definitions/format';
import Literal from './expression/definitions/literal';
import CompoundExpression from './expression/compound_expression';
-import {VariableAnchorOffsetCollectionSpecification} from './types.g';
+import {ProjectionSpecification, VariableAnchorOffsetCollectionSpecification} from './types.g';
import format from './format';
import validate from './validate/validate';
import migrate from './migrate';
diff --git a/src/reference/v8.json b/src/reference/v8.json
index 5e083926c..e3c96d3e5 100644
--- a/src/reference/v8.json
+++ b/src/reference/v8.json
@@ -130,7 +130,7 @@
"doc": "The projection configuration",
"example": {
"type": [
- "interpolate-projection",
+ "interpolate",
["linear"],
["zoom"],
10, "globe",
@@ -3063,24 +3063,6 @@
}
}
},
- "interpolate-projection": {
- "doc": "Produces continuous, smooth results by interpolating between pairs of input and output values (\"stops\"). Works like `interpolate`, but the output type must be a [`projection`](./types.md#projection).",
- "example": {
- "syntax": {
- "method": ["[\"linear\"] | [\"exponential\", base] | [\"cubic-bezier\", x1, y1, x2, y2]", "number", "string", "number", "..."],
- "result": "projection"
- },
- "value": ["interpolate-projection", ["linear"], ["zoom"], 10, "vertical-perspective", 12, "mercator"]
- },
- "group": "Ramps, scales, curves",
- "sdk-support": {
- "basic functionality": {
- "js": "https://github.com/maplibre/maplibre-gl-js/issues/5039",
- "ios": "https://github.com/maplibre/maplibre-native/issues/3013",
- "android": "https://github.com/maplibre/maplibre-native/issues/3013"
- }
- }
- },
"ln2": {
"doc": "Returns mathematical constant ln(2).",
"example": {
@@ -4597,7 +4579,13 @@
"type": "projection",
"doc": "The projection type. Can be specified as a string, a transition state, or an expression.",
"default": "mercator",
- "property-type": "data-constant"
+ "property-type": "data-constant",
+ "expression": {
+ "interpolated": true,
+ "parameters": [
+ "zoom"
+ ]
+ }
}
},
"paint": [
diff --git a/src/util/projection.ts b/src/util/projection.ts
index d0e7043c6..ecdcaa814 100644
--- a/src/util/projection.ts
+++ b/src/util/projection.ts
@@ -15,6 +15,19 @@ export default class Projection extends Array {
toString() {
return `["${this[0]}", "${this[1]}", ${this[2]}]`;
}
+
+ static parse(input: any): Projection {
+ if (input instanceof Projection) {
+ return input;
+ }
+ if (Array.isArray(input) && input.length === 3) {
+ return new Projection(input[0], input[1], input[2]);
+ }
+ if (typeof input === 'string') {
+ return new Projection(input, input, 1);
+ }
+ return undefined;
+ }
}
export function isProjectionConfig(value: unknown): value is ProjectionSpecification {
@@ -23,7 +36,7 @@ export function isProjectionConfig(value: unknown): value is ProjectionSpecifica
export function isPropertyValueSpecification(value: unknown): value is PropertyValueSpecification {
- if (['interpolate-projection', 'step', 'literal'].includes(value[0])) {
+ if (['interpolate', 'step', 'literal'].includes(value[0])) {
return true
}
return false
diff --git a/src/validate/validate_projection.test.ts b/src/validate/validate_projection.test.ts
index 30d7789c4..1ab2e30bb 100644
--- a/src/validate/validate_projection.test.ts
+++ b/src/validate/validate_projection.test.ts
@@ -42,7 +42,7 @@ describe('validateProjection function', () => {
});
test('Should return no errors when projection is valid interpolation-projection expression', () => {
- const errors = validateProjection({value: ['interpolate-projection', ['linear'], ['zoom'], 0, 'mercator', 5, 'vertical-perspective'], key});
+ const errors = validateProjection({value: ['interpolate', ['linear'], ['zoom'], 0, 'mercator', 5, 'vertical-perspective'], key});
expect(errors).toHaveLength(0);
});
diff --git a/src/validate/validate_projectionconfig.test.ts b/src/validate/validate_projectionconfig.test.ts
index 40448ae82..b822c3e88 100644
--- a/src/validate/validate_projectionconfig.test.ts
+++ b/src/validate/validate_projectionconfig.test.ts
@@ -42,7 +42,7 @@ describe('Validate projectionConfig', () => {
});
test('should parse iterpolate-projection', () => {
- const errors = validateProjectionConfig({validateSpec, value: {'type': ['interpolate-projection', ['linear'], ['zoom'], 0, 'mercator', 5, 'vertical-perspective']}, styleSpec: v8, style: {} as any});
+ const errors = validateProjectionConfig({validateSpec, value: {'type': ['interpolate', ['linear'], ['zoom'], 0, 'mercator', 5, 'vertical-perspective']}, styleSpec: v8, style: {} as any});
expect(errors).toHaveLength(0);
});
diff --git a/test/integration/expression/tests/interpolate-projection/higher-than-stop/test.json b/test/integration/expression/tests/interpolate-projection/higher-than-stop/test.json
index 7e92658e4..5acf555c2 100644
--- a/test/integration/expression/tests/interpolate-projection/higher-than-stop/test.json
+++ b/test/integration/expression/tests/interpolate-projection/higher-than-stop/test.json
@@ -1,6 +1,16 @@
{
+ "propertySpec": {
+ "type": "projection",
+ "property-type": "data-constant",
+ "expression": {
+ "interpolated": true,
+ "parameters": [
+ "zoom"
+ ]
+ }
+ },
"expression": [
- "interpolate-projection",
+ "interpolate",
[
"linear"
],
diff --git a/test/integration/expression/tests/interpolate-projection/linear/test.json b/test/integration/expression/tests/interpolate-projection/linear/test.json
index 8c104c8f1..ced897e9d 100644
--- a/test/integration/expression/tests/interpolate-projection/linear/test.json
+++ b/test/integration/expression/tests/interpolate-projection/linear/test.json
@@ -1,6 +1,16 @@
{
+ "propertySpec": {
+ "type": "projection",
+ "property-type": "data-constant",
+ "expression": {
+ "interpolated": true,
+ "parameters": [
+ "zoom"
+ ]
+ }
+ },
"expression": [
- "interpolate-projection",
+ "interpolate",
[
"linear"
],
diff --git a/test/integration/expression/tests/interpolate-projection/lower-than-stop/test.json b/test/integration/expression/tests/interpolate-projection/lower-than-stop/test.json
index 348227556..1b7bf17da 100644
--- a/test/integration/expression/tests/interpolate-projection/lower-than-stop/test.json
+++ b/test/integration/expression/tests/interpolate-projection/lower-than-stop/test.json
@@ -1,6 +1,16 @@
{
+ "propertySpec": {
+ "type": "projection",
+ "property-type": "data-constant",
+ "expression": {
+ "interpolated": true,
+ "parameters": [
+ "zoom"
+ ]
+ }
+ },
"expression": [
- "interpolate-projection",
+ "interpolate",
[
"linear"
],
diff --git a/test/integration/expression/tests/interpolate-projection/same-from-to/test.json b/test/integration/expression/tests/interpolate-projection/same-from-to/test.json
index 31517dd60..4e3acc6ca 100644
--- a/test/integration/expression/tests/interpolate-projection/same-from-to/test.json
+++ b/test/integration/expression/tests/interpolate-projection/same-from-to/test.json
@@ -1,6 +1,16 @@
{
+ "propertySpec": {
+ "type": "projection",
+ "property-type": "data-constant",
+ "expression": {
+ "interpolated": true,
+ "parameters": [
+ "zoom"
+ ]
+ }
+ },
"expression": [
- "interpolate-projection",
+ "interpolate",
[
"linear"
],
diff --git a/test/integration/expression/tests/zoom/interpolate-projection/test.json b/test/integration/expression/tests/zoom/interpolate-projection/test.json
index 1b7c7c815..35041d3ca 100644
--- a/test/integration/expression/tests/zoom/interpolate-projection/test.json
+++ b/test/integration/expression/tests/zoom/interpolate-projection/test.json
@@ -1,6 +1,16 @@
{
+ "propertySpec": {
+ "type": "projection",
+ "property-type": "data-constant",
+ "expression": {
+ "interpolated": true,
+ "parameters": [
+ "zoom"
+ ]
+ }
+ },
"expression": [
- "interpolate-projection",
+ "interpolate",
[
"linear"
],