Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
194 changes: 153 additions & 41 deletions inst/htmlwidgets/maplibregl.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,28 @@
function onMouseMoveTooltip(e, map, tooltipPopup, tooltipProperty) {
map.getCanvas().style.cursor = "pointer";
if (e.features.length > 0) {
const description = e.features[0].properties[tooltipProperty];
tooltipPopup.setLngLat(e.lngLat).setHTML(description).addTo(map);

// Store reference to currently active tooltip
window._activeTooltip = tooltipPopup;
} else {
tooltipPopup.remove();
// If this was the active tooltip, clear the reference
if (window._activeTooltip === tooltipPopup) {
delete window._activeTooltip;
}
}
}

function onMouseLeaveTooltip(map, tooltipPopup) {
map.getCanvas().style.cursor = "";
tooltipPopup.remove();
if (window._activeTooltip === tooltipPopup) {
delete window._activeTooltip;
}
}

HTMLWidgets.widget({
name: "maplibregl",

Expand Down Expand Up @@ -288,28 +313,30 @@ HTMLWidgets.widget({
closeOnClick: false,
});

map.on("mousemove", layer.id, function (e) {
map.getCanvas().style.cursor =
"pointer";

if (e.features.length > 0) {
const description =
e.features[0].properties[
layer.tooltip
];
tooltip
.setLngLat(e.lngLat)
.setHTML(description)
.addTo(map);
} else {
tooltip.remove();
}
});

map.on("mouseleave", layer.id, function () {
map.getCanvas().style.cursor = "";
tooltip.remove();
});
// Create a reference to the mousemove handler function.
// We need to pass 'e', 'map', 'tooltip', and 'layer.tooltip' to onMouseMoveTooltip.
const mouseMoveHandler = function(e) {
onMouseMoveTooltip(e, map, tooltip, layer.tooltip);
};

// Create a reference to the mouseleave handler function.
// We need to pass 'map' and 'tooltip' to onMouseLeaveTooltip.
const mouseLeaveHandler = function() {
onMouseLeaveTooltip(map, tooltip);
};

// Attach the named handler references, not anonymous functions.
map.on("mousemove", layer.id, mouseMoveHandler);
map.on("mouseleave", layer.id, mouseLeaveHandler);

// Store these handler references so you can remove them later if needed
if (!window._mapboxHandlers) {
window._mapboxHandlers = {};
}
window._mapboxHandlers[layer.id] = {
mousemove: mouseMoveHandler,
mouseleave: mouseLeaveHandler
};
}

// Add hover effect if provided
Expand Down Expand Up @@ -1053,27 +1080,27 @@ if (HTMLWidgets.shinyMode) {
closeOnClick: false,
});

map.on("mousemove", message.layer.id, function (e) {
map.getCanvas().style.cursor = "pointer";
// Define named handler functions:
const mouseMoveHandler = function(e) {
onMouseMoveTooltip(e, map, tooltip, message.layer.tooltip);
};

if (e.features.length > 0) {
const description =
e.features[0].properties[
message.layer.tooltip
];
tooltip
.setLngLat(e.lngLat)
.setHTML(description)
.addTo(map);
} else {
tooltip.remove();
}
});
const mouseLeaveHandler = function() {
onMouseLeaveTooltip(map, tooltip);
};

map.on("mouseleave", message.layer.id, function () {
map.getCanvas().style.cursor = "";
tooltip.remove();
});
// Attach handlers by reference:
map.on("mousemove", message.layer.id, mouseMoveHandler);
map.on("mouseleave", message.layer.id, mouseLeaveHandler);

// Store these handler references for later removal:
if (!window._mapboxHandlers) {
window._mapboxHandlers = {};
}
window._mapboxHandlers[message.layer.id] = {
mousemove: mouseMoveHandler,
mouseleave: mouseLeaveHandler
};
}

// Add hover effect if provided
Expand Down Expand Up @@ -1155,7 +1182,24 @@ if (HTMLWidgets.shinyMode) {
);
}
} else if (message.type === "remove_layer") {
// If there's an active tooltip, remove it first
if (window._activeTooltip) {
window._activeTooltip.remove();
delete window._activeTooltip;
}
if (map.getLayer(message.layer)) {
// Check if we have stored handlers for this layer
if (window._mapboxHandlers && window._mapboxHandlers[message.layer]) {
const handlers = window._mapboxHandlers[message.layer];
if (handlers.mousemove) {
map.off("mousemove", message.layer, handlers.mousemove);
}
if (handlers.mouseleave) {
map.off("mouseleave", message.layer, handlers.mouseleave);
}
// Clean up the reference
delete window._mapboxHandlers[message.layer];
}
map.removeLayer(message.layer);
}
if (map.getSource(message.layer)) {
Expand Down Expand Up @@ -1731,6 +1775,74 @@ if (HTMLWidgets.shinyMode) {
} else {
console.error("Invalid image data:", message);
}
} else if (message.type === "set_tooltip") {
const layerId = message.layer;
const newTooltipProperty = message.tooltip;

// If there's an active tooltip open, remove it first
if (window._activeTooltip) {
window._activeTooltip.remove();
delete window._activeTooltip;
}

// Remove old handlers if any
if (window._mapboxHandlers && window._mapboxHandlers[layerId]) {
const handlers = window._mapboxHandlers[layerId];
if (handlers.mousemove) {
map.off("mousemove", layerId, handlers.mousemove);
}
if (handlers.mouseleave) {
map.off("mouseleave", layerId, handlers.mouseleave);
}
delete window._mapboxHandlers[layerId];
}

// Create a new tooltip popup
const tooltip = new maplibregl.Popup({
closeButton: false,
closeOnClick: false,
});

// Define new handlers referencing the updated tooltip property
const mouseMoveHandler = function(e) {
onMouseMoveTooltip(e, map, tooltip, newTooltipProperty);
};
const mouseLeaveHandler = function() {
onMouseLeaveTooltip(map, tooltip);
};

// Add the new event handlers
map.on("mousemove", layerId, mouseMoveHandler);
map.on("mouseleave", layerId, mouseLeaveHandler);

// Store these handlers so we can remove/update them in the future
if (!window._mapboxHandlers) {
window._mapboxHandlers = {};
}
window._mapboxHandlers[layerId] = {
mousemove: mouseMoveHandler,
mouseleave: mouseLeaveHandler
};
} else if (message.type === "set_source") {
const layerId = message.layer;
const newData = message.source;
const layerObject = map.getLayer(layerId);

if (!layerObject) {
console.error("Layer not found: ", layerId);
return;
}

const sourceId = layerObject.source;
const sourceObject = map.getSource(sourceId);

if (!sourceObject) {
console.error("Source not found: ", sourceId);
return;
}

// Update the geojson data
sourceObject.setData(newData);
}
}
});
Expand Down