Skip to content

Commit 05fca35

Browse files
committed
chg: handle rgb rasters in titiler
1 parent 36102b5 commit 05fca35

File tree

5 files changed

+80
-49
lines changed

5 files changed

+80
-49
lines changed

src/components/LayerIcon.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export function LayerIcon({ layer, size = 'md', className = '' }: LayerIconProps
3030

3131
if (layer.type === 'titiler') {
3232
const titilerLayer = layer as TitilerSource;
33-
if (titilerLayer.legend?.type === 'linear') {
33+
if (titilerLayer.titiler.bidx === 'single' && titilerLayer.legend?.type === 'linear') {
3434
const colorMapUrl = `${titiler_uri}/colorMaps/${titilerLayer.legend.colormap_name}?format=png&width=32&height=32`;
3535
return (
3636
<img

src/components/Legend.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,10 @@ export function Legend(props: LayerConfig) {
7777
let rows: ReactNode[] = [];
7878

7979
if (l.children.legend?.field) {
80-
let index = new Set();
80+
const index = new Set();
8181
rows = [];
8282
l.children.legend?.values?.forEach((l: VectorFillValue) => {
83-
let key = [l.color, l.borderColor, l.opacity, l.description].join('_');
83+
const key = [l.color, l.borderColor, l.opacity, l.description].join('_');
8484
if (!index.has(key)) {
8585
rows.push(
8686
<LegendRow
@@ -172,7 +172,11 @@ export function Legend(props: LayerConfig) {
172172
}
173173
return null;
174174
} else if (props.type === 'titiler') {
175-
const { legend } = props as TitilerSource;
175+
const { legend, titiler } = props as TitilerSource;
176+
177+
if (!legend || titiler.bidx === 'rgb') {
178+
return null;
179+
}
176180

177181
if (legend.type === 'interval') {
178182
return [];

src/libs/toMaplibre.ts

Lines changed: 43 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -53,23 +53,52 @@ function buildRasterLayer(layer: LayerWithId, titiler_api_url: string): SourcePr
5353
throw new Error(`Missing required 'url' parameter for raster layer ${layer.id}`);
5454
}
5555

56-
// Convert bidx string format to array
57-
const bidxArray = bidx === BAND_TYPES.RGB ? [1, 2, 3, 4] : [1];
56+
let tileUrl = `${titiler_api_url}/cog/tiles/WebMercatorQuad/{z}/{x}/{y}@1x?`;
57+
let extra = '';
5858

59-
// Add band indices to query parameters
60-
bidxArray.forEach(index => {
61-
search.append('bidx', index.toString());
62-
});
59+
if (bidx === BAND_TYPES.SINGLE) {
60+
if (!l.legend) {
61+
throw Error('Legend should be provided for a single band raster!');
62+
}
63+
search.append('bidx', '1');
64+
65+
// Add rescale values if provided
66+
if (rescale?.length) {
67+
rescale.forEach(v => {
68+
if (typeof v === 'string' && v.includes(',')) {
69+
search.append('rescale', v);
70+
} else {
71+
console.warn(`Invalid rescale value format: ${v}. Expected format: "min,max"`);
72+
}
73+
});
74+
}
6375

64-
// Add rescale values if provided
65-
if (rescale?.length) {
66-
rescale.forEach(v => {
67-
if (typeof v === 'string' && v.includes(',')) {
68-
search.append('rescale', v);
76+
// Handle colormap configuration
77+
if (l.legend.type === 'linear') {
78+
if (l.legend.colormap_name) {
79+
search.append('colormap_name', l.legend.colormap_name);
6980
} else {
70-
console.warn(`Invalid rescale value format: ${v}. Expected format: "min,max"`);
81+
console.warn(`Linear legend missing colormap_name for layer ${layer.id}`);
7182
}
72-
});
83+
} else if (l.legend.type === 'interval') {
84+
if (l.legend.intervals?.length) {
85+
try {
86+
const cmap = l.legend.intervals.map(interval => [
87+
[interval.min, interval.max],
88+
hexRgb(interval.color, { format: 'array' }),
89+
]);
90+
extra = `&colormap=${JSON.stringify(cmap)}`;
91+
} catch (error) {
92+
console.error(`Failed to process interval colormap for layer ${layer.id}:`, error);
93+
}
94+
} else {
95+
console.warn(`Interval legend missing intervals for layer ${layer.id}`);
96+
}
97+
}
98+
} else if (bidx === BAND_TYPES.RGB) {
99+
search.append('bidx', '1');
100+
search.append('bidx', '2');
101+
search.append('bidx', '3');
73102
}
74103

75104
// Add other titiler parameters
@@ -80,31 +109,7 @@ function buildRasterLayer(layer: LayerWithId, titiler_api_url: string): SourcePr
80109
}
81110
});
82111

83-
// Handle colormap configuration
84-
let colormap = '';
85-
if (l.legend.type === 'linear') {
86-
if (l.legend.colormap_name) {
87-
search.append('colormap_name', l.legend.colormap_name);
88-
} else {
89-
console.warn(`Linear legend missing colormap_name for layer ${layer.id}`);
90-
}
91-
} else if (l.legend.type === 'interval') {
92-
if (l.legend.intervals?.length) {
93-
try {
94-
const cmap = l.legend.intervals.map(interval => [
95-
[interval.min, interval.max],
96-
hexRgb(interval.color, { format: 'array' }),
97-
]);
98-
colormap = `&colormap=${JSON.stringify(cmap)}`;
99-
} catch (error) {
100-
console.error(`Failed to process interval colormap for layer ${layer.id}:`, error);
101-
}
102-
} else {
103-
console.warn(`Interval legend missing intervals for layer ${layer.id}`);
104-
}
105-
}
106-
107-
const tileUrl = `${titiler_api_url}/cog/tiles/WebMercatorQuad/{z}/{x}/{y}@1x?${search.toString()}${colormap}`;
112+
tileUrl += `${search.toString()}${extra}`;
108113

109114
return {
110115
type: LAYER_TYPES.RASTER,

src/rjsf/schemas/layer.ts

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ export const LAYER_SCHEMA: RJSFSchema = {
128128
additionalProperties: {
129129
type: 'string',
130130
},
131+
required: ['url', 'bidx'],
131132
properties: {
132133
url: { type: 'string' },
133134
bidx: {
@@ -154,11 +155,30 @@ export const LAYER_SCHEMA: RJSFSchema = {
154155
type: {
155156
const: 'titiler',
156157
},
157-
legend: {
158-
$ref: '#/$defs/RasterLinearLegend',
159-
title: 'Legend Configuration',
160-
},
161158
},
159+
allOf: [
160+
{
161+
if: {
162+
properties: {
163+
titiler: {
164+
properties: {
165+
bidx: {
166+
const: 'single',
167+
},
168+
},
169+
},
170+
},
171+
},
172+
then: {
173+
properties: {
174+
legend: {
175+
title: 'Legend Configuration',
176+
$ref: '#/$defs/RasterLinearLegend',
177+
},
178+
},
179+
},
180+
},
181+
],
162182
},
163183
RasterSource: {
164184
type: 'object',
@@ -353,7 +373,8 @@ export const LAYER_SCHEMA: RJSFSchema = {
353373
dasharray: {
354374
type: 'array',
355375
title: 'Dash pattern',
356-
description: 'Array of numbers defining dash and gap lengths (e.g., [5, 5] for dashed, [10, 5, 2, 5] for dash-dot)',
376+
description:
377+
'Array of numbers defining dash and gap lengths (e.g., [5, 5] for dashed, [10, 5, 2, 5] for dash-dot)',
357378
items: {
358379
type: 'number',
359380
minimum: 0,
@@ -587,7 +608,8 @@ export const LAYER_SCHEMA: RJSFSchema = {
587608
dasharray: {
588609
type: 'array',
589610
title: 'Dash pattern',
590-
description: 'Array of numbers defining dash and gap lengths (e.g., [5, 5] for dashed, [10, 5, 2, 5] for dash-dot)',
611+
description:
612+
'Array of numbers defining dash and gap lengths (e.g., [5, 5] for dashed, [10, 5, 2, 5] for dash-dot)',
591613
items: {
592614
type: 'number',
593615
minimum: 0,

src/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ export interface TitilerSource extends Partial<Source> {
118118
bidx?: string;
119119
[key: string]: unknown; // Allow additional properties
120120
};
121-
legend: RasterSequentialLegend | RasterIntervalLegend;
121+
legend?: RasterSequentialLegend | RasterIntervalLegend;
122122
}
123123

124124
export interface RasterSource extends Partial<Source> {

0 commit comments

Comments
 (0)