Step 1:
=====
Create a Static Container Region.
Name: Saler Visiting Map
HTML Code:
<!-- Leaflet CSS & JS -->
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
<!-- MarkerCluster CSS & JS -->
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster/dist/MarkerCluster.css" />
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster/dist/MarkerCluster.Default.css" />
<script src="https://unpkg.com/leaflet.markercluster/dist/leaflet.markercluster.js"></script>
<!-- Map container -->
<div id="map" style="height:700px; width:100%;"></div>
Static ID: map
Step 2:
=====
Create Page Items.
- P66_SALESREP_NUMBER
- P66_FROM_DATE
- P66_TO_DATE
And Create a Submit Button.
Step 3:
=====
=====
Create an Ajax Callback process.
Name: GET_LOCATIONS_JSON
Name: GET_LOCATIONS_JSON
PLSQL Code:
DECLARE
l_json CLOB;
l_buffer VARCHAR2(32767);
l_amount BINARY_INTEGER := 32000;
l_pos INTEGER := 1;
l_length INTEGER;
BEGIN
SELECT JSON_ARRAYAGG(
JSON_OBJECT(
'id' VALUE r.retailer_id,
'title' VALUE NVL(r.retailer_name,'Retailer Location'),
'lat' VALUE r.latitude,
'lng' VALUE r.longitude
) RETURNING CLOB
)
INTO l_json
FROM xx_retailer r
WHERE r.latitude IS NOT NULL
AND r.longitude IS NOT NULL
AND ( :P23004_SALESREP_NUMBER IS NULL OR r.salesrep_number = :P23004_SALESREP_NUMBER )
AND ( :P23004_FROM_DATE IS NULL OR TRUNC(r.creation_date) >= TO_DATE(:P23004_FROM_DATE,'YYYY-MM-DD') )
AND ( :P23004_TO_DATE IS NULL OR TRUNC(r.creation_date) <= TO_DATE(:P23004_TO_DATE,'YYYY-MM-DD') )
--------------
--------------
AND r.latitude BETWEEN NVL(apex_application.g_x01,-90) AND NVL(apex_application.g_x03,90)
AND r.longitude BETWEEN NVL(apex_application.g_x02,-180) AND NVL(apex_application.g_x04,180);
IF l_json IS NULL THEN
l_json := '[]';
END IF;
owa_util.mime_header('application/json', FALSE);
htp.p('Cache-Control: no-cache');
owa_util.http_header_close;
l_length := DBMS_LOB.getlength(l_json);
WHILE l_pos <= l_length LOOP
DBMS_LOB.read(l_json, l_amount, l_pos, l_buffer);
htp.prn(l_buffer);
l_pos := l_pos + l_amount;
END LOOP;
END;
Step 4:
=====
=====
Create Page Load Dynamic Action.
Action Name: Ajax call by JavaScript
Action: Execute JavaScript Code
Code:
Action Name: Ajax call by JavaScript
Action: Execute JavaScript Code
Code:
// ---------- Globals ----------
var map, markerCluster, markersMap = {}; // markersMap: { id -> marker }
var _initialFit = false;
var _debounceTimer = null;
// ---------- Helpers ----------
function parseNum(v) {
if (v === undefined || v === null) return null;
var n = Number(v);
return isNaN(n) ? null : n;
}
// ---------- Load data for current bounds ----------
function loadVisibleData() {
if (!map) return;
var b = map.getBounds();
var south = b.getSouth();
var west = b.getWest();
var north = b.getNorth();
var east = b.getEast();
// send bounds as x01..x04, and submit page items for filters
apex.server.process('GET_LOCATIONS_JSON', {
x01: south,
x02: west,
x03: north,
x04: east,
pageItems: '#P23004_SALESREP_NUMBER,#P23004_FROM_DATE,#P23004_TO_DATE'
}, {
dataType: 'text',
success: function(data) {
try {
// debug: uncomment if you need to inspect raw JSON
// console.log("RAW response:", data);
var locations = JSON.parse(data || '[]');
// build set of returned ids (as strings)
var newIds = {};
locations.forEach(function(loc) {
if (loc && loc.id !== null && loc.id !== undefined) {
newIds[String(loc.id)] = true;
}
});
// 1) Remove markers that are currently loaded but NOT in newIds
for (var existingId in markersMap) {
if (!newIds[existingId]) {
try {
markerCluster.removeLayer(markersMap[existingId]);
} catch (e) { /* ignore */ }
delete markersMap[existingId];
}
}
// 2) Add markers for ids that are in newIds but not yet loaded
locations.forEach(function(loc) {
if (!loc || loc.id === undefined || loc.lat === undefined || loc.lng === undefined) return;
var id = String(loc.id);
if (markersMap[id]) return; // already added
var lat = parseNum(loc.lat);
var lng = parseNum(loc.lng);
if (lat === null || lng === null) return;
var marker = L.marker([lat, lng]);
if (loc.title) marker.bindPopup(String(loc.title));
markersMap[id] = marker;
markerCluster.addLayer(marker);
});
// optional: on first meaningful load, fit bounds
if (!_initialFit) {
var all = Object.values(markersMap);
if (all.length > 0) {
var group = L.featureGroup(all);
map.fitBounds(group.getBounds(), { maxZoom: 16 });
_initialFit = true;
}
}
} catch (e) {
console.error("Failed to parse JSON or render markers:", e, data);
// Open Network tab and inspect GET_LOCATIONS_JSON response
}
},
error: function(xhr, status, err) {
console.error("AJAX error:", status, err);
}
});
}
// ---------- Initialize Map ----------
function initMap23004() {
// avoid double init
if (map) return;
map = L.map('map', { preferCanvas: true }).setView([23.8103, 90.4125], 7);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 18,
attribution: '© OpenStreetMap contributors'
}).addTo(map);
// marker cluster
markerCluster = L.markerClusterGroup();
map.addLayer(markerCluster);
// initial load (use a reasonable Bangladesh bounding box)
loadVisibleData();
// debounced moveend
map.on('moveend', function() {
if (_debounceTimer) clearTimeout(_debounceTimer);
_debounceTimer = setTimeout(function() {
loadVisibleData();
}, 300);
});
// optional: if user changes filters (page items), reload map
// create a dynamic-action-like watcher: if you have a submit button, call loadVisibleData() on click
}
// start
initMap23004();
Tags:
Oracle Apex (NPG)