用D3.js 十分钟实现字符跳动效果
用D3.js 十分钟实现字符跳动效果
注
本文基于 D3.js 作者
Mike Bostock
的 例子
原文分为三部分, 在这里笔者将其整合为了一篇方便阅读.
该效果基于 D3.js, 主要使用到了 d3-selection. 如果对d3-selection的基本使用逻辑不太清楚可以参见 这篇文章.
效果图
- Step1 首先代码会随机生成一个字符串, 该字符以绿色进入画面.
- Step2 接下来, 代码随机生成一个新字符串, 新生成的字符串会和原始字符串进行对比:
2.1 新字符串和原始字符串中相同的字母,会变成黑色保留在屏幕上
2.2 原始字符串中有, 而新字符串中没有的字母, 会变成红色,被移除屏幕
2.3 新字符串中有, 而原始字符串中没有的字母, 会变成绿色,被添加到屏幕
代码实现
1. 字符切换
第一步要完成的效果是:
- 完成基本字符切换
- 进入时为绿色, 不变时为黑色
- 被移除的字符直接被从界面中移除
先上代码, 点我运行
<script> var alphabet = "abcdefghijklmnopqrstuvwxyz".split(""); var svg = d3.select("svg"), width = +svg.attr("width"), height = +svg.attr("height"), g = svg.append("g").attr("transform", "translate(32," + (height / 2) + ")"); function update(data) { // DATA JOIN // Join new data with old elements, if any. var text = g.selectAll("text") .data(data); // UPDATE // Update old elements as needed. text.attr("class", "update"); // ENTER // Create new elements as needed. // // ENTER + UPDATE // After merging the entered elements with the update selection, // apply operations to both. text.enter().append("text") .attr("class", "enter") .attr("x", function(d, i) { return i * 32; }) .attr("dy", ".35em") .merge(text) .text(function(d) { return d; }); // EXIT // Remove old elements as needed. text.exit().remove(); } // The initial display. update(alphabet); // Grab a random sample of letters from the alphabet, in alphabetical order. d3.interval(function() { update(d3.shuffle(alphabet) .slice(0, Math.floor(Math.random() * 26)) .sort()); }, 1500); </script>
代码不长, 接下来一步步分析代码逻辑:
首先, 获取svg的宽高信息. 并创建一个 元素用来承接接下来要创建的字符( 元素)
var svg = d3.select("svg"), width = +svg.attr("width"), height = +svg.attr("height"), g = svg.append("g").attr("transform", "translate(32," + (height / 2) + ")");
在 update()
方法中, 我们传进来一个字符串 data (data由26个字母中随机选出一些组成). 首先我们选中所有的 text 元素并将其和data 进行绑定:
var text = g.selectAll("text") .data(data);
然后我们处理enter集合 (也就是新加入的字符), 为每一个新字符添加一个 text 元素, 并为其添加class属性, 使用index为其计算出横纵坐标:
text.enter().append("text") // 添加svg text元素 .attr("class", "enter") // 添加class属性 (绿色) .attr("x", function(d, i) { return i * 32; }) // 按每个字符32像素, 为其计算x坐标 .attr("dy", ".35em") // 设置y轴偏移量
接下来同时处理 enter 和 update 集合, 将字符数据填入 text 元素中:
.merge(text) .text(function(d) { return d; });
最后处理 exit集合, 我们暂时直接将其从屏幕中移除:
text.exit().remove();
我们用 d3.interval(callback, timeInterval)
定时调用update()
来实现字符刷新. 现在我们就得到了下面的效果:
2. 为字符设定key值
如果你观察仔细的话, 你可能已经发现第一步实现的效果中: 新加的字符总是出现在最后. 这显然不是我们想要的效果, 新加的字符出现的位置应该是随机的. 那么出现现在这个效果的原因是什么呢?
答案在于我们在绑定字符数据时: data(data)
并没有指定data的key值, 那么d3会默认使用index作为key, 这样就是为什么新增加的字符总是出现在最后面.
所以我们为字符加入key值的accessor:
var text = g.selectAll("text") .data(data, function(d) { return d; });
现在 key 值绑定好后, 已经存在的字符在update时text已经不会再改变, 但是坐标需要重新计算, 所以我们做以下改动:
text.enter().append("text") .attr("class", "enter") .attr("dy", ".35em") .text(function(d) { return d; }) // 将text赋值移动到 enter中 .merge(text) .attr("x", function(d, i) { return i * 32; }); // 将坐标计算移动到 merge后 (enter & update)
现在我们的代码长这样, 点我在线运行:
<script> var alphabet = "abcdefghijklmnopqrstuvwxyz".split(""); var svg = d3.select("svg"), width = +svg.attr("width"), height = +svg.attr("height"), g = svg.append("g").attr("transform", "translate(32," + (height / 2) + ")"); function update(data) { // DATA JOIN // Join new data with old elements, if any. var text = g.selectAll("text") .data(data, function(d) { return d; }); // UPDATE // Update old elements as needed. text.attr("class", "update"); // ENTER // Create new elements as needed. // // ENTER + UPDATE // After merging the entered elements with the update selection, // apply operations to both. text.enter().append("text") .attr("class", "enter") .attr("dy", ".35em") .text(function(d) { return d; }) .merge(text) .attr("x", function(d, i) { return i * 32; }); // EXIT // Remove old elements as needed. text.exit().remove(); } // The initial display. update(alphabet); // Grab a random sample of letters from the alphabet, in alphabetical order. d3.interval(function() { update(d3.shuffle(alphabet) .slice(0, Math.floor(Math.random() * 26)) .sort()); }, 1500); </script>
现在我们得到的效果:
3.添加动画
动画能让我们更好的观察元素的变化过程和状态, 给不同状态的元素赋予不同的动画可以更直观的展示我们的数据.
现在我们给字符的变化增加动画效果, 并把字符移除时的颜色变化补上.
首先我们定义一个 transition变量, 并设置其动画间隔为 750
var t = d3.transition() .duration(750);
在D3中使用动画非常简单, 在动画前指定元素的一些属性, 调用动画, 再指定动画后的一些属性. D3会自动根据插值器生成动画.
下面的代码对于离开界面的字符(exit selection)进行了处理:
text.exit() .attr("class", "exit") // 动画前, 设置class属性, 字体变红 .transition(t) // 设置动画 .attr("y", 60) // 设置y坐标, 使元素向下离开界面 (y: 0 => 60) .style("fill-opacity", 1e-6) // 设置透明度, 使元素渐变消失 (opacity: 1 => 0) .remove(); // 最后将其移出界面
同样的, 我们对 enter 和 update selection进行处理:
// UPDATE old elements present in new data. text.attr("class", "update") .attr("y", 0) .style("fill-opacity", 1) .transition(t) .attr("x", function(d, i) { return i * 32; }); // ENTER new elements present in new data. text.enter().append("text") .attr("class", "enter") .attr("dy", ".35em") .attr("y", -60) .attr("x", function(d, i) { return i * 32; }) .style("fill-opacity", 1e-6) .text(function(d) { return d; }) .transition(t) .attr("y", 0) .style("fill-opacity", 1);
最终我们的代码长这样, 点我运行
<script> var alphabet = "abcdefghijklmnopqrstuvwxyz".split(""); var svg = d3.select("svg"), width = +svg.attr("width"), height = +svg.attr("height"), g = svg.append("g").attr("transform", "translate(32," + (height / 2) + ")"); function update(data) { var t = d3.transition() .duration(750); // JOIN new data with old elements. var text = g.selectAll("text") .data(data, function(d) { return d; }); // EXIT old elements not present in new data. text.exit() .attr("class", "exit") .transition(t) .attr("y", 60) .style("fill-opacity", 1e-6) .remove(); // UPDATE old elements present in new data. text.attr("class", "update") .attr("y", 0) .style("fill-opacity", 1) .transition(t) .attr("x", function(d, i) { return i * 32; }); // ENTER new elements present in new data. text.enter().append("text") .attr("class", "enter") .attr("dy", ".35em") .attr("y", -60) .attr("x", function(d, i) { return i * 32; }) .style("fill-opacity", 1e-6) .text(function(d) { return d; }) .transition(t) .attr("y", 0) .style("fill-opacity", 1); } // The initial display. update(alphabet); // Grab a random sample of letters from the alphabet, in alphabetical order. d3.interval(function() { update(d3.shuffle(alphabet) .slice(0, Math.floor(Math.random() * 26)) .sort()); }, 1500); </script>
最终效果:
如果觉得不错的话, 不妨点击下面的链接关注一下 : )
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Confluence 6 配置时间和日期格式
你可以修改你 Confluence 为用户显示的时期和时间格式。设置的句法使用的是 SimpleDateFormat class,请参考 Java SimpleDateFormat 文档中的内容来设置日期和时间格式。 有下面 3 个时间和日期的格式需要设置: 时间格式:使用在日期中显示的时间的格式。例如,当博客页面被添加后,示例的配置为:h:mm a 日期时间格式:需要同时显示日期和时间的时候使用。例如,在页面的历史版本中,示例的配置为:MMM dd, yyyy HH:mm 日期格式:需要只显示日期的时候使用。例如,在创建和最近修改的页面中,示例的配置为:MMM dd, yyyy 如何修改时间和日期格式: 在屏幕的右上角单击控制台按钮,然后选择General Configuration 链接。 在左侧面板中 选择 基本配置(General Configuration)。 选择 编辑(Edit)。 为 时间格式,日期时间格式(Time Format,Date Time Format)和 日期格式(Date Format)输入你需要的值。 选择 保存(Save)。 https://www....
- 下一篇
可视化讲解 DOM 构建过程
前言 最近在看 _Secrets of the JavaScript Ninja_, 书中第二章讲到 DOM 的构建流程. 记得我之前也为理解 DOM 构建流程查阅过数次资料, 虽然每次查阅完都觉得 DOM 构建流程很简单, 看完便懂, 但是懂了又忘还是让人有些头疼. 为了给自己加深印象, 也为了为大家提供一个可视化的理解 DOM 构建过程的方式, 笔者制作了一个简单的网页来动态演示 DOM 构建过程. 希望能给大家带来一些帮助. 效果 在线查看 在线 demo (请使用 pc 访问) 前进, 后退 网页展示了一个简单的 HTML 页面的 DOM 渲染过程. 用户点击前进,后退按钮时, 页面左侧会显示出当前的 HTML 代码, 右侧则会显示出实时的 DOM 结构图: 自动播放 点击 Auto Play 按钮, 页面会自动播放页面的整个构建过程: DOM 构建过程 DOM 元素的作用 & 基本构建过程: 这里直接引用一下原文: The goal of this page-building phase is to set up the UI of a web application...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
-
Docker使用Oracle官方镜像安装(12C,18C,19C)
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS8编译安装MySQL8.0.19
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- MySQL8.0.19开启GTID主从同步CentOS8
- CentOS7,8上快速安装Gitea,搭建Git服务器
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
推荐阅读
最新文章
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- CentOS8编译安装MySQL8.0.19
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- SpringBoot2整合Redis,开启缓存,提高访问速度
- CentOS关闭SELinux安全模块
- Hadoop3单机部署,实现最简伪集群
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- SpringBoot2全家桶,快速入门学习开发网站教程
- SpringBoot2更换Tomcat为Jetty,小型站点的福音