import { Colour, Shape, Symbol } from "facilmap-types"; import { makeTextColour, quoteHtml } from "facilmap-utils"; import L, { Icon } from "leaflet"; const rawIconsContext = require.context("../../assets/icons"); const rawIcons: Record> = {}; for (const key of rawIconsContext.keys() as string[]) { const [set, fname] = key.split("/").slice(-2); if (!rawIcons[set]) rawIcons[set] = {}; rawIcons[set][fname.replace(/\.svg$/, "")] = rawIconsContext(key); } const iconList = Object.keys(rawIcons).map((key) => Object.keys(rawIcons[key])).flat(); export const RAINBOW_STOPS = ``; interface ShapeInfo { svg: string; highlightSvg: string; height: number; width: number; baseX: number; baseY: number; } const MARKER_SHAPES: Partial> = { drop: { svg: ` %SYMBOL%`, highlightSvg: ` %SYMBOL%`, height: 31, width: 23, baseX: 12, baseY: 31 }, circle: { svg: ` %SYMBOL%`, highlightSvg: ` %SYMBOL%`, height: 26, width: 26, baseX: 13, baseY: 13 } }; const sizes: Record = { osmi: 580, mdiconic: 1000, glyphicons: 1410 }; export function getIcon(colour: Colour, size: number, iconName: string): string | undefined { const set = Object.keys(rawIcons).filter((i) => (rawIcons[i][iconName]))[0]; if(!set) return undefined; if(set == "osmi") { return `${rawIcons[set][iconName].replace(/#000/g, colour)}`; } const div = document.createElement('div'); div.innerHTML = rawIcons[set][iconName]; const el = div.firstChild as SVGElement; const scale = size / sizes[set]; const moveX = (sizes[set] - Number(el.getAttribute("width"))) / 2; const moveY = (sizes[set] - Number(el.getAttribute("height"))) / 2; return `${el.innerHTML}`; } export function getSymbolCode(colour: Colour, size: number, symbol?: Symbol): string { if(symbol && iconList.includes(symbol)) return getIcon(colour, size, symbol)!; else if(symbol && symbol.length == 1) return `${quoteHtml(symbol)}`; else return ``; } export function createSymbol(colour: Colour, height: number, symbol?: Symbol): string { const svg = `` + `` + getSymbolCode('#'+colour, height, symbol) + ``; return `data:image/svg+xml,${encodeURIComponent(svg)}`; } export function createSymbolHtml(colour: string, height: number | string, symbol?: Symbol): string { return `` + getSymbolCode(colour, 25, symbol) + ``; } export function createMarkerGraphic(colour = "ffffff", height: number, symbol?: Symbol, shape?: Shape, padding = 0, highlight = false): string { const borderColour = makeTextColour(colour, 0.3); padding = Math.max(padding, highlight ? 10 * height / 31 : 0); const shapeObj = (shape && MARKER_SHAPES[shape]) || MARKER_SHAPES.drop!; const shapeCode = (highlight ? shapeObj.highlightSvg : shapeObj.svg) .replace(/%BORDER_COLOUR%/g, "#"+borderColour) .replace(/%COLOUR%/g, colour == null ? "url(#rainbow)" : "#" + colour) .replace(/%SYMBOL%/g, getSymbolCode("#"+borderColour, 17, symbol)); const scale = height / 31; return "data:image/svg+xml,"+encodeURIComponent(`` + `` + (colour == null ? `${RAINBOW_STOPS}` : ``) + `` + shapeCode + `` + ``); } export function createMarkerIcon(colour: Colour, height: number, symbol?: Symbol, shape?: Shape, padding = 0, highlight = false): Icon { const scale = height / 31; padding = Math.max(padding, highlight ? 10 * scale : 0); const shapeObj = (shape && MARKER_SHAPES[shape]) || MARKER_SHAPES.drop!; return L.icon({ iconUrl: createMarkerGraphic(colour, height, symbol, shape, padding, highlight), iconSize: [padding*2 + shapeObj.width*scale, padding*2 + shapeObj.height*scale], iconAnchor: [padding + Math.round(shapeObj.baseX*scale), padding + Math.round(shapeObj.baseY*scale)], popupAnchor: [0, -height] }); }