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
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ map.on('load', () => {
| uniforms | object | - | Shader uniform values (requires `customFrag`) |
| onLoadingStateChange | function | - | Loading state callback |
| throttleMs | number | `100` | Throttle interval (ms) for data fetching during rapid selector changes. Set to `0` to disable. |
| transformRequest | function | - | Transform request URLs and add headers/credentials (see [authentication](#authentication)) |

## methods

Expand Down Expand Up @@ -210,6 +211,23 @@ const result = await layer.queryData({

**Note:** Query results match rendered values (`scale_factor`/`add_offset` applied, `fillValue`/NaN filtered). For datasets rendered via `proj4` reprojection, queries sample the underlying source grid; because reprojection/resampling occurs for display, a visual pixel click may not align perfectly with the nearest source pixel.

## authentication

Use `transformRequest` to add headers or credentials to requests. The function receives the fully resolved URL for each request, enabling per-path authentication like presigned S3 URLs. Supports any [fetch options](https://developer.mozilla.org/en-US/docs/Web/API/fetch#options).

```ts
// Static auth (same headers for all requests)
transformRequest: (url) => ({
url,
headers: { Authorization: `Bearer ${token}` },
})

// Presigned URLs (path-specific signatures)
transformRequest: async (url) => ({
url: await getPresignedUrl(url),
})
```

## thanks

This experiment is only possible following in the footsteps of other work in this space. [zarr-gl](https://github.com/carderne/zarr-gl) showed that custom layers are a viable rendering option and [zarr-cesium](https://github.com/NOC-OI/zarr-cesium) showed how flexible web rendering can be. We borrow code and concepts from both. This library also leans on our prior work on [@carbonplan/maps](https://github.com/carbonplan/maps) for many of its patterns. LLMs of several makes aided in the coding and debugging of this library.
Expand Down
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ export type {
LoadingState,
LoadingStateCallback,
Selector,
TransformRequest,
RequestParameters,
} from './types'

// Query interface exports
Expand Down
15 changes: 15 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@ import * as zarr from 'zarrita'
/** Bounds tuple: [xMin, yMin, xMax, yMax] */
export type Bounds = [number, number, number, number]

export interface RequestParameters extends Omit<RequestInit, 'headers'> {
url: string
headers?: { [key: string]: string }
}

export type TransformRequest = (
url: string
) => RequestParameters | Promise<RequestParameters>

export type ColormapArray = number[][] | string[]

export type SelectorValue = number | number[] | string | string[]
Expand Down Expand Up @@ -81,6 +90,12 @@ export interface ZarrLayerOptions {
* Example: "+proj=lcc +lat_1=38.5 +lat_2=38.5 +lat_0=38.5 +lon_0=-97.5 +x_0=0 +y_0=0 +R=6371229 +units=m +no_defs"
*/
proj4?: string
/**
* Function to transform request URLs and add custom headers/credentials.
* Useful for authentication, proxy routing, or request customization.
* When provided, the store cache is bypassed to prevent credential sharing between layers.
*/
transformRequest?: TransformRequest
}

export type CRS = 'EPSG:4326' | 'EPSG:3857'
Expand Down
5 changes: 5 additions & 0 deletions src/zarr-layer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import type {
Selector,
NormalizedSelector,
ZarrLayerOptions,
TransformRequest,
} from './types'
import type { ZarrMode, RenderContext } from './zarr-mode'
import { TiledMode } from './tiled-mode'
Expand Down Expand Up @@ -114,6 +115,7 @@ export class ZarrLayer {
private initError: Error | null = null
private throttleMs: number
private proj4: string | undefined
private transformRequest: TransformRequest | undefined

get fillValue(): number | null {
return this._fillValue
Expand Down Expand Up @@ -146,6 +148,7 @@ export class ZarrLayer {
onLoadingStateChange,
throttleMs = 100,
proj4,
transformRequest,
}: ZarrLayerOptions) {
if (!id) {
throw new Error('[ZarrLayer] id is required')
Expand Down Expand Up @@ -206,6 +209,7 @@ export class ZarrLayer {
this.onLoadingStateChange = onLoadingStateChange
this.throttleMs = throttleMs
this.proj4 = proj4
this.transformRequest = transformRequest
}

private emitLoadingState(): void {
Expand Down Expand Up @@ -443,6 +447,7 @@ export class ZarrLayer {
latIsAscending: this.latIsAscending,
coordinateKeys: Object.keys(this.selector),
proj4: this.proj4,
transformRequest: this.transformRequest,
})

await this.zarrStore.initialized
Expand Down
Loading