Skip to content

Commit bc7f91c

Browse files
authored
Merge pull request #7 from boettiger-lab/feat/default-style-tooltip-visible
feat: config-driven default style, hover tooltip, and default visibility
2 parents 02754fb + 0c7dc72 commit bc7f91c

File tree

5 files changed

+108
-6
lines changed

5 files changed

+108
-6
lines changed

app/dataset-catalog.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,9 @@ export class DatasetCatalog {
156156
url: asset.href,
157157
sourceLayer: asset['vector:layers']?.[0] || asset['pmtiles:layer'] || assetId,
158158
description: asset.description || '',
159+
defaultStyle: perAsset.default_style || null,
160+
tooltipFields: perAsset.tooltip_fields || null,
161+
defaultVisible: perAsset.visible === true,
159162
});
160163
} else if (type.includes('geotiff') || type.includes('tiff')) {
161164
const colormap = perAsset.colormap || options.colormap || 'reds';
@@ -357,8 +360,10 @@ export class DatasetCatalog {
357360
url: `pmtiles://${ml.url}`,
358361
},
359362
sourceLayer: ml.sourceLayer,
360-
paint: { 'fill-color': '#2E7D32', 'fill-opacity': 0.5 },
363+
paint: ml.defaultStyle || { 'fill-color': '#2E7D32', 'fill-opacity': 0.5 },
361364
columns: ds.columns,
365+
tooltipFields: ml.tooltipFields || null,
366+
defaultVisible: ml.defaultVisible || false,
362367
});
363368
} else if (ml.layerType === 'raster') {
364369
let tilesUrl = `${this.titilerUrl}/cog/tiles/WebMercatorQuad/{z}/{x}/{y}.png?url=${encodeURIComponent(ml.cogUrl)}&colormap_name=${ml.colormap}`;

app/map-manager.js

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ export class MapManager {
5555
this.ready = new Promise(resolve => {
5656
this.map.on('load', resolve);
5757
});
58+
59+
// Shared hover tooltip element
60+
this._tooltip = document.createElement('div');
61+
this._tooltip.className = 'map-tooltip';
62+
document.body.appendChild(this._tooltip);
5863
}
5964

6065
/**
@@ -72,7 +77,7 @@ export class MapManager {
7277
* Register a single layer on the map.
7378
*/
7479
registerLayer(config) {
75-
const { layerId, datasetId, displayName, type, source, sourceLayer, paint, columns } = config;
80+
const { layerId, datasetId, displayName, type, source, sourceLayer, paint, columns, tooltipFields, defaultVisible } = config;
7681
const sourceId = `src-${layerId.replace(/\//g, '-')}`;
7782
const mapLayerId = `layer-${layerId.replace(/\//g, '-')}`;
7883

@@ -85,7 +90,7 @@ export class MapManager {
8590
const layerDef = {
8691
id: mapLayerId,
8792
source: sourceId,
88-
layout: { visibility: 'none' },
93+
layout: { visibility: defaultVisible ? 'visible' : 'none' },
8994
};
9095

9196
if (type === 'vector') {
@@ -108,11 +113,35 @@ export class MapManager {
108113
displayName,
109114
type,
110115
sourceLayer: sourceLayer || null,
111-
visible: false,
116+
visible: defaultVisible || false,
112117
filter: null,
113118
columns: columns || [],
114119
defaultPaint: { ...(paint || {}) },
120+
tooltipFields: tooltipFields || null,
115121
});
122+
123+
// Wire hover tooltip if fields are declared
124+
if (tooltipFields && tooltipFields.length > 0) {
125+
this.map.on('mousemove', mapLayerId, (e) => {
126+
if (!e.features || e.features.length === 0) return;
127+
const props = e.features[0].properties;
128+
const rows = tooltipFields
129+
.filter(f => props[f] !== undefined && props[f] !== null && props[f] !== '')
130+
.map(f => `<tr><th>${f}</th><td>${props[f]}</td></tr>`)
131+
.join('');
132+
if (!rows) return;
133+
this._tooltip.innerHTML = `<table>${rows}</table>`;
134+
this._tooltip.style.display = 'block';
135+
this._tooltip.style.left = (e.originalEvent.clientX + 12) + 'px';
136+
this._tooltip.style.top = (e.originalEvent.clientY - 12) + 'px';
137+
this.map.getCanvas().style.cursor = 'pointer';
138+
});
139+
140+
this.map.on('mouseleave', mapLayerId, () => {
141+
this._tooltip.style.display = 'none';
142+
this.map.getCanvas().style.cursor = '';
143+
});
144+
}
116145
}
117146

118147
// ---- Layer Visibility ----

app/style.css

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,44 @@ body {
251251
border-color: rgba(0, 124, 191, 0.35);
252252
}
253253

254+
/* Hover tooltip */
255+
.map-tooltip {
256+
display: none;
257+
position: fixed;
258+
z-index: 100;
259+
background: rgba(255, 255, 255, 0.95);
260+
-webkit-backdrop-filter: blur(4px);
261+
backdrop-filter: blur(4px);
262+
border: 1px solid rgba(0, 0, 0, 0.2);
263+
border-radius: 4px;
264+
padding: 8px 10px;
265+
font-family: 'Open Sans', sans-serif;
266+
font-size: 12px;
267+
color: #333;
268+
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
269+
pointer-events: none;
270+
max-width: 260px;
271+
}
272+
273+
.map-tooltip table {
274+
border-collapse: collapse;
275+
width: 100%;
276+
}
277+
278+
.map-tooltip th {
279+
font-weight: 600;
280+
color: #666;
281+
text-align: left;
282+
padding: 2px 10px 2px 0;
283+
white-space: nowrap;
284+
}
285+
286+
.map-tooltip td {
287+
color: #333;
288+
padding: 2px 0;
289+
word-break: break-word;
290+
}
291+
254292
#h3-res-badge {
255293
position: absolute;
256294
z-index: 1;

example-ghpages/layers-input.json

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,22 @@
3131
{
3232
"collection_id": "pad-us-4.1-combined",
3333
"assets": [
34-
"pmtiles"
34+
{
35+
"id": "pmtiles",
36+
"display_name": "Protected Areas (PAD-US)",
37+
"visible": true,
38+
"default_style": {
39+
"fill-color": ["match", ["get", "GAP_Sts"],
40+
1, "#26633A",
41+
2, "#3E9C47",
42+
3, "#7EB3D3",
43+
4, "#BDBDBD",
44+
"#888888"
45+
],
46+
"fill-opacity": 0.7
47+
},
48+
"tooltip_fields": ["Unit_Nm", "GAP_Sts", "Mang_Type"]
49+
}
3550
]
3651
},
3752
{

example-k8s/layers-input.json

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,22 @@
1313
{
1414
"collection_id": "pad-us-4.1-combined",
1515
"assets": [
16-
"pmtiles"
16+
{
17+
"id": "pmtiles",
18+
"display_name": "Protected Areas (PAD-US)",
19+
"visible": true,
20+
"default_style": {
21+
"fill-color": ["match", ["get", "GAP_Sts"],
22+
1, "#26633A",
23+
2, "#3E9C47",
24+
3, "#7EB3D3",
25+
4, "#BDBDBD",
26+
"#888888"
27+
],
28+
"fill-opacity": 0.7
29+
},
30+
"tooltip_fields": ["Unit_Nm", "GAP_Sts", "Mang_Type"]
31+
}
1732
]
1833
},
1934
{

0 commit comments

Comments
 (0)