dyomedea/src/components/map/TiledLayer.tsx

56 lines
1.7 KiB
TypeScript
Raw Normal View History

2022-10-17 15:15:24 +00:00
import react, { useRef } from 'react';
import { range } from 'lodash';
2022-10-17 10:04:25 +00:00
2022-10-17 11:47:35 +00:00
import { Rectangle, TileKeyObject } from './types';
2022-10-17 15:15:24 +00:00
import tileUri from './uris';
2022-10-17 10:04:25 +00:00
export interface TiledLayerProperties {
/** The key of the first (ie top/left) tile */
2022-10-17 11:47:35 +00:00
keyObject: TileKeyObject;
/** The current viewport expressed in tiles coordinates */
viewPort: Rectangle;
2022-10-17 10:04:25 +00:00
}
/**
2022-10-17 15:48:30 +00:00
* A lazily loaded layer of tiles.
2022-10-17 11:47:35 +00:00
*
* This component is rather dumb and is mainly a sparse array of tiles.
2022-10-17 15:48:30 +00:00
*
2022-10-17 11:47:35 +00:00
* New tiles are added to the array when the viewport is updated and they stay in the array until
* the component is destroyed or its number of tiles is updated.
2022-10-17 10:04:25 +00:00
*
2022-10-17 15:48:30 +00:00
* This component has no need to know the number nor the size of its tiles: tiles can be added when needed and
* its unit is the tile size (the parent component needs to transform its enclosing SVG group to adapt its units)
*
2022-10-17 10:04:25 +00:00
*/
export const TiledLayer: react.FC<TiledLayerProperties> = (
props: TiledLayerProperties
) => {
2022-10-17 15:15:24 +00:00
console.log(`Rendering TiledLayer: ${JSON.stringify(props)}`);
const tiles = useRef<any>({});
range(props.viewPort.topLeft.y, props.viewPort.bottomRight.y + 1).map(
(row) => {
range(props.viewPort.topLeft.x, props.viewPort.bottomRight.x + 1).map(
(col) => {
const key = tileUri({
provider: props.keyObject.provider,
zoomLevel: props.keyObject.zoomLevel,
x: props.keyObject.x + row,
y: props.keyObject.x + col,
});
if (!Object.hasOwn(tiles.current, key)) {
2022-10-17 15:48:30 +00:00
tiles.current[key] = (
<g key={key} transform={`translate(${col}, ${row})`} />
);
2022-10-17 15:15:24 +00:00
}
}
);
}
);
return <>{Object.values(tiles.current)}</>;
2022-10-17 10:04:25 +00:00
};
export default TiledLayer;