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

Support loaders.gl v4 Table object #8664

Merged
merged 2 commits into from Mar 18, 2024
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 9 additions & 0 deletions docs/upgrade-guide.md
Expand Up @@ -97,6 +97,15 @@ const layer = new CartoLayer({
});
```

### loaders.gl

loaders.gl dependencies are updated to v4. Although most version differences are handled internal to deck.gl, some changes may be required for applications that work directly with loaders:

- If an application imports `@loaders.gl/*` sub packages to load specific data formats, they should be upgraded from v3.x to v4.x.
- If the layer prop `dataTransform` is used to pre-process data, the loaded data object might have changed. For example, `CSVLoader` now yields [a new table format](https://loaders.gl/docs/specifications/category-table).
- For a complete list of breaking changes and improvements, see [loaders.gl 4.0 upgrade guide](https://loaders.gl/docs/upgrade-guide#upgrading-to-v40).


## Upgrading from deck.gl v8.8 to v8.9

#### Breaking changes
Expand Down
16 changes: 15 additions & 1 deletion modules/core/src/lifecycle/prop-types.ts
Expand Up @@ -192,8 +192,22 @@ const TYPE_DEFINITIONS = {
},
data: {
transform: (value, propType: DataPropType, component) => {
if (!value) {
return value;
}
const {dataTransform} = component.props;
return dataTransform && value ? dataTransform(value) : value;
if (dataTransform) {
return dataTransform(value);
Pessimistress marked this conversation as resolved.
Show resolved Hide resolved
}
// Detect loaders.gl v4 table format
if (
typeof value.shape === 'string' &&
value.shape.endsWith('-table') &&
Array.isArray(value.data)
) {
return value.data;
}
return value;
}
},
image: {
Expand Down
45 changes: 45 additions & 0 deletions test/data/bart-stations.csv
@@ -0,0 +1,45 @@
name,code,longitude,latitude,entries,exits
"Lafayette (LAFY)",LF,-122.123801,37.893394,3481,3616
"12th St. Oakland City Center (12TH)",12,-122.271604,37.803664,13418,13547
"16th St. Mission (16TH)",16,-122.419694,37.765062,12409,12351
"19th St. Oakland (19TH)",19,-122.269029,37.80787,13108,13090
"24th St. Mission (24TH)",24,-122.418466,37.752254,12817,12529
"Ashby (ASHB)",AS,-122.26978,37.853024,5452,5341
"Balboa Park (BALB)",BP,-122.447414,37.721981,11170,9817
"Bay Fair (BAYF)",BF,-122.126871,37.697185,5564,5516
"Castro Valley (CAST)",CV,-122.075567,37.690754,2781,2735
"Civic Center/UN Plaza (CIVC)",CC,-122.413756,37.779528,24798,22626
"Colma (COLM)",CM,-122.466233,37.684638,4397,4214
"Coliseum/Oakland Airport (COLS)",CL,-122.197273,37.754006,5837,5902
"Concord (CONC)",CN,-122.029095,37.973737,6035,6008
"Daly City (DALY)",DC,-122.469081,37.706121,8681,8502
"Downtown Berkeley (DBRK)",BK,-122.268045,37.869867,11043,11762
"El Cerrito del Norte (DELN)",EN,-122.317269,37.925655,8176,8668
"Dublin/Pleasanton (DUBL)",ED,-121.900367,37.701695,7702,7554
"Embarcadero (EMBR)",EM,-122.396742,37.792976,40376,46951
"Fremont (FRMT)",FM,-121.9764,37.557355,8748,8673
"Fruitvale (FTVL)",FV,-122.224274,37.774963,7701,8012
"Glen Park (GLEN)",GP,-122.434092,37.732921,7732,7072
"Hayward (HAYW)",HY,-122.087967,37.670399,4958,5003
"Lake Merritt (LAKE)",LM,-122.265609,37.797484,6539,6604
"MacArthur (MCAR)",MA,-122.267227,37.828415,9000,9228
"Millbrae (MLBR)",MB,-122.38666,37.599787,6570,6149
"Montgomery St. (MONT)",MT,-122.401407,37.789256,43430,45128
"North Berkeley (NBRK)",NB,-122.283451,37.87404,4363,4563
"North Concord/Martinez (NCON)",NC,-122.024597,38.003275,2800,2652
"Orinda (ORIN)",OR,-122.183791,37.878361,2896,2970
"Pleasant Hill/Contra Costa Centre (PHIL)",PH,-122.056013,37.928403,7574,7442
"Pittsburg/Bay Point (PITT)",WP,-121.945154,38.018914,6262,6343
"El Cerrito Plaza (PLZA)",EP,-122.299272,37.903059,4763,4952
"Powell St. (POWL)",PL,-122.406857,37.784991,29460,25621
"Richmond (RICH)",RM,-122.353165,37.936887,4184,4029
"Rockridge (ROCK)",RR,-122.251793,37.844601,5299,5775
"San Leandro (SANL)",SL,-122.161311,37.722619,5836,5921
"San Bruno (SBRN)",SB,-122.416038,37.637753,3628,3634
"San Francisco Int'l Airport (SFIA)",SO,-122.392612,37.616035,5833,4904
"South Hayward (SHAY)",SH,-122.057551,37.6348,3007,2829
"South San Francisco (SSAN)",SS,-122.444116,37.664174,3542,3441
"Union City (UCTY)",UC,-122.017867,37.591208,4772,4770
"Walnut Creek (WCRK)",WC,-122.067423,37.905628,6719,6917
"West Dublin/Pleasanton (WDUB)",WD,-121.928099,37.699759,3303,3447
"West Oakland (WOAK)",OW,-122.294582,37.804675,7312,6838
69 changes: 36 additions & 33 deletions test/modules/core/lifecycle/component-state.spec.ts
Expand Up @@ -3,6 +3,8 @@
import test from 'tape-promise/tape';
import {_ComponentState as ComponentState, _Component as Component} from '@deck.gl/core';
import {device} from '@deck.gl/test-utils';
import {load} from '@loaders.gl/core';
import {CSVLoader} from '@loaders.gl/csv';

const EMPTY_ARRAY = Object.freeze([]);

Expand All @@ -15,7 +17,7 @@ type TestComponentProps = {
const defaultProps = {
// data: Special handling for null, see below
data: {type: 'data', value: EMPTY_ARRAY, async: true},
dataTransform: data => data,
dataTransform: null,
image: {type: 'image', value: null, async: true}
};

Expand Down Expand Up @@ -192,8 +194,7 @@ test('ComponentState#asynchronous async props', async t => {
t.end();
});

// TODO - disabled for v9
test('ComponentState#async props with transform', t => {
test('ComponentState#async props with transform', async t => {
const testContext = {device};

const testData = [0, 1, 2, 3, 4];
Expand All @@ -205,10 +206,11 @@ test('ComponentState#async props with transform', t => {
0, 0, 255, 255
]), width: 2, height: 2};

// @ts-expect-error
const state = new ComponentState();

// Simulate Layer class
const makeComponent = (props: Record<string, unknown>, onAsyncPropUpdated = () => {}) => {
const makeComponent = (props: Record<string, unknown>) => {
const comp = new TestComponent(props);
// @ts-expect-error
comp.internalState = state;
Expand All @@ -217,7 +219,6 @@ test('ComponentState#async props with transform', t => {

state.component = comp;
state.setAsyncProps(comp.props);
state.onAsyncPropUpdated = onAsyncPropUpdated;

return comp;
};
Expand Down Expand Up @@ -251,32 +252,34 @@ test('ComponentState#async props with transform', t => {
t.is(component.props.image, image, 'Unchanged image value is not transformed again');

// Async value for async prop
component = makeComponent(
{
data: Promise.resolve(testData),
dataTransform: d => d.slice(0, 2),
image: Promise.resolve(testImage)
},
// @ts-expect-error
(propName, value) => {
if (propName === 'image') {
t.ok(image.destroyed, 'Last texture is deleted');
image = component.props.image;
t.ok(image, 'Async value for image should be transformed');
}
if (propName === 'data') {
data = component.props.data;
t.deepEqual(data, [0, 1], 'Async value for data should be transformed');
}

// @ts-expect-error
if (!state.isAsyncPropLoading()) {
// @ts-expect-error
state.finalize();
t.ok(image.destroyed, 'Texture is deleted on finalization');

t.end();
}
}
);
const testDataAsync = Promise.resolve(testData);
const testImageAsync = Promise.resolve(testImage);
component = makeComponent({
data: testDataAsync,
dataTransform: d => d.slice(0, 2),
image: testImageAsync
});

await testDataAsync;
data = component.props.data;
t.deepEqual(data, [0, 1], 'Async value for data should be transformed');

await testImageAsync;
t.ok(image.destroyed, 'Last texture is deleted');
image = component.props.image;
t.ok(image, 'Async value for image should be transformed');

const loadDataAsync = load('./test/data/bart-stations.csv', [CSVLoader]);
component = makeComponent({
data: loadDataAsync,
image: testImageAsync
});

await loadDataAsync;
t.is(component.props.image, image, 'Unchanged image value is not transformed again');
data = component.props.data;
t.ok(Array.isArray(data), 'loaders.gl table object is properly transformed');

state.finalize();
t.ok(image.destroyed, 'Texture is deleted on finalization');
});