Switch to 100% server-side map clustering
Removes client-side Leaflet MarkerCluster library in favor of server-side clustering at all zoom levels: - Zoom 1-8: Density dots - Zoom 9-15: Server-generated numbered clusters - Zoom 16+: Individual property markers This prevents the visual issue where server-returned clusters were being re-clustered by the client into a single merged marker. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -120,7 +120,7 @@ $view_class = $show_map ? 'is-map-view' : 'is-grid-view';
|
||||
$initial_filters = array(
|
||||
'status' => isset($_GET['property_status']) ? sanitize_text_field($_GET['property_status']) : 'Active',
|
||||
'property_type' => isset($_GET['property_type']) ? sanitize_text_field($_GET['property_type']) : '',
|
||||
'city' => isset($_GET['property_location']) ? sanitize_text_field($_GET['property_location']) : '',
|
||||
'city' => isset($_GET['city']) ? sanitize_text_field($_GET['city']) : '',
|
||||
'min_price' => isset($_GET['min_price']) ? intval($_GET['min_price']) : '',
|
||||
'max_price' => isset($_GET['max_price']) ? intval($_GET['max_price']) : '',
|
||||
'min_beds' => isset($_GET['beds']) ? intval($_GET['beds']) : '',
|
||||
@@ -137,13 +137,8 @@ if (function_exists('mls_get_property_count')) {
|
||||
?>
|
||||
<!-- Leaflet CSS -->
|
||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin=""/>
|
||||
<!-- Leaflet MarkerCluster CSS -->
|
||||
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.4.1/dist/MarkerCluster.css" crossorigin=""/>
|
||||
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.4.1/dist/MarkerCluster.Default.css" crossorigin=""/>
|
||||
<!-- Leaflet JS -->
|
||||
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script>
|
||||
<!-- Leaflet MarkerCluster JS -->
|
||||
<script src="https://unpkg.com/leaflet.markercluster@1.4.1/dist/leaflet.markercluster.js" crossorigin=""></script>
|
||||
<script>
|
||||
var homeprozMapData = {
|
||||
isMapView: <?php echo $show_map ? 'true' : 'false'; ?>,
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
@@ -271,9 +271,8 @@
|
||||
markers: {}, // Object keyed by property ID
|
||||
markerData: {}, // Object keyed by property ID -> {lat, lng, ...}
|
||||
densityLayer: null, // Layer group for density dots (zoom 1-11)
|
||||
clusterLayer: null, // Layer group for server clusters (zoom 12-15)
|
||||
markerCluster: null, // MarkerClusterGroup for individual markers (zoom 16+)
|
||||
markerLayer: null, // Plain layer group for unclustered markers (low count)
|
||||
clusterLayer: null, // Layer group for server clusters (zoom 9-15)
|
||||
markerLayer: null, // Plain layer group for individual markers (zoom 16+)
|
||||
selectedPropertyId: null,
|
||||
isPinClickPan: false, // Flag: true when map pan is caused by pin click (don't clear selection)
|
||||
hoveredPropertyId: null,
|
||||
@@ -304,42 +303,15 @@
|
||||
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>'
|
||||
}).addTo(this.map);
|
||||
|
||||
// Create layer for density dots (zoom 1-11)
|
||||
// Create layer for density dots (zoom 1-8)
|
||||
this.densityLayer = L.layerGroup().addTo(this.map);
|
||||
|
||||
// Create layer for server-side clusters (zoom 12-15)
|
||||
// Create layer for server-side clusters (zoom 9-15)
|
||||
this.clusterLayer = L.layerGroup().addTo(this.map);
|
||||
|
||||
// Create plain layer for unclustered markers (low count)
|
||||
// Create plain layer for individual markers (zoom 16+ or low count)
|
||||
this.markerLayer = L.layerGroup().addTo(this.map);
|
||||
|
||||
// Create marker cluster group for individual markers (when zoomed in)
|
||||
this.markerCluster = L.markerClusterGroup({
|
||||
maxClusterRadius: 50,
|
||||
spiderfyOnMaxZoom: true,
|
||||
showCoverageOnHover: false,
|
||||
zoomToBoundsOnClick: true,
|
||||
disableClusteringAtZoom: 18,
|
||||
chunkedLoading: true,
|
||||
chunkInterval: 200,
|
||||
chunkDelay: 50,
|
||||
iconCreateFunction: function(cluster) {
|
||||
var count = cluster.getChildCount();
|
||||
var size = 'small';
|
||||
if (count >= 100) {
|
||||
size = 'large';
|
||||
} else if (count >= 10) {
|
||||
size = 'medium';
|
||||
}
|
||||
return L.divIcon({
|
||||
html: '<div><span>' + count + '</span></div>',
|
||||
className: 'marker-cluster marker-cluster-' + size,
|
||||
iconSize: L.point(40, 40)
|
||||
});
|
||||
}
|
||||
});
|
||||
this.map.addLayer(this.markerCluster);
|
||||
|
||||
// Bind map events for dynamic loading
|
||||
var self = this;
|
||||
this.map.on('moveend zoomend', function() {
|
||||
@@ -455,7 +427,6 @@
|
||||
clearAllLayers: function() {
|
||||
this.densityLayer.clearLayers();
|
||||
this.clusterLayer.clearLayers();
|
||||
this.markerCluster.clearLayers();
|
||||
this.markerLayer.clearLayers();
|
||||
this.markers = {};
|
||||
|
||||
@@ -653,16 +624,11 @@
|
||||
}
|
||||
});
|
||||
|
||||
// Add markers to appropriate layer based on count
|
||||
// Use plain layer for <= 30 markers (no client-side clustering)
|
||||
// Use MarkerClusterGroup for > 30 markers (client-side clustering)
|
||||
if (markersToAdd.length <= 30) {
|
||||
markersToAdd.forEach(function(marker) {
|
||||
self.markerLayer.addLayer(marker);
|
||||
});
|
||||
} else {
|
||||
this.markerCluster.addLayers(markersToAdd);
|
||||
}
|
||||
// Add all markers to plain layer (server handles clustering)
|
||||
// Individual markers only come at zoom 16+ where no clustering is needed
|
||||
markersToAdd.forEach(function(marker) {
|
||||
self.markerLayer.addLayer(marker);
|
||||
});
|
||||
|
||||
// Reset the pin-click-pan flag now that markers are rendered
|
||||
this.isPinClickPan = false;
|
||||
@@ -844,27 +810,20 @@
|
||||
var needsTemporaryMarker = false;
|
||||
|
||||
if (marker) {
|
||||
// Marker exists - check if it's visible (not clustered and in viewport)
|
||||
// Marker exists - check if it's in viewport
|
||||
var markerLatLng = marker.getLatLng();
|
||||
var inViewport = self.map.getBounds().contains(markerLatLng);
|
||||
|
||||
// Check if marker is clustered (part of a cluster group)
|
||||
var isClustered = false;
|
||||
if (self.markerCluster && self.markerCluster.hasLayer(marker)) {
|
||||
var visibleParent = self.markerCluster.getVisibleParent(marker);
|
||||
isClustered = visibleParent && visibleParent !== marker;
|
||||
}
|
||||
|
||||
if (!isClustered && inViewport) {
|
||||
// Marker is visible as individual pin - highlight it
|
||||
if (inViewport) {
|
||||
// Marker is visible - highlight it
|
||||
self.setMarkerColor(propertyId, 'blue');
|
||||
self.setMarkerZIndex(propertyId, 9000);
|
||||
} else {
|
||||
// Marker is clustered or outside viewport - need temporary marker
|
||||
// Marker outside viewport - need temporary marker
|
||||
needsTemporaryMarker = true;
|
||||
}
|
||||
} else {
|
||||
// Marker doesn't exist in current dataset - need temporary marker
|
||||
// Marker doesn't exist in current dataset (server-side clustered or not loaded)
|
||||
needsTemporaryMarker = true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user