Skip to content

Commit b723a25

Browse files
committed
work on spec
1 parent 0221c42 commit b723a25

File tree

14 files changed

+143
-78
lines changed

14 files changed

+143
-78
lines changed

build/generate-docs.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ function typeToMarkdownLink(type: string): string {
166166
case 'promoteid':
167167
return ` [${type}](types.md)`;
168168
case 'color':
169-
case 'projectiontype':
169+
case 'projectiontransition':
170170
case 'number':
171171
case 'string':
172172
case 'boolean':

build/generate-style-spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ export type ColorSpecification = string;
126126
127127
export type PrimitiveProjection = 'mercator' | 'globe';
128128
export type ProjectionTransition = [PrimitiveProjection, PrimitiveProjection, number];
129-
export type ProjectionTypeSpecification = PrimitiveProjection | ProjectionTransition | PropertyValueSpecification<ProjectionTransition>
129+
export type ProjectionTransitionSpecification = PrimitiveProjection | ProjectionTransition | PropertyValueSpecification<ProjectionTransition>
130130
131131
132132
export type PaddingSpecification = number | number[];

docs/types.md

Lines changed: 57 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -134,26 +134,37 @@ The following example applies 2em padding on top and bottom and 3em padding left
134134
}
135135
```
136136

137-
## ProjectionType
138137

139-
The `projectionType` type is used to define the projection of the map.
138+
139+
## ProjectionTransition
140+
141+
The `projectionTransition` is used to configure which projection to use for the map.
140142

141143
There are currently two projections implemented.
142144

143145
- `mercator` - Web Mercator projection
146+
- `stereographic` - Stereographic sphere projection
147+
148+
And the following [presets](#use-a-projection-preset)
149+
144150
- `globe` - Globe projection
145151

146-
This value can be uses either with a single projection or as an intermediate between two.
152+
The `projectionTransition` output sent to the renderer is always of the shape:
147153

148-
It's possible to use an expression to change projection between zoom levels using a [`camera expression`](./expressions.md#camera-expressions), either with an immediate [`step`](./expressions.md#step), or an animated [`interpolate-projection`](./expressions.md#interpolate-projection).
154+
`[from, to, transition]: [string, string, number]`
149155

150-
**Use a single projection**
156+
- `from` is the transition of lower zoom level
157+
- `to` is the transition of higher zoom level
158+
- `transition` is the interpolation value, going from 0 to 1, with 0 being in the `from` projection, and 1 being in the `to` projection.
151159

152-
```ts
153-
type: "mercator"
154-
```
160+
In case `from` and `to` are equal, the `transition` will have no effect.
161+
162+
### Examples
163+
164+
#### Step between projection at discrete zoom levels
165+
166+
Use a [`camera expression`](./expressions.md#camera-expressions), to discretely [`step`](./expressions.md#step) between projections at certain zoom levels.
155167

156-
**Change projection at zoom level**
157168

158169
```ts
159170
type: ["step", ["zoom"],
@@ -162,18 +173,50 @@ type: ["step", ["zoom"],
162173
]
163174
```
164175

165-
**Animate between different projections based on zoom level**
176+
`output at zoom 10.9: ["globe", "globe", 1]`
177+
`output at zoom 11.0: ["globe", "globe", 1]`
178+
`output at zoom 11.1: ["mercator", "mercator", 1]`
179+
180+
#### Animate between different projections based on zoom level**
181+
182+
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 transitions from `stereographic` to `mercator` between zoom 10 and 12.
166183

167184
```ts
168185
type: ["interpolate-projection", ["linear"], ["zoom"],
169-
0,"globe",
170-
10,"globe",
186+
0,"stereographic",
187+
10,"stereographic",
171188
12,"mercator"
172189
]
173190
```
174191

175-
**Use a projection transition intermediate**
192+
`output at zoom 10: ["stereographic", "stereographic", 1]`
193+
`output at zoom 11: ["stereographic", "mercator", 0.5]`
194+
`output at zoom 12: ["mercator", "mercator", 1]`
195+
196+
#### Provide a constant `projection` transition
176197

177198
```ts
178-
type: ["globe", "mercator", 0.7]
199+
type: ["stereographic", "mercator", 0.7]
179200
```
201+
202+
#### Use a projection preset
203+
204+
For all supported projections, providing just name will convert into the projection transition syntax for convenience:
205+
206+
207+
```ts
208+
type: "mercator"
209+
```
210+
211+
Is equivalent to:
212+
213+
```ts
214+
["mercator", "mercator", 1]
215+
```
216+
217+
There are also additional presets that yield commonly used expressions:
218+
219+
220+
| Preset | Full value | Description |
221+
|--------|------------|-------------|
222+
| `globe` | `["interpolate-projection", ["linear"], ["zoom"],`<br>`0, "stereographic", 10, "stereographic", 12, "mercator"]` | Adaptive globe: Transitions from stereographic to mercator projection between zoom levels 10 and 12. |

src/expression/definitions/interpolate.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import UnitBezier from '@mapbox/unitbezier';
22

33
import interpolate from '../../util/interpolate';
4-
import {array, ArrayType, ColorType, ProjectionTypeT, ColorTypeT, NumberType, NumberTypeT, PaddingType, PaddingTypeT, VariableAnchorOffsetCollectionType, VariableAnchorOffsetCollectionTypeT, toString, verifyType, ProjectionType} from '../types';
4+
import {array, ArrayType, ColorType, ProjectionTransitionT, ColorTypeT, NumberType, NumberTypeT, PaddingType, PaddingTypeT, VariableAnchorOffsetCollectionType, VariableAnchorOffsetCollectionTypeT, toString, verifyType, ProjectionTransition} from '../types';
55
import {findStopLessThanOrEqualTo} from '../stops';
66

77
import type {Stops} from '../stops';
@@ -19,7 +19,7 @@ export type InterpolationType = {
1919
name: 'cubic-bezier';
2020
controlPoints: [number, number, number, number];
2121
};
22-
type InterpolatedValueType = NumberTypeT | ColorTypeT | ProjectionTypeT | PaddingTypeT | VariableAnchorOffsetCollectionTypeT | ArrayType<NumberTypeT>;
22+
type InterpolatedValueType = NumberTypeT | ColorTypeT | ProjectionTransitionT | PaddingTypeT | VariableAnchorOffsetCollectionTypeT | ArrayType<NumberTypeT>;
2323
type InterpolationOperator = 'interpolate' | 'interpolate-hcl' | 'interpolate-lab' | 'interpolate-projection';
2424
class Interpolate implements Expression {
2525
type: InterpolatedValueType;
@@ -109,7 +109,7 @@ class Interpolate implements Expression {
109109
if (operator === 'interpolate-hcl' || operator === 'interpolate-lab') {
110110
outputType = ColorType;
111111
} else if (operator === 'interpolate-projection') {
112-
outputType = ProjectionType;
112+
outputType = ProjectionTransition;
113113
} else if (context.expectedType && context.expectedType.kind !== 'value') {
114114
outputType = context.expectedType;
115115
}
@@ -137,7 +137,7 @@ class Interpolate implements Expression {
137137

138138
if (!verifyType(outputType, NumberType) &&
139139
!verifyType(outputType, ColorType) &&
140-
!verifyType(outputType, ProjectionType) &&
140+
!verifyType(outputType, ProjectionTransition) &&
141141
!verifyType(outputType, PaddingType) &&
142142
!verifyType(outputType, VariableAnchorOffsetCollectionType) &&
143143
!verifyType(outputType, array(NumberType))

src/expression/types.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export type BooleanTypeT = {
1313
export type ColorTypeT = {
1414
kind: 'color';
1515
};
16-
export type ProjectionTypeT = {
16+
export type ProjectionTransitionT = {
1717
kind: 'projection';
1818
};
1919
export type ObjectTypeT = {
@@ -43,7 +43,7 @@ export type VariableAnchorOffsetCollectionTypeT = {
4343

4444
export type EvaluationKind = 'constant' | 'source' | 'camera' | 'composite';
4545

46-
export type Type = NullTypeT | NumberTypeT | StringTypeT | BooleanTypeT | ColorTypeT | ProjectionTypeT | ObjectTypeT | ValueTypeT |
46+
export type Type = NullTypeT | NumberTypeT | StringTypeT | BooleanTypeT | ColorTypeT | ProjectionTransitionT | ObjectTypeT | ValueTypeT |
4747
ArrayType | ErrorTypeT | CollatorTypeT | FormattedTypeT | PaddingTypeT | ResolvedImageTypeT | VariableAnchorOffsetCollectionTypeT;
4848

4949
export interface ArrayType<T extends Type = Type> {
@@ -59,7 +59,7 @@ export const NumberType = {kind: 'number'} as NumberTypeT;
5959
export const StringType = {kind: 'string'} as StringTypeT;
6060
export const BooleanType = {kind: 'boolean'} as BooleanTypeT;
6161
export const ColorType = {kind: 'color'} as ColorTypeT;
62-
export const ProjectionType = {kind: 'projection'} as ProjectionTypeT;
62+
export const ProjectionTransition = {kind: 'projection'} as ProjectionTransitionT;
6363
export const ObjectType = {kind: 'object'} as ObjectTypeT;
6464
export const ValueType = {kind: 'value'} as ValueTypeT;
6565
export const ErrorType = {kind: 'error'} as ErrorTypeT;
@@ -94,7 +94,7 @@ const valueMemberTypes = [
9494
StringType,
9595
BooleanType,
9696
ColorType,
97-
ProjectionType,
97+
ProjectionTransition,
9898
FormattedType,
9999
ObjectType,
100100
array(ValueType),

src/expression/values.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import Formatted from './types/formatted';
55
import Padding from '../util/padding';
66
import VariableAnchorOffsetCollection from '../util/variable_anchor_offset_collection';
77
import ResolvedImage from './types/resolved_image';
8-
import {NullType, NumberType, StringType, BooleanType, ColorType, ObjectType, ValueType, CollatorType, FormattedType, ResolvedImageType, array, PaddingType, VariableAnchorOffsetCollectionType, ProjectionType} from './types';
8+
import {NullType, NumberType, StringType, BooleanType, ColorType, ObjectType, ValueType, CollatorType, FormattedType, ResolvedImageType, array, PaddingType, VariableAnchorOffsetCollectionType, ProjectionTransition} from './types';
99

1010
import type {Type} from './types';
1111
import {Projection} from '../util/projection';
@@ -77,7 +77,7 @@ export function typeOf(value: Value): Type {
7777
} else if (value instanceof Color) {
7878
return ColorType;
7979
} else if (value instanceof Projection) {
80-
return ProjectionType;
80+
return ProjectionTransition;
8181
} else if (value instanceof Collator) {
8282
return CollatorType;
8383
} else if (value instanceof Formatted) {

src/index.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ function validSchema(k, v, obj, ref, version, kind) {
7070
'padding',
7171
'variableAnchorOffsetCollection',
7272
'sprite',
73-
'projectionType'
73+
'projectionTransition'
7474
]);
7575
const keys = [
7676
'default',

src/reference/v8.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3065,7 +3065,7 @@
30653065
}
30663066
},
30673067
"interpolate-projection": {
3068-
"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 transition of shape `[from, to, transition]: [string, string, number]`.",
3068+
"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 transition](./types.md#projection-transition).",
30693069
"example": {
30703070
"syntax": {
30713071
"method": ["[\"linear\"] | [\"exponential\", base] | [\"cubic-bezier\", x1, y1, x2, y2]", "number", "string", "number", "..."],
@@ -4592,7 +4592,7 @@
45924592
},
45934593
"projection": {
45944594
"type": {
4595-
"type": "projectionType",
4595+
"type": "projectionTransition",
45964596
"doc": "The projection type. Can be specified as a string, or as an expression for supported projection types.",
45974597
"default": "mercator",
45984598
"expression": {

src/util/interpolate.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import Color from './color';
33
import Padding from './padding';
44
import VariableAnchorOffsetCollection from './variable_anchor_offset_collection';
55
import RuntimeError from '../expression/runtime_error';
6-
import type {PrimitiveProjection, VariableAnchorOffsetCollectionSpecification} from '../types.g';
6+
import type {ProjectionPrimitive, VariableAnchorOffsetCollectionSpecification} from '../types.g';
77
import {Projection} from './projection';
88

99
export type InterpolationColorSpace = 'rgb' | 'hcl' | 'lab';
@@ -39,7 +39,7 @@ function number(from: number, to: number, t: number): number {
3939
return from + t * (to - from);
4040
}
4141

42-
function projection(from: PrimitiveProjection, to: PrimitiveProjection, interpolation: number): Projection {
42+
function projection(from: ProjectionPrimitive, to: ProjectionPrimitive, interpolation: number): Projection {
4343
return new Projection(from, to, interpolation);
4444
}
4545

src/util/projection.ts

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import {PrimitiveProjection, ProjectionTransition, ProjectionTypeSpecification, PropertyValueSpecification} from '../types.g';
1+
import {ProjectionPrimitive, ProjectionTransition, ProjectionTransitionSpecification, PropertyValueSpecification} from '../types.g';
22

33
export class Projection {
4-
readonly from: PrimitiveProjection;
5-
readonly to: PrimitiveProjection;
4+
readonly from: ProjectionPrimitive;
5+
readonly to: ProjectionPrimitive;
66
readonly transition: number;
7-
constructor(from: PrimitiveProjection, to: PrimitiveProjection, transition: number){
7+
constructor(from: ProjectionPrimitive, to: ProjectionPrimitive, transition: number){
88
this.from = from;
99
this.to = to;
1010
this.transition = transition;
@@ -15,8 +15,8 @@ export class Projection {
1515
}
1616
}
1717

18-
export function isProjectionType(value: unknown): value is ProjectionTypeSpecification {
19-
return isPrimitiveProjection(value) || isProjectionTransition(value) || isPropertyValueSpecification(value);
18+
export function isProjectionTransitionConfig(value: unknown): value is ProjectionTransitionSpecification {
19+
return isProjectionPrimitive(value) || isProjectionTransitionValue(value) || isPropertyValueSpecification(value);
2020
}
2121

2222
export function isPropertyValueSpecification(value: unknown): value is PropertyValueSpecification<ProjectionTransition> {
@@ -27,14 +27,18 @@ export function isPropertyValueSpecification(value: unknown): value is PropertyV
2727
return false
2828
}
2929

30-
export function isProjectionTransition(value: unknown): value is ProjectionTransition {
30+
export function isProjectionTransitionValue(value: unknown): value is ProjectionTransition {
3131
return Array.isArray(value) &&
3232
value.length === 3 &&
33-
isPrimitiveProjection(value[0]) &&
34-
isPrimitiveProjection(value[1]) &&
33+
isProjectionPrimitive(value[0]) &&
34+
isProjectionPrimitive(value[1]) &&
3535
typeof value[2] === 'number';
3636
}
3737

38-
export function isPrimitiveProjection(value: unknown): value is PrimitiveProjection {
39-
return value === 'mercator' || value === 'globe';
38+
export function isProjectionPrimitive(value: unknown): value is ProjectionPrimitive {
39+
return value === 'mercator' || value === 'stereographic';
40+
}
41+
42+
export function isProjectionPreset(value: unknown): value is ProjectionPrimitive {
43+
return value === 'globe';
4044
}

0 commit comments

Comments
 (0)