16、数据可视化交互与力模拟技术全解析

数据可视化交互与力模拟技术全解析

1. 触摸交互

在数据可视化中,触摸交互是提升用户体验的重要手段。我们可以通过 touchstart touchend 事件来实现触摸交互,同时也能使用相同的模式处理浏览器支持的其他触摸事件。W3C 推荐的触摸事件类型如下:
- touchstart :当用户在触摸表面放置触摸点时触发。
- touchend :当用户从触摸表面移除触摸点时触发。
- touchmove :当用户在触摸表面移动触摸点时触发。
- touchcancel :当触摸点以特定于实现的方式被中断时触发。

2. 缩放与平移行为

缩放和平移是数据可视化中常用且实用的技术,尤其适用于基于 SVG 的可视化,因为矢量图形不会像位图那样出现像素化问题。在处理大型数据集时,缩放功能特别有用,当无法一次性可视化整个数据集时,就需要采用缩放和深入挖掘的方法。

2.1 准备工作

在浏览器中打开以下文件的本地副本:

https://github.com/NickQiZhu/d3-cookbook/blob/master/src/chapter10/zoom.html
2.2 代码实现
<script type="text/javascript">
    var width = 960, height = 500, r = 50;
    var data = [
        [width / 2 - r, height / 2 - r],
        [width / 2 - r, height / 2 + r],
        [width / 2 + r, height / 2 - r],
        [width / 2 + r, height / 2 + r]
    ];
    var svg = d3.select("body").append("svg")
            .attr("width", width)
            .attr("height", height)
            .call(
                d3.behavior.zoom()
                    .scaleExtent([1, 10])
                    .on("zoom", zoom)
            )
            .append("g");
    svg.selectAll("circle")
            .data(data)
            .enter().append("circle")
            .attr("r", r)
            .attr("transform", function (d) {
                return "translate(" + d + ")";
            });
    function zoom() {
        svg.attr("transform", "translate(" 
            + d3.event.translate 
+ ")scale(" + d3.event.scale + ")");
    }
</script>
2.3 工作原理

使用 D3 实现缩放和平移效果所需的代码量很少。大部分工作由 D3 库完成,我们只需定义缩放行为。具体步骤如下:
1. 在 SVG 容器上定义缩放行为:

var svg = d3.select("body").append("svg")
        .attr("style", "1px solid black")
        .attr("width", width)
        .attr("height", height)
        .call(
            d3.behavior.zoom()
                .scaleExtent([1, 10])
                .on("zoom", zoom)
        )
        .append("g");

d3.behavior.zoom 会自动创建事件监听器,处理 SVG 容器上的低级缩放和平移手势,并将其转换为高级的 D3 缩放事件。默认的事件监听器支持鼠标和触摸事件。 scaleExtent 定义了允许的缩放范围,这里设置为 1 到 10 倍。
2. 定义缩放事件处理函数:

function zoom() {
    svg.attr("transform", "translate(" 
        + d3.event.translate 
        + ")scale(" + d3.event.scale + ")");
}

zoom 函数中,我们将实际的缩放和平移操作委托给 SVG 变换。D3 缩放事件已经计算出了必要的平移和缩放值,我们只需将它们嵌入到 SVG 的 transform 属性中。缩放事件包含以下属性:
- scale :表示当前缩放比例的数字。
- translate :表示当前平移向量的二元数组。

缩放函数的作用是将通用的缩放和平移事件转换为 SVG 特定的变换,因为 D3 缩放行为是作为通用的缩放行为支持机制设计的,并非专门为 SVG 设计。此外,缩放函数还可以执行其他任务,例如在用户进行缩放操作时加载额外的数据,实现深入挖掘功能。

3. 拖动行为

拖动是交互式可视化中另一种常见的行为,可用于图形重新排列或用户输入。

3.1 准备工作

在浏览器中打开以下文件的本地副本:

https://github.com/NickQiZhu/d3-cookbook/blob/master/src/chapter10/drag.html
3.2 代码实现
<script type="text/javascript">
    var width = 960, height = 500, r = 50;
    var data = [
        [width / 2 - r, height / 2 - r],
        [width / 2 - r, height / 2 + r],
        [width / 2 + r, height / 2 - r],
        [width / 2 + r, height / 2 + r]
    ];
    var svg = d3.select("body").append("svg")
            .attr("width", width)
            .attr("height", height)
            .append("g");
    var drag = d3.behavior.drag()
            .on("drag", move);
    svg.selectAll("circle")
            .data(data)
            .enter().append("circle")
            .attr("r", r)
            .attr("transform", function (d) {
                return "translate(" + d + ")";
            })
            .call(drag);
    function move(d) {
        var x = d3.event.x, 
            y = d3.event.y;
        if(inBoundaries(x, y))
            d3.select(this) 
                .attr("transform", function (d) {
                    return "translate(" + x + ", " + y + ")";
                });
    }

    function inBoundaries(x, y){
        return (x >= (0 + r) && x <= (width - r)) 
            && (y >= (0 + r) && y <= (height - r));
    }
</script>
3.3 工作原理

D3 的拖动支持与缩放支持模式类似。主要的拖动功能由 d3.behavior.drag 函数提供,它会自动创建适当的低级事件监听器,处理给定元素上的拖动手势,并将低级事件转换为高级的 D3 拖动事件,支持鼠标和触摸事件。

var drag = d3.behavior.drag()
        .on("drag", move);

move 函数中,我们根据拖动事件提供的信息,使用 SVG 变换将被拖动的元素移动到合适的位置。同时,我们还检查元素是否在 SVG 边界内,以防止元素被拖出 SVG 区域。

function move(d) {
    var x = d3.event.x, 
        y = d3.event.y;
    if(inBoundaries(x, y))
        d3.select(this) 
            .attr("transform", function (d) {
                return "translate(" + x + ", " + y + ")";
            });
}

function inBoundaries(x, y){
    return (x >= (0 + r) && x <= (width - r)) 
        && (y >= (0 + r) && y <= (height - r));
}

D3 拖动行为支持的事件类型如下:
- dragstart :拖动手势开始时触发。
- drag :元素被拖动时触发, d3.event 包含 x y 属性,表示元素当前的绝对拖动坐标,还包含 dx dy 属性,表示元素相对于手势开始时位置的坐标。
- dragend :拖动手势结束时触发。

4. 力模拟技术

力模拟是 D3 中非常有趣的一个方面,它可以为可视化添加令人惊叹的效果。D3 的力模拟支持是作为一种额外的布局实现的,最初是为了实现力导向图而创建的。它使用基于标准 Verlet 积分的粒子运动模拟,并支持简单的约束。

4.1 重力与电荷

在这个示例中,我们将介绍两种基本力:重力和电荷。力布局的设计目标之一是在粒子级别上大致模拟牛顿运动方程,电荷是这种模拟的一个主要特征。此外,力布局还实现了伪重力,即一种弱几何约束,可防止可视化元素逃离 SVG 画布。

4.1.1 准备工作

在浏览器中打开以下文件的本地副本:

https://github.com/NickQiZhu/d3-cookbook/blob/master/src/chapter11/gravity-and-charge.html
4.1.2 代码实现
<script type="text/javascript">
    var w = 1280, h = 800,
        force = d3.layout.force()
            .size([w ,h])
            .gravity(0)
            .charge(0)
            .friction(0.7);
    var svg = d3.select("body")
        .append("svg")
            .attr("width", w)
            .attr("height", h);
    force.on("tick", function () {
        svg.selectAll("circle")
            .attr("cx", function (d) {return d.x;})
            .attr("cy", function (d) {return d.y;});
    });
    svg.on("mousemove", function () {
        var point = d3.mouse(this),
            node = {x: point[0], y: point[1]};
        svg.append("circle")
                .data([node])
            .attr("class", "node")
            .attr("cx", function (d) {return d.x;})
            .attr("cy", function (d) {return d.y;})
            .attr("r", 1e-6)
        .transition()
            .attr("r", 4.5)
        .transition()
            .delay(7000)
            .attr("r", 1e-6)
            .each("end", function () {
                force.nodes().shift();
            })
            .remove();
        force.nodes().push(node);
        force.start();
    });
    function changeForce(charge, gravity) {
        force.charge(charge).gravity(gravity);
    }
</script>
<div class="control-group">
    <button onclick="changeForce(0, 0)">
        No Force
    </button>
    <button onclick="changeForce(-60, 0)">
        Mutual Repulsion
    </button>
    <button onclick="changeForce(60, 0)">
        Mutual Attraction
    </button>
    <button onclick="changeForce(0, 0.02)">
        Gravity
    </button>
    <button onclick="changeForce(-30, 0.1)">
        Gravity with Repulsion
    </button>    
</div>
4.1.3 工作原理

在深入研究代码之前,我们先了解一下重力、电荷和摩擦力的概念:
- 电荷 :用于模拟粒子之间的相互 n 体作用力。负值会导致节点相互排斥,正值会导致节点相互吸引。默认电荷值为 -30,电荷值也可以是一个函数,在力模拟开始时为每个节点进行评估。
- 重力 :力布局中的重力模拟并非模拟物理重力,而是一种弱几何约束,类似于从布局中心连接到每个节点的虚拟弹簧。默认重力强度为 0.1,节点离中心越远,重力强度越强,在布局中心附近重力强度几乎为零,因此重力最终会克服排斥电荷,防止节点逃离布局。
- 摩擦力 :D3 力布局中的摩擦力并非标准的物理摩擦系数,而是实现为速度衰减。在模拟的每个时间步,粒子的速度会按指定的摩擦力进行缩放。值为 1 表示无摩擦环境,值为 0 会使所有粒子立即失去速度而冻结。不建议使用超出 [0, 1] 范围的值,因为可能会使布局不稳定。

下面我们来看不同力设置下的效果:
- 零力布局

var w = 1280, h = 800,
    force = d3.layout.force()
        .size([w ,h])
        .gravity(0)
        .charge(0)
        .friction(0.7);

在这种设置下,当用户移动鼠标时,会在 SVG 上创建节点。节点对象的坐标设置为当前鼠标位置,每个创建的节点都需要添加到布局的节点数组中,并在节点的可视化表示被移除时从数组中移除。调用 start 函数启动力模拟,此时布局允许我们通过鼠标移动放置一系列节点。
- 相互排斥

function changeForce(charge, gravity) {
    force.charge(charge).gravity(gravity);
}
changeForce(-60, 0);

将电荷设置为负值,同时保持重力为零,会产生相互排斥的力场。为了将力布局中操作的数据与图形元素连接起来,我们需要注册一个 tick 事件监听器:

force.on("tick", function () {
    svg.selectAll("circle")
        .attr("cx", function (d) {return d.x;})
        .attr("cy", function (d) {return d.y;});
});

在每个时间步,根据力布局的计算更新所有圆形元素的位置。
- 相互吸引

changeForce(60, 0);

将电荷设置为正值会使粒子之间产生相互吸引的效果。
- 重力

changeForce(0, 0.02);

开启重力并关闭电荷,会产生类似于相互吸引的效果,但可以注意到随着鼠标远离中心,重力拉力呈线性缩放。
- 重力与排斥结合

changeForce(-30, 0.1);

同时开启重力和相互排斥,会使所有粒子达到一种力的平衡,既不会逃离布局,也不会相互碰撞。

力布局支持的事件类型如下:
- start :模拟开始时触发。
- tick :模拟的每个时间步触发。
- end :模拟结束时触发。

综上所述,通过触摸交互、缩放平移、拖动以及力模拟等技术,我们可以为数据可视化添加丰富的交互性和动态效果,提升用户体验和数据展示的效果。这些技术不仅适用于数据可视化领域,还在其他许多领域有实际应用。

数据可视化交互与力模拟技术全解析

5. 力模拟的应用拓展

力模拟技术在数据可视化中有着广泛的应用,除了前面提到的基本力的设置和效果展示,还可以通过力模拟来实现更复杂的可视化效果,例如力导向图。力导向图是一种常用的可视化方式,用于展示节点之间的关系,通过节点之间的引力和斥力来布局节点,使得关系紧密的节点靠近,关系疏远的节点远离。

5.1 构建力导向图的基本步骤
  • 定义节点和链接数据 :首先需要定义节点和链接的数据结构,节点表示可视化中的元素,链接表示节点之间的关系。
  • 创建力布局 :使用 D3 的力布局函数创建力布局,并设置相关参数,如重力、电荷、摩擦力等。
  • 绑定数据到图形元素 :将节点和链接的数据绑定到 SVG 图形元素上,如圆形表示节点,线条表示链接。
  • 启动力模拟 :调用力布局的 start 方法启动力模拟,在模拟过程中,根据节点的位置更新图形元素的位置。
5.2 示例代码
// 定义节点和链接数据
var nodes = [
    { id: 1 },
    { id: 2 },
    { id: 3 }
];
var links = [
    { source: 0, target: 1 },
    { source: 1, target: 2 }
];

// 创建力布局
var force = d3.layout.force()
    .nodes(nodes)
    .links(links)
    .size([width, height])
    .gravity(0.1)
    .charge(-100)
    .friction(0.9);

// 创建 SVG 容器
var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height);

// 绑定链接数据到线条元素
var link = svg.selectAll(".link")
    .data(links)
    .enter().append("line")
    .attr("class", "link");

// 绑定节点数据到圆形元素
var node = svg.selectAll(".node")
    .data(nodes)
    .enter().append("circle")
    .attr("class", "node")
    .attr("r", 5);

// 启动力模拟
force.on("tick", function () {
    link.attr("x1", function (d) { return d.source.x; })
        .attr("y1", function (d) { return d.source.y; })
        .attr("x2", function (d) { return d.target.x; })
        .attr("y2", function (d) { return d.target.y; });

    node.attr("cx", function (d) { return d.x; })
        .attr("cy", function (d) { return d.y; });
});

force.start();
6. 不同交互技术的对比
交互技术 适用场景 实现难度 效果特点
触摸交互 移动设备或支持触摸的屏幕,需要用户直接与可视化元素进行触摸操作 较低,主要通过处理触摸事件实现 提供直观的触摸操作体验,增强用户与可视化的互动性
缩放与平移 处理大型数据集或需要详细查看局部数据的场景 中等,需要设置缩放范围和处理缩放事件 可以灵活查看数据的整体和局部细节,避免数据过于拥挤
拖动行为 需要用户对可视化元素进行位置调整或重新排列的场景 中等,需要处理拖动手势和边界检测 允许用户自由移动元素,实现个性化的布局
力模拟 展示节点之间关系、动态布局的场景 较高,需要理解物理模拟原理和力布局的参数设置 可以生成自然、动态的布局效果,突出节点之间的关系
7. 交互技术的综合应用

在实际的数据可视化项目中,通常会综合使用多种交互技术,以提供更丰富的用户体验。例如,在一个地理信息可视化项目中,可以使用缩放与平移技术让用户查看不同范围的地图,使用触摸交互让用户在移动设备上进行操作,使用拖动行为让用户调整地图上的标记位置,使用力模拟技术展示地理区域之间的关系。

以下是一个简单的 mermaid 流程图,展示了综合应用交互技术的流程:

graph LR
    A[数据准备] --> B[创建可视化元素]
    B --> C[添加交互功能]
    C --> D{用户操作}
    D -->|缩放平移| E[更新视图]
    D -->|触摸交互| F[处理触摸事件]
    D -->|拖动行为| G[移动元素位置]
    D -->|力模拟| H[更新力布局]
    E --> D
    F --> D
    G --> D
    H --> D
8. 总结

通过本文的介绍,我们了解了数据可视化中多种交互技术的实现方法和应用场景,包括触摸交互、缩放与平移、拖动行为和力模拟技术。这些技术可以为数据可视化添加丰富的交互性和动态效果,提升用户体验和数据展示的效果。在实际应用中,可以根据项目的需求和特点选择合适的交互技术,并综合使用多种技术以实现更复杂的可视化效果。同时,需要注意不同交互技术的实现难度和性能影响,合理设置参数以达到最佳的效果。

希望本文能够帮助你更好地掌握数据可视化中的交互技术,为你的可视化项目带来更多的创意和价值。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值