Skip to content
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
15 changes: 9 additions & 6 deletions packages/deck.gl-geotiff/src/cog-layer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,9 @@ export class COGLayer<
// Clear stale state so renderLayers returns null until the new GeoTIFF is
// ready
this.clearState();
this._parseGeoTIFF();
this._parseGeoTIFF().catch((error: Error) =>
this.raiseError(error, "loading GeoTIFF"),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Oh interesting is raiseError an upstream method in the base deck.gl Layer?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yep it is. Marked (Internal) in the docstring but the types are public. Not sure how you feel about that!

My use case is a display in my UI if a GeoTIFF fails to load.

The alternative is a new prop like onGeoTIFFError, but this seemed easier + hooks into Deck's error handling.

);
}
}

Expand All @@ -219,23 +221,24 @@ export class COGLayer<
const signal = this.state.abortController?.signal;

let geotiff: GeoTIFF;
let sourceProjection: ProjectionDefinition;
try {
geotiff = await fetchGeoTIFF(this.props.geotiff, {
concurrencyLimiter: this.props.concurrencyLimiter,
signal,
});
const crs = geotiff.crs;
sourceProjection =
typeof crs === "number"
? await this.props.epsgResolver!(crs)
: parseWkt(crs);
} catch (err) {
// Layer removed mid-open (finalizeState aborted the signal); drop it.
if (signal?.aborted) {
return;
}
throw err;
}
const crs = geotiff.crs;
const sourceProjection =
typeof crs === "number"
? await this.props.epsgResolver!(crs)
: parseWkt(crs);

if (signal?.aborted) {
return;
Expand Down
4 changes: 3 additions & 1 deletion packages/deck.gl-geotiff/src/multi-cog-layer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,9 @@ export class MultiCOGLayer extends RasterTileLayer<
sources: null,
multiDescriptor: null,
});
this._parseAllSources();
this._parseAllSources().catch((error: Error) =>
this.raiseError(error, "loading COG sources"),
);
}
}

Expand Down
22 changes: 22 additions & 0 deletions packages/deck.gl-geotiff/tests/cog-layer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,25 @@ describe("COGLayer._onTileUnloadCallback", () => {
expect(unloadCallback(layer)).toBe(onTileUnload);
});
});

describe("COGLayer.updateState", () => {
it("raises a GeoTIFF open failure through onError", async () => {
const onError = vi.fn((_error: Error) => true);
const layer = new COGLayer({
id: "cog",
geotiff: "https://example.com/x.tif",
onError,
} as never);
vi.spyOn(layer, "clearState").mockImplementation(() => {});
vi.spyOn(layer, "_parseGeoTIFF").mockRejectedValue(new Error("boom"));

layer.updateState({
props: layer.props,
oldProps: layer.props,
changeFlags: { dataChanged: true },
} as never);

await vi.waitFor(() => expect(onError).toHaveBeenCalledOnce());
expect(onError.mock.calls[0]?.[0]?.message).toBe("loading GeoTIFF: boom");
});
});
24 changes: 24 additions & 0 deletions packages/deck.gl-geotiff/tests/multi-cog-layer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,27 @@ describe("MultiCOGLayer._onTileUnloadCallback", () => {
expect(() => cb?.({ content: null })).not.toThrow();
});
});

describe("MultiCOGLayer.updateState", () => {
it("raises a COG open failure through onError", async () => {
const onError = vi.fn((_error: Error) => true);
const layer = new MultiCOGLayer({
id: "multi",
sources: { a: { url: "https://example.com/a.tif" } },
onError,
} as never);
vi.spyOn(layer, "setState").mockImplementation(() => {});
vi.spyOn(layer, "_parseAllSources").mockRejectedValue(new Error("boom"));

layer.updateState({
props: layer.props,
oldProps: layer.props,
changeFlags: { dataChanged: true },
} as never);

await vi.waitFor(() => expect(onError).toHaveBeenCalledOnce());
const error = onError.mock.calls[0]?.[0];
expect(error?.message).toBe("loading COG sources: boom");
expect(error?.cause).toBeInstanceOf(Error);
});
});
Loading