import react, { JSXElementConstructor, ReactElement, ReactNode } from 'react'; import useDimensions from 'react-cool-dimensions'; import { Point, MapScope } from './types'; import Marker from './Marker'; import LayerStack from './LayerStack'; import { tileProviders } from './tile-providers'; import { lon2tile, lat2tile } from '../../lib/geo'; export interface MapProperties { scope: MapScope; numberOfTiledLayers?: number; /** Markers are non scalable SVG snippets tied to geo location */ markers?: ReactElement>[]; } /** * * @returns A `` component * * `` components display the map specified by their {@link MapProperties}'s scope. * * They can be driven by {@link components/map/LiveMap!LiveMap} component to react to user's event. * */ export const Map: react.FC = (props: MapProperties) => { const { observe, width, height } = useDimensions(); const tileProvider = tileProviders[props.scope.tileProvider]; const tilesZoom = Math.min( Math.max(Math.round(props.scope.zoom), tileProvider.minZoom), tileProvider.maxZoom ); const tilesCenter: Point = { x: lon2tile(props.scope.center.lon, tilesZoom), y: lat2tile(props.scope.center.lat, tilesZoom), }; const softZoom = props.scope.zoom - tilesZoom; const relativeScale = 2 ** softZoom; const visibleTileSize = tileProvider.tileSize * relativeScale; const nbTilesLeft = width / 2 / visibleTileSize; const nbTilesTop = height / 2 / visibleTileSize; const firstTileLeft = Math.floor(tilesCenter.x - nbTilesLeft); const firstTileTop = Math.floor(tilesCenter.y - nbTilesTop); return (
); }; export default Map;