From a4ef58276728ec859a1a1a6cf1220f0a6bd45dfe Mon Sep 17 00:00:00 2001 From: christof-wittreich Date: Fri, 29 Dec 2023 09:27:05 -0500 Subject: [PATCH 1/3] Most stories preloaded --- web/js/containers/tour.js | 30 ++++++++++++++++++++++++++- web/js/map/layerbuilder.js | 5 ++++- web/js/modules/map/util.js | 42 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 2 deletions(-) diff --git a/web/js/containers/tour.js b/web/js/containers/tour.js index 5a9e1c4d7a..6416421a08 100644 --- a/web/js/containers/tour.js +++ b/web/js/containers/tour.js @@ -39,6 +39,7 @@ import { changeTab as changeTabAction } from '../modules/sidebar/actions'; import ErrorBoundary from './error-boundary'; import history from '../main'; import util from '../util/util'; +import { promiseImageryForTour } from '../modules/map/util'; const { HIDE_TOUR } = safeLocalStorage.keys; @@ -138,7 +139,7 @@ class Tour extends React.Component { selectTour(e, currentStory, currentStoryIndex, currentStoryId) { const { - config, renderedPalettes, selectTour, processStepLink, isKioskModeActive, isEmbedModeActive, + config, renderedPalettes, selectTour, processStepLink, isKioskModeActive, isEmbedModeActive, preProcessStepLink, promiseImageryForTour, } = this.props; if (e) e.preventDefault(); const kioskParam = this.getKioskParam(isKioskModeActive); @@ -157,6 +158,13 @@ class Tour extends React.Component { this.fetchMetadata(currentStory, 0); const storyStep = currentStory.steps[0]; const transitionParam = getTransitionAttr(storyStep.transition); + currentStory.steps.forEach((step) => { + preProcessStepLink( + `${step.stepLink}&tr=${currentStoryId}${transitionParam}${kioskParam}&em=${isEmbedModeActive}`, + config, + promiseImageryForTour, + ); + }); processStepLink( currentStoryId, 1, @@ -522,6 +530,24 @@ const mapDispatchToProps = (dispatch) => ({ dispatch({ type: LOCATION_POP_ACTION, payload: location }); } }, + preProcessStepLink: async (search, config, promiseImageryForTour) => { + search = search.split('/?').pop(); + const parameters = util.fromQueryString(search); + let layers = []; + const promises = []; + + if (parameters.l) { + layers = layersParse12(parameters.l, config); + layers = uniqBy(layers, 'id'); + promises.push(promiseImageryForTour(layers, parameters.t)); + if (parameters.l1) { + layers = layersParse12(parameters.l1, config); + layers = uniqBy(layers, 'id'); + promises.push(promiseImageryForTour(layers, parameters.t1, 'activeB')); + } + } + await Promise.all(promises); + }, startTour: () => { dispatch(startTourAction()); }, @@ -561,6 +587,7 @@ const mapStateToProps = (state) => { screenHeight, renderedPalettes: palettes.rendered, activeTab: sidebar.activeTab, + promiseImageryForTour: (layers, dateString, activeString) => promiseImageryForTour(state, layers, dateString, activeString), }; }; @@ -582,6 +609,7 @@ Tour.propTypes = { isActive: PropTypes.bool, isKioskModeActive: PropTypes.bool, processStepLink: PropTypes.func, + preProcessStepLink: PropTypes.func, renderedPalettes: PropTypes.object, resetProductPicker: PropTypes.func, screenHeight: PropTypes.number, diff --git a/web/js/map/layerbuilder.js b/web/js/map/layerbuilder.js index 71ee646a2a..a180ea222b 100644 --- a/web/js/map/layerbuilder.js +++ b/web/js/map/layerbuilder.js @@ -115,6 +115,9 @@ export default function mapLayerBuilder(config, cache, store) { if (isVectorStyleActive(def.id, activeGroupStr, state)) { style = getVectorStyleKeys(def.id, undefined, state); } + if (options.style) { + style = options.style; + } return [layerId, projId, date, style, activeGroupStr].join(':'); }; @@ -241,7 +244,7 @@ export default function mapLayerBuilder(config, cache, store) { previousDate, } = getRequestDates(def, options); const date = closestDate; - if (date) { + if (date && !options.date) { options.date = date; } const dateOptions = { date, nextDate, previousDate }; diff --git a/web/js/modules/map/util.js b/web/js/modules/map/util.js index 5e1cdc65ee..5433169af2 100644 --- a/web/js/modules/map/util.js +++ b/web/js/modules/map/util.js @@ -11,6 +11,7 @@ import OlRendererCanvasTileLayer from 'ol/renderer/canvas/TileLayer'; import Promise from 'bluebird'; import { encode } from '../link/util'; import { getActiveVisibleLayersAtDate } from '../layers/selectors'; +import { tryCatchDate } from '../date/util'; /* * Set default extent according to time of day: @@ -305,3 +306,44 @@ export async function promiseImageryForTime(state, date, activeString) { selected.getView().changed(); return date; } + +/** + * Trigger tile requests for all given layers on a given date. + * @method promiseImageryForTour + */ +export async function promiseImageryForTour(state, layers, dateString, activeString) { + const { map } = state; + if (!map.ui.proj) return; + const { + cache, selected, createLayer, layerKey, + } = map.ui; + const appNow = lodashGet(state, 'date.appNow'); + const date = tryCatchDate(dateString, appNow); + await Promise.all(layers.map(async (layer) => { + if (layer.type === 'granule' || layer.type === 'ttiler') { + return Promise.resolve(); + } + const options = { date, group: activeString }; + const keys = []; + if (layer.custom) { + keys.push(`palette=${layer.custom}`); + } + if (layer.min) { + keys.push(`min=${layer.min}`); + } + if (layer.max) { + keys.push(`max=${layer.max}`); + } + if (layer.squash) { + keys.push('squash'); + } + if (keys.length > 0) { + options.style = keys.join(','); + } + + const key = layerKey(layer, options, state); + const layerGroup = cache.getItem(key) || await createLayer(layer, options); + return promiseLayerGroup(layerGroup, selected); + })); + selected.getView().changed(); +} From 374a0f9dd3614603ad4905dcab4991efcd2d3f50 Mon Sep 17 00:00:00 2001 From: christof-wittreich Date: Wed, 10 Jan 2024 10:19:48 -0500 Subject: [PATCH 2/3] Custom palette issues --- web/js/containers/tour.js | 6 ++++++ web/js/map/layerbuilder.js | 2 +- web/js/modules/palettes/selectors.js | 5 +++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/web/js/containers/tour.js b/web/js/containers/tour.js index 6416421a08..4d34365823 100644 --- a/web/js/containers/tour.js +++ b/web/js/containers/tour.js @@ -546,6 +546,12 @@ const mapDispatchToProps = (dispatch) => ({ promises.push(promiseImageryForTour(layers, parameters.t1, 'activeB')); } } + preloadPalettes(layers, {}, false).then((obj) => { + dispatch({ + type: BULK_PALETTE_RENDERING_SUCCESS, + rendered: obj.rendered, + }); + }); await Promise.all(promises); }, startTour: () => { diff --git a/web/js/map/layerbuilder.js b/web/js/map/layerbuilder.js index a180ea222b..cb330706d7 100644 --- a/web/js/map/layerbuilder.js +++ b/web/js/map/layerbuilder.js @@ -115,7 +115,7 @@ export default function mapLayerBuilder(config, cache, store) { if (isVectorStyleActive(def.id, activeGroupStr, state)) { style = getVectorStyleKeys(def.id, undefined, state); } - if (options.style) { + if (def.custom && options.style) { style = options.style; } return [layerId, projId, date, style, activeGroupStr].join(':'); diff --git a/web/js/modules/palettes/selectors.js b/web/js/modules/palettes/selectors.js index 08d317456b..48362bee5b 100644 --- a/web/js/modules/palettes/selectors.js +++ b/web/js/modules/palettes/selectors.js @@ -350,15 +350,16 @@ export function getKey(layerId, groupStr, state) { return ''; } const def = getPalette(layerId, undefined, groupStr, state); + const { values } = getPalette(layerId, 0, groupStr, state).entries; const keys = []; if (def.custom) { keys.push(`palette=${def.custom}`); } if (def.min) { - keys.push(`min=${def.min}`); + keys.push(`min=${getMinValue(values[def.min])}`); } if (def.max) { - keys.push(`max=${def.max}`); + keys.push(`max=${getMinValue(values[def.max])}`); } if (def.squash) { keys.push('squash'); From ddded2f58be458862b8b4c2ad85d98f149baca10 Mon Sep 17 00:00:00 2001 From: christof-wittreich Date: Tue, 16 Jan 2024 15:03:08 -0500 Subject: [PATCH 3/3] Custom palette implemented --- web/js/containers/tour.js | 43 ++++++++++++++++++---------- web/js/map/layerbuilder.js | 11 +++++++ web/js/modules/map/util.js | 1 - web/js/modules/palettes/constants.js | 1 + web/js/modules/palettes/reducers.js | 6 ++++ web/js/modules/palettes/util.js | 2 ++ 6 files changed, 48 insertions(+), 16 deletions(-) diff --git a/web/js/containers/tour.js b/web/js/containers/tour.js index 4d34365823..9e072b6ae6 100644 --- a/web/js/containers/tour.js +++ b/web/js/containers/tour.js @@ -24,7 +24,10 @@ import { import { clearCustoms, } from '../modules/palettes/actions'; -import { BULK_PALETTE_RENDERING_SUCCESS } from '../modules/palettes/constants'; +import { + BULK_PALETTE_RENDERING_SUCCESS, + BULK_PALETTE_PRELOADING_SUCCESS, +} from '../modules/palettes/constants'; import { stop as stopAnimation } from '../modules/animation/actions'; import { onClose as closeModal } from '../modules/modal/actions'; import { LOCATION_POP_ACTION } from '../redux-location-state-customs'; @@ -158,13 +161,6 @@ class Tour extends React.Component { this.fetchMetadata(currentStory, 0); const storyStep = currentStory.steps[0]; const transitionParam = getTransitionAttr(storyStep.transition); - currentStory.steps.forEach((step) => { - preProcessStepLink( - `${step.stepLink}&tr=${currentStoryId}${transitionParam}${kioskParam}&em=${isEmbedModeActive}`, - config, - promiseImageryForTour, - ); - }); processStepLink( currentStoryId, 1, @@ -173,6 +169,13 @@ class Tour extends React.Component { config, renderedPalettes, ); + currentStory.steps.forEach((step) => { + preProcessStepLink( + `${step.stepLink}&tr=${currentStoryId}${transitionParam}${kioskParam}&em=${isEmbedModeActive}`, + config, + promiseImageryForTour, + ); + }); } fetchMetadata(currentStory, stepIndex) { @@ -524,6 +527,10 @@ const mapDispatchToProps = (dispatch) => ({ type: BULK_PALETTE_RENDERING_SUCCESS, rendered: obj.rendered, }); + dispatch({ + type: BULK_PALETTE_PRELOADING_SUCCESS, + tourStoryPalettes: obj.rendered, + }); dispatch({ type: LOCATION_POP_ACTION, payload: location }); }); } else { @@ -535,24 +542,30 @@ const mapDispatchToProps = (dispatch) => ({ const parameters = util.fromQueryString(search); let layers = []; const promises = []; + const temp = []; if (parameters.l) { layers = layersParse12(parameters.l, config); layers = uniqBy(layers, 'id'); - promises.push(promiseImageryForTour(layers, parameters.t)); + temp.push({ layers, dateString: parameters.t }); if (parameters.l1) { layers = layersParse12(parameters.l1, config); layers = uniqBy(layers, 'id'); - promises.push(promiseImageryForTour(layers, parameters.t1, 'activeB')); + temp.push({ layers, dateString: parameters.t1, activeString: 'activeB' }); } } - preloadPalettes(layers, {}, false).then((obj) => { - dispatch({ - type: BULK_PALETTE_RENDERING_SUCCESS, - rendered: obj.rendered, + console.log(layers); + preloadPalettes(layers, {}, false).then(async (obj) => { + console.log(obj); + await dispatch({ + type: BULK_PALETTE_PRELOADING_SUCCESS, + tourStoryPalettes: obj.rendered, + }); + temp.forEach((set) => { + promises.push(promiseImageryForTour(set.layers, set.dateString, set.activeString)); }); + await Promise.all(promises); }); - await Promise.all(promises); }, startTour: () => { dispatch(startTourAction()); diff --git a/web/js/map/layerbuilder.js b/web/js/map/layerbuilder.js index cb330706d7..a4f6cfb499 100644 --- a/web/js/map/layerbuilder.js +++ b/web/js/map/layerbuilder.js @@ -41,6 +41,9 @@ import { applyStyle, } from '../modules/vector-styles/selectors'; import { nearestInterval } from '../modules/layers/util'; +import { + lookup as createLookup, +} from '../modules/palettes/util'; import { LEFT_WING_EXTENT, RIGHT_WING_EXTENT, LEFT_WING_ORIGIN, RIGHT_WING_ORIGIN, CENTER_MAP_ORIGIN, } from '../modules/map/constants'; @@ -377,9 +380,17 @@ export default function mapLayerBuilder(config, cache, store) { wrapX: false, style: typeof style === 'undefined' ? 'default' : style, }; + console.log(def.id, def, options, state.palettes); if (isPaletteActive(id, options.group, state)) { const lookup = getPaletteLookup(id, options.group, state); + console.log(def.id, lookup); + sourceOptions.tileClass = lookupFactory(lookup, sourceOptions); + } else if (def.palette && def.custom && state.palettes.tourStoryPalettes && state.palettes.tourStoryPalettes[def.palette.id]) { + const lookup = createLookup(state.palettes.tourStoryPalettes[def.palette.id].maps[0].entries, state.palettes.custom[def.custom[0]]); + console.log(def.id, lookup); sourceOptions.tileClass = lookupFactory(lookup, sourceOptions); + // Lookup is now working, so custom palette is properly preloaded + // Still TODO: fix min & max, still not working when preloading } const tileSource = new OlSourceWMTS(sourceOptions); diff --git a/web/js/modules/map/util.js b/web/js/modules/map/util.js index 5433169af2..e51932bee7 100644 --- a/web/js/modules/map/util.js +++ b/web/js/modules/map/util.js @@ -345,5 +345,4 @@ export async function promiseImageryForTour(state, layers, dateString, activeStr const layerGroup = cache.getItem(key) || await createLayer(layer, options); return promiseLayerGroup(layerGroup, selected); })); - selected.getView().changed(); } diff --git a/web/js/modules/palettes/constants.js b/web/js/modules/palettes/constants.js index a843678b0f..0fed270830 100644 --- a/web/js/modules/palettes/constants.js +++ b/web/js/modules/palettes/constants.js @@ -10,6 +10,7 @@ export const CLEAR_CUSTOMS = 'PALETTES/CLEAR_CUSTOMS'; export const SET_CUSTOM = 'PALETTES/SET_CUSTOM'; export const LOADED_CUSTOM_PALETTES = 'PALETTES/LOADED_CUSTOM_PALETTES'; export const BULK_PALETTE_RENDERING_SUCCESS = 'PALETTES/BULK_PALETTE_RENDERING_SUCCESS'; +export const BULK_PALETTE_PRELOADING_SUCCESS = 'PALETTES/BULK_PALETTE_PRELOADING_SUCCESS'; export const PALETTE_STRINGS_PERMALINK_ARRAY = [ 'palette', diff --git a/web/js/modules/palettes/reducers.js b/web/js/modules/palettes/reducers.js index 8bd01dc404..1bc7f31ade 100644 --- a/web/js/modules/palettes/reducers.js +++ b/web/js/modules/palettes/reducers.js @@ -12,6 +12,7 @@ import { SET_THRESHOLD_RANGE_AND_SQUASH, LOADED_CUSTOM_PALETTES, BULK_PALETTE_RENDERING_SUCCESS, + BULK_PALETTE_PRELOADING_SUCCESS, CLEAR_CUSTOM, SET_DISABLED_CLASSIFICATION, } from './constants'; @@ -23,6 +24,7 @@ export const defaultPaletteState = { active: {}, activeB: {}, isLoading: {}, + tourStoryPalettes: {}, }; export function getInitialPaletteState(config) { const rendered = lodashGet(config, 'palettes.rendered') || {}; @@ -46,6 +48,10 @@ export function paletteReducer(state = defaultPaletteState, action) { return update(state, { rendered: { $merge: action.rendered || {} }, }); + case BULK_PALETTE_PRELOADING_SUCCESS: + return update(state, { + tourStoryPalettes: { $merge: action.tourStoryPalettes || {} }, + }); case REQUEST_PALETTE_SUCCESS: { const isLoading = update(state.isLoading, { $unset: [action.id] }); return lodashAssign({}, state, { diff --git a/web/js/modules/palettes/util.js b/web/js/modules/palettes/util.js index 091ac1588a..2216814793 100644 --- a/web/js/modules/palettes/util.js +++ b/web/js/modules/palettes/util.js @@ -375,6 +375,7 @@ export function loadPalettes(permlinkState, state) { } lodashEach(stateArray, (stateObj) => { lodashEach(state.layers[stateObj.groupStr].layers, (layerDef) => { + console.log(layerDef.id, layerDef); if (layerDef.palette) { const layerId = layerDef.id; const min = []; @@ -529,6 +530,7 @@ export function preloadPalettes(layersArray, renderedPalettes, customLoaded) { && !loading[obj.palette.id] ) { const paletteId = obj.palette.id; + console.log(paletteId, obj); const location = `config/palettes/${paletteId}.json`; const promise = util.fetch(location, 'application/json'); loading[paletteId] = true;