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

Plotly.kt Kotlin/JS应用中监听hover事件实现自定义悬浮内容

在Kotlin/JS中用Plotly.kt监听Hover事件实现自定义悬浮内容

1. 禁用默认悬浮提示

先通过hoverinfo = "none"关闭默认提示,Plotly.kt中的实现示例:

val trace = Scatter {
    x = listOf(1, 2, 3)
    y = listOf(4, 5, 6)
    hoverinfo = "none" // 禁用默认悬浮提示
}

2. 监听Plotly Hover事件

Plotly.js原生支持hover事件,在Kotlin/JS中可以通过两种方式监听:

方式一:使用Plotly.kt封装的事件API

创建图表实例后,直接调用on方法绑定hover事件:

val plotDiv = document.getElementById("plot") as HTMLElement
val plot = Plotly.newPlot(plotDiv, listOf(trace), Layout())

plot.on("hover") { event ->
    val points = event.points as Array<dynamic>
    if (points.isNotEmpty()) {
        val targetPoint = points[0]
        // 根据数据点信息加载自定义内容
        renderCustomTooltip(targetPoint)
    }
}

方式二:直接绑定DOM事件(备用)

如果Plotly.kt的封装不够灵活,可直接给图表DOM元素绑定plotly_hover事件:

plotDiv.addEventListener("plotly_hover", { event ->
    val eventDetail = (event as dynamic).detail
    val points = eventDetail.points
    if (points.isNotEmpty()) {
        renderCustomTooltip(points[0])
    }
})

3. 实现自定义悬浮内容

编写renderCustomTooltip函数,生成包含图片、视频、子图表的自定义提示框,并定位到对应位置:

fun renderCustomTooltip(point: dynamic) {
    // 移除已存在的提示框
    document.getElementById("custom-tooltip")?.remove()

    // 创建提示容器
    val tooltip = document.createElement("div").apply {
        id = "custom-tooltip"
        style.position = "absolute"
        style.backgroundColor = "#fff"
        style.border = "1px solid #ddd"
        style.padding = "10px"
        style.borderRadius = "4px"
        style.boxShadow = "0 2px 6px rgba(0,0,0,0.15)"
        style.zIndex = "9999"
    }

    // 添加图片(根据数据点动态设置路径)
    val img = document.createElement("img").apply {
        src = point.customdata?.imgPath ?: "default-img.jpg"
        style.width = "120px"
        style.marginBottom = "8px"
    }
    tooltip.appendChild(img)

    // 添加视频
    val video = document.createElement("video").apply {
        src = point.customdata?.videoPath ?: "default-video.mp4"
        controls = true
        style.width = "200px"
        style.marginBottom = "8px"
    }
    tooltip.appendChild(video)

    // 添加子图表
    val subPlotDiv = document.createElement("div").apply {
        style.width = "200px"
        style.height = "160px"
    }
    tooltip.appendChild(subPlotDiv)
    val subTrace = Bar {
        x = listOf("指标1", "指标2")
        y = listOf(point.y * 0.5, point.y * 0.8)
    }
    Plotly.newPlot(subPlotDiv, listOf(subTrace), Layout(title = "关联指标"))

    // 定位提示框到数据点附近
    val plotRect = (document.getElementById("plot") as HTMLElement).getBoundingClientRect()
    tooltip.style.left = "${plotRect.left + point.xPixel + 15}px"
    tooltip.style.top = "${plotRect.top + point.yPixel - 20}px"

    document.body.appendChild(tooltip)
}

// 监听mouseleave事件移除提示框
plot.on("mouseleave") {
    document.getElementById("custom-tooltip")?.remove()
}

4. 关联数据点与自定义资源

可以在trace的customdata字段中存储每个数据点对应的资源路径,方便hover时调用:

val trace = Scatter {
    x = listOf(1, 2, 3)
    y = listOf(4, 5, 6)
    hoverinfo = "none"
    // 存储每个点的自定义资源信息
    customdata = arrayOf(
        js("{imgPath: 'data-point-1.jpg', videoPath: 'point-1.mp4'}"),
        js("{imgPath: 'data-point-2.jpg', videoPath: 'point-2.mp4'}"),
        js("{imgPath: 'data-point-3.jpg', videoPath: 'point-3.mp4'}")
    )
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 06:52:30