Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WV-3380 show no-data granules outside of data availability ranges #5530

Merged
merged 5 commits into from
Oct 31, 2024
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
72 changes: 52 additions & 20 deletions web/js/map/granule/granule-layer-builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,11 +153,29 @@ export default function granuleLayerBuilder(cache, store, createLayerWMTS) {
* @returns {boolean} - true if date is within a range
*/
const isWithinRanges = (date, ranges) => {
if (!ranges) return false;
if (!ranges) return;

return ranges.some(([start, end]) => date >= new Date(start) && date <= new Date(end));
};

/**
* Identify gaps between date ranges
* @param {array} ranges - array of date ranges
* @returns {array} - array of date ranges
*/
const identifyGaps = (ranges) => {
if (!ranges) return [];
const MAX_TIME = 8.64e15;

const gaps = ranges.reduce((acc, [start, end]) => {
acc.at(-1)[1] = new Date(start);

return [...acc, [new Date(end), new Date(MAX_TIME)]];
}, [[new Date(-MAX_TIME), new Date(MAX_TIME)]]);

return gaps;
};

/**
* Get granuleCount number of granules that have visible imagery based on
* predetermined longitude bounds.
Expand All @@ -169,28 +187,38 @@ export default function granuleLayerBuilder(cache, store, createLayerWMTS) {
*/
const getVisibleGranules = (availableGranules, granuleCount, leadingEdgeDate, granuleDateRanges) => {
const { proj: { selected: { crs } } } = store.getState();
const granules = [];
const visibleGranules = [];
const invisibleGranules = [];
const availableCount = availableGranules?.length;
if (!availableCount) return granules;
if (!availableCount) return { visibleGranules, invisibleGranules };
const count = granuleCount > availableCount ? availableCount : granuleCount;
const sortedAvailableGranules = availableGranules.sort((a, b) => new Date(b.date) - new Date(a.date));
for (let i = 0; granules.length < count; i += 1) {
let totalLength = visibleGranules.length + invisibleGranules.length;
for (let i = 0; totalLength < count; i += 1) {
const item = sortedAvailableGranules[i];
if (!item) break;
const { date } = item;
const dateDate = new Date(date);
const leadingEdgeDateUTC = new Date(leadingEdgeDate.toUTCString());
leadingEdgeDateUTC.setSeconds(59);
const isWithinRange = isWithinRanges(leadingEdgeDateUTC, granuleDateRanges);
if (dateDate <= leadingEdgeDateUTC && isWithinRange && isWithinBounds(crs, item)) {
granules.unshift(item);
leadingEdgeDate.setSeconds(59); // force currently selected time to be 59 seconds. This is to compensate for the inability to select seconds in the timeline
const isWithinRange = isWithinRanges(leadingEdgeDate, granuleDateRanges); // check if currently selected time is within a date range
const granuleIsWithinRange = isWithinRanges(dateDate, granuleDateRanges) ?? true; // check if the current granule is within a date range, defaults to true
const gaps = identifyGaps(granuleDateRanges); // identify gaps between date ranges
const currentlySelectedGap = !isWithinRange ? gaps.find(([start, end]) => leadingEdgeDate >= start && leadingEdgeDate <= end) : null; // get the gap that the currently selected time is within
const granuleIsWithinSelectedGap = currentlySelectedGap ? dateDate >= currentlySelectedGap[0] && dateDate <= currentlySelectedGap[1] : false; // check if the current granule is within the currently selected gap

if (dateDate <= leadingEdgeDate && isWithinRange && granuleIsWithinRange && isWithinBounds(crs, item)) {
visibleGranules.unshift(item);
} else if (dateDate <= leadingEdgeDate && !isWithinRange && !granuleIsWithinRange && isWithinBounds(crs, item) && granuleIsWithinSelectedGap) {
invisibleGranules.unshift(item);
}

totalLength = visibleGranules.length + invisibleGranules.length;
}

if (granules.length < granuleCount) {
console.warn('Could not find enough matching granules', `${granules.length}/${granuleCount}`);
if (totalLength < granuleCount) {
console.warn('Could not find enough matching granules', `${totalLength}/${granuleCount}`);
}
return granules;
return { visibleGranules, invisibleGranules };
};

/**
Expand All @@ -209,13 +237,15 @@ export default function granuleLayerBuilder(cache, store, createLayerWMTS) {

// get granule dates waiting for CMR query and filtering (if necessary)
const availableGranules = await getQueriedGranuleDates(def, date, group);
const visibleGranules = getVisibleGranules(availableGranules, count, date, granuleDateRanges);
const transformedGranules = transformGranulesForProj(visibleGranules, crs);
const { visibleGranules, invisibleGranules } = getVisibleGranules(availableGranules, count, date, granuleDateRanges);
const transformedVisibleGranules = transformGranulesForProj(visibleGranules, crs);
const transformedInvisibleGranules = transformGranulesForProj(invisibleGranules, crs);

return {
count,
granuleDates: transformedGranules.map((g) => g.date),
visibleGranules: transformedGranules,
granuleDates: [...transformedVisibleGranules.map((g) => g.date), ...transformedInvisibleGranules.map((g) => g.date)],
visibleGranules: transformedVisibleGranules,
invisibleGranules: transformedInvisibleGranules,
granuleDateRanges,
};
};
Expand Down Expand Up @@ -243,18 +273,20 @@ export default function granuleLayerBuilder(cache, store, createLayerWMTS) {
}

const granuleAttributes = await getGranuleAttributes(def, options);
const { visibleGranules } = granuleAttributes;
const { visibleGranules, invisibleGranules } = granuleAttributes;
const shouldShift = def.shiftadjacentdays ?? true; // defaults to true
const granules = shouldShift ? datelineShiftGranules(visibleGranules, date, crs) : visibleGranules;
const tileLayers = new OlCollection(createGranuleTileLayers(granules, def, attributes));
const shiftedVisibleGranules = shouldShift ? datelineShiftGranules(visibleGranules, date, crs) : visibleGranules;
const shiftedInvisibleGranules = shouldShift ? datelineShiftGranules(invisibleGranules, date, crs) : invisibleGranules;
const tileLayers = new OlCollection(createGranuleTileLayers(shiftedVisibleGranules, def, attributes));
granuleLayer.setLayers(tileLayers);
granuleLayer.setExtent(crs === CRS.GEOGRAPHIC ? FULL_MAP_EXTENT : maxExtent);
granuleLayer.set('granuleGroup', true);
granuleLayer.set('layerId', `${id}-${group}`);
granuleLayer.wv = {
...attributes,
...granuleAttributes,
visibleGranules: granules,
visibleGranules: shiftedVisibleGranules,
invisibleGranules: shiftedInvisibleGranules,
};

// Don't update during animation due to the performance hit
Expand Down
12 changes: 8 additions & 4 deletions web/js/map/granule/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,19 +115,23 @@ export const isWithinBounds = (crs, granule) => {

export const getGranuleFootprints = (layer) => {
const {
def, visibleGranules, granuleDates,
def, visibleGranules, invisibleGranules, granuleDates,
} = layer.wv;
const { endDate, startDate } = def;
const mostRecentGranuleDate = granuleDates[0];
const isMostRecentDateOutOfRange = new Date(mostRecentGranuleDate) > new Date(endDate);

return visibleGranules.reduce((dates, { date, polygon }) => {
const reduceFunc = (dates, { date, polygon }) => {
const granuleDate = new Date(date);
if (!isMostRecentDateOutOfRange && isWithinDateRange(granuleDate, startDate, endDate)) {
dates[date] = polygon;
}
return dates;
}, {});
};

const visibleGranuleFootprints = visibleGranules.reduce(reduceFunc, {});
const invisibleGranuleFootprints = invisibleGranules.reduce(reduceFunc, {});

return { ...invisibleGranuleFootprints, ...visibleGranuleFootprints };
};

/**
Expand Down
6 changes: 5 additions & 1 deletion web/js/workers/dd.worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,13 @@ async function requestDescribeDomains(params) {
proj,
} = params;

const describeDomainsUrl = `https://gibs.earthdata.nasa.gov/wmts/${projDict[proj]}/best/1.0.0/${id}/default/250m/all/${startDate.split('T')[0]}--${endDate.split('T')[0]}.xml`;
const start = new Date(startDate).toISOString().replace('.000', '');
const end = new Date(endDate).toISOString().replace('.000', '');

const describeDomainsUrl = `https://gibs.earthdata.nasa.gov/wmts/${projDict[proj]}/best/1.0.0/${id}/default/250m/all/${start}--${end}.xml`;
const describeDomainsResponse = await fetch(describeDomainsUrl);
const describeDomainsText = await describeDomainsResponse.text();

return describeDomainsText;
}

Expand Down
Loading