diff --git a/js/data/create_bucket.js b/js/data/create_bucket.js index ae9cb162100..2a17bc50ff0 100644 --- a/js/data/create_bucket.js +++ b/js/data/create_bucket.js @@ -7,31 +7,23 @@ var FillBucket = require('./fill_bucket'); var SymbolBucket = require('./symbol_bucket'); var LayoutProperties = require('../style/layout_properties'); var featureFilter = require('feature-filter'); -var StyleDeclaration = require('../style/style_declaration'); -var util = require('../util/util'); +var StyleDeclarationSet = require('../style/style_declaration_set'); function createBucket(layer, buffers, collision, z) { + var values = new StyleDeclarationSet('layout', layer.type, layer.layout, {}).values(), + fakeZoomHistory = { lastIntegerZoom: Infinity, lastIntegerZoomTime: 0, lastZoom: 0 }, + layout = {}; - if (!LayoutProperties[layer.type]) { - //console.warn('unknown bucket type'); - return null; + for (var k in values) { + layout[k] = values[k].calculate(z, fakeZoomHistory); } - var calculatedLayout = util.extend({}, layer.layout); - for (var k in calculatedLayout) { - var fakeZoomHistory = { lastIntegerZoom: Infinity, lastIntegerZoomTime: 0, lastZoom: 0 }; - calculatedLayout[k] = new StyleDeclaration('layout', layer.type, k, calculatedLayout[k]).calculate(z, fakeZoomHistory); - } - - var layoutProperties = new LayoutProperties[layer.type](calculatedLayout); - layoutProperties.zoom = z; - var BucketClass = layer.type === 'line' ? LineBucket : layer.type === 'fill' ? FillBucket : layer.type === 'symbol' ? SymbolBucket : null; - var bucket = new BucketClass(buffers, layoutProperties, collision); + var bucket = new BucketClass(buffers, new LayoutProperties[layer.type](layout), collision); bucket.id = layer.id; bucket.type = layer.type; diff --git a/js/style/style.js b/js/style/style.js index 967bd8ce1b2..ff8fb786034 100644 --- a/js/style/style.js +++ b/js/style/style.js @@ -95,7 +95,7 @@ Style.prototype = util.inherit(Evented, { this._groups = []; for (var i = 0; i < this.stylesheet.layers.length; i++) { - layer = new StyleLayer(this.stylesheet.layers[i], this.stylesheet.constants); + layer = new StyleLayer(this.stylesheet.layers[i], this.stylesheet.constants || {}); this._layers[layer.id] = layer; } @@ -107,7 +107,7 @@ Style.prototype = util.inherit(Evented, { // Resolve reference and paint properties. for (id in this._layers) { this._layers[id].resolveReference(this._layers); - this._layers[id].resolvePaint(this.stylesheet.transition); + this._layers[id].resolvePaint(); } // Split into groups of consecutive top-level layers with the same source. @@ -136,7 +136,9 @@ Style.prototype = util.inherit(Evented, { }; for (var id in this._layers) { - this._layers[id].cascade(classes, options, this.animationLoop); + this._layers[id].cascade(classes, options, + this.stylesheet.transition || {}, + this.animationLoop); } this.fire('change'); @@ -238,6 +240,14 @@ Style.prototype = util.inherit(Evented, { return this._layers[id]; }, + setPaintProperty: function(layer, name, value, klass) { + this.getLayer(layer).setPaintProperty(name, value, klass); + }, + + getPaintProperty: function(layer, name, klass) { + return this.getLayer(layer).getPaintProperty(name, klass); + }, + featuresAt: function(point, params, callback) { var features = []; var error = null; diff --git a/js/style/style_declaration.js b/js/style/style_declaration.js index b766f174335..89dc66e0095 100644 --- a/js/style/style_declaration.js +++ b/js/style/style_declaration.js @@ -6,27 +6,17 @@ var parseCSSColor = require('csscolorparser').parseCSSColor; module.exports = StyleDeclaration; -/* - * A parsed representation of a property:value pair - */ -function StyleDeclaration(propType, renderType, prop, value, transition) { - var className = [propType, '_', renderType].join(''); - var propReference = reference[className] && reference[className][prop]; - if (!propReference) return; - - this.transition = transition; - this.value = this.parseValue(value, propReference); - this.prop = prop; - this.type = propReference.type; - this.transitionable = propReference.transition; +function StyleDeclaration(reference, value) { + this.value = this.parseValue(value, reference); + this.type = reference.type; + this.transitionable = reference.transition; // immuatable representation of value. used for comparison this.json = JSON.stringify(value); - } -StyleDeclaration.prototype.calculate = function(z, zoomHistory) { - return typeof this.value === 'function' ? this.value(z, zoomHistory) : this.value; +StyleDeclaration.prototype.calculate = function(z, zoomHistory, transitionDuration) { + return typeof this.value === 'function' ? this.value(z, zoomHistory, transitionDuration) : this.value; }; StyleDeclaration.prototype.parseValue = function(value, propReference) { @@ -41,7 +31,7 @@ StyleDeclaration.prototype.parseValue = function(value, propReference) { return value; } else if (propReference.transition) { - return transitionedPiecewiseConstantFunction(value.stops ? value.stops : [[0, value]], this.transition.duration); + return transitionedPiecewiseConstantFunction(value.stops ? value.stops : [[0, value]]); } if (value.stops) { @@ -66,9 +56,9 @@ function piecewiseConstantFunction(params) { }; } -function transitionedPiecewiseConstantFunction(stops, duration) { +function transitionedPiecewiseConstantFunction(stops) { - return function(z, zh) { + return function(z, zh, duration) { var fraction = z % 1; var t = Math.min((Date.now() - zh.lastIntegerZoomTime) / duration, 1); diff --git a/js/style/style_declaration_set.js b/js/style/style_declaration_set.js new file mode 100644 index 00000000000..ba5037b87ac --- /dev/null +++ b/js/style/style_declaration_set.js @@ -0,0 +1,85 @@ +'use strict'; + +var util = require('../util/util'); +var reference = require('./reference'); +var StyleConstant = require('./style_constant'); +var StyleDeclaration = require('./style_declaration'); + +var lookup = { + paint: {}, + layout: {} +}; + +reference.layer.type.values.forEach(function(type) { + lookup.paint[type] = makeConstructor(reference['paint_' + type]); + lookup.layout[type] = makeConstructor(reference['layout_' + type]); +}); + +function makeConstructor(reference) { + function StyleDeclarationSet(properties, constants) { + this._values = {}; + this._transitions = {}; + + this._constants = constants; + + for (var k in properties) { + this[k] = StyleConstant.resolve(properties[k], this._constants); + } + } + + Object.keys(reference).forEach(function(k) { + var property = reference[k]; + + Object.defineProperty(StyleDeclarationSet.prototype, k, { + set: function(v) { + this._values[k] = new StyleDeclaration(property, StyleConstant.resolve(v, this._constants)); + }, + get: function() { + return this._values[k].value; + } + }); + + if (property.transition) { + Object.defineProperty(StyleDeclarationSet.prototype, k + '-transition', { + set: function(v) { + this._transitions[k] = v; + }, + get: function() { + return this._transitions[k]; + } + }); + } + }); + + StyleDeclarationSet.prototype.values = function() { + return this._values; + }; + + StyleDeclarationSet.prototype.transition = function(k, global) { + var t = this._transitions[k] || {}; + return { + duration: util.coalesce(t.duration, global.duration, 300), + delay: util.coalesce(t.delay, global.delay, 0) + }; + }; + + StyleDeclarationSet.prototype.json = function() { + var result = {}; + + for (var v in this._values) { + result[v] = this._values[v].value; + } + + for (var t in this._transitions) { + result[t + '-transition'] = this._transitions[v]; + } + + return result; + }; + + return StyleDeclarationSet; +} + +module.exports = function(renderType, layerType, properties, constants) { + return new lookup[renderType][layerType](properties, constants); +}; diff --git a/js/style/style_layer.js b/js/style/style_layer.js index 5c03abe6cba..dfde857e0c6 100644 --- a/js/style/style_layer.js +++ b/js/style/style_layer.js @@ -3,7 +3,7 @@ var util = require('../util/util'); var StyleConstant = require('./style_constant'); var StyleTransition = require('./style_transition'); -var StyleDeclaration = require('./style_declaration'); +var StyleDeclarationSet = require('./style_declaration_set'); var LayoutProperties = require('./layout_properties'); var PaintProperties = require('./paint_properties'); @@ -16,6 +16,10 @@ function StyleLayer(layer, 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); } @@ -43,50 +47,47 @@ StyleLayer.prototype = { } }, - resolvePaint: function(globalTrans) { - globalTrans = globalTrans || {}; - - // Resolved and cascaded paint properties. - this._resolved = {}; // class name -> (property name -> StyleDeclaration) - this._cascaded = {}; // property name -> StyleTransition - + 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); + } + }, - var paint = StyleConstant.resolveAll(this._layer[p], this._constants), - declarations = this._resolved[match[1] || ''] = {}; - - for (var k in paint) { - if (/-transition$/.test(k)) - continue; - - var t = paint[k + '-transition'] || {}; - var transition = { - duration: util.coalesce(t.duration, globalTrans.duration, 300), - delay: util.coalesce(t.delay, globalTrans.delay, 0) - }; - - declarations[k] = - new StyleDeclaration('paint', this.type, k, paint[k], transition); - } + 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; }, - cascade: function(classes, options, animationLoop) { + 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]; - for (var k in declarations) { - var newDeclaration = declarations[k]; - var newStyleTrans = options.transition ? declarations[k].transition : {duration: 0, delay: 0}; + var declarations = this._resolved[klass], + values = declarations.values(); + + for (var k in values) { + var newDeclaration = values[k]; var oldTransition = this._cascaded[k]; // Only create a new transition if the declaration changed if (!oldTransition || oldTransition.declaration.json !== newDeclaration.json) { + var newStyleTrans = options.transition ? declarations.transition(k, globalTrans) : {duration: 0, delay: 0}; var newTransition = this._cascaded[k] = new StyleTransition(newDeclaration, oldTransition, newStyleTrans); diff --git a/js/style/style_transition.js b/js/style/style_transition.js index 9273af1f445..d5581c8c204 100644 --- a/js/style/style_transition.js +++ b/js/style/style_transition.js @@ -46,7 +46,7 @@ StyleTransition.prototype.instant = function() { */ StyleTransition.prototype.at = function(z, zoomHistory, t) { - var value = this.declaration.calculate(z, zoomHistory); + var value = this.declaration.calculate(z, zoomHistory, this.duration); if (this.instant()) return value; diff --git a/js/ui/map.js b/js/ui/map.js index 4ba946b630b..b67fa33aa34 100644 --- a/js/ui/map.js +++ b/js/ui/map.js @@ -247,6 +247,17 @@ util.extend(Map.prototype, { return this; }, + setPaintProperty: function(layer, name, value, klass) { + this.style.setPaintProperty(layer, name, value, klass); + this.style._cascade(this._classes); + this.update(true); + return this; + }, + + getPaintProperty: function(layer, name, klass) { + return this.style.getPaintProperty(layer, name, klass); + }, + _move: function(zoom, rotate) { this.update(zoom).fire('move'); diff --git a/test/js/style/style.test.js b/test/js/style/style.test.js index f6929d14ce3..34cbed5d0d4 100644 --- a/test/js/style/style.test.js +++ b/test/js/style/style.test.js @@ -222,6 +222,24 @@ test('Style#removeSource', function(t) { }); }); +test('Style#setPaintProperty', function(t) { + t.test('sets property', function(t) { + var style = new Style({ + "version": 7, + "layers": [{ + "id": "background", + "type": "background" + }] + }); + + style.on('load', function() { + style.setPaintProperty('background', 'background-color', 'red'); + t.deepEqual(style.getPaintProperty('background', 'background-color'), [1, 0, 0, 1]); + t.end(); + }); + }); +}); + test('Style#featuresAt', function(t) { var style = new Style({ "version": 7, diff --git a/test/js/style/style_declaration.test.js b/test/js/style/style_declaration.test.js index 7cdc9ec24bc..7aa05e2957b 100644 --- a/test/js/style/style_declaration.test.js +++ b/test/js/style/style_declaration.test.js @@ -3,77 +3,60 @@ var test = require('tape'); var StyleDeclaration = require('../../../js/style/style_declaration'); -test('styledeclaration', function(t) { - +test('StyleDeclaration', function(t) { t.test('boolean', function(t) { - t.equal((new StyleDeclaration('paint', 'fill', 'fill-antialias', false)).calculate(0), false); + var decl = new StyleDeclaration({type: "boolean"}, false); + t.equal(decl.calculate(0), false); t.end(); }); t.test('image', function(t) { - t.deepEqual((new StyleDeclaration('paint', 'fill', 'fill-image', 'smilingclownstaringatyou.png', { duration: 300 })).calculate(0, { lastIntegerZoomTime: 0, lastIntegerZoom: 0 }), + var decl = new StyleDeclaration({type: "image", transition: true}, 'smilingclownstaringatyou.png'); + t.deepEqual(decl.calculate(0, { lastIntegerZoomTime: 0, lastIntegerZoom: 0 }, 300), { to: 'smilingclownstaringatyou.png', toScale: 1, from: 'smilingclownstaringatyou.png', fromScale: 0.5, t: 1 }); t.end(); }); - t.test('keywords', function(t) { - t.equal((new StyleDeclaration('paint', 'fill', 'fill-translate-anchor', 'viewport')).calculate(0), - 'viewport'); + t.test('enum', function(t) { + var decl = new StyleDeclaration({type: "enum"}, 'viewport'); + t.equal(decl.calculate(0), 'viewport'); t.end(); }); - t.test('parseWidthArray', function(t) { - var dashFn = new StyleDeclaration('paint', 'line', 'line-dasharray', [0, 10, 5], { duration: 300 }); - t.ok(dashFn instanceof StyleDeclaration); - t.deepEqual(dashFn.calculate(0, { lastIntegerZoomTime: 0, lastIntegerZoom: 0 }), + t.test('array', function(t) { + var decl = new StyleDeclaration({type: "array", transition: true}, [0, 10, 5]); + t.deepEqual(decl.calculate(0, { lastIntegerZoomTime: 0, lastIntegerZoom: 0 }, 300), { to: [ 0, 10, 5 ], toScale: 1, from: [ 0, 10, 5 ], fromScale: 0.5, t: 1 }); t.end(); }); t.test('constant', function(t) { - t.equal((new StyleDeclaration('paint', 'line', 'line-width', 5)).calculate(0), 5); - t.equal((new StyleDeclaration('paint', 'line', 'line-width', 5)).calculate(100), 5); - t.end(); - }); - - t.test('paint functions', function(t) { - t.equal((new StyleDeclaration('paint', 'fill', 'fill-opacity', { stops: [] })).calculate(0), 1); - t.equal((new StyleDeclaration('paint', 'fill', 'fill-opacity', { stops: [[2, 2], [5, 10]] })).calculate(0), 2); - t.equal((new StyleDeclaration('paint', 'fill', 'fill-opacity', { stops: [[0, 0], [5, 10]] })).calculate(12), 10); - t.equal((new StyleDeclaration('paint', 'fill', 'fill-opacity', { stops: [[0, 0], [5, 10]] })).calculate(6), 10); - t.equal(Math.round((new StyleDeclaration('paint', 'fill', 'fill-opacity', { stops: [[0, 0], [5, 10]], base: 1.01 })).calculate(2.5)), 5); - t.equal((new StyleDeclaration('paint', 'fill', 'fill-opacity', { stops: [[0, 0], [1, 10], [2, 20]] })).calculate(2), 20); - t.equal((new StyleDeclaration('paint', 'fill', 'fill-opacity', { stops: [[0, 0], [1, 10], [2, 20]] })).calculate(1), 10); - t.equal((new StyleDeclaration('paint', 'fill', 'fill-opacity', { stops: [[0, 0]] })).calculate(6), 0); - + t.equal((new StyleDeclaration({type: "number"}, 5)).calculate(0), 5); + t.equal((new StyleDeclaration({type: "number"}, 5)).calculate(100), 5); t.end(); }); - t.test('layout functions', function(t) { - t.equal((new StyleDeclaration('layout', 'line', 'line-miter-limit', { stops: [] })).calculate(0), 1); - t.equal((new StyleDeclaration('layout', 'symbol', 'symbol-min-distance', { stops: [[8, 0], [12, 250]] })).calculate(6), 0); - t.equal((new StyleDeclaration('layout', 'symbol', 'icon-rotate', { stops: [[8, 0], [12, 360]] })).calculate(11), 270); - t.deepEqual((new StyleDeclaration('layout', 'symbol', 'text-offset', { stops: [[8, [0, 10]], [12, [10, 10]]] })).calculate(10), [5, 10]); - + t.test('functions', function(t) { + var reference = {type: "number", function: "interpolated"}; + t.equal((new StyleDeclaration(reference, { stops: [] })).calculate(0), 1); + t.equal((new StyleDeclaration(reference, { stops: [[2, 2], [5, 10]] })).calculate(0), 2); + t.equal((new StyleDeclaration(reference, { stops: [[0, 0], [5, 10]] })).calculate(12), 10); + t.equal((new StyleDeclaration(reference, { stops: [[0, 0], [5, 10]] })).calculate(6), 10); + t.equal(Math.round((new StyleDeclaration(reference, { stops: [[0, 0], [5, 10]], base: 1.01 })).calculate(2.5)), 5); + t.equal((new StyleDeclaration(reference, { stops: [[0, 0], [1, 10], [2, 20]] })).calculate(2), 20); + t.equal((new StyleDeclaration(reference, { stops: [[0, 0], [1, 10], [2, 20]] })).calculate(1), 10); + t.equal((new StyleDeclaration(reference, { stops: [[0, 0]] })).calculate(6), 0); t.end(); }); t.test('color parsing', function(t) { - t.deepEqual(new StyleDeclaration('paint', 'line', 'line-color', 'red').calculate(0), [ 1, 0, 0, 1 ]); - t.deepEqual(new StyleDeclaration('paint', 'line', 'line-color', '#ff00ff').calculate(0), [ 1, 0, 1, 1 ]); - t.deepEqual(new StyleDeclaration('paint', 'line', 'line-color', { stops: [[0, '#f00'], [1, '#0f0']] }).calculate(0), [1, 0, 0, 1]); + var reference = {type: "color", function: "interpolated"}; + t.deepEqual(new StyleDeclaration(reference, 'red').calculate(0), [ 1, 0, 0, 1 ]); + t.deepEqual(new StyleDeclaration(reference, '#ff00ff').calculate(0), [ 1, 0, 1, 1 ]); + t.deepEqual(new StyleDeclaration(reference, { stops: [[0, '#f00'], [1, '#0f0']] }).calculate(0), [1, 0, 0, 1]); // cached - t.deepEqual(new StyleDeclaration('paint', 'line', 'line-color', '#ff00ff').calculate(0), [ 1, 0, 1, 1 ]); - t.deepEqual(new StyleDeclaration('paint', 'line', 'line-color', 'rgba(255, 51, 0, 1)').calculate(0), [ 1, 0.2, 0, 1 ]); + t.deepEqual(new StyleDeclaration(reference, '#ff00ff').calculate(0), [ 1, 0, 1, 1 ]); + t.deepEqual(new StyleDeclaration(reference, 'rgba(255, 51, 0, 1)').calculate(0), [ 1, 0.2, 0, 1 ]); t.end(); }); - - t.equal((new StyleDeclaration('paint', '', 'unknown-prop')).prop, undefined, 'unknown prop'); - - var widthfn = new StyleDeclaration('paint', 'line', 'line-width', function(z) { - return Math.pow(z, 2); - }); - t.equal(widthfn.calculate(10), 100); - - t.end(); }); diff --git a/test/js/style/style_declaration_set.test.js b/test/js/style/style_declaration_set.test.js new file mode 100644 index 00000000000..92a2fd08934 --- /dev/null +++ b/test/js/style/style_declaration_set.test.js @@ -0,0 +1,49 @@ +'use strict'; + +var test = require('tape'); +var StyleDeclarationSet = require('../../../js/style/style_declaration_set'); + +test('StyleDeclarationSet', function(t) { + t.test('creates value setters', function(t) { + var set = new StyleDeclarationSet('paint', 'background'); + set['background-color'] = 'blue'; + t.deepEqual(set._values['background-color'].value, [0, 0, 1, 1]); + t.end(); + }); + + t.test('creates transition setters', function(t) { + var set = new StyleDeclarationSet('paint', 'background'); + set['background-color-transition'] = {duration: 400}; + t.deepEqual(set._transitions, {'background-color': {duration: 400}}); + t.end(); + }); + + t.test('constructs with a property set', function(t) { + var set = new StyleDeclarationSet('paint', 'background', { + 'background-color': 'blue' + }); + t.deepEqual(set._values['background-color'].value, [0, 0, 1, 1]); + t.end(); + }); + + t.test('resolves constants', function(t) { + var set = new StyleDeclarationSet('paint', 'background', { + 'background-color': '@blue' + }, { + '@blue': 'blue' + }); + t.deepEqual(set._values['background-color'].value, [0, 0, 1, 1]); + t.end(); + }); + + t.test('returns external representation', function(t) { + var set = new StyleDeclarationSet('paint', 'background'); + set['background-color'] = 'blue'; + set['background-color-transition'] = {duration: 400}; + t.deepEqual(set.json(), { + 'background-color': [0, 0, 1, 1], + 'background-color-transition': {duration: 400} + }); + t.end(); + }); +}); diff --git a/test/js/style/style_layer.test.js b/test/js/style/style_layer.test.js index c1178683fab..5b9b33c87b9 100644 --- a/test/js/style/style_layer.test.js +++ b/test/js/style/style_layer.test.js @@ -61,76 +61,137 @@ test('StyleLayer#resolvePaint', function(t) { t.deepEqual(Object.keys(layer._resolved), ['', 'night']); t.end(); }); +}); - t.test('matches paint properties with their transitions', function(t) { +//test('StyleLayer#cascade', function(t) { +// t.test('applies default transitions', function(t) { +// var layer = new StyleLayer({ +// type: 'fill', +// paint: { +// 'fill-color': 'blue' +// } +// }); +// +// layer.resolvePaint({}); +// +// var declaration = layer._resolved['']['fill-color']; +// t.deepEqual(declaration.value, [0, 0, 1, 1]); +// t.deepEqual(declaration.transition, {delay: 0, duration: 300}); +// +// t.end(); +// }); +//}); + +test('StyleLayer#setPaintProperty', function(t) { + t.test('sets new property value', function(t) { var layer = new StyleLayer({ - type: 'fill', - paint: { - 'fill-color': 'blue', - 'fill-color-transition': { - delay: 10, - duration: 20 - } + "id": "background", + "type": "background" + }); + + layer.setPaintProperty('background-color', 'blue'); + + t.deepEqual(layer.getPaintProperty('background-color'), [0, 0, 1, 1]); + t.end(); + }); + + t.test('updates property value', function(t) { + var layer = new StyleLayer({ + "id": "background", + "type": "background", + "paint": { + "background-color": "red" } }); layer.resolvePaint({}); + layer.setPaintProperty('background-color', 'blue'); - var declaration = layer._resolved['']['fill-color']; - t.deepEqual(declaration.value, [0, 0, 1, 1]); - t.deepEqual(declaration.transition, {delay: 10, duration: 20}); - + t.deepEqual(layer.getPaintProperty('background-color'), [0, 0, 1, 1]); t.end(); }); - t.test('applies default transitions', function(t) { + t.test('sets classed paint value', function(t) { var layer = new StyleLayer({ - type: 'fill', - paint: { - 'fill-color': 'blue' + "id": "background", + "type": "background", + "paint.night": { + "background-color": "red" } }); layer.resolvePaint({}); + layer.setPaintProperty('background-color', 'blue', 'night'); - var declaration = layer._resolved['']['fill-color']; - t.deepEqual(declaration.value, [0, 0, 1, 1]); - t.deepEqual(declaration.transition, {delay: 0, duration: 300}); - + t.deepEqual(layer.getPaintProperty('background-color', 'night'), [0, 0, 1, 1]); t.end(); }); - t.test('ignores transitions without a matching base value', function(t) { + t.test('preserves existing transition', function(t) { var layer = new StyleLayer({ - type: 'fill', - paint: { - 'fill-color-transition': { - delay: 10, - duration: 20 + "id": "background", + "type": "background", + "paint": { + "background-color": "red", + "background-color-transition": { + duration: 600 } } }); layer.resolvePaint({}); + layer.setPaintProperty('background-color', 'blue'); - t.equal(layer._resolved['']['fill-color'], undefined); + t.deepEqual(layer.getPaintProperty('background-color-transition'), {duration: 600}); t.end(); }); - t.test('resolves paint constants', function(t) { + t.test('sets transition', function(t) { var layer = new StyleLayer({ - type: 'fill', - paint: { - 'fill-color': '@blue' + "id": "background", + "type": "background", + "paint": { + "background-color": "red" + } + }); + + layer.resolvePaint({}); + layer.setPaintProperty('background-color-transition', {duration: 400}); + + t.deepEqual(layer.getPaintProperty('background-color-transition'), {duration: 400}); + t.end(); + }); + + t.test('resolves constants (create)', function(t) { + var layer = new StyleLayer({ + "id": "background", + "type": "background" + }, { + '@blue': 'blue' + }); + + layer.resolvePaint(); + layer.setPaintProperty('background-color', '@blue'); + + t.deepEqual(layer.getPaintProperty('background-color'), [0, 0, 1, 1]); + t.end(); + }); + + t.test('resolves constants (update)', function(t) { + var layer = new StyleLayer({ + "id": "background", + "type": "background", + "paint": { + "background-color": "red" } }, { '@blue': 'blue' }); layer.resolvePaint(); + layer.setPaintProperty('background-color', '@blue'); - var declaration = layer._resolved['']['fill-color']; - t.deepEqual(declaration.value, [0, 0, 1, 1]); + t.deepEqual(layer.getPaintProperty('background-color'), [0, 0, 1, 1]); t.end(); }); });