UNPKG

mapbox-gl

Version:
198 lines (164 loc) 7.01 kB
'use strict'; var util = require('../util/util'); var StyleConstant = require('./style_constant'); var StyleTransition = require('./style_transition'); var StyleDeclarationSet = require('./style_declaration_set'); var LayoutProperties = require('./layout_properties'); var PaintProperties = require('./paint_properties'); module.exports = StyleLayer; function StyleLayer(layer, constants) { this._layer = layer; this._constants = constants; this.id = layer.id; this.ref = layer.ref; // Resolved and cascaded paint properties. this._resolved = {}; // class name -> StyleDeclarationSet this._cascaded = {}; // property name -> StyleTransition this.assign(layer); } StyleLayer.prototype = { resolveLayout: function() { if (!this.ref) { this.layout = new LayoutProperties[this.type]( StyleConstant.resolveAll(this._layer.layout, this._constants)); if (this.layout['symbol-placement'] === 'line') { if (!this.layout.hasOwnProperty('text-rotation-alignment')) { this.layout['text-rotation-alignment'] = 'map'; } if (!this.layout.hasOwnProperty('icon-rotation-alignment')) { this.layout['icon-rotation-alignment'] = 'map'; } this.layout['symbol-avoid-edges'] = true; } } }, setLayoutProperty: function(name, value) { this.layout[name] = StyleConstant.resolve(value, this._constants); }, getLayoutProperty: function(name) { return this.layout[name]; }, resolveReference: function(layers) { if (this.ref) { this.assign(layers[this.ref]); } }, resolvePaint: function() { for (var p in this._layer) { var match = p.match(/^paint(?:\.(.*))?$/); if (!match) continue; this._resolved[match[1] || ''] = new StyleDeclarationSet('paint', this.type, this._layer[p], this._constants); } }, setPaintProperty: function(name, value, klass) { var declarations = this._resolved[klass || '']; if (!declarations) { declarations = this._resolved[klass || ''] = new StyleDeclarationSet('paint', this.type, {}, this._constants); } declarations[name] = value; }, getPaintProperty: function(name, klass) { var declarations = this._resolved[klass || '']; if (!declarations) return undefined; return declarations[name]; }, cascade: function(classes, options, globalTrans, animationLoop) { for (var klass in this._resolved) { if (klass !== "" && !classes[klass]) continue; var declarations = this._resolved[klass], values = declarations.values(); for (var k in values) { var newDeclaration = values[k]; var oldTransition = options.transition ? this._cascaded[k] : undefined; // Only create a new transition if the declaration changed if (!oldTransition || oldTransition.declaration.json !== newDeclaration.json) { var newStyleTrans = declarations.transition(k, globalTrans); var newTransition = this._cascaded[k] = new StyleTransition(newDeclaration, oldTransition, newStyleTrans); // Run the animation loop until the end of the transition if (!newTransition.instant()) { newTransition.loopID = animationLoop.set(newTransition.endTime - (new Date()).getTime()); } if (oldTransition) { animationLoop.cancel(oldTransition.loopID); } } } } }, recalculate: function(z, zoomHistory) { var type = this.type, calculated = this.paint = new PaintProperties[type](); for (var k in this._cascaded) { calculated[k] = this._cascaded[k].at(z, zoomHistory); } this.hidden = (this.minzoom && z < this.minzoom) || (this.maxzoom && z >= this.maxzoom) || // include visibility check for non-bucketed background layers (this.layout.visibility === 'none'); if (type === 'symbol') { if ((calculated['text-opacity'] === 0 || !this.layout['text-field']) && (calculated['icon-opacity'] === 0 || !this.layout['icon-image'])) { this.hidden = true; } else { premultiplyLayer(calculated, 'text'); premultiplyLayer(calculated, 'icon'); } } else if (calculated[type + '-opacity'] === 0) { this.hidden = true; } else { premultiplyLayer(calculated, type); } if (this._cascaded['line-dasharray']) { // If the line is dashed, scale the dash lengths by the line // width at the previous round zoom level. var dashArray = calculated['line-dasharray']; var lineWidth = this._cascaded['line-width'] ? this._cascaded['line-width'].at(Math.floor(z), Infinity) : calculated['line-width']; dashArray.fromScale *= lineWidth; dashArray.toScale *= lineWidth; } return !this.hidden; }, assign: function(layer) { util.extend(this, util.pick(layer, ['type', 'source', 'source-layer', 'minzoom', 'maxzoom', 'filter', 'layout'])); }, json: function() { return util.extend({}, this._layer, util.pick(this, ['type', 'source', 'source-layer', 'minzoom', 'maxzoom', 'filter', 'layout', 'paint'])); } }; function premultiplyLayer(layer, type) { var colorProp = type + '-color', haloProp = type + '-halo-color', outlineProp = type + '-outline-color', color = layer[colorProp], haloColor = layer[haloProp], outlineColor = layer[outlineProp], opacity = layer[type + '-opacity']; var colorOpacity = color && (opacity * color[3]); var haloOpacity = haloColor && (opacity * haloColor[3]); var outlineOpacity = outlineColor && (opacity * outlineColor[3]); if (colorOpacity !== undefined && colorOpacity < 1) { layer[colorProp] = util.premultiply([color[0], color[1], color[2], colorOpacity]); } if (haloOpacity !== undefined && haloOpacity < 1) { layer[haloProp] = util.premultiply([haloColor[0], haloColor[1], haloColor[2], haloOpacity]); } if (outlineOpacity !== undefined && outlineOpacity < 1) { layer[outlineProp] = util.premultiply([outlineColor[0], outlineColor[1], outlineColor[2], outlineOpacity]); } }