Skip to content

Commit

Permalink
Put tile urls for datasets (#623)
Browse files Browse the repository at this point in the history
This PR is based on : #620 
Close #594 

- [x] check vector data
  • Loading branch information
hanbyul-here authored Aug 17, 2023
2 parents ac6b826 + d381a05 commit e95d4b4
Show file tree
Hide file tree
Showing 7 changed files with 284 additions and 86 deletions.
10 changes: 6 additions & 4 deletions app/scripts/components/common/mapbox/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import MapMessage from './map-message';
import { LayerLegendContainer, LayerLegend } from './layer-legend';
import { useBasemap } from './map-options/use-basemap';
import { DEFAULT_MAP_STYLE_URL } from './map-options/basemaps';
import { Styles } from './layers/styles';
import { ExtendedStyle, Styles } from './layers/styles';
import { Basemap } from './layers/basemap';
import { formatCompareDate, formatSingleDate } from './utils';
import { MapLoading } from '$components/common/loading-skeleton';
Expand Down Expand Up @@ -130,7 +130,8 @@ function MapboxMapComponent(
onAoiChange,
projection,
onProjectionChange,
isDatasetLayerHidden
isDatasetLayerHidden,
onStyleChange
} = props;
/* eslint-enable react/prop-types */

Expand Down Expand Up @@ -399,7 +400,7 @@ function MapboxMapComponent(
className={className}
id={id ?? 'mapbox-container'}
>
<Styles>
<Styles onStyleUpdate={onStyleChange}>
{/*
Each layer type is added to the map through a component. This component
has all the logic needed to add/update/remove the layer.
Expand Down Expand Up @@ -456,7 +457,7 @@ function MapboxMapComponent(
</Styles>

{shouldRenderCompare && (
<Styles>
<Styles onStyleUpdate={onStyleChange}>
{/*
Adding a layer to the comparison map is also done through a component,
which is this case targets a different map instance.
Expand Down Expand Up @@ -538,6 +539,7 @@ export interface MapboxMapProps {
projection?: ProjectionOptions;
onProjectionChange?: (projection: ProjectionOptions) => void;
isDatasetLayerHidden?: boolean;
onStyleChange?: (style: ExtendedStyle) => void;
}

export interface MapboxMapRef {
Expand Down
187 changes: 110 additions & 77 deletions app/scripts/components/common/mapbox/layers/raster-timeseries.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -337,92 +337,125 @@ export function MapLayerRasterTimeseries(props: MapLayerRasterTimeseriesProps) {
() => JSON.stringify(sourceParams),
[sourceParams]
);

useEffect(
() => {
let layers: AnyLayer[] = [];
let sources: Record<string, AnySourceImpl> = {};

if (mosaicUrl) {
const tileParams = qs.stringify(
{
assets: 'cog_default',
...sourceParams
},
// Temporary solution to pass different tile parameters for hls data
{ arrayFormat: id.toLowerCase().includes('hls') ? 'repeat' : 'comma' }
);

const mosaicSource: RasterSource = {
type: 'raster',
url: `${mosaicUrl}?${tileParams}`
};

const mosaicLayer: RasterLayer = {
id: id,
type: 'raster',
source: id,
layout: {
visibility: isHidden ? 'none' : 'visible'
},
paint: {
'raster-opacity': Number(!isHidden),
'raster-opacity-transition': {
duration: 320
const controller = new AbortController();

async function run() {
let layers: AnyLayer[] = [];
let sources: Record<string, AnySourceImpl> = {};

if (mosaicUrl) {
const tileParams = qs.stringify(
{
assets: 'cog_default',
...sourceParams
},
// Temporary solution to pass different tile parameters for hls data
{
arrayFormat: id.toLowerCase().includes('hls') ? 'repeat' : 'comma'
}
},
minzoom: minZoom,
metadata: {
layerOrderPosition: 'raster'
);

const tilejsonUrl = `${mosaicUrl}?${tileParams}`;

let tileServerUrl: string | undefined = undefined;
try {
const tilejsonData = await requestQuickCache({
url: tilejsonUrl,
method: 'GET',
payload: null,
controller
});
tileServerUrl = tilejsonData.tiles[0];
} catch (error) {
// Ignore errors.
}
};

sources = {
...sources,
[id]: mosaicSource
};
layers = [...layers, mosaicLayer];
}
const wmtsBaseUrl = mosaicUrl.replace('tilejson.json', 'WMTSCapabilities.xml');

const mosaicSource: RasterSource = {
type: 'raster',
url: tilejsonUrl
};

const mosaicLayer: RasterLayer = {
id: id,
type: 'raster',
source: id,
layout: {
visibility: isHidden ? 'none' : 'visible'
},
paint: {
'raster-opacity': Number(!isHidden),
'raster-opacity-transition': {
duration: 320
}
},
minzoom: minZoom,
metadata: {
id,
layerOrderPosition: 'raster',
xyzTileUrl: tileServerUrl,
wmtsTileUrl: `${wmtsBaseUrl}?${tileParams}`
}
};

if (points && minZoom > 0) {
const pointsSourceId = `${id}-points`;
const pointsSource: GeoJSONSourceRaw = {
type: 'geojson',
data: featureCollection(
points.map((p) => point(p.center, { bounds: p.bounds }))
)
};
sources = {
...sources,
[id]: mosaicSource
};
layers = [...layers, mosaicLayer];
}

const pointsLayer: SymbolLayer = {
type: 'symbol',
id: pointsSourceId,
source: pointsSourceId,
layout: {
...(markerLayout as any),
visibility: isHidden ? 'none' : 'visible',
'icon-allow-overlap': true
},
paint: {
'icon-color': theme.color?.primary,
'icon-halo-color': theme.color?.base,
'icon-halo-width': 1
},
maxzoom: minZoom,
metadata: {
layerOrderPosition: 'markers'
}
};
sources = {
...sources,
[pointsSourceId]: pointsSource as AnySourceImpl
};
layers = [...layers, pointsLayer];
if (points && minZoom > 0) {
const pointsSourceId = `${id}-points`;
const pointsSource: GeoJSONSourceRaw = {
type: 'geojson',
data: featureCollection(
points.map((p) => point(p.center, { bounds: p.bounds }))
)
};

const pointsLayer: SymbolLayer = {
type: 'symbol',
id: pointsSourceId,
source: pointsSourceId,
layout: {
...(markerLayout as any),
visibility: isHidden ? 'none' : 'visible',
'icon-allow-overlap': true
},
paint: {
'icon-color': theme.color?.primary,
'icon-halo-color': theme.color?.base,
'icon-halo-width': 1
},
maxzoom: minZoom,
metadata: {
layerOrderPosition: 'markers'
}
};
sources = {
...sources,
[pointsSourceId]: pointsSource as AnySourceImpl
};
layers = [...layers, pointsLayer];
}

updateStyle({
generatorId,
sources,
layers
});
}

updateStyle({
generatorId,
sources,
layers
});
run();

return () => {
controller.abort();
};
},
// sourceParams not included, but using a stringified version of it to detect changes (haveSourceParamsChanged)
[
Expand Down
9 changes: 7 additions & 2 deletions app/scripts/components/common/mapbox/layers/styles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ export interface GeneratorParams {
interface StylesContextType {
updateStyle: (params: GeneratorParams) => void;
style?: Style;
updateMetaData?: (params: unknown) => void;
metaData?: unknown;
}

export const StylesContext = createContext<StylesContextType>({
Expand All @@ -47,6 +49,8 @@ const LAYER_ORDER: LayerOrderPosition[] = [
'markers'
];

export type ExtendedStyle = ReturnType<typeof generateStyle>;

// Takes in a dictionary associating each generator id with a series of
// Mapbox layers and sources to be added to the final style. Outputs
// a style object directly usable by the map instance.
Expand Down Expand Up @@ -103,14 +107,15 @@ export function Styles({
onStyleUpdate,
children
}: {
onStyleUpdate?: (style: Style) => void;
onStyleUpdate?: (style: ExtendedStyle) => void;
children?: ReactNode;
}) {
const [stylesData, setStylesData] = useState<Record<string, GeneratorParams>>(
{}
);

const [style, setStyle] = useState<Style | undefined>();

const updateStyle = useCallback(
(params: GeneratorParams) => {
setStylesData((prevStyle) => ({
Expand All @@ -123,7 +128,7 @@ export function Styles({

useEffect(() => {
const style = generateStyle(stylesData);
onStyleUpdate?.(style as any);
onStyleUpdate?.(style);
setStyle(style as any);
}, [stylesData, onStyleUpdate]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,9 @@ export function MapLayerVectorTimeseries(props: MapLayerVectorTimeseriesProps) {
// filter: ['==', '$type', 'LineString'],
minzoom: minZoom,
metadata: {
layerOrderPosition: 'raster'
id,
layerOrderPosition: 'raster',
xyzTileUrl: `${featuresApiEndpoint}/tiles/{z}/{x}/{y}?${tileParams}`
}
},
{
Expand Down
1 change: 1 addition & 0 deletions app/scripts/components/common/mapbox/map.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ export function SimpleMap(props: SimpleMapProps): ReactElement {
if (!mapRef.current || !style) return;
mapRef.current.setStyle(style);
/* mapRef is a ref */
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [style]);

// Handle Attribution
Expand Down
16 changes: 14 additions & 2 deletions app/scripts/components/datasets/s-explore/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { ProjectionOptions } from 'veda';
import { FormSwitch } from '@devseed-ui/form';

import LayerVisibilityToggleButton from './layer-visibility-toggle';
import TileLinkButton from './tile-link';
import DatasetLayers from './dataset-layers';
import { PanelDateWidget } from './panel-date-widget';
import { resourceNotFound } from '$components/uhoh';
Expand Down Expand Up @@ -55,6 +56,7 @@ import { variableGlsp } from '$styles/variable-utils';
import { S_SUCCEEDED } from '$utils/status';
import { projectionDefault } from '$components/common/mapbox/map-options/utils';
import { NotebookConnectButton } from '$components/common/notebook-connect';
import { ExtendedStyle } from '$components/common/mapbox/layers/styles';

const Explorer = styled.div`
position: relative;
Expand Down Expand Up @@ -314,11 +316,16 @@ function DatasetsExplore() {
}
});

// END QsState setup
/** *********************************************************************** */

const [isComparing, setIsComparing] = useState(!!selectedCompareDatetime);
const [isDatasetLayerHidden, setIsDatasetLayerHidden] = useState(false);
const [layerStyle, setLayerStyle] = useState<ExtendedStyle | undefined>(undefined);

// END QsState setup
/** *********************************************************************** */
const currentLayerStyle = layerStyle?.layers.find((l) => {
return l.metadata.id === `base-${selectedLayerId}`;
});

// Get the dataset's layers.
// Since async data has to be loaded, each layer is in an async format which
Expand Down Expand Up @@ -566,6 +573,10 @@ function DatasetsExplore() {
<Carto>
<CustomControlWrapper>
<NotebookConnectButton dataset={dataset.data} />
<TileLinkButton
layerData={currentLayerStyle}
disabled={!currentLayerStyle?.metadata.xyzTileUrl}
/>
<LayerVisibilityToggleButton
isDatasetLayerHidden={isDatasetLayerHidden}
onLayerVisibilityClick={setIsDatasetLayerHidden}
Expand All @@ -591,6 +602,7 @@ function DatasetsExplore() {
projection={mapProjection ?? projectionDefault}
onProjectionChange={setMapProjection}
isDatasetLayerHidden={isDatasetLayerHidden}
onStyleChange={setLayerStyle}
/>
</Carto>
</Explorer>
Expand Down
Loading

0 comments on commit e95d4b4

Please sign in to comment.