import { IconLayer, TextLayer } from '@deck.gl/layers';
import type { Layer, PickingInfo } from '@deck.gl/core';
import { svgToDataUri } from '../../utils/svgToDataUri';
import { middleEastAirports } from '../../data/airports';
import type { Airport } from '../../data/airports';
export { type Airport };
export const IRAN_AIRPORT_COUNT = middleEastAirports.length;
const US_BASE_ICAOS = new Set([
'OMAD', 'OTBH', 'OKAJ', 'LTAG', 'OEPS', 'ORAA', 'ORBD', 'OBBS', 'OMTH', 'HDCL',
]);
function getAirportColor(airport: Airport): string {
const isMil = airport.type === 'military';
const isUS = isMil && US_BASE_ICAOS.has(airport.icao);
if (isUS) return '#3b82f6';
if (isMil) return '#ef4444';
if (airport.type === 'international') return '#f59e0b';
return '#7c8aaa';
}
function airportSvg(color: string, size: number): string {
return ``;
}
const iconCache = new Map();
function getIconUrl(airport: Airport): string {
const color = getAirportColor(airport);
const size = airport.type === 'military' && US_BASE_ICAOS.has(airport.icao) ? 48 : 40;
const key = `${color}-${size}`;
if (!iconCache.has(key)) {
iconCache.set(key, svgToDataUri(airportSvg(color, size)));
}
return iconCache.get(key)!;
}
function hexToRgba(hex: string, alpha = 255): [number, number, number, number] {
const r = parseInt(hex.slice(1, 3), 16);
const g = parseInt(hex.slice(3, 5), 16);
const b = parseInt(hex.slice(5, 7), 16);
return [r, g, b, alpha];
}
export interface IranAirportLayerConfig {
visible: boolean;
sc: number;
fs?: number;
onPick: (airport: Airport) => void;
}
export function createIranAirportLayers(config: IranAirportLayerConfig): Layer[] {
const { visible, sc, onPick } = config;
const fs = config.fs ?? 1;
if (!visible) return [];
const iconLayer = new IconLayer({
id: 'iran-airport-icon',
data: middleEastAirports,
getPosition: (d) => [d.lng, d.lat],
getIcon: (d) => {
const isMilUS = d.type === 'military' && US_BASE_ICAOS.has(d.icao);
const sz = isMilUS ? 48 : 40;
return { url: getIconUrl(d), width: sz, height: sz, anchorX: sz / 2, anchorY: sz / 2 };
},
getSize: (d) => (d.type === 'military' && US_BASE_ICAOS.has(d.icao) ? 20 : 16) * sc,
updateTriggers: { getSize: [sc] },
pickable: true,
onClick: (info: PickingInfo) => {
if (info.object) onPick(info.object);
return true;
},
});
const labelLayer = new TextLayer({
id: 'iran-airport-label',
data: middleEastAirports,
getPosition: (d) => [d.lng, d.lat],
getText: (d) => {
const nameKo = d.nameKo ?? d.name;
return nameKo.length > 10 ? nameKo.slice(0, 10) + '..' : nameKo;
},
getSize: 11 * sc * fs,
updateTriggers: { getSize: [sc] },
getColor: (d) => hexToRgba(getAirportColor(d)),
getTextAnchor: 'middle',
getAlignmentBaseline: 'top',
getPixelOffset: [0, 10],
fontFamily: 'monospace',
fontWeight: 600,
fontSettings: { sdf: true },
outlineWidth: 8,
outlineColor: [0, 0, 0, 255],
billboard: false,
characterSet: 'auto',
});
return [iconLayer, labelLayer];
}