Skip to content

Commit

Permalink
Track the stylesheet as a pure JSON object
Browse files Browse the repository at this point in the history
Adds `style.json()` which returns the stylesheet as a pure JSON object
that is equivalent to the stylesheet necessary to recreate the style
object.

Mutations to the style object are reflected by subsequent calls to
`.json()`

Issue: #1341
  • Loading branch information
scothis committed Jun 29, 2015
1 parent 0913eae commit d33c899
Show file tree
Hide file tree
Showing 3 changed files with 217 additions and 18 deletions.
28 changes: 24 additions & 4 deletions js/style/style.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ var browser = require('../util/browser');
var Dispatcher = require('../util/dispatcher');
var AnimationLoop = require('./animation_loop');
var validate = require('mapbox-gl-style-spec/lib/validate/latest');
var clone = require('lodash.clonedeep');

module.exports = Style;

Expand Down Expand Up @@ -73,7 +74,7 @@ function Style(stylesheet, animationLoop) {
if (typeof stylesheet === 'string') {
ajax.getJSON(normalizeURL(stylesheet), loaded);
} else {
browser.frame(loaded.bind(this, null, stylesheet));
browser.frame(loaded.bind(this, null, clone(stylesheet)));
}
}

Expand Down Expand Up @@ -222,6 +223,7 @@ Style.prototype = util.inherit(Evented, {
if (this.sources[id] !== undefined) {
throw new Error('There is already a source with this ID');
}
this.stylesheet.sources[id] = source;
source = Source.create(source);
this.sources[id] = source;
source.id = id;
Expand Down Expand Up @@ -255,6 +257,7 @@ Style.prototype = util.inherit(Evented, {
throw new Error('There is no source with this ID');
}
var source = this.sources[id];
delete this.stylesheet.sources[id];
delete this.sources[id];
source
.off('load', this._forwardSourceEvent)
Expand Down Expand Up @@ -294,11 +297,14 @@ Style.prototype = util.inherit(Evented, {
if (this._layers[layer.id] !== undefined) {
throw new Error('There is already a layer with this ID');
}
var _layer = layer;
if (!(layer instanceof StyleLayer)) {
layer = new StyleLayer(layer, this.stylesheet.constants || {});
}
var position = before ? this._order.indexOf(before) : Infinity;
this.stylesheet.layers.splice(position, 0, _layer);
this._order.splice(position, 0, layer.id);
this._layers[layer.id] = layer;
this._order.splice(before ? this._order.indexOf(before) : Infinity, 0, layer.id);
layer.resolveLayout();
layer.resolveReference(this._layers);
layer.resolvePaint();
Expand Down Expand Up @@ -332,7 +338,9 @@ Style.prototype = util.inherit(Evented, {
}
}
delete this._layers[id];
this._order.splice(this._order.indexOf(id), 1);
var position = this._order.indexOf(id);
this.stylesheet.layers.splice(position, 1);
this._order.splice(position, 1);
this._groupLayers();
this._broadcastLayers();
this.fire('layer.remove', {layer: layer});
Expand Down Expand Up @@ -371,6 +379,7 @@ Style.prototype = util.inherit(Evented, {
}
layer = this.getReferentLayer(layer);
layer.filter = filter;
this.stylesheet.layers[this._order.indexOf(layer.id)].filter = filter;
this._broadcastLayers();
this.sources[layer.source].reload();
this.fire('change');
Expand All @@ -392,6 +401,9 @@ Style.prototype = util.inherit(Evented, {
}
layer = this.getReferentLayer(layer);
layer.setLayoutProperty(name, value);
var styleLayer = this.stylesheet.layers[this._order.indexOf(layer.id)];
styleLayer.layout = styleLayer.layout || {};
styleLayer.layout[name] = value;
this._broadcastLayers();
if (layer.source) {
this.sources[layer.source].reload();
Expand All @@ -414,7 +426,11 @@ Style.prototype = util.inherit(Evented, {
if (!this._loaded) {
throw new Error('Style is not done loading');
}
this.getLayer(layer).setPaintProperty(name, value, klass);
layer = this.getLayer(layer);
layer.setPaintProperty(name, value, klass);
var styleLayer = this.stylesheet.layers[this._order.indexOf(layer.id)];
styleLayer.paint = styleLayer.paint || {};
styleLayer.paint[name] = value;
this.fire('change');
},

Expand Down Expand Up @@ -475,6 +491,10 @@ Style.prototype = util.inherit(Evented, {
this.fire(e.type, util.extend({source: e.target}, e));
},

json: function() {
return this.stylesheet;
},

// Callbacks from web workers

'get sprite json': function(params, callback) {
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"geojson-vt": "^2.1.0",
"gl-matrix": "^2.3.1",
"glify": "^0.5.0",
"lodash.clonedeep": "^3.0.1",
"mapbox-gl-function": "^1.0.0",
"mapbox-gl-style-spec": "^7.4.1",
"minifyify": "^7.0.1",
Expand Down
206 changes: 192 additions & 14 deletions test/js/style/style.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,16 @@ function createStyleJSON(properties) {
}, properties);
}

function createGeoJSONSourceJSON() {
return {
"type": "geojson",
"data": {
"type": "FeatureCollection",
"features": []
}
};
}

function createSource() {
return new VectorTileSource({
type: 'vector',
Expand Down Expand Up @@ -64,6 +74,31 @@ test('Style', function(t) {
});
});

t.test('preserves json', function(t) {
var style = new Style(util.extend(createStyleJSON(), {
"sources": {
"mapbox": {
"type": "vector",
"tiles": []
}
}
}));
style.on('load', function() {
t.deepEqual(
style.json(),
util.extend(createStyleJSON(), {
"sources": {
"mapbox": {
"type": "vector",
"tiles": []
}
}
})
);
t.end();
});
});

t.test('after', function(t) {
server.close(t.end);
});
Expand Down Expand Up @@ -195,6 +230,28 @@ test('Style#addSource', function(t) {
source.fire('tile.remove');
});
});

t.test('updates json', function(t) {
var style = new Style(createStyleJSON());
style.on('load', function() {
style.addSource('mapbox', {
"type": "vector",
"tiles": []
});
t.deepEqual(
style.json(),
util.extend(createStyleJSON(), {
"sources": {
"mapbox": {
"type": "vector",
"tiles": []
}
}
})
);
t.end();
});
});
});

test('Style#removeSource', function(t) {
Expand Down Expand Up @@ -274,6 +331,25 @@ test('Style#removeSource', function(t) {
t.end();
});
});

t.test('updates json', function(t) {
var style = new Style(createStyleJSON({
"sources": {
"mapbox": {
"type": "vector",
"tiles": []
}
}
}));
style.on('load', function() {
style.removeSource('mapbox');
t.deepEqual(
style.json(),
createStyleJSON()
);
t.end();
});
});
});

test('Style#addLayer', function(t) {
Expand Down Expand Up @@ -385,6 +461,22 @@ test('Style#addLayer', function(t) {
t.end();
});
});

t.test('updates json', function(t) {
var style = new Style(createStyleJSON());
style.on('load', function() {
style.addLayer({ id: 'background', type: 'background' });
t.deepEqual(
style.json(),
createStyleJSON({
layers: [
{ id: 'background', type: 'background' }
]
})
);
t.end();
});
});
});

test('Style#removeLayer', function(t) {
Expand Down Expand Up @@ -473,20 +565,30 @@ test('Style#removeLayer', function(t) {
t.end();
});
});

t.test('updates json', function(t) {
var style = new Style(createStyleJSON({
layers: [
{ id: 'background', type: 'background' }
]
}));
style.on('load', function() {
style.removeLayer('background');
t.deepEqual(
style.json(),
createStyleJSON()
);
t.end();
});
});
});

test('Style#setFilter', function(t) {
t.test('sets a layer filter', function(t) {
var style = new Style({
"version": 7,
"sources": {
"geojson": {
"type": "geojson",
"data": {
"type": "FeatureCollection",
"features": []
}
}
"geojson": createGeoJSONSourceJSON()
},
"layers": [{
"id": "symbol",
Expand All @@ -506,13 +608,7 @@ test('Style#setFilter', function(t) {
t.test('throw before loaded', function(t) {
var style = new Style(createStyleJSON({
"sources": {
"geojson": {
"type": "geojson",
"data": {
"type": "FeatureCollection",
"features": []
}
}
"geojson": createGeoJSONSourceJSON()
},
"layers": [{
"id": "symbol",
Expand All @@ -528,6 +624,38 @@ test('Style#setFilter', function(t) {
t.end();
});
});

t.test('updates json', function(t) {
var style = new Style(createStyleJSON({
"sources": {
"geojson": createGeoJSONSourceJSON()
},
"layers": [{
"id": "symbol",
"type": "symbol",
"source": "geojson",
"filter": ["==", "id", 0]
}]
}));
style.on('load', function() {
style.setFilter('symbol', ['==', 'id', 1]);
t.deepEqual(
style.json(),
createStyleJSON({
"sources": {
"geojson": createGeoJSONSourceJSON()
},
"layers": [{
"id": "symbol",
"type": "symbol",
"source": "geojson",
"filter": ["==", "id", 1]
}]
})
);
t.end();
});
});
});

test('Style#setLayoutProperty', function(t) {
Expand Down Expand Up @@ -688,6 +816,31 @@ test('Style#setLayoutProperty', function(t) {
t.end();
});
});

t.test('updates json', function(t) {
var style = new Style(createStyleJSON({
"layers": [{
"id": "background",
"type": "background"
}]
}));
style.on('load', function() {
style.setLayoutProperty('background', 'visibility', 'none');
t.deepEqual(
style.json(),
createStyleJSON({
"layers": [{
"id": "background",
"type": "background",
"layout": {
"visibility": "none"
}
}]
})
);
t.end();
});
});
});

test('Style#setPaintProperty', function(t) {
Expand Down Expand Up @@ -727,6 +880,31 @@ test('Style#setPaintProperty', function(t) {
t.end();
});
});

t.test('updates json', function(t) {
var style = new Style(createStyleJSON({
"layers": [{
"id": "background",
"type": "background"
}]
}));
style.on('load', function() {
style.setPaintProperty('background', 'background-color', 'red');
t.deepEqual(
style.json(),
createStyleJSON({
"layers": [{
"id": "background",
"type": "background",
"paint": {
"background-color": "red"
}
}]
})
);
t.end();
});
});
});

test('Style#featuresAt - race condition', function(t) {
Expand Down

0 comments on commit d33c899

Please sign in to comment.