dyomedea/src/components/map/TileSet.tsx

121 lines
3.7 KiB
TypeScript
Raw Normal View History

2022-10-30 19:23:12 +00:00
import react, { memo } from 'react';
import { isEqual, range } from 'lodash';
2022-10-17 10:04:25 +00:00
2022-10-30 19:18:21 +00:00
import { Rectangle, TileKeyObject } from './types';
2022-10-17 15:15:24 +00:00
import tileUri from './uris';
2022-10-30 19:18:21 +00:00
import Tile from './Tile';
2022-10-31 21:14:28 +00:00
import { tileSetConfig } from './config';
2022-10-17 10:04:25 +00:00
2022-10-20 14:58:33 +00:00
/**
* @hidden
*/
export const thisIsAModule = true;
/**
*
*/
2022-10-20 14:58:33 +00:00
declare global {
2022-10-30 19:18:21 +00:00
var cacheForTileSet: any;
}
2022-10-20 14:58:33 +00:00
//export {};
2022-10-30 19:18:21 +00:00
globalThis.cacheForTileSet = new Map();
2022-10-30 19:18:21 +00:00
export interface TileSetProperties {
/** A partial Tile key object specifying the provider and zoom level */
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-30 19:18:21 +00:00
* A lazily loaded set 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.
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-20 14:58:33 +00:00
* The `globalThis.cacheForTiledLayer` global variable is used as a cache to store tiles without being subject
* to re-initialization when components are unmounted/remounted.
*
* This cache is a map of map, the first key identifying the `<TiledLayer` and the second one for `<Tile>`s.
*
* Idea stolen [on the web](https://dev.to/tiagof/react-re-mounting-vs-re-rendering-lnh)
*
*
2022-10-17 10:04:25 +00:00
*/
2022-10-30 19:23:12 +00:00
export const TileSet: react.FC<TileSetProperties> = memo(
(props: TileSetProperties) => {
// console.log(`Rendering TiledLayer: ${JSON.stringify(props)}`);
2022-10-30 19:23:12 +00:00
const key = tileUri({
provider: props.keyObject.provider,
zoomLevel: props.keyObject.zoomLevel,
});
2022-10-17 15:15:24 +00:00
2022-10-30 19:23:12 +00:00
const tiles: any = globalThis.cacheForTileSet.get(key) ?? new Map();
if (props.viewPort !== undefined) {
range(props.viewPort.topLeft.y, props.viewPort.bottomRight.y + 1).forEach(
(row) => {
range(
props.viewPort!.topLeft.x,
props.viewPort!.bottomRight.x + 1
).forEach((col) => {
const keyObject = {
provider: props.keyObject.provider,
zoomLevel: props.keyObject.zoomLevel,
x: props.keyObject.x + col,
y: props.keyObject.y + row,
};
const key = tileUri(keyObject);
if (!tiles.has(key)) {
tiles.set(
key,
<Tile
key={key}
keyObject={{
provider: props.keyObject.provider,
zoomLevel: props.keyObject.zoomLevel,
x: col,
y: row,
}}
/>
);
2022-10-31 21:14:28 +00:00
} else {
const tile = tiles.get(key);
tiles.delete(key);
tiles.set(key, tile);
2022-10-30 19:23:12 +00:00
}
});
}
);
if (tiles.size > tileSetConfig.cacheSizePerLayer) {
2022-10-31 21:14:28 +00:00
const oldestTileKeys = [...tiles.keys()];
oldestTileKeys.splice(-tileSetConfig.cacheSizePerLayer);
2022-10-31 21:14:28 +00:00
oldestTileKeys.forEach((tileKey) => {
tiles.delete(tileKey);
});
}
2022-10-30 19:23:12 +00:00
globalThis.cacheForTileSet.set(key, tiles);
if (globalThis.cacheForTileSet > tileSetConfig.numberOfCachedLayers) {
const oldestCachedLayerKeys = [...globalThis.cacheForTileSet.keys()];
oldestCachedLayerKeys.slice(-tileSetConfig.numberOfCachedLayers);
oldestCachedLayerKeys.forEach((cachedLayerKey) => {
globalThis.cacheForTileSet.delete(cachedLayerKey);
});
}
2022-10-30 19:23:12 +00:00
}
2022-10-17 15:15:24 +00:00
2022-10-30 19:23:12 +00:00
return <>{Array.from(tiles.values())}</>;
},
isEqual
);
2022-10-17 10:04:25 +00:00
2022-10-30 19:18:21 +00:00
export default TileSet;