求助:R Plotly散点地图(scattermapbox)悬停显示图片失效
问题背景
我参考Stack Overflow上的示例实现了R Plotly散点图中鼠标悬停显示图片的功能,该方案在散点图中正常运行,但切换为scattermapbox地图时失效,需要修改代码使其适配Plotly地图。
原始代码(含依赖与JS逻辑)
library(dplyr) library(plotly) df <- data.frame(x = c(-81.026, -81.025, -81.028), y = c(44.13, 44.14, 44.15), url = c("https://upload.wikimedia.org/wikipedia/commons/6/6f/Beethoven.jpg", "https://upload.wikimedia.org/wikipedia/commons/4/47/Croce-Mozart-Detail.jpg", "https://upload.wikimedia.org/wikipedia/commons/6/6a/Johann_Sebastian_Bach.jpg")) d3 <- htmltools::htmlDependency( "d3", "7.3", src = c(href = "https://cdnjs.cloudflare.com/ajax/libs/d3/7.3.0/"), script = "d3.min.js" ) js <- ' function(el) { var tooltip = d3.select("#" + el.id + " .svg-container") .append("div") .attr("class", "my-custom-tooltip"); el.on("plotly_hover", function(d) { var pt = d.points[0]; var x = pt.xaxis.range[0]; var y = pt.yaxis.range[1]; var xPixel = pt.xaxis.l2p(x) + pt.xaxis._offset; var yPixel = pt.yaxis.l2p(y) + pt.yaxis._offset; var img = "<img src=\\\"" + pt.customdata + "\\\" width=100>"; tooltip.html(img) .style("position", "absolute") .style("left", xPixel + "px") .style("top", yPixel + "px"); tooltip.transition() .duration(300) .style("opacity", 1); }); el.on("plotly_unhover", function(d) { tooltip.transition() .duration(500) .style("opacity", 0); }); } '
可正常运行的散点图代码
p <-plot_ly(df, x = ~x, y = ~y, type = "scatter", mode = "markers", hoverinfo = ~x, customdata = ~url) %>% htmlwidgets::onRender(js) p$dependencies <- c(p$dependencies, list(d3)) p
失效的scattermapbox地图代码
p <- plot_ly(df, lon = ~x, lat = ~y, type = "scattermapbox", mode = "markers", hoverinfo = ~x, customdata = ~url) %>% layout(mapbox = list(style = "white-bg", sourcetype = 'raster', zoom = 4, center = list(lon = -81 ,lat= 44), layers = list(list(below = 'traces', sourcetype = "raster", source = list("https://basemap.nationalmap.gov/arcgis/rest/services/USGSImageryOnly/MapServer/tile/{z}/{y}/{x}"))))) %>% htmlwidgets::onRender(js) p$dependencies <- c(p$dependencies, list(d3)) p
解决方案(修改后的代码)
修改后的JS逻辑
scattermapbox基于Mapbox GL,DOM结构和坐标体系与普通散点图不同,需调整容器选择和坐标计算方式:
js <- ' function(el) { // 选择地图专属容器,替代原svg容器 var tooltip = d3.select("#" + el.id + " .mapboxgl-canvas-container") .append("div") .attr("class", "my-custom-tooltip") .style("opacity", 0) .style("position", "absolute") .style("pointer-events", "none") .style("z-index", 1000); el.on("plotly_hover", function(d) { var pt = d.points[0]; // 直接使用鼠标的屏幕坐标定位tooltip var mouseX = d.event.clientX; var mouseY = d.event.clientY; var img = "<img src=\\\"" + pt.customdata + "\\\" width=100>"; tooltip.html(img) .style("left", (mouseX + 10) + "px") .style("top", (mouseY + 10) + "px"); tooltip.transition() .duration(300) .style("opacity", 1); }); el.on("plotly_unhover", function(d) { tooltip.transition() .duration(500) .style("opacity", 0); }); } '
修改后的地图代码
p <- plot_ly(df, lon = ~x, lat = ~y, type = "scattermapbox", mode = "markers", hoverinfo = "none", customdata = ~url) %>% layout(mapbox = list(style = "white-bg", sourcetype = 'raster', zoom = 12, center = list(lon = -81.026 ,lat= 44.14), layers = list(list(below = 'traces', sourcetype = "raster", source = list("https://basemap.nationalmap.gov/arcgis/rest/services/USGSImageryOnly/MapServer/tile/{z}/{y}/{x}"))))) %>% htmlwidgets::onRender(js) p$dependencies <- c(p$dependencies, list(d3)) p
修改说明
- 容器适配:替换为Mapbox专属的
.mapboxgl-canvas-container容器,匹配地图的DOM结构 - 坐标逻辑:使用鼠标事件的
clientX/clientY直接获取屏幕坐标,避免依赖散点图的xaxis/yaxis对象 - 样式优化:添加
pointer-events: none防止tooltip遮挡鼠标交互,设置z-index确保tooltip显示在地图上方;关闭默认tooltip避免冲突
内容的提问来源于stack exchange,提问作者user2602640
相关产品推荐
相关产品推荐

