Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow programmatic construction of style even when one is not passed in initially ( h/t @stepankuzmin ) #8924

Merged
merged 3 commits into from
Dec 20, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions src/style-spec/empty.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import latest from './reference/latest';

export default function emptyStyle() {
const style = {};

const version = latest['$version'];
for (const styleKey in latest['$root']) {
const spec = latest['$root'][styleKey];

if (spec.required) {
let value = null;
if (styleKey === 'version') {
value = version;
} else {
if (spec.type === 'array') {
value = [];
} else {
value = {};
}
}

if (value != null) {
style[styleKey] = value;
}
}
}

return style;
}
8 changes: 8 additions & 0 deletions src/style/style.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import GeoJSONSource from '../source/geojson_source';
import styleSpec from '../style-spec/reference/latest';
import getWorkerPool from '../util/global_worker_pool';
import deref from '../style-spec/deref';
import emptyStyle from '../style-spec/empty';
import diffStyles, {operations as diffOperations} from '../style-spec/diff';
import {
registerForPluginStateChange,
Expand Down Expand Up @@ -88,6 +89,8 @@ const ignoredDiffOperations = pick(diffOperations, [
'setPitch'
]);

const empty = emptyStyle();

export type StyleOptions = {
validate?: boolean,
localIdeographFontFamily?: string
Expand Down Expand Up @@ -229,6 +232,11 @@ class Style extends Evented {
});
}

loadEmpty() {
this.fire(new Event('dataloading', {dataType: 'style'}));
this._load(empty, false);
}

_load(json: StyleSpecification, validate: boolean) {
if (validate && emitValidationErrors(this, validateStyle(json))) {
return;
Expand Down
14 changes: 13 additions & 1 deletion src/ui/map.js
Original file line number Diff line number Diff line change
Expand Up @@ -1210,6 +1210,14 @@ class Map extends Camera {
return this;
}

_lazyInitEmptyStyle() {
if (!this.style) {
this.style = new Style(this, {});
this.style.setEventedParent(this, {style: this.style});
this.style.loadEmpty();
}
}

_diffStyle(style: StyleSpecification | string, options?: {diff?: boolean} & StyleOptions) {
if (typeof style === 'string') {
const url = this._requestManager.normalizeStyleURL(style);
Expand Down Expand Up @@ -1301,6 +1309,7 @@ class Map extends Camera {
* @see Raster DEM source: [Add hillshading](https://docs.mapbox.com/mapbox-gl-js/example/hillshade/)
*/
addSource(id: string, source: SourceSpecification) {
this._lazyInitEmptyStyle();
this.style.addSource(id, source);
return this._update(true);
}
Expand Down Expand Up @@ -1353,6 +1362,7 @@ class Map extends Camera {
* @param {Function} callback Called when the source type is ready or with an error argument if there is an error.
*/
addSourceType(name: string, SourceType: any, callback: Function) {
this._lazyInitEmptyStyle();
return this.style.addSourceType(name, SourceType, callback);
}

Expand Down Expand Up @@ -1433,7 +1443,7 @@ class Map extends Camera {
addImage(id: string,
image: HTMLImageElement | ImageData | {width: number, height: number, data: Uint8Array | Uint8ClampedArray} | StyleImageInterface,
{pixelRatio = 1, sdf = false, stretchX, stretchY, content}: $Shape<StyleImageMetadata> = {}) {

this._lazyInitEmptyStyle();
const version = 0;

if (image instanceof HTMLImageElement) {
Expand Down Expand Up @@ -1621,6 +1631,7 @@ class Map extends Camera {
* @see [Add a WMS source](https://www.mapbox.com/mapbox-gl-js/example/wms/)
*/
addLayer(layer: LayerSpecification | CustomLayerInterface, beforeId?: string) {
this._lazyInitEmptyStyle();
this.style.addLayer(layer, beforeId);
return this._update(true);
}
Expand Down Expand Up @@ -1802,6 +1813,7 @@ class Map extends Camera {
* @returns {Map} `this`
*/
setLight(light: LightSpecification, options: StyleSetterOptions = {}) {
this._lazyInitEmptyStyle();
this.style.setLight(light, options);
return this._update(true);
}
Expand Down
15 changes: 15 additions & 0 deletions test/unit/style-spec/empty.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import {test} from '../../util/test';
import emptyStyle from '../../../src/style-spec/empty';
import validateStyleMin from '../../../src/style-spec/validate_style.min';

test('it generates something', (t) => {
const style = emptyStyle();
t.ok(style);
t.end();
});

test('generated empty style is a valid style', (t) => {
const errors = validateStyleMin(emptyStyle());
t.equal(errors.length, 0);
t.end();
});
17 changes: 17 additions & 0 deletions test/unit/ui/map.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,23 @@ test('Map', (t) => {
});
});

t.test('a layer can be added even if a map is created without a style', (t) => {
const map = createMap(t, {deleteStyle: true});
const layer = {
id: 'background',
type: 'background'
};
map.addLayer(layer);
t.end();
});

t.test('a source can be added even if a map is created without a style', (t) => {
const map = createMap(t, {deleteStyle: true});
const source = createStyleSource();
map.addSource('fill', source);
t.end();
});

t.test('returns the style with added source and layer', (t) => {
const style = createStyle();
const map = createMap(t, {style});
Expand Down
17 changes: 9 additions & 8 deletions test/util/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,7 @@ import {extend} from '../../src/util/util';

export function createMap(t, options, callback) {
const container = window.document.createElement('div');

Object.defineProperty(container, 'clientWidth', {value: 200, configurable: true});
Object.defineProperty(container, 'clientHeight', {value: 200, configurable: true});

if (!options || !options.skipCSSStub) t.stub(Map.prototype, '_detectMissingCSS');

const map = new Map(extend({
const defaultOptions = {
container,
interactive: false,
attributionControl: false,
Expand All @@ -20,8 +14,15 @@ export function createMap(t, options, callback) {
"sources": {},
"layers": []
}
}, options));
};

Object.defineProperty(container, 'clientWidth', {value: 200, configurable: true});
Object.defineProperty(container, 'clientHeight', {value: 200, configurable: true});

if (!options || !options.skipCSSStub) t.stub(Map.prototype, '_detectMissingCSS');
if (options && options.deleteStyle) delete defaultOptions.style;

const map = new Map(extend(defaultOptions, options));
if (callback) map.on('load', () => {
callback(null, map);
});
Expand Down