MapView
MoleculeLeaflet-based interactive map. Tooltip-enabled markers, predefined zones (polygon), route lines (polyline), and click-to-add marker mode.
<%- include('modules/ui/MapView/MapView', {
center: [41.015, 28.979],
zoom: 6,
height: 400,
markers: CITIES,
zones: ZONES,
routes: ROUTES,
}) %>
<%- include('modules/ui/MapView/MapView', {
center: [39.5, 35.0],
zoom: 5,
height: 360,
}) %>
<%- include('modules/ui/MapView/MapView', {
center: [39.5, 35.0],
zoom: 5,
height: 360,
zones: ZONES,
routes: ROUTES,
}) %>
<%
// MapView — provider-agnostic interactive map (EJS).
// Mirror of NextJS modules/ui/MapView/index.tsx.
//
// M1: leaflet provider, token-aware CartoDB tiles (Voyager / Dark Matter),
// IntersectionObserver-driven lazy load, fit-to-bounds.
//
// Locals:
// id — DOM id base (auto-generated when omitted)
// provider — 'leaflet' | 'mapbox' | 'google' (default 'leaflet')
// center, zoom — view start
// markers, zones, routes
// fitBoundsPadding — number → enables fit-to-bounds
// tiles — { url, attribution } (both themes) or { light, dark };
// default CARTO Voyager / Dark Matter
// loadingLabel — text shown until the map is built (default 'Loading map…')
// height — px or CSS string
// className — extra root classes
//
// TODO M1+: providers/mapbox + google adapters.
// TODO M2: cluster, hover popup, activeMarkerId, custom marker icons.
// TODO M3: search, geocode, route.
// TODO M4: draw, locate, layer toggle.
// TODO M5: a11y polish, i18n messages, telemetry.
var _id = locals.id || ('map-' + Math.random().toString(36).substr(2, 9));
var _provider = locals.provider || 'leaflet';
var _center = locals.center || [39.9334, 32.8597];
var _zoom = locals.zoom || 6;
var _height = locals.height || 480;
var _markers = locals.markers || [];
var _zones = locals.zones || [];
var _routes = locals.routes || [];
var _fitBoundsPadding = locals.fitBoundsPadding;
var _cls = locals.className || '';
var _tiles = locals.tiles || null;
var _loadingLabel = locals.loadingLabel || 'Loading map…';
if (_provider !== 'leaflet') {
throw new Error('MapView provider "' + _provider + '" is not yet implemented — TODO M1+');
}
// Button base classes — kept in sync with Button.ejs `xs` size + primary/outline variants.
var btnBase = 'inline-flex items-center justify-center gap-2 rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus disabled:opacity-50 disabled:cursor-not-allowed px-2 py-1 text-xs';
var btnPrimary = 'bg-primary text-primary-fg hover:bg-primary-hover';
var btnOutline = 'border border-border text-text-primary hover:bg-surface-overlay';
// CSS height
var _cssHeight = (typeof _height === 'number') ? (_height + 'px') : _height;
%>
<%/*
Inline Card(variant="raised") wrapper with -mx-6 -my-4 cancel-padding inner
so toolbar + map render edge-to-edge inside Card's rounded border.
*/%>
<div class="rounded-xl border border-border overflow-hidden text-left bg-surface-raised shadow-sm<%= _cls ? ' ' + _cls : '' %>"
style="isolation:isolate">
<div class="px-6 py-4">
<div class="-mx-6 -my-4 flex flex-col">
<%- include('./partials/_controls', {
_id: _id,
_zones: _zones,
_routes: _routes,
btnBase: btnBase,
btnPrimary: btnPrimary,
btnOutline: btnOutline
}) %>
<!-- Map canvas -->
<div id="<%= _id %>-map" style="height:<%= _cssHeight %>">
<div data-map-loading class="w-full h-full flex items-center justify-center bg-surface-raised">
<span class="text-sm text-text-secondary"><%= _loadingLabel %></span>
</div>
</div>
</div>
</div>
</div>
<script>
<%- include('./scripts/map-leaflet.js') %>
<%- include('./scripts/markers.js') %>
(function () {
var opts = {
id: '<%- _id %>',
center: [<%- _center[0] %>, <%- _center[1] %>],
zoom: <%- _zoom %>,
markers: <%- JSON.stringify(_markers) %>,
zones: <%- JSON.stringify(_zones) %>,
routes: <%- JSON.stringify(_routes) %>,
fitBoundsPadding: <%- _fitBoundsPadding != null ? _fitBoundsPadding : 'undefined' %>,
tiles: <%- JSON.stringify(_tiles) %>,
onReady: function (ctx) { window.__MapViewMarkers.attach({ id: '<%- _id %>', ctx: ctx }); }
};
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function () { window.__MapViewLeaflet.init(opts); });
} else {
window.__MapViewLeaflet.init(opts);
}
})();
</script>