HTML Map location point show

 


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
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:

// ---------- 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: '&copy; 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();

Post a Comment

Previous Post Next Post