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

Improve layer load #623

Merged
merged 14 commits into from
Jul 4, 2018
30 changes: 24 additions & 6 deletions src/api/layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ import CartoValidationError from './error-handling/carto-validation-error';
import { cubic } from '../core/viz/functions';
import RenderLayer from '../core/renderLayer';

const mapboxDataType = Object.freeze({
STYLE: 'style',
SOURCE: 'source'
});

/**
*
* LayerEvent objects are fired by {@link carto.Layer|Layer} objects.
Expand Down Expand Up @@ -376,12 +381,25 @@ export default class Layer {
}

_addToMGLMap(map, beforeLayerID) {
if (map.isStyleLoaded()) {
this._onMapLoaded(map, beforeLayerID);
} else {
map.on('load', () => {
this._onMapLoaded(map, beforeLayerID);
});
map.once('data', (event) => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why does this work? Does it work? I thought that MGL required the style to be loaded before the addLayer method works

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MGL requires the style to be loaded if the data event type is sytle. About the data event, after reading the documentation I think it is the only change that needs to be listened, and only the first time (that is why I am using once).

https://www.mapbox.com/mapbox-gl-js/api/#map.event:data

Fired when any map data loads or changes

The examples in the editor work, but I agree it needs further testing.

this._onMapData(event.dataType, map, beforeLayerID);
});
}

_onMapData(dataType, map, beforeLayerID) {
switch (dataType) {
case mapboxDataType.STYLE:
if (map.isStyleLoaded()) {
this._onMapLoaded(map, beforeLayerID);
}
break;
case mapboxDataType.SOURCE:
if (map.areTilesLoaded()) {
this._onMapLoaded(map, beforeLayerID);
}
break;
default:
throw new Error(`Unkown data type: ${dataType}`);
}
}

Expand Down
119 changes: 86 additions & 33 deletions test/unit/api/layer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,51 +131,104 @@ describe('api/layer', () => {

describe('.addTo', () => {
describe('._addToMGLMap', () => {
let layer;
beforeEach(() => {
layer = new Layer('layer0', source, viz);
layer._onMapLoaded = () => { };
spyOn(layer, '_onMapLoaded');
});

it('should call onMapLoaded when the map is loaded', () => {
const mapMock = { isStyleLoaded: () => true };
layer._addToMGLMap(mapMock);
expect(layer._onMapLoaded).toHaveBeenCalledWith(mapMock, undefined);
});

it('should not call onMapLoaded when the map is not loaded', () => {
const mapMock = { isStyleLoaded: () => false, on: () => { } };
layer._addToMGLMap(mapMock);
expect(layer._onMapLoaded).not.toHaveBeenCalled();
});

it('should call onMapLoaded when the map `load` event is triggered', () => {
describe('and dataType is style', () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when datatype is style ?


let layer;
let eventId = 'data';
const event = {
dataType: 'style'
};

const mapMock = {
isStyleLoaded: () => false,
on: (id, callback) => {
if (id === 'load') {
callback();
isStyleLoaded: jasmine.createSpy('isStyleLoaded').and.returnValue(true),
areTilesLoaded: jasmine.createSpy('areTilesLoaded').and.returnValue(true),
once: (id, callback) => {
if (id === eventId) {
callback(event);
}
}
};
layer._addToMGLMap(mapMock);
expect(layer._onMapLoaded).toHaveBeenCalledWith(mapMock, undefined);

beforeEach(() => {
layer = new Layer('layer0', source, viz);
layer._onMapLoaded = () => { };
spyOn(layer, '_onMapLoaded');
});

it('should call onMapLoaded when the map is loaded', () => {
layer._addToMGLMap(mapMock);
expect(layer._onMapLoaded).toHaveBeenCalled();
});

it('should not call onMapLoaded when the map is not loaded', () => {
mapMock.isStyleLoaded = jasmine.createSpy('isStyleLoaded').and.returnValue(false),
layer._addToMGLMap(mapMock);
expect(layer._onMapLoaded).not.toHaveBeenCalled();
});

it('should call onMapLoaded when the map `data` event is triggered', () => {
mapMock.isStyleLoaded = jasmine.createSpy('isStyleLoaded').and.returnValue(true),
layer._addToMGLMap(mapMock);
expect(layer._onMapLoaded).toHaveBeenCalled();
});

it('should not call onMapLoaded when other map event is triggered', () => {
eventId = 'other';
layer._addToMGLMap(mapMock);
expect(layer._onMapLoaded).not.toHaveBeenCalled();
});
});

it('should not call onMapLoaded when other the map event is triggered', () => {
describe('and dataType is source', () => {

let layer;
let eventId = 'data';
const event = {
dataType: 'source'
};

const mapMock = {
isStyleLoaded: () => false,
on: (id, callback) => {
if (id === 'other') {
callback();
isStyleLoaded: jasmine.createSpy('isStyleLoaded').and.returnValue(false),
areTilesLoaded: jasmine.createSpy('areTilesLoaded').and.returnValue(true),
once: (id, callback) => {
if (id === eventId) {
callback(event);
}
}
};
layer._addToMGLMap(mapMock);
expect(layer._onMapLoaded).not.toHaveBeenCalled();

beforeEach(() => {
layer = new Layer('layer0', source, viz);
layer._onMapLoaded = () => { };
spyOn(layer, '_onMapLoaded');
});

it('should call onMapLoaded when the map is loaded', () => {
layer._addToMGLMap(mapMock);
expect(layer._onMapLoaded).toHaveBeenCalled();
});

it('should not call onMapLoaded when the map is not loaded', () => {
mapMock.areTilesLoaded = jasmine.createSpy('areTilesLoaded').and.returnValue(false),
layer._addToMGLMap(mapMock);
expect(layer._onMapLoaded).not.toHaveBeenCalled();
});

it('should call onMapLoaded when the map `data` event is triggered', () => {
mapMock.areTilesLoaded = jasmine.createSpy('areTilesLoaded').and.returnValue(true),
layer._addToMGLMap(mapMock);
expect(layer._onMapLoaded).toHaveBeenCalled();
});

it('should not call onMapLoaded when other map event is triggered', () => {
eventId = 'other';
layer._addToMGLMap(mapMock);
expect(layer._onMapLoaded).not.toHaveBeenCalled();
});
});
});


});

describe('.getFeaturesAtPosition', () => {
Expand Down