feat: initialize mini program map engine
This commit is contained in:
61
miniprogram/utils/projection.ts
Normal file
61
miniprogram/utils/projection.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
export interface LonLatPoint {
|
||||
lon: number
|
||||
lat: number
|
||||
}
|
||||
|
||||
export interface WebMercatorPoint {
|
||||
x: number
|
||||
y: number
|
||||
}
|
||||
|
||||
export interface WorldTilePoint {
|
||||
x: number
|
||||
y: number
|
||||
}
|
||||
|
||||
const MAX_LATITUDE = 85.05112878
|
||||
const EARTH_RADIUS = 6378137
|
||||
|
||||
function clampLatitude(lat: number): number {
|
||||
return Math.max(-MAX_LATITUDE, Math.min(MAX_LATITUDE, lat))
|
||||
}
|
||||
|
||||
export function lonLatToWebMercator(point: LonLatPoint): WebMercatorPoint {
|
||||
const latitude = clampLatitude(point.lat)
|
||||
const lonRad = point.lon * Math.PI / 180
|
||||
const latRad = latitude * Math.PI / 180
|
||||
|
||||
return {
|
||||
x: EARTH_RADIUS * lonRad,
|
||||
y: EARTH_RADIUS * Math.log(Math.tan(Math.PI / 4 + latRad / 2)),
|
||||
}
|
||||
}
|
||||
|
||||
export function webMercatorToLonLat(point: WebMercatorPoint): LonLatPoint {
|
||||
return {
|
||||
lon: point.x / EARTH_RADIUS * 180 / Math.PI,
|
||||
lat: (2 * Math.atan(Math.exp(point.y / EARTH_RADIUS)) - Math.PI / 2) * 180 / Math.PI,
|
||||
}
|
||||
}
|
||||
|
||||
export function lonLatToWorldTile(point: LonLatPoint, zoom: number): WorldTilePoint {
|
||||
const latitude = clampLatitude(point.lat)
|
||||
const scale = Math.pow(2, zoom)
|
||||
const latRad = latitude * Math.PI / 180
|
||||
|
||||
return {
|
||||
x: (point.lon + 180) / 360 * scale,
|
||||
y: (1 - Math.log(Math.tan(latRad) + 1 / Math.cos(latRad)) / Math.PI) / 2 * scale,
|
||||
}
|
||||
}
|
||||
|
||||
export function worldTileToLonLat(point: WorldTilePoint, zoom: number): LonLatPoint {
|
||||
const scale = Math.pow(2, zoom)
|
||||
const lon = point.x / scale * 360 - 180
|
||||
const latRad = Math.atan(Math.sinh(Math.PI * (1 - 2 * point.y / scale)))
|
||||
|
||||
return {
|
||||
lon,
|
||||
lat: latRad * 180 / Math.PI,
|
||||
}
|
||||
}
|
||||
61
miniprogram/utils/tile.ts
Normal file
61
miniprogram/utils/tile.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
export interface TileItem {
|
||||
key: string
|
||||
url: string
|
||||
x: number
|
||||
y: number
|
||||
leftPx: number
|
||||
topPx: number
|
||||
sizePx: number
|
||||
isCenter: boolean
|
||||
}
|
||||
|
||||
const TILE_OVERLAP_PX = 2
|
||||
|
||||
export interface TileGridOptions {
|
||||
urlTemplate: string
|
||||
zoom: number
|
||||
centerTileX: number
|
||||
centerTileY: number
|
||||
viewportWidth: number
|
||||
viewportHeight: number
|
||||
tileSize: number
|
||||
overdraw: number
|
||||
}
|
||||
|
||||
export function buildTileUrl(template: string, z: number, x: number, y: number): string {
|
||||
return template
|
||||
.replace('{z}', String(z))
|
||||
.replace('{x}', String(x))
|
||||
.replace('{y}', String(y))
|
||||
}
|
||||
|
||||
export function createTileGrid(options: TileGridOptions): TileItem[] {
|
||||
const tiles: TileItem[] = []
|
||||
const halfWidth = options.viewportWidth / 2
|
||||
const halfHeight = options.viewportHeight / 2
|
||||
const horizontalRange = Math.ceil(halfWidth / options.tileSize) + options.overdraw
|
||||
const verticalRange = Math.ceil(halfHeight / options.tileSize) + options.overdraw
|
||||
|
||||
for (let dy = -verticalRange; dy <= verticalRange; dy += 1) {
|
||||
for (let dx = -horizontalRange; dx <= horizontalRange; dx += 1) {
|
||||
const x = options.centerTileX + dx
|
||||
const y = options.centerTileY + dy
|
||||
|
||||
const rawLeft = halfWidth + (dx - 0.5) * options.tileSize
|
||||
const rawTop = halfHeight + (dy - 0.5) * options.tileSize
|
||||
|
||||
tiles.push({
|
||||
key: `${options.zoom}-${x}-${y}`,
|
||||
url: buildTileUrl(options.urlTemplate, options.zoom, x, y),
|
||||
x,
|
||||
y,
|
||||
leftPx: Math.floor(rawLeft - TILE_OVERLAP_PX / 2),
|
||||
topPx: Math.floor(rawTop - TILE_OVERLAP_PX / 2),
|
||||
sizePx: Math.ceil(options.tileSize) + TILE_OVERLAP_PX,
|
||||
isCenter: dx === 0 && dy === 0,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return tiles
|
||||
}
|
||||
19
miniprogram/utils/util.ts
Normal file
19
miniprogram/utils/util.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
export const formatTime = (date: Date) => {
|
||||
const year = date.getFullYear()
|
||||
const month = date.getMonth() + 1
|
||||
const day = date.getDate()
|
||||
const hour = date.getHours()
|
||||
const minute = date.getMinutes()
|
||||
const second = date.getSeconds()
|
||||
|
||||
return (
|
||||
[year, month, day].map(formatNumber).join('/') +
|
||||
' ' +
|
||||
[hour, minute, second].map(formatNumber).join(':')
|
||||
)
|
||||
}
|
||||
|
||||
const formatNumber = (n: number) => {
|
||||
const s = n.toString()
|
||||
return s[1] ? s : '0' + s
|
||||
}
|
||||
Reference in New Issue
Block a user