diff --git a/js/deck-gl/utils/tiles.js b/js/deck-gl/utils/tiles.js index 57d85b14..29f3f32d 100644 --- a/js/deck-gl/utils/tiles.js +++ b/js/deck-gl/utils/tiles.js @@ -99,8 +99,10 @@ export const create_render_tile_sublayers = const { bbox } = tile; // Optional clipping for Yearbook: only render tiles that intersect - // any of the windows defined in viz_state.yearbook_windows. - const windows = viz_state?.yearbook_windows; + // any of the windows defined for this layer. Fall back to the + // shared viz_state windows so plain TileLayers keep working. + const windows = + props.yearbookWindows || props.tile?.layer?.props?.yearbookWindows || viz_state?.yearbook_windows; if (bbox && Array.isArray(windows) && windows.length > 0) { const { left, right, bottom, top } = bbox; diff --git a/js/widgets/yearbook.js b/js/widgets/yearbook.js index 22993357..a191882b 100644 --- a/js/widgets/yearbook.js +++ b/js/widgets/yearbook.js @@ -291,7 +291,8 @@ export const render_yearbook = async ({ model, el }) => { layer.clone({ maxCacheSize: Math.max(state.capacity * 2, 12), refinementStrategy: 'best-available', - // keep the original getTileData + // restrict tile requests to the active portrait windows + getTileData: create_yearbook_get_tile_data(viz_state, layer.props?.getTileData), }) ); @@ -381,16 +382,18 @@ export const render_yearbook = async ({ model, el }) => { state.deck.setProps({ layers: nextLayers }); }; + const isYearbookImageLayer = (layerId) => { + if (!layerId) return false; + if (layerId.startsWith('background-layer-')) return true; + return Array.from(state.imageLayerIds).some((baseId) => + layerId.startsWith(`${baseId}-yearbook`) + ); + }; + const imgButton = makeModeButton('IMG', true, (visible) => { - const layers = (state.deck?.props?.layers || []).map((layer) => { - if ( - layer.id?.startsWith('background-layer-') || - (layer.id && state.imageLayerIds.has(layer.id.replace(/-\d+$/, ''))) - ) { - return layer.clone({ visible }); - } - return layer; - }); + const layers = (state.deck?.props?.layers || []).map((layer) => + isYearbookImageLayer(layer.id) ? layer.clone({ visible }) : layer + ); state.deck?.setProps({ layers }); }); @@ -861,26 +864,31 @@ export const render_yearbook = async ({ model, el }) => { }) ); - // One TileLayer per channel, shared across all views + // One TileLayer per channel, per portrait view const windowsForLayer = state.viz_state?.yearbook_windows || []; const yearbookZoom = state.globalZoom ?? computeZoomForWindow(cellSizeUm, state.cellWidth); - const imageLayers = state.imageLayerTemplates.map((layer) => { - const existingTriggers = layer.props?.updateTriggers || {}; - const windowTrigger = windowsForLayer.map( - (w) => `${w.minX}:${w.maxX}:${w.minY}:${w.maxY}` - ); - - return layer.clone({ - id: `${layer.id}-yearbook`, // unique vs Landscape - // no viewId or viewportIds → deck renders this layer in *every* view - yearbookWindows: windowsForLayer, - yearbookZoom, - updateTriggers: { - ...existingTriggers, - yearbookWindows: windowTrigger, + const imageLayers = selectedCells.flatMap((_, idx) => { + const windowForLayer = windowsForLayer[idx]; + const viewId = `cell-${idx}`; + const windowTrigger = windowForLayer + ? `${windowForLayer.minX}:${windowForLayer.maxX}:${windowForLayer.minY}:${windowForLayer.maxY}` + : 'none'; + + return state.imageLayerTemplates.map((layer) => { + const existingTriggers = layer.props?.updateTriggers || {}; + return layer.clone({ + id: `${layer.id}-yearbook-${idx}`, + viewId, + viewportId: viewId, + yearbookWindows: windowForLayer ? [windowForLayer] : [], yearbookZoom, - }, + updateTriggers: { + ...existingTriggers, + yearbookWindows: windowTrigger, + yearbookZoom, + }, + }); }); });