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

基于pdfjs与PDFObject实现PDF指定文本动态高亮及标注tooltip方案咨询

基于PDF.js+PDFObject的文本高亮+自定义Tooltip实现方案

核心实现逻辑

你已经持有待标注文本的索引位置,无需额外做文本搜索匹配,直接复用PDF.js内置的标注层能力即可实现和HTML预览器一致的效果,整体逻辑和你现有HTML标注方案对齐,仅需要新增文本坐标获取、坐标转换两个环节。

可直接复用的实现代码

// 提前定义你的标注列表,可直接代入你已有的索引、tooltip内容数据
const customAnnotations = [
  {
    pageIndex: 0, // PDF页码,从0开始计数
    startCharIndex: 151, // 你已掌握的文本起始索引
    endCharIndex: 169, // 你已掌握的文本结束索引
    tooltipContent: `<table class='tooltiptable'>....</table>` // 自定义HTML格式的tooltip内容
  }
]

// 监听PDF.js页面渲染完成事件,逐页处理标注
document.addEventListener('pagerendered', async (e) => {
  const currentPageIndex = e.detail.pageNumber - 1
  const currentPdfPage = e.detail.page
  const annotationLayer = e.detail.annotationLayer
  const currentPageAnnotations = customAnnotations.filter(ann => ann.pageIndex === currentPageIndex)

  // 1. 获取当前页所有文本块数据
  const textContent = await currentPdfPage.getTextContent()
  const textItems = textContent.items
  let currentPageCharCount = 0

  currentPageAnnotations.forEach(ann => {
    const matchedTextItems = []
    // 2. 匹配索引范围内的文本块
    for (let i = 0; i < textItems.length; i++) {
      const item = textItems[i]
      const itemCharLength = item.str.length
      const itemStartIdx = currentPageCharCount
      const itemEndIdx = currentPageCharCount + itemCharLength - 1

      if (itemEndIdx < ann.startCharIndex) {
        currentPageCharCount += itemCharLength
        continue
      }
      if (itemStartIdx > ann.endCharIndex) break

      matchedTextItems.push(item)
      currentPageCharCount += itemCharLength
      if (itemEndIdx >= ann.endCharIndex) break
    }

    // 3. 转换坐标并渲染高亮元素
    const viewport = currentPdfPage.getViewport({ scale: e.detail.viewport.scale })
    matchedTextItems.forEach(item => {
      // 从文本块属性提取坐标参数:[x轴缩放, x轴倾斜, y轴倾斜, y轴缩放, x坐标, y坐标]
      const [scaleX, , , scaleY, x, y] = item.transform
      const itemWidth = item.str.length * scaleX
      const itemHeight = scaleY

      // 创建高亮DOM,参数和你现有HTML标注完全对齐
      const highlightEl = document.createElement('div')
      highlightEl.className = 'marked hilite-on symp'
      highlightEl.setAttribute('data-toggle', 'tooltip')
      highlightEl.setAttribute('data-placement', 'bottom')
      highlightEl.setAttribute('data-html', 'true')
      highlightEl.setAttribute('data-original-title', ann.tooltipContent)
      // 适配PDF坐标系设置位置
      highlightEl.style.cssText = `
        position: absolute;
        left: ${x}px;
        top: ${viewport.height - y - itemHeight}px;
        width: ${itemWidth}px;
        height: ${itemHeight}px;
        background: rgba(255,255,0,0.3);
        pointer-events: auto;
      `
      annotationLayer.appendChild(highlightEl)
    })
  })

  // 4. 初始化tooltip,和你现有HTML场景的逻辑完全一致
  $('[data-toggle="tooltip"]').tooltip({html: true})
})

注意事项

  • PDF.js默认坐标系原点为页面左下角,HTML页面坐标系原点为左上角,计算高亮元素top值时需要做对应转换,避免标注偏移
  • 如果你的预览器支持缩放功能,需要监听PDF缩放事件,同步重新计算所有高亮元素的坐标即可适配
  • 你现有HTML场景下的Tooltip样式、交互逻辑可直接复用,只需确保Tooltip的z-index层级高于PDF预览层即可正常展示

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 19:09:03