Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions build/generate-style-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
6 changes: 3 additions & 3 deletions docs/types.md
Original file line number Diff line number Diff line change
Expand Up @@ -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"
]
Expand All @@ -205,4 +205,4 @@ There are also additional presets that yield commonly used expressions:

| Preset | Full value | Description |
|--------|------------|-------------|
| `globe` | `["interpolate-projection", ["linear"], ["zoom"],`<br>`10, "vertical-perspective", 12, "mercator"]` | Adaptive globe: interpolates from vertical-perspective to mercator projection between zoom levels 10 and 12. |
| `globe` | `["interpolate", ["linear"], ["zoom"],`<br>`10, "vertical-perspective", 12, "mercator"]` | Adaptive globe: interpolates from vertical-perspective to mercator projection between zoom levels 10 and 12. |
2 changes: 2 additions & 0 deletions src/expression/definitions/coercion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Expand Down
1 change: 0 additions & 1 deletion src/expression/definitions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
10 changes: 3 additions & 7 deletions src/expression/definitions/interpolate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export type InterpolationType = {
controlPoints: [number, number, number, number];
};
type InterpolatedValueType = NumberTypeT | ColorTypeT | ProjectionTypeT | PaddingTypeT | VariableAnchorOffsetCollectionTypeT | ArrayType<NumberTypeT>;
type InterpolationOperator = 'interpolate' | 'interpolate-hcl' | 'interpolate-lab' | 'interpolate-projection';
type InterpolationOperator = 'interpolate' | 'interpolate-hcl' | 'interpolate-lab';
class Interpolate implements Expression {
type: InterpolatedValueType;

Expand Down Expand Up @@ -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;
}
Expand All @@ -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;
Expand Down Expand Up @@ -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);
}
}
}

Expand Down
6 changes: 5 additions & 1 deletion src/expression/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -391,6 +391,8 @@ export function normalizePropertyExpression<T>(
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',
Expand Down Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion src/expression/parsing_context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down
8 changes: 7 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'};
Expand Down Expand Up @@ -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';
Expand Down
28 changes: 8 additions & 20 deletions src/reference/v8.json
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@
"doc": "The projection configuration",
"example": {
"type": [
"interpolate-projection",
"interpolate",
["linear"],
["zoom"],
10, "globe",
Expand Down Expand Up @@ -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": {
Expand Down Expand Up @@ -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": [
Expand Down
15 changes: 14 additions & 1 deletion src/util/projection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -23,7 +36,7 @@ export function isProjectionConfig(value: unknown): value is ProjectionSpecifica

export function isPropertyValueSpecification(value: unknown): value is PropertyValueSpecification<ProjectionT> {

if (['interpolate-projection', 'step', 'literal'].includes(value[0])) {
if (['interpolate', 'step', 'literal'].includes(value[0])) {
return true
}
return false
Expand Down
2 changes: 1 addition & 1 deletion src/validate/validate_projection.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});

Expand Down
2 changes: 1 addition & 1 deletion src/validate/validate_projectionconfig.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
{
"propertySpec": {
"type": "projection",
"property-type": "data-constant",
"expression": {
"interpolated": true,
"parameters": [
"zoom"
]
}
},
"expression": [
"interpolate-projection",
"interpolate",
[
"linear"
],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
{
"propertySpec": {
"type": "projection",
"property-type": "data-constant",
"expression": {
"interpolated": true,
"parameters": [
"zoom"
]
}
},
"expression": [
"interpolate-projection",
"interpolate",
[
"linear"
],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
{
"propertySpec": {
"type": "projection",
"property-type": "data-constant",
"expression": {
"interpolated": true,
"parameters": [
"zoom"
]
}
},
"expression": [
"interpolate-projection",
"interpolate",
[
"linear"
],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
{
"propertySpec": {
"type": "projection",
"property-type": "data-constant",
"expression": {
"interpolated": true,
"parameters": [
"zoom"
]
}
},
"expression": [
"interpolate-projection",
"interpolate",
[
"linear"
],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
{
"propertySpec": {
"type": "projection",
"property-type": "data-constant",
"expression": {
"interpolated": true,
"parameters": [
"zoom"
]
}
},
"expression": [
"interpolate-projection",
"interpolate",
[
"linear"
],
Expand Down