diff --git a/src/components/map/Tile.test.tsx b/src/components/map/Tile.test.tsx new file mode 100644 index 0000000..1c09aa5 --- /dev/null +++ b/src/components/map/Tile.test.tsx @@ -0,0 +1,45 @@ +import { render, screen } from '@testing-library/react'; +import Tile from './Tile'; + +describe('The Tile component ', () => { + test('Is initially empty', () => { + const { baseElement } = render( + + + + ); + screen.debug(); + expect(baseElement).toMatchInlineSnapshot(` + +
+ + + +
+ +`); + }); + test('Gets its image immediately with a fake URL', () => { + const { baseElement } = render( + + + + ); + screen.debug(); + expect(baseElement).toMatchInlineSnapshot(` + +
+ + + + + +
+ +`); + }); +}); diff --git a/src/components/map/Tile.tsx b/src/components/map/Tile.tsx new file mode 100644 index 0000000..757c0a1 --- /dev/null +++ b/src/components/map/Tile.tsx @@ -0,0 +1,53 @@ +import react, { useEffect, useRef } from 'react'; + +export interface TileProperties { + // The image's source URL + href: string; + // Its size + size: number; + // A delay to add (for test/debug purposes) + delay?: number; +} + +/** + * + * @param props + * @returns A tile + */ +export const Tile: react.FC = (props: TileProperties) => { + const g = useRef(null); + + const timeout = (ms: number) => { + return new Promise((resolve) => setTimeout(resolve, ms)); + }; + + useEffect(() => { + const loadImage = async () => { + console.log(`Pre loading: ${props.href}`); + const image = new Image(props.size, props.size); + image.loading = 'eager'; + // @ts-ignore + image.setAttribute('href', props.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', props.size.toString()); + svgImage.setAttribute('height', props.size.toString()); + // @ts-ignore + svgImage.setAttribute('href', props.href); + g.current?.replaceChildren(svgImage); + }; + loadImage(); + }, [props.href, props.size]); + + return ; +}; + +export default Tile;