121 lines
4.0 KiB
TypeScript
121 lines
4.0 KiB
TypeScript
import { Controller, Get, Query, UseGuards, Res } from '@nestjs/common';
|
|
import { ApiTags, ApiOperation } from '@nestjs/swagger';
|
|
import type { Response } from 'express';
|
|
import * as fs from 'fs';
|
|
import * as path from 'path';
|
|
import { MapsService } from './maps.service';
|
|
import { ApiKeyGuard } from '../common/guards/api-key.guard';
|
|
|
|
@ApiTags('maps')
|
|
@Controller('maps')
|
|
@UseGuards(ApiKeyGuard)
|
|
export class MapsController {
|
|
constructor(private readonly mapsService: MapsService) { }
|
|
|
|
@Get('style.json')
|
|
@ApiOperation({ summary: 'Get MapLibre style JSON 🎨' })
|
|
async getStyleJson(@Query('theme') theme: string, @Res() res: Response) {
|
|
// Determine filenames based on theme
|
|
const isDark = theme === 'obsidian';
|
|
const filename = isDark ? 'style-dark.json' : 'style.json';
|
|
const fallbackFilename = 'style.json';
|
|
|
|
// Paths to check
|
|
const pathsToCheck = [
|
|
path.join('/data', filename),
|
|
path.join(process.cwd(), '../../', filename),
|
|
path.join(process.cwd(), filename),
|
|
// Fallbacks to light style if dark is missing
|
|
path.join('/data', fallbackFilename),
|
|
path.join(process.cwd(), '../../', fallbackFilename),
|
|
path.join(process.cwd(), fallbackFilename),
|
|
];
|
|
|
|
let stylePath = '';
|
|
for (const p of pathsToCheck) {
|
|
if (fs.existsSync(p)) {
|
|
stylePath = p;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!stylePath) {
|
|
return res.status(404).send('Style not found');
|
|
}
|
|
|
|
try {
|
|
const styleRaw = fs.readFileSync(stylePath, 'utf8');
|
|
const styleObj = JSON.parse(styleRaw);
|
|
|
|
// Dynamic Theme support (Safety overrides or fine-tuning)
|
|
if (theme === 'light') {
|
|
styleObj.layers.forEach((layer: any) => {
|
|
if (layer.id === 'background') {
|
|
layer.paint['background-color'] = '#FFFFFF';
|
|
}
|
|
});
|
|
} else if (theme === 'obsidian') {
|
|
// If we found style-dark.json, we don't strictly need this,
|
|
// but keeping it as a helper or if it fell back to style.json
|
|
styleObj.layers.forEach((layer: any) => {
|
|
if (layer.id === 'background') {
|
|
layer.paint['background-color'] = '#101014'; // Dark tone
|
|
}
|
|
});
|
|
}
|
|
|
|
res.setHeader('Content-Type', 'application/json');
|
|
res.send(styleObj);
|
|
} catch (e) {
|
|
res.status(500).send('Error parsing style.json');
|
|
}
|
|
}
|
|
|
|
@Get('route')
|
|
@ApiOperation({ summary: 'Calculate a route with dynamic waypoints 🚗' })
|
|
async getRoute(@Query() query: any) {
|
|
const waypoints: [number, number][] = [];
|
|
|
|
// 1. Extract Origin (fromLat, fromLng)
|
|
if (query.fromLat && query.fromLng) {
|
|
waypoints.push([parseFloat(query.fromLat), parseFloat(query.fromLng)]);
|
|
}
|
|
|
|
// 2. Extract Intermediate Stops (stop1Lat, stop1Lng, stop2Lat, etc.)
|
|
// We sort keys to ensure stops are in order: stop1, stop2, stop3...
|
|
const stopKeys = Object.keys(query)
|
|
.filter(key => key.startsWith('stop') && key.endsWith('Lat'))
|
|
.sort((a, b) => {
|
|
const numA = parseInt(a.replace('stop', '').replace('Lat', ''), 10);
|
|
const numB = parseInt(b.replace('stop', '').replace('Lat', ''), 10);
|
|
return numA - numB;
|
|
});
|
|
|
|
for (const latKey of stopKeys) {
|
|
const prefix = latKey.replace('Lat', '');
|
|
const lngKey = `${prefix}Lng`;
|
|
if (query[latKey] && query[lngKey]) {
|
|
waypoints.push([parseFloat(query[latKey]), parseFloat(query[lngKey])]);
|
|
}
|
|
}
|
|
|
|
// 3. Extract Destination (toLat, toLng)
|
|
if (query.toLat && query.toLng) {
|
|
waypoints.push([parseFloat(query.toLat), parseFloat(query.toLng)]);
|
|
}
|
|
|
|
const profile = query.profile || 'car';
|
|
const steps = query.steps === 'true';
|
|
const locale = query.locale || 'en';
|
|
const alternatives = query.alternatives === 'true';
|
|
|
|
return this.mapsService.getRoute(waypoints, profile, steps, locale, alternatives);
|
|
}
|
|
|
|
@Get('config')
|
|
@ApiOperation({ summary: 'Get map configuration for the region 🗺️' })
|
|
async getConfig() {
|
|
return this.mapsService.getMapConfig();
|
|
}
|
|
}
|