【d3.js入门】使用Tooltip增强数据可视化效果

在数据可视化中,Tooltip(工具提示)是一个常用的交互元素,它可以提供更详细的数据信息,并在用户悬停或点击某个数据点时显示。本文将介绍如何使用D3.js的交互来实现Tooltip功能,从而增强图表的数据展示效果。

柱状图比较常见,其Tooltip也比较简单也很典型,鼠标hover到矩形上就弹出提示信息,而且弹出的位置跟随鼠标即可。

折线图要比柱状图复杂。为了方便鼠标hover,我们通常需要鼠标移动到指定区域的时候就会触发tooltip,比如线上面的点,以及单根线的时候 线所对应的区域。如图所示,红色区域都对于芒果这个点的tooltip,而且为了准确tooltip弹出的位置固定在点的位置。

柱状图Tooltip

我们需要准备一个数据集,用于展示每周某一天的数据值。假设我们有以下数据集:

javascript 复制代码
let dataset = [
    { name: "周一", value: 30 },
    { name: "周二", value: 20 },
    { name: "周三", value: 50 },
    { name: "周四", value: 20 },
    { name: "周五", value: 80 },
    { name: "周六", value: 30 },
    { name: "周日", value: 60 }
];

然后,我们使用D3.js的scaleBandscaleLinear函数来设置x轴和y轴的比例尺:

javascript 复制代码
let xScale = d3.scaleBand()
    .domain(d3.range(dataset.length))
    .range([padding, svgWidth - padding])
    .padding(0.3);

let yScale = d3.scaleLinear()
    .domain([0, d3.max(dataset, function (d) { return d.value; })])
    .range([svgHeight - padding, padding]);

为了实现Tooltip的功能,我们需要在HTML文档中定义一个Tooltip容器:

html 复制代码
<div id="tooltip" class="tooltip">
    <div class="tooltip-range">
        Name: <span id="range"></span>
    </div>
    <div class="tooltip-value">
        Value: <span id="count"></span>
    </div>
</div>

然后,我们根据数据集的长度和比例尺的设置,计算每个柱形的宽度:

javascript 复制代码
let barWidth = xScale.bandwidth();

通过使用D3.js的selectAlldataenter方法,我们创建一组矩形元素来表示数据集中的每个数据点,并设置相应的属性和事件处理程序:

javascript 复制代码
let bars = svg.selectAll(".bar")
    .data(dataset)
    .enter()
    .append("rect")
    .attr("class", "bar")
    .attr("fill", "#69b3a2")
    .attr("x", function (d, i) {
        return xScale(i);
    })
    .attr("y", function (d) {
        return yScale(d.value);
    })
    .attr("width", barWidth)
    .attr("height", function (d) {
        return svgHeight - yScale(d.value) - padding;
    })
    .on("mouseover", function (d) {
        tooltip.style("opacity", 1);
        tooltip.select("#range").text(d.name);
        tooltip.select("#count").text(d.value);
    })
    .on("mousemove", function (d) {
        tooltip.style("left", (d3.event.pageX) + "px")
            .style("top", (d3.event.pageY) + "px");
    })
    .on("mouseout", function (d) {
        tooltip.style("opacity", 0);
    });

最后,我们使用D3.js的axisBottomaxisLeft方法来创建x轴和y轴,并将它们添加到SVG元素中。 以上代码实现了一个带有Tooltip的柱状图,当鼠标悬停在柱形上时,Tooltip将显示相应的数据信息。通过设置Tooltip的样式和位置,可以更好地展示数据,提高用户体验。

折线图 Tooltip

折线图的教程前面有【d3.js入门】基本折线图动画,这里不再复述,主要为了交互添加了点和隐藏的矩形区域。代码中比较关键的地方是计算弹窗的位置。

javascript 复制代码
// 绘制圆点 
svg.selectAll(".circle")
    .data(dataset)
    .enter()
    .append("circle")
    .attr("class", "circle")
    .attr("cx", function (d, i) {
        return xScale(i) + xScale.bandwidth() / 2;
    })
    .attr("cy", function (d) {
        return yScale(d.value);
    })
    .attr("r", 4)
    .attr("fill", "#ffffff")
    .attr("stroke", "#69b3a2")
    .attr("stroke-width", "3px")

// 每个区域绘制一个矩形 用于触发事件
let _w = (svgWidth - padding * 2) / (dataset.length - 1)
svg.selectAll(".rect")
    .data(dataset)
    .enter()
    .append("rect")
    .attr("class", "rect")
    .attr("x", function (d, i) {
        return xScale(i) - _w / 2;
    })
    .attr("y", padding)
    .attr("width", _w)
    .attr("height", svgHeight - padding * 2)
    .attr("fill", "transparent")
    .on("mouseover", function (d,i) {
        tooltip.style("opacity", 1)
        tooltip.select("#range").text(d.name)
        tooltip.select("#count").text(d.value)
        // tooltip 在 点上方显示 考虑svg在页面中的位置
        // 计算svg 在页面中的位置
        let svgRect = svg.node().getBoundingClientRect();
        let svgLeft = svgRect.left;
        let svgTop = svgRect.top;
        // 滚动条的位置
        let scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
        tooltip.style("left", xScale(i) + xScale.bandwidth() / 2 + svgLeft + "px")
            .style("top", yScale(d.value) + svgTop + scrollTop + "px")

    })
    .on("mouseout", function (d) {
        tooltip.style("opacity", 0)
    })

在线演示地址:scqilin.github.io/d3js/intera...

相关推荐
拉不动的猪8 分钟前
前端常见数组分析
前端·javascript·面试
小吕学编程24 分钟前
ES练习册
java·前端·elasticsearch
Asthenia041232 分钟前
Netty编解码器详解与实战
前端
袁煦丞36 分钟前
每天省2小时!这个网盘神器让我告别云存储混乱(附内网穿透神操作)
前端·程序员·远程工作
一个专注写代码的程序媛2 小时前
vue组件间通信
前端·javascript·vue.js
一笑code2 小时前
美团社招一面
前端·javascript·vue.js
懒懒是个程序员2 小时前
layui时间范围
前端·javascript·layui
NoneCoder2 小时前
HTML响应式网页设计与跨平台适配
前端·html
凯哥19702 小时前
在 Uni-app 做的后台中使用 Howler.js 实现强大的音频播放功能
前端
烛阴2 小时前
面试必考!一招教你区分JavaScript静态函数和普通函数,快收藏!
前端·javascript