交互式数据可视化:动画 viewBox

Avatar of Sarah Drasner
Sarah Drasner

DigitalOcean 为您的旅程各个阶段提供云产品。从 $200 免费信用 开始!

动态控制数据可视化在页面上的布局方式在传达信息方面非常强大。过去,我们讨论过如何利用它 隐藏和显示信息 以进行响应式开发。在使用 SVG 时,我们可以通过将 viewBox 作为相机来实现这一点,从而隔离页面上的相关信息,以突出显示供查看者查看的信息。这种技术有许多用途。我们将探讨一种新的动态使用它的方法,让处理器为我们完成繁重的工作。

在深入研究 viewBox 动画之前,我们应该先了解 SVG 中的 viewBox 究竟是什么。在这里,我只介绍基本内容,但如果您想深入研究,可以参考一些 很棒的文章 帮助您做到这一点

viewBox 充当一个窗口,您通过它可以看到您的 SVG。它通过 4 个坐标值定义:min-xmin-ywidthheight。在下面的图形中,您可以看到完整的绘图

周围的黑色框定义了 viewBox。如果您熟悉 Illustrator,这就是“画板”。您可以通过转到文件 > 文档设置 > 编辑画板来更改 Illustrator 中的画板。然后,您可以动态裁剪图像并更改可见区域。如果您知道您的图形与所需的 viewBox 大小完全相同,则可以通过对象 > 画板 > 适应图稿边界快速执行此操作。

查看 Sarah Drasner(@sdras)在 CodePen 上创建的笔 显示完整 viewBox

当我们保持 viewBox 相同时,可以更改 SVG 的宽度和高度

查看 Sarah Drasner(@sdras)在 CodePen 上创建的笔 显示完整 viewBox

您可以将其视为 SVG DOM 沿网格进行自身绘制。该网格可以收缩和扩展,但网格的纵横比保持一致。这里,我们绘制的 SVG 位于网格 x 轴的 0 最小值和 y 的 0 最小值处。宽度大约在 384.5 处扩展,高度大约在 250 处扩展。

如果我们将这些房子分组,我们可以看到它们的位置

我们可以通过将 viewBox 更改为 "215 160 42.2 20" 来将整个可见区域裁剪为仅包含房子。

为了找到该组的 viewBox 坐标,我们可以进行一些测量,手动进行编辑,但这非常繁琐,而且由于 viewBox 是可缩放的,因此会变得很复杂。幸运的是,我们可以使用一种称为 getBBox() 的本机方法。这会返回调用该方法时所处的边界框,并且不包括描边、遮罩或滤镜效果。它会在调用时返回一个 SVGRect 对象(即使它尚未渲染)。

SVGRect 对象的妙处在于它返回四个值。x-miny-minwidthheight。听起来有点耳熟吧?

这非常方便,因为为了动态更新 viewBox,我们只需将来自对象的这些值存储为新的 viewBox 字符串,如下所示:var newView = "" + s.x + " " + s.y + " " + s.width + " " + s.height;

然后,我们可以将新的 viewBox 字符串设置为 SVG 上的 viewBox 属性:foo.setAttribute("viewBox", newView);

查看 Sarah Drasner(@sdras)在 CodePen 上创建的笔 显示完整 viewBox

现在我们已经可以开始使用了。

要动画化到新的 viewBox 值,我们有几个选项,所有这些选项都使用 JavaScript(目前)。

  • 我们可以使用 requestAnimationFrame(带有一个 polyfill)来随时间更新坐标值。
  • 我们可以使用 GreenSock 的 attr 插件(已与 TweenMax 的典型默认库捆绑在一起)来动画化它。

GreenSock 的妙处在于它可以动画化任何两个整数,因此它非常适合此目的。我将在以下示例中使用 GreenSock,因为我还想动画化其他一些内容,并且想要快速准确地控制我的缓动值。但是,两种方法都非常有效。

需要牢记的一点是,SVGRect 始终会返回一个矩形,即使所讨论的元素不是矩形,而且即使它进行了变换,也没有对角线。以下是一些带描边的旋转形状的快速演示,以便您了解我的意思

查看 Sarah Drasner(@sdras)在 CodePen 上创建的笔 显示当 SVG 元素旋转时边界框发生的情况

在以下示例中,我有一个地图,当用户与它交互时,我想提供有关他们选择的特定国家/地区的更多信息。

查看 Sarah Drasner(@sdras)在 CodePen 上创建的笔 动画 viewBox 数据可视化

我为热点重复了动画。我还使用了一些元素本身上的简单数据属性,以便我可以存储并使用这些信息来执行动画。这里保持一致的命名非常重要——它是我控制哪个国家/地区被扩展以及显示哪些细节的方式。

<g data-name="usa" class="hotspot">
  <circle id="dot2" cx="221" cy="249" r="2.4" fill="url(#radial-gradient)"/>
  <circle id="dot1" cx="221" cy="249" r="2.4" fill="url(#radial-gradient)"/>
  <circle id="dotmid" cx="221" cy="249" r="2.3" fill="#45c6db"/>
</g>

我还向热点元素添加了一些额外的填充,以便它们的点击目标足够大,以适用于移动设备和我们的手指

.hotspot {
  cursor: pointer;
  /* make the hit targets bigger for mobile */
  padding: 20px;
}

然后,我可以编写一个函数,该函数在点击时传入数据属性,并根据国家/地区的形状更新 viewBox。我在宽度上添加了 200,以适应国家/地区旁边的文本。

// interaction
function zoomIn(country) {
// zooming in part
var currentCountry = document.getElementById(country),
    s = currentCountry.getBBox(),
    newView = "" + s.x + " " + s.y + " " + (s.width + 200) + " " + s.height,
    group1 = [".text-" + country, ".x-out"],
    tl = new TimelineMax();
  
    tl.add("zIn");
    tl.fromTo(map, 1.5, {
      attr: { viewBox: "0 0 1795.2 875.1"}
    }, {
      attr: { viewBox: newView }
    }, "zIn");
    tl.to(".text-" + country, 0.1, {
      display: "block"
    }, "zIn");
    tl.fromTo(group2, 0.25, {
      opacity: 1
    }, {
      opacity: 0,
      ease: Circ.easeIn
    }, "zIn");
    tl.fromTo(currentCountry, 0.35, {
      opacity: 0
    }, {
      opacity: 1,
      ease: Circ.easeOut
    }, "zIn+=0.5");
    tl.fromTo(group1, 0.5, {
      opacity: 0
    }, {
      opacity: 0.65,
      ease: Sine.easeOut
    }, "zIn+=1");
}

$(".hotspot").on("click", function() {
  var area = this.getAttribute('data-name');
  $(".x-out").attr("data-info", area);
  zoomIn(area);
});

如果我想让我的代码超级简洁,我可以将时间轴包装到一个函数中,并在有人点击 X 按钮时简单地反转它,但是当我尝试这样做时,动画比我喜欢的要稍微差一些,因此我创建了一个新函数来稍微调整一下时间。我也可以使用 tl.to 而不是 fromTo,但是我发现,在重新启动动画时,在 fromTo 中提供初始值有助于稳定它(尤其是如果您不知道谁可能会更新您的代码)。

viewBox 在 CSS 中?

Jake Archibald 提出了一个提案,即 将 viewBox 提升为 CSS 属性,我对此表示大力支持。如果您也想要支持它,请在现有评论中添加一条包含技术反馈的评论或点赞(以避免评论过多)。能够控制 viewBox 的 CSS 属性非常棒,因为我们可以轻松地应用媒体查询和动画,甚至可以减少此类更新的布局触发和重绘。

另一个演示:引导式信息图表

为了更有趣,我做了一个小的流程图,展示了如何使用这种技术来引导用户。这个特定的图表引导用户选择最适合的工作图像格式。

查看 Sarah Drasner(@sdras)在 CodePen 上创建的笔 动画流程图 3

动画警告:它可能令人头晕,因此如果您患有前庭疾病,请勿玩它。如果我将它嵌入到生产网站中,我可能会添加一个切换开关来关闭动画或回退到一个简化的问卷。

其他探索

还有其他人也在研究动画化 viewBox 的想法。Louis Hoebregts 撰写了一篇 很棒的文章,David Bachmann Johannesson 创建了 简洁而酷炫的笔,等等。

您见过其他示例吗?请在评论区中分享。