tile.ts 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. export interface TileItem {
  2. key: string
  3. url: string
  4. x: number
  5. y: number
  6. leftPx: number
  7. topPx: number
  8. sizePx: number
  9. isCenter: boolean
  10. }
  11. const TILE_OVERLAP_PX = 2
  12. export interface TileGridOptions {
  13. urlTemplate: string
  14. zoom: number
  15. centerTileX: number
  16. centerTileY: number
  17. viewportWidth: number
  18. viewportHeight: number
  19. tileSize: number
  20. overdraw: number
  21. }
  22. export function buildTileUrl(template: string, z: number, x: number, y: number): string {
  23. return template
  24. .replace('{z}', String(z))
  25. .replace('{x}', String(x))
  26. .replace('{y}', String(y))
  27. }
  28. export function createTileGrid(options: TileGridOptions): TileItem[] {
  29. const tiles: TileItem[] = []
  30. const halfWidth = options.viewportWidth / 2
  31. const halfHeight = options.viewportHeight / 2
  32. const horizontalRange = Math.ceil(halfWidth / options.tileSize) + options.overdraw
  33. const verticalRange = Math.ceil(halfHeight / options.tileSize) + options.overdraw
  34. for (let dy = -verticalRange; dy <= verticalRange; dy += 1) {
  35. for (let dx = -horizontalRange; dx <= horizontalRange; dx += 1) {
  36. const x = options.centerTileX + dx
  37. const y = options.centerTileY + dy
  38. const rawLeft = halfWidth + (dx - 0.5) * options.tileSize
  39. const rawTop = halfHeight + (dy - 0.5) * options.tileSize
  40. tiles.push({
  41. key: `${options.zoom}-${x}-${y}`,
  42. url: buildTileUrl(options.urlTemplate, options.zoom, x, y),
  43. x,
  44. y,
  45. leftPx: Math.floor(rawLeft - TILE_OVERLAP_PX / 2),
  46. topPx: Math.floor(rawTop - TILE_OVERLAP_PX / 2),
  47. sizePx: Math.ceil(options.tileSize) + TILE_OVERLAP_PX,
  48. isCenter: dx === 0 && dy === 0,
  49. })
  50. }
  51. }
  52. return tiles
  53. }