import react, { memo, useEffect, useRef } from 'react'; import { isEqual } from 'lodash'; import { TileKeyObject } from './types'; import { getTileUrl } from './tile-providers'; export interface TileProperties { /** The image's source URL */ keyObject: TileKeyObject; /** A delay to add (for test/debug purposes) */ delay?: number; } /** * * @param props * @returns A tile * * Tile components are containers for images. * * They return an empty `` element immediately so that the rendering can proceed * and append an `` element whenever the image is loaded. * * They are designed to be part of {@link components/map/TiledLayer!TiledLayer} components in SVG `` elements * in which the unit is the tile size. In this coordinate system their size is thus always equal to 1. */ export const Tile: react.FC = memo((props: TileProperties) => { const g = useRef(null); const timeout = (ms: number) => { return new Promise((resolve) => setTimeout(resolve, ms)); }; // console.log(`Rendering tile: ${JSON.stringify(props)}`); useEffect(() => { const loadImage = async () => { // console.log(`Pre loading: ${props.href}`); const href = getTileUrl(props.keyObject); const image = new Image(1, 1); image.loading = 'eager'; // @ts-ignore image.setAttribute('href', href); if (!image.complete) { await image.decode(); } if (props.delay !== undefined) { await timeout(props.delay); } const svgImage = document.createElementNS( 'http://www.w3.org/2000/svg', 'image' ) as unknown as SVGImageElement; svgImage.setAttribute('width', '1'); svgImage.setAttribute('height', '1'); // @ts-ignore svgImage.setAttribute('href', href); g.current?.replaceChildren(svgImage); }; loadImage(); }, [props.keyObject]); return ( ); }, isEqual); export default Tile;