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

Fixed some bugs in addInTheRightPosition function #103

Merged
merged 7 commits into from
Jul 29, 2020
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)

- Aggregated data filtering in widgets ([#96](https://github.com/CartoDB/web-sdk/pull/96))

### Changed
- Rename `beforeLayerId|afterLayerId` options in `carto.viz.Layer.addTo` to a more clear `overLayerId|underLayerId`.

### Fixed

- Fix `dataReady` event in `carto.viz.Layer` ([#99](https://github.com/CartoDB/web-sdk/pull/99/))
Expand Down
110 changes: 110 additions & 0 deletions examples/_debug/basic/severalLayersWithCustomOrder.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Add several layers</title>

<link
rel="stylesheet"
type="text/css"
href="https://api.tiles.mapbox.com/mapbox-gl-js/v1.10.0/mapbox-gl.css"
/>

<link
rel="stylesheet"
type="text/css"
href="https://libs.cartocdn.com/airship-style/v2.4/airship.min.css"
/>

<style>
body {
margin: 0;
padding: 0;
}

#map {
width: 100vw;
height: 100vh;
}
</style>
</head>

<body class="as-app-body as-app">
<div class="as-content">
<main class="as-main">
<div class="as-map-area">
<!-- map -->
<div id="map"></div>

<!-- panel -->
<div class="as-panel as-panel--top as-panel--right as-bg--ui-01">
<div class="as-panel__element as-p--16 as-body">
<h1 class="as-title">Add several layers</h1>
<h4 class="as-subheader as-mb--12">
Add several CARTO layers to your map, using just multiple <em>carto.viz.Layer.addTo</em> calls
</h4>
</div>
</div>
</main>
</div>

<script src="https://api.tiles.mapbox.com/mapbox-gl-js/v1.10.0/mapbox-gl.js"></script>
<script src="https://unpkg.com/deck.gl@8.2.0/dist.min.js"></script>
<script src="/dist/umd/index.min.js"></script>

<script>
async function initialize() {
carto.auth.setDefaultCredentials({ username: 'public' });

/*
A createMap, setting up a custom initial viewport
*/
const deckMap = carto.viz.createMap({
view: {
longitude: -116.846099,
latitude: 50.2672297,
zoom: 2.5
}
});

// CASE 1: await --> last layer is on top
// ORDER: from top to bottom: ports > usa > world
// const states = new carto.viz.Layer('ne_50m_admin_0_countries', carto.viz.style.basic({ color: "#ff0000"}), { id: 'world' });
// await states.addTo(deckMap);

// const boundaries = new carto.viz.Layer('ne_50m_admin_1_states_1', carto.viz.style.basic({ color: "#00ff00"}), { id: 'usa' });
// await boundaries.addTo(deckMap);

// const ports = new carto.viz.Layer('world_ports', carto.viz.style.basic({ color: "#0000ff"}), { id: 'ports' });
// await ports.addTo(deckMap);


// CASE 2: await, but custom order (overLayerId)
// ORDER: from top to bottom: usa > ports > world
const states = new carto.viz.Layer('ne_50m_admin_0_countries', carto.viz.style.basic({ color: "#ff0000"}), { id: 'world' });
await states.addTo(deckMap);

const boundaries = new carto.viz.Layer('ne_50m_admin_1_states_1', carto.viz.style.basic({ color: "#00ff00"}), { id: 'usa' });
await boundaries.addTo(deckMap, { overLayerId: 'world'});

const ports = new carto.viz.Layer('world_ports', carto.viz.style.basic({ color: "#0000ff"}), { id: 'ports' });
await ports.addTo(deckMap, { overLayerId: 'world'});

// CASE 3: await, but custom order (underLayerId)
// ORDER: from top to bottom: world > ports > usa
// const states = new carto.viz.Layer('ne_50m_admin_0_countries', carto.viz.style.basic({ color: "#ff0000"}), { id: 'world' });
// await states.addTo(deckMap);

// const boundaries = new carto.viz.Layer('ne_50m_admin_1_states_1', carto.viz.style.basic({ color: "#00ff00"}), { id: 'usa' });
// await boundaries.addTo(deckMap, { underLayerId: 'world'});

// const ports = new carto.viz.Layer('world_ports', carto.viz.style.basic({ color: "#0000ff"}), { id: 'ports' });
// await ports.addTo(deckMap, { underLayerId: 'world'});

}

initialize();
</script>
</body>
</html>
5 changes: 5 additions & 0 deletions examples/basic/severalLayers.html
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ <h4 class="as-subheader as-mb--12">
const ports = new carto.viz.Layer('world_ports');
ports.addTo(deckMap);

/*
Another option to control the layer order is using 'overLayerId|underLayerId' options in addTo
methods. See the reference for a description on how to use it.
*/

/*
A note on async/await. Modern JS code tries to use async/await pattern to better manage Promises
and in general asynchronous code (vs the 'callback hell'). If you are not used to id, have
Expand Down
18 changes: 9 additions & 9 deletions src/lib/viz/__tests__/Layer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,34 +91,34 @@ describe('Layer', () => {
expect(deckInstanceMock.props.layers[1].id).toBe('layer2');
});

it('should allow adding before a layer', async () => {
it('should allow adding over a layer', async () => {
const layer1 = new Layer(DEFAULT_DATASET, {}, { id: 'layer1' });
await layer1.addTo(deckInstanceMock);

const layer2 = new Layer(DEFAULT_DATASET, {}, { id: 'layer2' });
await layer2.addTo(deckInstanceMock, { beforeLayerId: 'layer1' });
await layer2.addTo(deckInstanceMock, { overLayerId: 'layer1' });

await layer1.replaceDeckGLLayer();
expect(deckInstanceMock.props.layers.length).toBe(2);
expect(deckInstanceMock.props.layers[0].id).toBe('layer2');
expect(deckInstanceMock.props.layers[1].id).toBe('layer1');
expect(deckInstanceMock.props.layers[0].id).toBe('layer1');
expect(deckInstanceMock.props.layers[1].id).toBe('layer2');
});

it('should allow adding after a layer', async () => {
it('should allow adding under a layer', async () => {
const layer1 = new Layer(DEFAULT_DATASET, {}, { id: 'layer1' });
await layer1.addTo(deckInstanceMock);

const layer2 = new Layer(DEFAULT_DATASET, {}, { id: 'layer2' });
await layer2.addTo(deckInstanceMock, { beforeLayerId: 'layer1' });
await layer2.addTo(deckInstanceMock, { overLayerId: 'layer1' });

const layer3 = new Layer(DEFAULT_DATASET, {}, { id: 'layer3' });
await layer3.addTo(deckInstanceMock, { afterLayerId: 'layer2' });
await layer3.addTo(deckInstanceMock, { underLayerId: 'layer2' });

await layer1.replaceDeckGLLayer();
expect(deckInstanceMock.props.layers.length).toBe(3);
expect(deckInstanceMock.props.layers[0].id).toBe('layer2');
expect(deckInstanceMock.props.layers[0].id).toBe('layer1');
expect(deckInstanceMock.props.layers[1].id).toBe('layer3');
expect(deckInstanceMock.props.layers[2].id).toBe('layer1');
expect(deckInstanceMock.props.layers[2].id).toBe('layer2');
});
});
});
Expand Down
36 changes: 20 additions & 16 deletions src/lib/viz/layer/Layer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ export class Layer extends WithEvents implements StyledLayer {
/**
* Add the current layer to a Deck map instance.
* By default the layer will be the last positioned (on top).
* To achieve a custom ordering, `beforeLayerId` or `afterLayerId` options can be used (and then the
* To achieve a custom ordering, `overLayerId` or `underLayerId` options can be used (and then the
* referenced layer must have an `id`)
*
* Example:
Expand All @@ -160,7 +160,7 @@ export class Layer extends WithEvents implements StyledLayer {
* await layer1.addTo(deckMap);
*
* const layer2 = new Layer('dataset2', {}, { id: 'layer2' });
* await layer2.addTo(deckMap, { beforeLayerId: 'layer1' });
* await layer2.addTo(deckMap, { overLayerId: 'layer1' });
*
* // at this point, the order would be 'layer2' < 'layer1' and not the opposite
* ```
Expand All @@ -171,7 +171,7 @@ export class Layer extends WithEvents implements StyledLayer {
* add more layers or to use it in a `DataView` then you must use `await` for it to finish.
*
* @param {Deck} instance of the map to add the layer to
* @param {{ beforeLayerId?: string; afterLayerId?: string }} [opts={}] options to control relative layer position
* @param {{ overLayerId?: string; underLayerId?: string }} [opts={}] options to control relative layer position
* @memberof Layer
*/
public async addTo(deckInstance: Deck, opts: LayerPosition = {}) {
Expand Down Expand Up @@ -613,33 +613,37 @@ function ensureRelatedStyleProps(layerProps: any) {

// eslint-disable-next-line @typescript-eslint/no-explicit-any
function addInTheRightPosition(deckglLayer: any, layers: any[], opts: LayerPosition = {}) {
const { beforeLayerId, afterLayerId } = opts;
const { overLayerId, underLayerId } = opts;

if (beforeLayerId && afterLayerId) {
if (overLayerId && underLayerId) {
throw new CartoLayerError(
'Cannot use beforeLayerId and afterLayerId at the same time',
'Cannot use overLayerId and underLayerId at the same time',
layerErrorTypes.DEFAULT
);
}

if (beforeLayerId || afterLayerId) {
const beforeAfterLayerIdx = layers.findIndex(l => l.id === beforeLayerId || afterLayerId);
const baseLayerId = overLayerId || underLayerId;

if (beforeAfterLayerIdx !== -1) {
if (beforeLayerId) {
layers.splice(beforeAfterLayerIdx, 0, deckglLayer);
} else if (afterLayerId) {
layers.splice(beforeAfterLayerIdx + 1, 0, deckglLayer);
if (baseLayerId) {
const layerIdx = layers.findIndex(l => l.id === baseLayerId);

const baseLayerFound = layerIdx !== -1;

if (baseLayerFound) {
if (overLayerId) {
layers.splice(layerIdx + 1, 0, deckglLayer); // higher index = nearer the top
} else if (underLayerId) {
layers.splice(layerIdx, 0, deckglLayer); // lower index = nearer the bottom
}
} else {
layers.push(deckglLayer);
layers.push(deckglLayer); // place latest layer on top by default
}
} else {
layers.push(deckglLayer);
}
}

interface LayerPosition {
beforeLayerId?: string;
afterLayerId?: string;
overLayerId?: string;
underLayerId?: string;
}