You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

R Plotly中D3 Tooltip加载Twitter小部件失败问题求助

R Plotly点击数据点无法加载Twitter小部件Tooltip的问题

我尝试用publish.twitter.com生成的代码,在R的Plotly图表中实现自定义D3 Tooltip——点击数据点时显示Twitter推文小部件。之前参考过图片Tooltip的实现方法,现在适配成Twitter小部件后,点击仅显示推文文本、账号和日期,小部件无法渲染,虽然已经引入了Twitter的widgets.js脚本但没生效。

最小复现代码

R代码

# Load packages
library(plotly)
library(htmlwidgets)
library(htmltools)
library(magrittr)

# Define text and position
x <- 1 
y <- 1
label <- c("Click here for tweet")

# D3 dependency
d3 <- htmltools::htmlDependency(
  "d3", "7.3",
  src = c(href = "https://cdnjs.cloudflare.com/ajax/libs/d3/7.3.0/"),
  script = "d3.min.js"
)

# Define plot, provide .js file with custom tweet tooltip & add D3 dependency
p <- plot_ly() %>%
  add_text(x = x, y = y, text = label) %>%
  htmlwidgets::onRender(readLines("tweet_tooltip.js")) 

p$dependencies <- c(p$dependencies, list(d3))

# Render plot
p

tweet_tooltip.js代码

// tweet_tooltip.js
// Adapted from image tooltip implementation
function(el) {
    
    // Define tooltip
    var tooltip = d3.select('#' + el.id + ' .svg-container')
      .append("div")
      .attr("class", "my-custom-tooltip");
      
    el.on('plotly_click', function(d) {
      
      var pt = d.points[0];
        
      // Choose a location (on the data scale) to place the image: upper left corner
      var x = pt.xaxis.range[0];
      var y = pt.yaxis.range[1];
      
      // Transform the data scale to the pixel scale
      var xPixel = pt.xaxis.l2p(x) + pt.xaxis._offset;
      var yPixel = pt.yaxis.l2p(y) + pt.yaxis._offset;
      
      // Define tweet variable with twitter blockquote/script
      var tweet = '<blockquote class="twitter-tweet"><p lang="en" dir="ltr">How much is it?</p>&mdash; Elon Musk (@elonmusk) <a href="https://twitter.com/elonmusk/status/943902052542849024?ref_src=twsrc%5Etfw">December 21, 2017</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>'
      
      // Add to tooltip & define position
      tooltip.html(tweet)
       .style("position", "absolute")
       .style("left", xPixel + "px")
       .style("top", yPixel + "px");
      
      tooltip
    });
}

问题原因与解决方案

核心问题

  1. 动态插入的<script>标签不会自动执行,直接通过html()插入脚本无法触发Twitter小部件的初始化
  2. Twitter的widgets.js默认只会在页面首次加载时扫描DOM并渲染推文,动态添加的blockquote不会被自动识别

修改后的代码

更新R代码(添加Twitter脚本依赖)

# Load packages
library(plotly)
library(htmlwidgets)
library(htmltools)
library(magrittr)

# Define text and position
x <- 1 
y <- 1
label <- c("Click here for tweet")

# D3 dependency
d3 <- htmltools::htmlDependency(
  "d3", "7.3",
  src = c(href = "https://cdnjs.cloudflare.com/ajax/libs/d3/7.3.0/"),
  script = "d3.min.js"
)

# 添加Twitter widgets依赖,提前加载脚本
twitter_widgets <- htmltools::htmlDependency(
  "twitter-widgets", "1.0",
  src = c(href = "https://platform.twitter.com/"),
  script = "widgets.js"
)

# Define plot, provide .js file with custom tweet tooltip & add dependencies
p <- plot_ly() %>%
  add_text(x = x, y = y, text = label) %>%
  htmlwidgets::onRender(readLines("tweet_tooltip.js")) 

p$dependencies <- c(p$dependencies, list(d3, twitter_widgets))

# Render plot
p

更新tweet_tooltip.js(触发小部件渲染+优化显示逻辑)

// tweet_tooltip.js
function(el) {
    
    // 初始化tooltip容器,默认隐藏
    var tooltip = d3.select('#' + el.id + ' .svg-container')
      .append("div")
      .attr("class", "my-custom-tooltip")
      .style("position", "absolute")
      .style("display", "none")
      .style("z-index", "9999"); // 确保tooltip在顶层显示
    
    el.on('plotly_click', function(d) {
      var pt = d.points[0];
        
      // 转换点击点坐标到像素位置,偏移避免遮挡
      var xPixel = pt.xaxis.l2p(pt.x) + pt.xaxis._offset + 10;
      var yPixel = pt.yaxis.l2p(pt.y) + pt.yaxis._offset + 10;
      
      // 仅插入blockquote标签,不再重复添加脚本
      var tweetBlockquote = '<blockquote class="twitter-tweet"><p lang="en" dir="ltr">How much is it?</p>&mdash; Elon Musk (@elonmusk) <a href="https://twitter.com/elonmusk/status/943902052542849024?ref_src=twsrc%5Etfw">December 21, 2017</a></blockquote>';
      
      // 更新tooltip内容与位置并显示
      tooltip.html(tweetBlockquote)
       .style("left", xPixel + "px")
       .style("top", yPixel + "px")
       .style("display", "block");
      
      // 触发Twitter小部件渲染新插入的节点
      if (window.twttr) {
        twttr.widgets.load(tooltip.node());
      }
    });

    // 点击页面其他区域隐藏tooltip
    d3.select('body').on('click', function(event) {
      var target = event.target;
      // 判断点击目标是否在tooltip或推文内部,否则隐藏
      if (!tooltip.node().contains(target) && 
          !d3.select(target).closest('.twitter-tweet').node()) {
        tooltip.style("display", "none");
      }
    });
}

关键修改说明

  • 提前通过htmlDependency引入Twitter的widgets.js,确保页面加载时脚本已就绪,避免重复插入脚本
  • 动态添加blockquote后,调用twttr.widgets.load(tooltip.node())主动通知Twitter脚本渲染新节点
  • 添加了tooltip的默认隐藏和外部点击关闭逻辑,提升交互体验
  • 设置tooltip的z-index确保不会被图表元素遮挡

内容的提问来源于stack exchange,提问作者Rcoleptic

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 13:18:10