From ef35ffca324993ff7d9ee0a26f786ac88bef56c0 Mon Sep 17 00:00:00 2001 From: evlist Date: Sun, 30 Oct 2022 21:35:32 +0100 Subject: [PATCH] Adding a component to take care of translations and scalings around `` components (not used yeti but should simplify ``). --- src/components/map/TiledLayer.test.tsx | 165 +++++++++++++++++++++++++ src/components/map/TiledLayer.tsx | 85 +++++++++++++ 2 files changed, 250 insertions(+) create mode 100644 src/components/map/TiledLayer.test.tsx create mode 100644 src/components/map/TiledLayer.tsx diff --git a/src/components/map/TiledLayer.test.tsx b/src/components/map/TiledLayer.test.tsx new file mode 100644 index 0000000..f4691cc --- /dev/null +++ b/src/components/map/TiledLayer.test.tsx @@ -0,0 +1,165 @@ +import { renderHook, act, render, screen } from '@testing-library/react'; +import { useAtom } from 'jotai'; +import LayerStack from './LayerStack'; +import { coordinateSystemAtom, relativeCoordinateSystemAtom } from './Map'; +import TiledLayer from './TiledLayer'; + +describe('The TiledLayer component', () => { + beforeEach(() => { + globalThis.cacheForTileSet = new Map(); + }); + + test('generates an empty layer if inactive', () => { + // const { result } = renderHook(() => useAtom(tiledLayersAtom)); + render( + + + + ); + const svg = screen.getByTestId('tiled-layer'); + expect(svg).toMatchInlineSnapshot(` + + + +`); + }); + test('generates a populated layer if active', () => { + // const { result } = renderHook(() => useAtom(tiledLayersAtom)); + render( + + + + ); + const svg = screen.getByTestId('tiled-layer'); + expect(svg).toMatchInlineSnapshot(` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +`); + }); +}); diff --git a/src/components/map/TiledLayer.tsx b/src/components/map/TiledLayer.tsx new file mode 100644 index 0000000..7f1d6c2 --- /dev/null +++ b/src/components/map/TiledLayer.tsx @@ -0,0 +1,85 @@ +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; + /** + * A flag to indicate if the layer is active and should add tiles which are in its viewport or if it is "only" a backup. + */ + shift: Point; + /** + * The zoom to apply. If equal to 1, 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 `` in an SVG `` element taking care of the scale and translation. + * + */ +export const TiledLayer: react.FC = ( + props: TiledLayerProperties +) => { + const [coordinateSystem] = useAtom(coordinateSystemAtom); + const viewPort = + props.zoom === 1 + ? { + 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 ( + + + + ); +}; + +export default TiledLayer;