2026-06-23 10:04:23 +00:00
/**
2026-07-30 09:33:03 +00:00
* Export Intel map — Leaflet + clustering (multi-instance per tab)
2026-06-23 10:04:23 +00:00
*/
window . ExportIntelMap = ( function () {
var HALAL_COLORS = {
hot : '#22c55e' ,
warm : '#eab308' ,
mild : '#f97316' ,
low : '#64748b' ,
};
var TYPE_CFG = {
distributor : { color : '#f59e0b' , icon : '📦' , label : 'Distributeur' },
wholesaler : { color : '#eab308' , icon : '🏪' , label : 'Groothandel' },
importer : { color : '#f97316' , icon : '🚢' , label : 'Importeur' },
logistics : { color : '#38bdf8' , icon : '🚚' , label : 'Logistiek' },
contract_caterer : { color : '#a78bfa' , icon : '🏢' , label : 'Cateraar' },
restaurant : { color : '#34d399' , icon : '🍽️' , label : 'Restaurant' },
doner_shoarma : { color : '#4ade80' , icon : '🥙' , label : 'Döner / shoarma' },
butcher : { color : '#f87171' , icon : '🥩' , label : 'Slager' },
foodservice : { color : '#2dd4bf' , icon : '🍴' , label : 'Foodservice' },
};
2026-07-30 09:33:03 +00:00
var instances = {};
var DEFAULT_ID = 'ei-map' ;
2026-06-23 10:04:23 +00:00
function cfg ( type ) {
return TYPE_CFG [ type ] || { color : '#0ea5e9' , icon : '📍' , label : String ( type || 'entity' ). replace ( /_/g , ' ' ) };
}
function escapeHtml ( s ) {
return String ( s || '' )
. replace ( /&/g , '&' )
. replace ( /</g , '<' )
. replace ( />/g , '>' )
. replace ( /"/g , '"' );
}
function row ( label , val , link ) {
if ( ! val ) return '' ;
var inner = link
? '<a href="' + escapeHtml ( link ) + '" target="_blank" rel="noopener">' + escapeHtml ( val ) + '</a>'
: escapeHtml ( val );
return (
'<div class="ei-popup-row">' +
'<span class="ei-popup-k">' + escapeHtml ( label ) + '</span>' +
'<span class="ei-popup-v">' + inner + '</span>' +
'</div>'
);
}
2026-07-30 09:33:03 +00:00
function normalizeUrl ( u ) {
if ( ! u ) return null ;
u = String ( u ). trim ();
if ( ! u ) return null ;
if ( /^mailto:/i . test ( u ) || /^tel:/i . test ( u )) return u ;
if ( ! /^https?:\/\//i . test ( u )) u = 'https://' + u . replace ( /^\/+/ , '' );
return u ;
}
function channelList ( items , cls ) {
if ( ! items || ! items . length ) return '' ;
return items . map ( function ( it ) {
var val = escapeHtml ( it . value || it . display || '' );
var label = escapeHtml ( it . label || '' );
var href = it . href || it . url ;
if ( href ) {
return '<a class="ei-popup-link ' + ( cls || '' ) + '" href="' + escapeHtml ( href ) + '" target="_blank" rel="noopener" title="' + val + '">' +
( label ? '<span class="ei-popup-link-label">' + label + '</span>' : '' ) +
'<span class="ei-popup-link-val">' + val + '</span></a>' ;
}
return '<div class="ei-popup-plain">' + ( label ? '<span class="ei-popup-link-label">' + label + '</span>' : '' ) +
'<span class="ei-popup-link-val">' + val + '</span></div>' ;
}). join ( '' );
}
function contactPeopleBlock ( people ) {
if ( ! people || ! people . length ) return '' ;
var cards = people . map ( function ( c ) {
var head = escapeHtml ( c . name || c . role || 'Contact' );
var sub = escapeHtml ([ c . role , c . title , c . department ]. filter ( Boolean ). join ( ' · ' ));
var bits = [];
if ( c . email ) bits . push ( '<a class="ei-popup-link" href="mailto:' + escapeHtml ( c . email ) + '">📧 ' + escapeHtml ( c . email ) + '</a>' );
if ( c . email_alt ) bits . push ( '<a class="ei-popup-link" href="mailto:' + escapeHtml ( c . email_alt ) + '">📧 ' + escapeHtml ( c . email_alt ) + ' (alt)</a>' );
if ( c . phone ) bits . push ( '<a class="ei-popup-link" href="tel:' + escapeHtml ( c . phone ) + '">📞 ' + escapeHtml ( c . phone ) + '</a>' );
if ( c . mobile ) bits . push ( '<a class="ei-popup-link" href="tel:' + escapeHtml ( c . mobile ) + '">📱 ' + escapeHtml ( c . mobile ) + '</a>' );
if ( c . whatsapp ) bits . push ( '<a class="ei-popup-link" href="https://wa.me/' + escapeHtml ( String ( c . whatsapp ). replace ( /\D/g , '' )) + '" target="_blank" rel="noopener">💬 ' + escapeHtml ( c . whatsapp ) + '</a>' );
if ( c . website ) bits . push ( '<a class="ei-popup-link" href="' + escapeHtml ( c . website ) + '" target="_blank" rel="noopener">🌐 Website</a>' );
if ( c . linkedin_url ) bits . push ( '<a class="ei-popup-link" href="' + escapeHtml ( c . linkedin_url ) + '" target="_blank" rel="noopener">in LinkedIn</a>' );
return '<div class="ei-popup-person">' +
'<div class="ei-popup-person-head">' + head + ( c . is_primary ? ' <span class="ei-popup-primary">primair</span>' : '' ) + '</div>' +
( sub ? '<div class="ei-popup-person-sub">' + sub + '</div>' : '' ) +
( bits . length ? '<div class="ei-popup-person-links">' + bits . join ( '' ) + '</div>' : '' ) +
'</div>' ;
}). join ( '' );
return '<div class="ei-popup-section"><div class="ei-popup-section-title">Contactpersonen</div>' + cards + '</div>' ;
}
function reachBlock ( p ) {
var r = p . reach || {};
if ( ! r . has_any && ! p . email && ! p . phone && ! ( p . websites && p . websites . length )) {
return '<div class="ei-popup-empty-contact">Nog geen contact — sync contacten of vul handmatig aan.</div>' ;
}
var html = '<div class="ei-popup-reach">' ;
if (( r . emails && r . emails . length ) || p . email ) {
var emails = r . emails && r . emails . length ? r . emails : ( p . email ? [{ label : 'E-mail' , value : p . email , href : 'mailto:' + p . email }] : []);
html += '<div class="ei-popup-section"><div class="ei-popup-section-title">E-mail</div><div class="ei-popup-channel-list">' + channelList ( emails ) + '</div></div>' ;
}
if (( r . phones && r . phones . length ) || p . phone ) {
var phones = r . phones && r . phones . length ? r . phones : ( p . phone ? [{ label : 'Telefoon' , value : p . phone , href : 'tel:' + p . phone }] : []);
html += '<div class="ei-popup-section"><div class="ei-popup-section-title">Telefoon</div><div class="ei-popup-channel-list">' + channelList ( phones ) + '</div></div>' ;
}
var webHtml = websitesBlock ( p );
if ( webHtml ) html += webHtml . replace ( 'ei-popup-row ei-popup-websites' , 'ei-popup-section ei-popup-websites' ). replace ( 'ei-popup-k">Websites' , 'ei-popup-section-title">Websites' ). replace ( 'ei-popup-v ei-popup-web-list' , 'ei-popup-web-list' );
if ( r . addresses && r . addresses . length ) {
html += '<div class="ei-popup-section"><div class="ei-popup-section-title">Adres</div><div class="ei-popup-channel-list">' + channelList ( r . addresses ) + '</div></div>' ;
}
if ( r . social && r . social . length ) {
html += '<div class="ei-popup-section"><div class="ei-popup-section-title">Social</div><div class="ei-popup-channel-list">' + channelList ( r . social ) + '</div></div>' ;
}
if ( r . maps_url ) {
html += '<div class="ei-popup-section"><a class="ei-popup-maps" href="' + escapeHtml ( r . maps_url ) + '" target="_blank" rel="noopener">📍 Open in Google Maps</a></div>' ;
}
html += contactPeopleBlock ( r . contact_people );
html += '</div>' ;
return html ;
}
function websitesBlock ( p ) {
var sites = p . websites ;
if (( ! sites || ! sites . length ) && p . website ) {
var w = normalizeUrl ( p . website );
if ( w ) sites = [{ label : 'Organisatie' , url : w , display : p . website }];
}
if ( ! sites || ! sites . length ) return '' ;
var links = sites . map ( function ( s ) {
var href = normalizeUrl ( s . url || s );
if ( ! href ) return '' ;
var label = escapeHtml ( s . label || 'Website' );
var disp = escapeHtml ( s . display || s . url || '' );
return '<a class="ei-popup-web" href="' + escapeHtml ( href ) + '" target="_blank" rel="noopener" title="' + disp + '">' + label + '</a>' ;
}). filter ( Boolean ). join ( '' );
if ( ! links ) return '' ;
return (
'<div class="ei-popup-row ei-popup-websites">' +
'<span class="ei-popup-k">Websites</span>' +
'<span class="ei-popup-v ei-popup-web-list">' + links + '</span>' +
'</div>'
);
}
2026-06-23 10:04:23 +00:00
function halalColor ( p ) {
var tier = p . halal_tier || 'low' ;
return HALAL_COLORS [ tier ] || HALAL_COLORS . low ;
}
2026-07-30 09:33:03 +00:00
function MapInstance ( containerId ) {
this . containerId = containerId ;
this . map = null ;
this . clusterLayer = null ;
this . onEntityClick = null ;
this . halalMode = false ;
this . markersById = {};
}
MapInstance . prototype . popupHtml = function ( p ) {
2026-06-23 10:04:23 +00:00
var c = cfg ( p . entity_type );
var id = p . id ;
var halalRow = '' ;
if ( p . halal_score != null ) {
2026-07-30 09:33:03 +00:00
halalRow = row ( 'Halal kans' , p . halal_score + '/100' + ( this . halalMode ? ' · ' + ( p . halal_tier || '' ) : '' ));
2026-06-23 10:04:23 +00:00
}
var contactBits = [];
if ( p . email ) contactBits . push ( '📧 ' + escapeHtml ( p . email ));
if ( p . phone ) contactBits . push ( '📞 ' + escapeHtml ( p . phone ));
var contactRow = contactBits . length
? '<div class="ei-popup-row"><span class="ei-popup-k">Contact</span><span class="ei-popup-v">' + contactBits . join ( '<br>' ) + '</span></div>'
: '' ;
return (
'<div class="ei-popup-card" data-entity-id="' + escapeHtml ( id ) + '">' +
'<div class="ei-popup-top">' +
2026-07-30 09:33:03 +00:00
'<span class="ei-popup-badge" style="--badge-color:' + ( this . halalMode ? halalColor ( p ) : c . color ) + '">' + c . icon + ' ' + escapeHtml ( c . label ) + '</span>' +
2026-06-23 10:04:23 +00:00
'<span class="ei-popup-flag">' + escapeHtml ( p . country_iso2 || '' ) + '</span>' +
'</div>' +
'<h3 class="ei-popup-name">' + escapeHtml ( p . name ) + '</h3>' +
'<div class="ei-popup-grid">' +
halalRow +
contactRow +
row ( 'Stad' , p . city ) +
row ( 'Adres' , p . address_line ) +
row ( 'E-mail' , p . email , p . email ? 'mailto:' + p . email : null ) +
row ( 'Telefoon' , p . phone , p . phone ? 'tel:' + p . phone : null ) +
2026-07-30 09:33:03 +00:00
websitesBlock ( p ) +
2026-06-23 10:04:23 +00:00
row ( 'Volume' , p . volume_band ) +
row ( 'Contacten' , p . contact_count > 0 ? p . contact_count + ' in registry' : null ) +
row ( 'Confidence' , p . confidence != null ? p . confidence + '%' : null ) +
row ( 'Pipeline' , p . pipeline_stage ) +
'</div>' +
'<div class="ei-popup-actions">' +
'<button type="button" class="ei-popup-btn" data-entity-id="' + escapeHtml ( id ) + '">Volledig profiel →</button>' +
'</div>' +
'</div>'
);
2026-07-30 09:33:03 +00:00
};
2026-06-23 10:04:23 +00:00
2026-07-30 09:33:03 +00:00
MapInstance . prototype . pinIcon = function ( type , p ) {
2026-06-23 10:04:23 +00:00
var c = cfg ( type );
2026-07-30 09:33:03 +00:00
var color = this . halalMode && p && p . halal_score != null ? halalColor ( p ) : c . color ;
var ring = this . halalMode && p && p . halal_tier === 'hot' ? ' ei-pin-hot' : '' ;
2026-06-23 10:04:23 +00:00
return L . divIcon ({
className : 'ei-pin-wrap' ,
html :
'<div class="ei-pin' + ring + '" style="--pin-color:' + color + '">' +
'<span class="ei-pin-ring"></span>' +
'<span class="ei-pin-icon">' + c . icon + '</span>' +
'</div>' ,
iconSize : [ 30 , 30 ],
iconAnchor : [ 15 , 15 ],
popupAnchor : [ 0 , - 16 ],
});
2026-07-30 09:33:03 +00:00
};
2026-06-23 10:04:23 +00:00
2026-07-30 09:33:03 +00:00
MapInstance . prototype . openEntityId = function ( rawId ) {
2026-06-23 10:04:23 +00:00
var id = Number ( rawId );
if ( ! Number . isFinite ( id )) return ;
2026-07-30 09:33:03 +00:00
if ( this . onEntityClick ) {
this . onEntityClick ( id );
2026-06-23 10:04:23 +00:00
return ;
}
try {
document . dispatchEvent ( new CustomEvent ( 'export-intel:open-entity' , { detail : { id : id } }));
} catch ( e ) { /* empty */ }
2026-07-30 09:33:03 +00:00
};
MapInstance . prototype . enrichPopup = function ( entityId , popup ) {
if ( ! entityId || ! popup ) return ;
var self = this ;
fetch ( '/api/export-intel/entities/' + entityId )
. then ( function ( r ) { return r . ok ? r . json () : null ; })
. then ( function ( ent ) {
if ( ! ent || ! popup || ! popup . isOpen || ! popup . isOpen ()) return ;
var merged = {
id : ent . id ,
name : ent . name ,
entity_type : ent . entity_type ,
country_iso2 : ent . country_iso2 ,
city : ent . city ,
address_line : ent . address_line ,
postal_code : ent . postal_code ,
email : ent . email ,
phone : ent . phone ,
website : ent . website ,
websites : ent . websites || [],
reach : ent . reach || null ,
volume_band : ent . volume_band ,
confidence : ent . confidence ,
pipeline_stage : ent . pipeline_stage ,
contact_count : ent . contact_count ,
halal_score : ent . halal_score ,
halal_tier : ent . halal_tier ,
};
popup . setContent ( self . popupHtml ( merged ));
var el = popup . getElement ();
if ( el ) self . wirePopup ( el . querySelector ( '.leaflet-popup-content' ) || el );
})
. catch ( function () { /* keep cached popup */ });
};
2026-06-23 10:04:23 +00:00
2026-07-30 09:33:03 +00:00
MapInstance . prototype . wirePopup = function ( container ) {
2026-06-23 10:04:23 +00:00
if ( ! container ) return ;
2026-07-30 09:33:03 +00:00
var self = this ;
2026-06-23 10:04:23 +00:00
var popupRoot = container . closest ( '.leaflet-popup' ) || container ;
if ( window . L && L . DomEvent ) {
L . DomEvent . disableClickPropagation ( popupRoot );
L . DomEvent . disableScrollPropagation ( popupRoot );
}
var btn = container . querySelector ( '.ei-popup-btn' );
var id = btn && btn . getAttribute ( 'data-entity-id' );
if ( btn && id ) {
var onBtn = function ( e ) {
if ( e ) {
e . preventDefault ();
e . stopPropagation ();
}
2026-07-30 09:33:03 +00:00
self . openEntityId ( id );
2026-06-23 10:04:23 +00:00
};
if ( window . L && L . DomEvent ) {
L . DomEvent . on ( btn , 'click' , onBtn );
L . DomEvent . on ( btn , 'mousedown' , L . DomEvent . stopPropagation );
} else {
btn . addEventListener ( 'click' , onBtn );
btn . addEventListener ( 'mousedown' , function ( e ) { e . stopPropagation (); });
}
}
container . addEventListener ( 'click' , function ( e ) {
if ( e . target . closest ( '.ei-popup-btn' ) || e . target . closest ( 'a' )) return ;
var card = e . target . closest ( '[data-entity-id]' );
2026-07-30 09:33:03 +00:00
if ( card ) self . openEntityId ( card . getAttribute ( 'data-entity-id' ));
2026-06-23 10:04:23 +00:00
});
2026-07-30 09:33:03 +00:00
};
2026-06-23 10:04:23 +00:00
2026-07-30 09:33:03 +00:00
MapInstance . prototype . invalidateSize = function () {
if ( ! this . map ) return ;
var map = this . map ;
2026-07-19 18:36:02 +00:00
map . invalidateSize ( true );
setTimeout ( function () { if ( map ) map . invalidateSize ( true ); }, 120 );
setTimeout ( function () { if ( map ) map . invalidateSize ( true ); }, 400 );
2026-07-30 09:33:03 +00:00
};
2026-07-19 18:36:02 +00:00
2026-07-30 09:33:03 +00:00
MapInstance . prototype . init = function () {
var el = document . getElementById ( this . containerId );
2026-06-23 10:04:23 +00:00
if ( ! el || ! window . L ) return null ;
2026-07-30 09:33:03 +00:00
if ( this . map && this . map . getContainer () === el ) {
this . invalidateSize ();
return this . map ;
2026-07-19 18:42:47 +00:00
}
2026-07-30 09:33:03 +00:00
if ( this . map ) {
this . map . remove ();
this . map = null ;
this . clusterLayer = null ;
2026-06-23 10:04:23 +00:00
}
2026-07-30 09:33:03 +00:00
var self = this ;
this . map = L . map ( this . containerId , { zoomControl : true , attributionControl : true }). setView ([ 20 , 10 ], 2 );
2026-07-19 18:36:02 +00:00
L . tileLayer ( '/api/map/tiles/{z}/{x}/{y}.png' , {
2026-06-23 10:04:23 +00:00
attribution : '© OSM © CARTO' ,
maxZoom : 19 ,
2026-07-30 09:33:03 +00:00
}). addTo ( this . map );
2026-06-23 10:04:23 +00:00
if ( window . L . markerClusterGroup ) {
2026-07-30 09:33:03 +00:00
this . clusterLayer = L . markerClusterGroup ({
2026-06-23 10:04:23 +00:00
maxClusterRadius : 42 ,
spiderfyOnMaxZoom : true ,
showCoverageOnHover : false ,
zoomToBoundsOnClick : true ,
iconCreateFunction : function ( cluster ) {
var n = cluster . getChildCount ();
var size = n < 10 ? 'sm' : n < 50 ? 'md' : 'lg' ;
return L . divIcon ({
html : '<div class="ei-cluster ei-cluster-' + size + '"><span>' + n + '</span></div>' ,
className : 'ei-cluster-wrap' ,
iconSize : L . point ( 44 , 44 ),
});
},
});
2026-07-30 09:33:03 +00:00
this . map . addLayer ( this . clusterLayer );
2026-06-23 10:04:23 +00:00
} else {
2026-07-30 09:33:03 +00:00
this . clusterLayer = L . layerGroup ();
this . map . addLayer ( this . clusterLayer );
2026-06-23 10:04:23 +00:00
}
2026-07-30 09:33:03 +00:00
this . map . on ( 'popupopen' , function ( e ) {
2026-06-23 10:04:23 +00:00
var root = e . popup && e . popup . getElement ();
if ( ! root ) return ;
if ( window . L && L . DomEvent ) {
L . DomEvent . disableClickPropagation ( root );
L . DomEvent . disableScrollPropagation ( root );
}
2026-07-30 09:33:03 +00:00
self . wirePopup ( root . querySelector ( '.leaflet-popup-content' ) || root );
var card = root . querySelector ( '[data-entity-id]' );
var eid = card && card . getAttribute ( 'data-entity-id' );
if ( eid ) self . enrichPopup ( Number ( eid ), e . popup );
2026-06-23 10:04:23 +00:00
});
2026-07-30 09:33:03 +00:00
this . invalidateSize ();
return this . map ;
};
2026-06-23 10:04:23 +00:00
2026-07-30 09:33:03 +00:00
MapInstance . prototype . setFeatures = function ( geojson , opts ) {
2026-07-19 18:47:12 +00:00
opts = opts || {};
2026-07-30 09:33:03 +00:00
if ( ! this . map || ! this . clusterLayer ) return ;
this . clusterLayer . clearLayers ();
this . markersById = {};
2026-06-23 10:04:23 +00:00
var features = ( geojson && geojson . features ) || [];
var markers = [];
2026-07-30 09:33:03 +00:00
var self = this ;
2026-06-23 10:04:23 +00:00
features . forEach ( function ( f ) {
var coords = f . geometry && f . geometry . coordinates ;
if ( ! coords ) return ;
var p = f . properties || {};
2026-07-30 09:33:03 +00:00
var marker = L . marker ([ coords [ 1 ], coords [ 0 ]], { icon : self . pinIcon ( p . entity_type , p ) });
2026-06-23 10:04:23 +00:00
marker . _eiId = p . id ;
2026-07-30 09:33:03 +00:00
if ( p . id != null ) self . markersById [ p . id ] = marker ;
marker . bindPopup ( self . popupHtml ( p ), { maxWidth : 360 , minWidth : 280 , maxHeight : 420 , className : 'ei-leaflet-popup' , autoClose : false , closeOnClick : false });
marker . on ( 'click' , function ( e ) {
if ( window . L && L . DomEvent ) L . DomEvent . stopPropagation ( e );
marker . openPopup ();
if ( self . onEntityClick && p . id != null ) self . onEntityClick ( p . id );
2026-06-23 10:04:23 +00:00
});
markers . push ( marker );
});
2026-07-30 09:33:03 +00:00
if ( this . clusterLayer . addLayers ) this . clusterLayer . addLayers ( markers );
else markers . forEach ( function ( m ) { self . clusterLayer . addLayer ( m ); });
2026-06-23 10:04:23 +00:00
2026-07-30 09:33:03 +00:00
this . invalidateSize ();
2026-07-19 18:36:02 +00:00
2026-07-19 18:47:12 +00:00
if ( opts . autoFit === false ) {
2026-07-30 09:33:03 +00:00
this . map . setView ([ 20 , 10 ], 2 );
2026-07-19 18:47:12 +00:00
} else if ( features . length === 1 ) {
2026-06-23 10:04:23 +00:00
var c = features [ 0 ]. geometry . coordinates ;
2026-07-30 09:33:03 +00:00
this . map . setView ([ c [ 1 ], c [ 0 ]], 10 );
} else if ( opts . autoFit && markers . length > 1 && this . clusterLayer . getBounds ) {
2026-06-23 10:04:23 +00:00
try {
2026-07-30 09:33:03 +00:00
this . map . fitBounds ( this . clusterLayer . getBounds (), { padding : [ 40 , 40 ], maxZoom : 12 });
2026-06-23 10:04:23 +00:00
} catch ( e ) { /* empty */ }
}
2026-07-30 09:33:03 +00:00
};
MapInstance . prototype . setHalalMode = function ( on ) {
this . halalMode = !! on ;
};
MapInstance . prototype . setOnEntityClick = function ( fn ) {
this . onEntityClick = typeof fn === 'function' ? fn : null ;
};
MapInstance . prototype . flyTo = function ( lat , lon , zoom ) {
if ( this . map && lat && lon ) this . map . setView ([ lat , lon ], zoom || 10 );
};
MapInstance . prototype . highlightEntity = function ( id ) {
var marker = this . markersById [ id ];
if ( ! marker || ! this . map ) return ;
var latlng = marker . getLatLng ();
this . map . setView ( latlng , Math . max ( this . map . getZoom (), 14 ));
marker . openPopup ();
};
MapInstance . prototype . closePopup = function () {
if ( this . map ) this . map . closePopup ();
};
MapInstance . prototype . destroy = function () {
if ( this . map ) {
this . map . remove ();
this . map = null ;
this . clusterLayer = null ;
}
delete instances [ this . containerId ];
};
function resolveId ( containerId ) {
return containerId || DEFAULT_ID ;
2026-06-23 10:04:23 +00:00
}
2026-07-30 09:33:03 +00:00
function getOrCreate ( containerId ) {
var id = resolveId ( containerId );
if ( ! instances [ id ]) instances [ id ] = new MapInstance ( id );
return instances [ id ];
2026-06-23 10:04:23 +00:00
}
2026-07-30 09:33:03 +00:00
function init ( containerId ) {
return getOrCreate ( containerId ). init ();
2026-06-23 10:04:23 +00:00
}
2026-07-30 09:33:03 +00:00
function setFeatures ( geojson , opts , containerId ) {
getOrCreate ( containerId ). setFeatures ( geojson , opts );
2026-06-23 10:04:23 +00:00
}
2026-07-30 09:33:03 +00:00
function setHalalMode ( on , containerId ) {
getOrCreate ( containerId ). setHalalMode ( on );
2026-06-23 10:04:23 +00:00
}
2026-07-30 09:33:03 +00:00
function setOnEntityClick ( fn , containerId ) {
getOrCreate ( containerId ). setOnEntityClick ( fn );
2026-06-23 10:04:23 +00:00
}
2026-07-30 09:33:03 +00:00
function flyTo ( lat , lon , zoom , containerId ) {
getOrCreate ( containerId ). flyTo ( lat , lon , zoom );
}
function highlightEntity ( id , containerId ) {
getOrCreate ( containerId ). highlightEntity ( id );
}
function closePopup ( containerId ) {
getOrCreate ( containerId ). closePopup ();
}
function destroy ( containerId ) {
if ( containerId ) getOrCreate ( containerId ). destroy ();
else {
Object . keys ( instances ). forEach ( function ( k ) { instances [ k ]. destroy (); });
2026-06-23 10:04:23 +00:00
}
}
2026-07-30 09:33:03 +00:00
function invalidateAll () {
Object . keys ( instances ). forEach ( function ( k ) { instances [ k ]. invalidateSize (); });
}
2026-07-19 18:36:02 +00:00
if ( typeof window !== 'undefined' ) {
2026-07-30 09:33:03 +00:00
window . addEventListener ( 'resize' , invalidateAll );
2026-07-19 18:36:02 +00:00
}
2026-07-30 09:33:03 +00:00
return {
init : init ,
setFeatures : setFeatures ,
setOnEntityClick : setOnEntityClick ,
setHalalMode : setHalalMode ,
flyTo : flyTo ,
closePopup : closePopup ,
highlightEntity : highlightEntity ,
destroy : destroy ,
invalidateAll : invalidateAll ,
TYPE_CFG : TYPE_CFG ,
cfg : cfg ,
};
2026-06-23 10:04:23 +00:00
})();