mapbox-gl
Version:
A WebGL interactive maps library
145 lines (120 loc) • 4.83 kB
JavaScript
const styleSpec = require('../style-spec/reference/latest');
const util = require('../util/util');
const Evented = require('../util/evented');
const validateStyle = require('./validate_style');
const StyleDeclaration = require('./style_declaration');
const StyleTransition = require('./style_transition');
const TRANSITION_SUFFIX = '-transition';
/*
* Represents the light used to light extruded features.
*/
class Light extends Evented {
constructor(lightOptions) {
super();
this.properties = ['anchor', 'color', 'position', 'intensity'];
this._specifications = styleSpec.light;
this.set(lightOptions);
}
set(lightOpts) {
if (this._validate(validateStyle.light, lightOpts)) return;
this._declarations = {};
this._transitions = {};
this._transitionOptions = {};
this.calculated = {};
lightOpts = util.extend({
anchor: this._specifications.anchor.default,
color: this._specifications.color.default,
position: this._specifications.position.default,
intensity: this._specifications.intensity.default
}, lightOpts);
for (const prop of this.properties) {
this._declarations[prop] = new StyleDeclaration(this._specifications[prop], lightOpts[prop]);
}
return this;
}
getLight() {
return {
anchor: this.getLightProperty('anchor'),
color: this.getLightProperty('color'),
position: this.getLightProperty('position'),
intensity: this.getLightProperty('intensity')
};
}
getLightProperty(property) {
if (util.endsWith(property, TRANSITION_SUFFIX)) {
return (
this._transitionOptions[property]
);
} else {
return (
this._declarations[property] &&
this._declarations[property].value
);
}
}
getLightValue(property, globalProperties) {
if (property === 'position') {
const calculated = this._transitions[property].calculate(globalProperties),
cartesian = util.sphericalToCartesian(calculated);
return {
x: cartesian[0],
y: cartesian[1],
z: cartesian[2]
};
}
return this._transitions[property].calculate(globalProperties);
}
setLight(options) {
if (this._validate(validateStyle.light, options)) return;
for (const key in options) {
const value = options[key];
if (util.endsWith(key, TRANSITION_SUFFIX)) {
this._transitionOptions[key] = value;
} else if (value === null || value === undefined) {
delete this._declarations[key];
} else {
this._declarations[key] = new StyleDeclaration(this._specifications[key], value);
}
}
}
recalculate(zoom) {
for (const property in this._declarations) {
this.calculated[property] = this.getLightValue(property, {zoom: zoom});
}
}
_applyLightDeclaration(property, declaration, options, globalOptions, animationLoop) {
const oldTransition = options.transition ? this._transitions[property] : undefined;
const spec = this._specifications[property];
if (declaration === null || declaration === undefined) {
declaration = new StyleDeclaration(spec, spec.default);
}
if (oldTransition && oldTransition.declaration.json === declaration.json) return;
const transitionOptions = util.extend({
duration: 300,
delay: 0
}, globalOptions, this.getLightProperty(property + TRANSITION_SUFFIX));
const newTransition = this._transitions[property] =
new StyleTransition(spec, declaration, oldTransition, transitionOptions);
if (!newTransition.instant()) {
newTransition.loopID = animationLoop.set(newTransition.endTime - Date.now());
}
if (oldTransition) {
animationLoop.cancel(oldTransition.loopID);
}
}
updateLightTransitions(options, globalOptions, animationLoop) {
let property;
for (property in this._declarations) {
this._applyLightDeclaration(property, this._declarations[property], options, globalOptions, animationLoop);
}
}
_validate(validate, value) {
return validateStyle.emitErrors(this, validate.call(validateStyle, util.extend({
value: value,
// Workaround for https://github.com/mapbox/mapbox-gl-js/issues/2407
style: {glyphs: true, sprite: true},
styleSpec: styleSpec
})));
}
}
module.exports = Light;