The idea behind this proof-of-concept was to expand a JavaScript-based feature we’ve been using for years - previously limited to displaying extracted latitude and longitude values of a single instance for individual quality issues. Our goal was to use a Business Rule to display any number of locations on a map, such as construction sites or similar points of interest. As part of this, we also wanted to enable the display of additional information when clicking on a location marker (in another use case, we even included images). Perhaps it can also serve as inspiration for others to take this idea further.
--
Sharing this solution was prompted by Sébastien Anselment’s knowledge base article,
'[EXTERNAL] OpenStreetMap Integration in Portal with Leaflet'
(https://community.webcon.com/posts/post/external-openstreetmap-integration-in-portal-with-leaflet/569/3).
* Leaflet (https://leafletjs.com)
* (c) 2010–2023 Vladimir Agafonkin
* Licensed under the BSD 2-Clause License
* https://github.com/Leaflet/Leaflet/blob/main/LICENSE
*
* If used in your project, make sure to retain this notice as required by the license.
// Map functionality uses Leaflet (https://leafletjs.com)
// Map tiles by OpenStreetMap contributors — https://www.openstreetmap.org/copyright
Uses Leaflet.js v1.7.1 (2020). Current stable: v1.9.4 (2023). For CDN usage, SRI/Integrity is recommended.



<meta charset="UTF-8">
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script>
<style>
#map {
height: 480px;
width: 100%;
}
#popup {
position: fixed;
top: 50%;
left: 50%;
width: 1024px;
height: 520px;
background: white;
border: 1px solid #ccc;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
z-index: 1000000;
display: none;
transform: translate(-50%, -50%);
}
#popup-header {
background: #f4f4f4;
padding: 10px;
border-bottom: 1px solid #ccc;
display: flex;
justify-content: space-between;
align-items: center;
}
#popup-header h2 {
margin: 0;
font-size: 16px;
}
#close-btn {
background: none;
border: none;
font-size: 16px;
cursor: pointer;
}
#popup-content {
height: calc(100% - 40px);
overflow: hidden;
}
</style>
<script>
/*!
* Leaflet (https://leafletjs.com)
* (c) 2010–2023 Vladimir Agafonkin
* Licensed under the BSD 2-Clause License
* https://github.com/Leaflet/Leaflet/blob/main/LICENSE
*
* If used in your project, make sure to retain this notice as required by the license.
*/
// Map functionality uses Leaflet (https://leafletjs.com)
// Map tiles by OpenStreetMap contributors — https://www.openstreetmap.org/copyright
/* * ---------------------------------------------------------
* LEAFLET LICENSE & ATTRIBUTION
* ---------------------------------------------------------
* Leaflet (https://leafletjs.com)
* Copyright (c) 2010–2023 Vladimir Agafonkin
* Licensed under the BSD 2-Clause License.
* * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
var gpsCoordinates = [
#{BRD:16958}#
];
var mapInitialized = false;
var map;
function initializeMap() {
// OpenStreetMap Standard tile layer
var osmLayer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors',
maxZoom: 19
});
// Initialize map with OSM layer
map = L.map('map', {
layers: [osmLayer],
zoomControl: false
}).setView([49.237394362922295, 12.703130994908106], 6);
// Add layer control (only OSM)
L.control.layers({
"OpenStreetMap": osmLayer
}).addTo(map);
// Add markers and popups
gpsCoordinates.forEach(function(coords, index) {
// Skip row 5 and 6 if first value is empty
if (index >= 4 && !coords[0]) return;
var [lat, lng, kstnr, kstname, kstadresse] = coords;
var popupContent = `
<font size="4"><strong>${kstnr}</strong></font><br>
<strong>Name:</strong> ${kstname}<br>
<strong>Adress:</strong> ${kstadresse}<br>
`;
L.marker([lat, lng]).addTo(map).bindPopup(popupContent);
});
}
// Ensure the popup appears in the topmost frame
function ensurePopupInTopFrame() {
var popup = document.getElementById('popup');
if (window.top !== window.self) {
var topDocument = window.top.document;
if (!topDocument.getElementById('popup')) {
topDocument.body.appendChild(popup);
}
}
}
// Event listener to show the map popup
document.getElementById('show-map-btn').addEventListener('click', function () {
var popup = document.getElementById('popup');
ensurePopupInTopFrame();
window.top.document.getElementById('popup').style.display = 'block';
if (!mapInitialized) {
initializeMap();
mapInitialized = true;
} else {
map.invalidateSize();
}
});
// Event listener to close the popup
document.getElementById('close-btn').addEventListener('click', function () {
window.top.document.getElementById('popup').style.display = 'none';
});
</script>
<button id="show-map-btn">Show on OpenStreetMap</button>
<div id="popup">
<div id="popup-header">
<h2>Custom Title</h2>
<button id="close-btn">×</button>
</div>
<div id="popup-content">
<div id="map"></div>
</div>
</div>