Skip to content
Draft
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
6 changes: 5 additions & 1 deletion src/components/deck-layers/tile-layer-2d.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ export function TileLayer2d(props) {
landsatBands,
landsatBandCombination,
landsatColormapName,
onViewportLoad,
onTileLoad,
} = props || {};

return new TileLayer({
Expand All @@ -32,6 +34,8 @@ export function TileLayer2d(props) {
...landsatBands,
],
},
onViewportLoad,
onTileLoad,
});
}

Expand All @@ -49,7 +53,7 @@ function renderSubLayers(props) {
return null;
}

const { modules, images, ...moduleProps } = data;
const { modules, images, landsatAssetIds, ...moduleProps } = data;

return new RasterLayer(props, {
modules,
Expand Down
12 changes: 10 additions & 2 deletions src/components/options/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ export default class Options extends React.Component {
render() {
const { activeIndex } = this.state;
const {
_landsatMaxAssetDate,
_landsatMinAssetDate,
landsatMosaicId,
naipMosaicId,
useNaip,
Expand Down Expand Up @@ -58,7 +60,7 @@ export default class Options extends React.Component {
>
<Header as="h2">Landsat8.earth</Header>
<Header as="h3">Map Options</Header>

<DimensionSelection map3d={map3d} onChange={onChange} />
{map3d && <Experimental3dWarning />}

Expand All @@ -80,7 +82,6 @@ export default class Options extends React.Component {
onChange={onChange}
/>
</Accordion.Content>

<Accordion.Title
active={activeIndex === 1}
index={1}
Expand All @@ -97,6 +98,13 @@ export default class Options extends React.Component {
onChange={onChange}
/>
</Accordion.Content>
{_landsatMinAssetDate && _landsatMaxAssetDate && (
<p>
Date range:{' '}
<b>{_landsatMinAssetDate.format('MMMM D, YYYY')}</b> to{' '}
<b>{_landsatMaxAssetDate.format('MMMM D, YYYY')}</b>
</p>
)}
</Accordion>
</div>
);
Expand Down
18 changes: 14 additions & 4 deletions src/components/util/image.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ async function loadLandsatImages(options) {
);

// Note: imageBands (will be) an Array of objects, not direct textures
const imageBands = bandsUrls.map(url => loadSingleBandImage(url));
let imageBands = bandsUrls.map(url => loadSingleBandImage(url));

// Load colormap
// Only load if landsatBandCombination is not RGB
Expand All @@ -106,17 +106,27 @@ async function loadLandsatImages(options) {
// Await all images together
await Promise.all([imagePan, imageBands, imageColormap]);

// Split each image object into its `imageData` and `assets` identifiers
// https://stackoverflow.com/a/27386370/7319250
({ imageData: imagePan } = (await imagePan) || {});
({ imageData: imageColormap } = (await imageColormap) || {});

const imageBandsObjects = await Promise.all(imageBands);
imageBands = imageBandsObjects.map(({ imageData }) => imageData);
const landsatAssetIds = imageBandsObjects.map(({ assets }) => assets);

// The `Promise.all(imageBands)` converts an array of Promises to an array of
// objects
const images = {
imageBands: await Promise.all(imageBands),
imageColormap: await imageColormap,
imagePan: await imagePan,
imageBands,
imageColormap,
imagePan,
};

return {
images,
modules,
landsatAssetIds,
};
}

Expand Down
34 changes: 33 additions & 1 deletion src/components/util/landsat.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,38 @@
import dayjs from 'dayjs';

// NOTE change this to switch between precollection/collection based on string length, use substrings instead of regexp
// Simpler, faster landsat asset ID parser that uses string lengths instead of a
// regex
export function simpleLandsatParser(sceneid) {
if (sceneid.length === 40) {
return simpleLandsatCollection1Parser(sceneid);
} else if (sceneid.length == 21) {
return simpleLandsatPreCollectionParser(sceneid);
}

return null;
}

function simpleLandsatPreCollectionParser(sceneid) {
const acquisitionYear = sceneid.substring(9, 13);
const acquisitionJulianDay = sceneid.substring(13, 16);

// Note, this might be in local timezone
const acquisitionDate = dayjs(new Date(acquisitionYear, 0, 1)).add(
Number(acquisitionJulianDay) - 1,
'day'
);
return { acquisitionDate };
}

function simpleLandsatCollection1Parser(sceneid) {
const acquisitionYear = sceneid.substring(17, 21);
const acquisitionMonth = sceneid.substring(21, 23);
const acquisitionDay = sceneid.substring(23, 25);
const acquisitionDate = dayjs(
new Date(acquisitionYear, acquisitionMonth - 1, acquisitionDay)
);
return { acquisitionDate };
}

/**
* Parse Landsat-8 scene id
Expand Down
3 changes: 1 addition & 2 deletions src/components/util/webgl.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,7 @@ export async function loadSingleBandImage(url) {
// Load colormaps as RGB; all others as LUMINANCE
format: image && image.height === 10 ? GL.RGB : GL.LUMINANCE,
};
// return { imageData, assets };
return imageData;
return { imageData, assets };
}

async function loadImageUrl(url) {
Expand Down
121 changes: 103 additions & 18 deletions src/pages/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,15 @@ import {
setQueryParams,
getQueryParams,
} from '../components/util/view-state';
import { simpleLandsatParser } from '../components/util/landsat';

import dayjs from 'dayjs';
import minMax from 'dayjs/plugin/minMax';

import '../css/semantic-ui.css';

dayjs.extend(minMax);

const initialViewState = {
longitude: -112.1861,
latitude: 36.1284,
Expand All @@ -43,6 +50,8 @@ class IndexPage extends React.Component {
landsatBands: [4, 3, 2],
landsatColormapName: 'cfastie',
landsatBandCombination: 'rgb',
_landsatMinAssetDate: null,
_landsatMaxAssetDate: null,

// NAIP options
// Show NAIP imagery at zoom >= 12
Expand All @@ -68,8 +77,79 @@ class IndexPage extends React.Component {
setHashFromViewState(viewState);
};

onTileLoad = tile => {
if (!tile) {
return;
}

const { landsatAssetIds } = tile.content;

if (!landsatAssetIds || landsatAssetIds.length === 0) {
return;
}

const uniqueIds = [...new Set(landsatAssetIds.flat())];
const parsedIds = uniqueIds.map(sceneid => simpleLandsatParser(sceneid));

// console.log(parsedIds);

const minDate = dayjs.min(
...parsedIds.map(({ acquisitionDate }) => acquisitionDate)
);
const maxDate = dayjs.max(
...parsedIds.map(({ acquisitionDate }) => acquisitionDate)
);

// this.setState({
// _landsatMinAssetDate: dayjs.min(minDate, this.state._landsatMinAssetDate),
// _landsatMaxAssetDate: dayjs.max(maxDate, this.state._landsatMaxAssetDate),
// });

this.setState(prevState => {
const { _landsatMinAssetDate, _landsatMaxAssetDate } = prevState;
if (!_landsatMinAssetDate || !_landsatMaxAssetDate) {
return;
}
return {
_landsatMinAssetDate: dayjs.min(
minDate,
prevState._landsatMinAssetDate
),
_landsatMaxAssetDate: dayjs.max(
maxDate,
prevState._landsatMaxAssetDate
),
};
});
};

onViewportLoad = tileData => {
if (!tileData) {
return;
}

const landsatAssetIds = tileData
.map(({ landsatAssetIds }) => landsatAssetIds)
.flat(2);
const uniqueIds = [...new Set(landsatAssetIds)];
const parsedIds = uniqueIds.map(sceneid => simpleLandsatParser(sceneid));

const minDate = dayjs.min(
...parsedIds.map(({ acquisitionDate }) => acquisitionDate)
);
const maxDate = dayjs.max(
...parsedIds.map(({ acquisitionDate }) => acquisitionDate)
);
this.setState({
_landsatMinAssetDate: minDate,
_landsatMaxAssetDate: maxDate,
});
};

render() {
const {
_landsatMaxAssetDate,
_landsatMinAssetDate,
landsatBandCombination,
landsatBandPreset,
landsatBands,
Expand All @@ -85,43 +165,48 @@ class IndexPage extends React.Component {
<div>
{map3d ? (
<Map3d
viewState={viewState}
onViewStateChange={this.onViewStateChange}
onDragEnd={this.onDragEnd}
useNaip={useNaip}
naipMosaicId={naipMosaicId}
landsatMosaicId={landsatMosaicId}
landsatBandCombination={landsatBandCombination}
landsatBands={landsatBands}
landsatColormapName={landsatColormapName}
landsatBandCombination={landsatBandCombination}
landsatMosaicId={landsatMosaicId}
naipMosaicId={naipMosaicId}
onDragEnd={this.onDragEnd}
onViewportLoad={this.onViewportLoad}
onViewStateChange={this.onViewStateChange}
useNaip={useNaip}
viewState={viewState}
/>
) : (
<Map2d
viewState={viewState}
onViewStateChange={this.onViewStateChange}
onDragEnd={this.onDragEnd}
useNaip={useNaip}
landsatMosaicId={landsatMosaicId}
naipMosaicId={naipMosaicId}
landsatBandCombination={landsatBandCombination}
landsatBands={landsatBands}
landsatColormapName={landsatColormapName}
landsatBandCombination={landsatBandCombination}
landsatMosaicId={landsatMosaicId}
naipMosaicId={naipMosaicId}
onDragEnd={this.onDragEnd}
onTileLoad={this.onTileLoad}
onViewportLoad={this.onViewportLoad}
onViewStateChange={this.onViewStateChange}
useNaip={useNaip}
viewState={viewState}
/>
)}

<Options
landsatBands={landsatBands}
landsatBandPreset={landsatBandPreset}
_landsatMaxAssetDate={_landsatMaxAssetDate}
_landsatMinAssetDate={_landsatMinAssetDate}
landsatBandCombination={landsatBandCombination}
landsatBandPreset={landsatBandPreset}
landsatBands={landsatBands}
landsatColormapName={landsatColormapName}
landsatMosaicId={landsatMosaicId}
map3d={map3d}
naipMosaicId={naipMosaicId}
landsatColormapName={landsatColormapName}
useNaip={useNaip}
onChange={value => {
this.setState(value);
setQueryParams(value);
}}
map3d={map3d}
/>
</div>
);
Expand Down