dyomedea/src/components/map/TiledLayer.tsx

86 lines
2.1 KiB
TypeScript

import { useAtom } from 'jotai';
import react from 'react';
import TileSet from './TileSet';
import { Point, TileKeyObject } from './types';
import { coordinateSystemAtom } from './Map';
export interface TiledLayerProperties {
/**
* A key identifying the top left tile
*/
keyObject: TileKeyObject;
/**
* The translation to apply.
*/
shift: Point;
/**
* The zoom to apply. If equal to 256 (the tile size), the layer is considered active and should add tiles which are in its viewport
*/
zoom: number;
}
/**
*
* @param props
* @returns A layer of tiles.
* This component wraps a `<TileSet>` in an SVG `<g>` element taking care of the scale and translation.
*
*/
export const TiledLayer: react.FC<TiledLayerProperties> = (
props: TiledLayerProperties
) => {
const [coordinateSystem] = useAtom(coordinateSystemAtom);
const viewPort =
props.zoom === 256
? {
topLeft: {
x:
props.keyObject.x +
Math.floor(
-coordinateSystem.shift.x / coordinateSystem.zoom / 256
),
y:
props.keyObject.y +
Math.floor(
-coordinateSystem.shift.y / coordinateSystem.zoom / 256
),
},
bottomRight: {
x:
props.keyObject.x +
Math.ceil(
(-coordinateSystem.shift.x + window.innerWidth) /
coordinateSystem.zoom /
256
) -
1,
y:
props.keyObject.y +
Math.ceil(
(-coordinateSystem.shift.y + window.innerHeight) /
coordinateSystem.zoom /
256
) -
1,
},
}
: undefined;
return (
<g
transform={`scale(${props.zoom}) translate(${props.shift.x}, ${props.shift.y})`}
>
<TileSet
keyObject={{
provider: props.keyObject.provider,
zoomLevel: props.keyObject.zoomLevel,
x: 0,
y: 0,
}}
viewPort={viewPort}
/>
</g>
);
};
export default TiledLayer;