| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124 |
- import { createTileGrid, type TileItem } from '../../utils/tile'
- import { getTileSizePx, type CameraState } from '../camera/camera'
- import { type MapScene } from '../renderer/mapRenderer'
- import { type TileStore } from '../tile/tileStore'
- import { type MapLayer, type LayerRenderContext } from './mapLayer'
- function buildGridKey(scene: MapScene, tileSize: number): string {
- return [
- scene.tileSource,
- scene.zoom,
- scene.centerTileX,
- scene.centerTileY,
- scene.viewportWidth,
- scene.viewportHeight,
- tileSize,
- scene.overdraw,
- ].join('|')
- }
- export class TileLayer implements MapLayer {
- lastVisibleTileCount: number
- lastReadyTileCount: number
- cachedGridKey: string
- cachedTiles: TileItem[]
- constructor() {
- this.lastVisibleTileCount = 0
- this.lastReadyTileCount = 0
- this.cachedGridKey = ''
- this.cachedTiles = []
- }
- prepareTiles(scene: MapScene, camera: CameraState, tileStore: TileStore): TileItem[] {
- const tileSize = getTileSizePx(camera)
- if (!tileSize) {
- this.lastVisibleTileCount = 0
- this.lastReadyTileCount = 0
- this.cachedGridKey = ''
- this.cachedTiles = []
- return []
- }
- const gridKey = buildGridKey(scene, tileSize)
- if (gridKey !== this.cachedGridKey) {
- this.cachedGridKey = gridKey
- this.cachedTiles = createTileGrid({
- urlTemplate: scene.tileSource,
- zoom: scene.zoom,
- centerTileX: scene.centerTileX,
- centerTileY: scene.centerTileY,
- viewportWidth: scene.viewportWidth,
- viewportHeight: scene.viewportHeight,
- tileSize,
- overdraw: scene.overdraw,
- })
- }
- tileStore.queueVisibleTiles(this.cachedTiles, scene, gridKey)
- this.lastVisibleTileCount = this.cachedTiles.length
- this.lastReadyTileCount = 0
- return this.cachedTiles
- }
- draw(context: LayerRenderContext): void {
- const { ctx, scene, camera, tileStore } = context
- const tiles = this.prepareTiles(scene, camera, tileStore)
- for (const tile of tiles) {
- const entry = tileStore.getEntry(tile.url)
- const drawLeft = tile.leftPx + scene.translateX
- const drawTop = tile.topPx + scene.translateY
- if (entry && entry.status === 'ready' && entry.image) {
- ctx.drawImage(entry.image, drawLeft, drawTop, tile.sizePx, tile.sizePx)
- this.lastReadyTileCount += 1
- continue
- }
- const parentFallback = tileStore.getParentFallbackSlice(tile, scene)
- let drewFallback = false
- if (parentFallback) {
- ctx.drawImage(
- parentFallback.entry.image,
- parentFallback.sourceX,
- parentFallback.sourceY,
- parentFallback.sourceWidth,
- parentFallback.sourceHeight,
- drawLeft,
- drawTop,
- tile.sizePx,
- tile.sizePx,
- )
- drewFallback = true
- }
- const childFallback = tileStore.getChildFallback(tile, scene)
- if (childFallback) {
- const cellWidth = tile.sizePx / childFallback.division
- const cellHeight = tile.sizePx / childFallback.division
- for (const child of childFallback.children) {
- const childImageWidth = child.entry.image.width || 256
- const childImageHeight = child.entry.image.height || 256
- ctx.drawImage(
- child.entry.image,
- 0,
- 0,
- childImageWidth,
- childImageHeight,
- drawLeft + child.offsetX * cellWidth,
- drawTop + child.offsetY * cellHeight,
- cellWidth,
- cellHeight,
- )
- }
- drewFallback = true
- }
- if (!drewFallback) {
- ctx.fillStyle = entry && entry.status === 'error' ? '#d9b2b2' : '#dbeed4'
- ctx.fillRect(drawLeft, drawTop, tile.sizePx, tile.sizePx)
- }
- }
- }
- }
|