1 | import styleSpec from '../style-spec/reference/latest';
|
2 |
|
3 | import {extend, sphericalToCartesian} from '../util/util';
|
4 | import {Evented} from '../util/evented';
|
5 | import {
|
6 | validateStyle,
|
7 | validateLight,
|
8 | emitValidationErrors
|
9 | } from './validate_style';
|
10 | import Color from '../style-spec/util/color';
|
11 | import {number as interpolate} from '../style-spec/util/interpolate';
|
12 |
|
13 | import type {StylePropertySpecification} from '../style-spec/style-spec';
|
14 | import type EvaluationParameters from './evaluation_parameters';
|
15 | import type {StyleSetterOptions} from '../style/style';
|
16 | import {Properties, Transitionable, Transitioning, PossiblyEvaluated, DataConstantProperty} from './properties';
|
17 |
|
18 | import type {
|
19 | Property,
|
20 | PropertyValue,
|
21 | TransitionParameters
|
22 | } from './properties';
|
23 |
|
24 | import type {LightSpecification} from '../style-spec/types.g';
|
25 |
|
26 | type LightPosition = {
|
27 | x: number;
|
28 | y: number;
|
29 | z: number;
|
30 | };
|
31 |
|
32 | class LightPositionProperty implements Property<[number, number, number], LightPosition> {
|
33 | specification: StylePropertySpecification;
|
34 |
|
35 | constructor() {
|
36 | this.specification = styleSpec.light.position as StylePropertySpecification;
|
37 | }
|
38 |
|
39 | possiblyEvaluate(
|
40 | value: PropertyValue<[number, number, number], LightPosition>,
|
41 | parameters: EvaluationParameters
|
42 | ): LightPosition {
|
43 | return sphericalToCartesian(value.expression.evaluate(parameters));
|
44 | }
|
45 |
|
46 | interpolate(a: LightPosition, b: LightPosition, t: number): LightPosition {
|
47 | return {
|
48 | x: interpolate(a.x, b.x, t),
|
49 | y: interpolate(a.y, b.y, t),
|
50 | z: interpolate(a.z, b.z, t),
|
51 | };
|
52 | }
|
53 | }
|
54 |
|
55 | type Props = {
|
56 | 'anchor': DataConstantProperty<'map' | 'viewport'>;
|
57 | 'position': LightPositionProperty;
|
58 | 'color': DataConstantProperty<Color>;
|
59 | 'intensity': DataConstantProperty<number>;
|
60 | };
|
61 |
|
62 | type PropsPossiblyEvaluated = {
|
63 | 'anchor': 'map' | 'viewport';
|
64 | 'position': LightPosition;
|
65 | 'color': Color;
|
66 | 'intensity': number;
|
67 | };
|
68 |
|
69 | const properties: Properties<Props> = new Properties({
|
70 | 'anchor': new DataConstantProperty(styleSpec.light.anchor as StylePropertySpecification),
|
71 | 'position': new LightPositionProperty(),
|
72 | 'color': new DataConstantProperty(styleSpec.light.color as StylePropertySpecification),
|
73 | 'intensity': new DataConstantProperty(styleSpec.light.intensity as StylePropertySpecification),
|
74 | });
|
75 |
|
76 | const TRANSITION_SUFFIX = '-transition';
|
77 |
|
78 |
|
79 |
|
80 |
|
81 | class Light extends Evented {
|
82 | _transitionable: Transitionable<Props>;
|
83 | _transitioning: Transitioning<Props>;
|
84 | properties: PossiblyEvaluated<Props, PropsPossiblyEvaluated>;
|
85 |
|
86 | constructor(lightOptions?: LightSpecification) {
|
87 | super();
|
88 | this._transitionable = new Transitionable(properties);
|
89 | this.setLight(lightOptions);
|
90 | this._transitioning = this._transitionable.untransitioned();
|
91 | }
|
92 |
|
93 | getLight() {
|
94 | return this._transitionable.serialize();
|
95 | }
|
96 |
|
97 | setLight(light?: LightSpecification, options: StyleSetterOptions = {}) {
|
98 | if (this._validate(validateLight, light, options)) {
|
99 | return;
|
100 | }
|
101 |
|
102 | for (const name in light) {
|
103 | const value = light[name];
|
104 | if (name.endsWith(TRANSITION_SUFFIX)) {
|
105 | this._transitionable.setTransition(name.slice(0, -TRANSITION_SUFFIX.length) as keyof Props, value);
|
106 | } else {
|
107 | this._transitionable.setValue(name as keyof Props, value);
|
108 | }
|
109 | }
|
110 | }
|
111 |
|
112 | updateTransitions(parameters: TransitionParameters) {
|
113 | this._transitioning = this._transitionable.transitioned(parameters, this._transitioning);
|
114 | }
|
115 |
|
116 | hasTransition() {
|
117 | return this._transitioning.hasTransition();
|
118 | }
|
119 |
|
120 | recalculate(parameters: EvaluationParameters) {
|
121 | this.properties = this._transitioning.possiblyEvaluate(parameters);
|
122 | }
|
123 |
|
124 | _validate(validate: Function, value: unknown, options?: {
|
125 | validate?: boolean;
|
126 | }) {
|
127 | if (options && options.validate === false) {
|
128 | return false;
|
129 | }
|
130 |
|
131 | return emitValidationErrors(this, validate.call(validateStyle, extend({
|
132 | value,
|
133 |
|
134 | style: {glyphs: true, sprite: true},
|
135 | styleSpec
|
136 | })));
|
137 | }
|
138 | }
|
139 |
|
140 | export default Light;
|