Skip to content

Commit

Permalink
Style#get/setPaintProperty
Browse files Browse the repository at this point in the history
  • Loading branch information
jfirebaugh committed Feb 9, 2015
1 parent 8c7a6c2 commit a374e74
Show file tree
Hide file tree
Showing 11 changed files with 346 additions and 146 deletions.
22 changes: 7 additions & 15 deletions js/data/create_bucket.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
16 changes: 13 additions & 3 deletions js/style/style.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -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.
Expand Down Expand Up @@ -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');
Expand Down Expand Up @@ -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;
Expand Down
28 changes: 9 additions & 19 deletions js/style/style_declaration.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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) {
Expand All @@ -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);
Expand Down
85 changes: 85 additions & 0 deletions js/style/style_declaration_set.js
Original file line number Diff line number Diff line change
@@ -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);
};
59 changes: 30 additions & 29 deletions js/style/style_layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');

Expand All @@ -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);
}

Expand Down Expand Up @@ -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);

Expand Down
2 changes: 1 addition & 1 deletion js/style/style_transition.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
11 changes: 11 additions & 0 deletions js/ui/map.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down
18 changes: 18 additions & 0 deletions test/js/style/style.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Loading

0 comments on commit a374e74

Please sign in to comment.