动态控制数据可视化在页面上的布局方式在传达信息方面非常强大。过去,我们讨论过如何利用它 隐藏和显示信息 以进行响应式开发。在使用 SVG 时,我们可以通过将 viewBox
作为相机来实现这一点,从而隔离页面上的相关信息,以突出显示供查看者查看的信息。这种技术有许多用途。我们将探讨一种新的动态使用它的方法,让处理器为我们完成繁重的工作。
在深入研究 viewBox
动画之前,我们应该先了解 SVG 中的 viewBox
究竟是什么。在这里,我只介绍基本内容,但如果您想深入研究,可以参考一些 很棒的文章 帮助您做到这一点。
viewBox
充当一个窗口,您通过它可以看到您的 SVG。它通过 4 个坐标值定义:min-x
、min-y
、width
和 height
。在下面的图形中,您可以看到完整的绘图

周围的黑色框定义了 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-min
、y-min
、width
和 height
。听起来有点耳熟吧?

这非常方便,因为为了动态更新 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 创建了 简洁而酷炫的笔,等等。
您见过其他示例吗?请在评论区中分享。
还有一个!
http://codepen.io/Mamboleoo/pen/PZWPZx
看起来,这就是 Bustle 的交互式流程图 中使用的技术。
这些 Bustle 的流程图简直太棒了!哇,我喜欢它。太令人印象深刻了。尤其是它使用沿路径的运动(我猜是)从一个点移动到另一个点。太酷了。
我们无法像在 Codepen 上那样在这里点赞/喜欢评论,但是……非常感谢您分享我的笔 :’)
感谢 Sarah 在文章中分享了我的帖子 :3
很棒的文章,示例使解释很容易理解,感谢发布。
我使用了一个用 Greensock 动画的 viewbox,让观看者在他们观看我们主页上 http://thefoodwarriors.com 的视频系列时,沿着侧边栏上的纽约地铁地图 SVG “行驶”。
该网站仓促拼凑,有些东西我应该重新审视,但我对整体效果很满意。这是我第一次使用 Greensock 或对 SVG 进行任何有意义的操作。
另外,提醒一下… 你流程图中 “Do you have a specific thing you want it to do at every breakpoint?” 的 “No” 链接似乎已损坏。
我喜欢你将 YouTube 视频与 Greensock 动画相结合的方式。
做得简洁。非常酷。
很棒的文章和演示。
以下来自 Craig Roblewsky 的另外两个示例
http://codepen.io/PointC/pen/zrQLvO
http://codepen.io/PointC/pen/OMabPa
做得不错!!
如果
viewBox
成为一个 CSS 属性,这意味着它不仅可以用 CSS 动画化,还可以用 Web Animation API 动画化。哦,天哪。