The library that combines Icepick and Mapbox style spec
Built for the Maputnik editor, but should hopefully be generally useful.
Why does this exist?
- If we have an immutable data structure we can improve rendering performance in UI frameworks that checking object equality when updating the UI (for example React)
- More robust by having a library to deal with changes
Features include
- Methods for modifying data specific to the style spec, keeping object mutations to a minimum
- In library style specification validation
To install
npm install mgljs-contrib/icepick-style --save
General methods
valid
- is the current style validerrors
- list of current errorscurrent
- the current immutable objecthistory
- array of immutable objectsstack(idx)
- get a item from the history stack, supports negative index lookups to start from the end of historycanUndo()
- is there anything to undo in the history stackundo()
- move backward in the history stackcanRedo()
- is there anything to redo in the history stackredo()
- move forward in the history stackmerge(styleObject)
- merge a style into another stylereplace(styleObject)
- replace the style keeping object equality where possibleaddHook(key, fn)
- add a hook (see hooks)removeHook(key, fn)
- remove a hook (see hooks)
MapboxGL spec specific. These methods are chainable
addRoot(keyPath, value)
modifyRoot(keyPath, value)
removeRoot(keyPath)
addLayer(id, value)
modifyLayer(id, value)
renameLayer(id, newId)
removeLayer(id)
addSource(id, value)
modifySource(id, value)
removeSource(id)
renameSource(id, newId)
Creating a new style
const IcepickStyle = require("icepick-style");
const style = new IcepickStyle();
style
.modifyRoot("name", "Test style")
.modifySource("openmaptiles", {...});
// Sometime later....
style
.modifySource("openmaptiles", function(doc) {
doc.maxZoom = 13;
});
assert.equal(style.current.name, "Test style");
assert.equal(style.history.length, 2);
assert.equal(style.current.sources.openmaptiles.maxZoom, 13);
assert.equal(style.history[0].sources.openmaptiles.maxZoom, 16);
You can also start a transaction to group changes into a single history entry
style
.transaction((style) => {
style
.modifyRoot("name", "Foo bar")
.modifyLayer((layer) => {
layer.maxZoom = 14;
})
})
// Only a single history item
assert.equal(style.history.length, 1);
It also comes with a validate hook which will validate the current state of the style and output errors to style.errors
, see an example below
const IcepickStyle = require('icepick-style');
const mapboxGlValidateHook = require('icepick-style/hooks/validate/mapbox-gl');
const style = new IcepickStyle();
style.addHook('validate', mapboxGlValidateHook);
style.addLayer('foo', {
type: 'background',
paint: 1
});
assert.deepStrictEqual(
style.errors[0].message,
'layers[0].paint: object expected, number found'
);
Why icepick and not immutable.js
Because
- It's a "tiny (1kb min/gzipped), zero-dependency library"
- It's fast https://github.com/aearly/icepick-benchmarks