Adding a component to take care of translations and scalings around `<TileSet>` components (not used yeti but should simplify `<LayerStack>`).
This commit is contained in:
parent
7322e5f5c4
commit
ef35ffca32
|
@ -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(
|
||||
<svg data-testid='tiled-layer'>
|
||||
<TiledLayer
|
||||
keyObject={{ provider: 'fake', zoomLevel: 5, x: 2, y: 3 }}
|
||||
shift={{ x: 0.5, y: 0.25 }}
|
||||
zoom={4}
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
const svg = screen.getByTestId('tiled-layer');
|
||||
expect(svg).toMatchInlineSnapshot(`
|
||||
<svg
|
||||
data-testid="tiled-layer"
|
||||
>
|
||||
<g
|
||||
transform="scale(4) translate(0.5, 0.25)"
|
||||
/>
|
||||
</svg>
|
||||
`);
|
||||
});
|
||||
test('generates a populated layer if active', () => {
|
||||
// const { result } = renderHook(() => useAtom(tiledLayersAtom));
|
||||
render(
|
||||
<svg data-testid='tiled-layer'>
|
||||
<TiledLayer
|
||||
keyObject={{ provider: 'fake', zoomLevel: 5, x: 2, y: 3 }}
|
||||
shift={{ x: 0, y: 0 }}
|
||||
zoom={1}
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
const svg = screen.getByTestId('tiled-layer');
|
||||
expect(svg).toMatchInlineSnapshot(`
|
||||
<svg
|
||||
data-testid="tiled-layer"
|
||||
>
|
||||
<g
|
||||
transform="scale(1) translate(0, 0)"
|
||||
>
|
||||
<g
|
||||
transform="translate(2, 3)"
|
||||
>
|
||||
<image
|
||||
height="1"
|
||||
href="https://fakeurl/5/2/3.png"
|
||||
width="1"
|
||||
/>
|
||||
</g>
|
||||
<g
|
||||
transform="translate(3, 3)"
|
||||
>
|
||||
<image
|
||||
height="1"
|
||||
href="https://fakeurl/5/3/3.png"
|
||||
width="1"
|
||||
/>
|
||||
</g>
|
||||
<g
|
||||
transform="translate(4, 3)"
|
||||
>
|
||||
<image
|
||||
height="1"
|
||||
href="https://fakeurl/5/4/3.png"
|
||||
width="1"
|
||||
/>
|
||||
</g>
|
||||
<g
|
||||
transform="translate(5, 3)"
|
||||
>
|
||||
<image
|
||||
height="1"
|
||||
href="https://fakeurl/5/5/3.png"
|
||||
width="1"
|
||||
/>
|
||||
</g>
|
||||
<g
|
||||
transform="translate(2, 4)"
|
||||
>
|
||||
<image
|
||||
height="1"
|
||||
href="https://fakeurl/5/2/4.png"
|
||||
width="1"
|
||||
/>
|
||||
</g>
|
||||
<g
|
||||
transform="translate(3, 4)"
|
||||
>
|
||||
<image
|
||||
height="1"
|
||||
href="https://fakeurl/5/3/4.png"
|
||||
width="1"
|
||||
/>
|
||||
</g>
|
||||
<g
|
||||
transform="translate(4, 4)"
|
||||
>
|
||||
<image
|
||||
height="1"
|
||||
href="https://fakeurl/5/4/4.png"
|
||||
width="1"
|
||||
/>
|
||||
</g>
|
||||
<g
|
||||
transform="translate(5, 4)"
|
||||
>
|
||||
<image
|
||||
height="1"
|
||||
href="https://fakeurl/5/5/4.png"
|
||||
width="1"
|
||||
/>
|
||||
</g>
|
||||
<g
|
||||
transform="translate(2, 5)"
|
||||
>
|
||||
<image
|
||||
height="1"
|
||||
href="https://fakeurl/5/2/5.png"
|
||||
width="1"
|
||||
/>
|
||||
</g>
|
||||
<g
|
||||
transform="translate(3, 5)"
|
||||
>
|
||||
<image
|
||||
height="1"
|
||||
href="https://fakeurl/5/3/5.png"
|
||||
width="1"
|
||||
/>
|
||||
</g>
|
||||
<g
|
||||
transform="translate(4, 5)"
|
||||
>
|
||||
<image
|
||||
height="1"
|
||||
href="https://fakeurl/5/4/5.png"
|
||||
width="1"
|
||||
/>
|
||||
</g>
|
||||
<g
|
||||
transform="translate(5, 5)"
|
||||
>
|
||||
<image
|
||||
height="1"
|
||||
href="https://fakeurl/5/5/5.png"
|
||||
width="1"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
`);
|
||||
});
|
||||
});
|
|
@ -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 `<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 === 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 (
|
||||
<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;
|
Loading…
Reference in New Issue