File size: 2,758 Bytes
41e0c9e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
"""Dark Bay Area map (Leaflet) with glow-orange markers for the transit mode."""
from __future__ import annotations

import base64
import json

_TEMPLATE = r"""<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"/>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<style>
  html,body{margin:0;height:100%;background:#000;font-family:'Courier New',monospace;}
  #map{width:100%;height:100%;background:#000;}
  .leaflet-container{background:#000;}
  #hud{position:absolute;z-index:500;top:10px;left:12px;color:#FF9A1E;
       text-shadow:0 0 8px #FF7A00;font-size:12px;letter-spacing:1px;
       pointer-events:none;line-height:1.5;}
  .lbl{color:#FFB347;text-shadow:0 0 6px #FF7A00;font-size:11px;}
</style>
</head>
<body>
<div id="map"></div>
<div id="hud">&gt;&gt; BAYLINE // 511 LIVE<br/><span id="sub"></span></div>
<script>
const DATA = /*__DATA__*/;
const map = L.map('map', {zoomControl:true, attributionControl:false})
              .setView([37.77,-122.30], 10);
L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png',
            {maxZoom:19}).addTo(map);

const COLORS = {origin:'#FF9A1E', dest:'#19E0FF', incident:'#FF3B3B'};

// Dotted pathway between origin and destination (when both are present).
const _o = (DATA.markers||[]).find(m => m.kind === 'origin');
const _d = (DATA.markers||[]).find(m => m.kind === 'dest');
if (_o && _d) {
  L.polyline([[_o.lat,_o.lon],[_d.lat,_d.lon]], {
    color:'#FF9A1E', weight:3, opacity:0.95, dashArray:'2,9', lineCap:'round'
  }).addTo(map);
}

const pts = [];
(DATA.markers||[]).forEach(m => {
  const c = COLORS[m.kind] || '#FFB347';
  const mk = L.circleMarker([m.lat, m.lon], {
      radius: m.kind==='incident'?6:9, color:c, weight:2,
      fillColor:c, fillOpacity:0.65
  }).addTo(map);
  mk.bindTooltip(m.label||'', {className:'lbl'});
  // glow ring
  L.circleMarker([m.lat,m.lon],{radius:(m.kind==='incident'?12:16),color:c,
      weight:1,opacity:0.35,fill:false}).addTo(map);
  pts.push([m.lat,m.lon]);
});
if (pts.length===1){ map.setView(pts[0], 12); }
else if (pts.length>1){ map.fitBounds(pts, {padding:[40,40]}); }
document.getElementById('sub').textContent = DATA.stamp || '';
</script>
</body>
</html>"""


def build_map_html(markers, stamp: str = "") -> str:
    data = {"markers": markers or [], "stamp": stamp}
    html = _TEMPLATE.replace("/*__DATA__*/", json.dumps(data))
    b64 = base64.b64encode(html.encode("utf-8")).decode("ascii")
    return (
        f'<iframe src="data:text/html;base64,{b64}" '
        'style="width:100%;height:560px;border:0;border-radius:10px;'
        'box-shadow:0 0 24px #ff7a0055, inset 0 0 40px #00000080;"></iframe>'
    )