首先欢迎大家关注我的公众号获取更多前端干货: 前端夜谈

本文基于 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轴偏移量

接下来同时处理 enterupdate 集合, 将字符数据填入 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();                      // 最后将其移出界面

同样的, 我们对 enterupdate 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>

最终效果:

如果觉得不错的话, 不妨点击下面的链接关注一下 : )

github主页

知乎专栏

掘金

想直接联系我?

微信公众号: 前端夜谈

JS 打印 data数据_用D3.js 十分钟实现字符跳动效果相关推荐

  1. 用D3.js 十分钟实现字符跳动效果

    用D3.js 十分钟实现字符跳动效果 注 本文基于 D3.js 作者 Mike Bostock 的 例子 原文分为三部分, 在这里笔者将其整合为了一篇方便阅读. 该效果基于 D3.js, 主要使用到了 ...

  2. js添加class_用D3.js 十分钟实现字符跳动效果

    用D3.js 十分钟实现字符跳动效果 注 本文基于 D3.js 作者 Mike Bostock 的 例子 原文分为三部分, 在这里笔者将其整合为了一篇方便阅读. 该效果基于 D3.js, 主要使用到了 ...

  3. JS 打印 data数据_小程序导出数据到excel表

    小程序导出数据到excel表,借助云开发后台实现excel数据的保存 我们在开发小程序的过程中,可能会有这样的需求:如何将云数据库里的数据批量导出到excel表里? 这个需求可以用强大的云开发轻松实现 ...

  4. JS 打印 data数据_寒冬求职季之你必须要懂的原生JS(中)

    本文原载于SegmentFault专栏"前端进阶" 作者:前端小姐姐 整理编辑:SegmentFault 互联网寒冬之际,各大公司都缩减了HC,甚至是采取了"裁员&quo ...

  5. JS 打印 data数据_数据表格 Data Table - 复杂内容的15个设计点

    表格是桌面应用中常见的内容型组件,它包含大量的信息和丰富的交互形式,表格具有极高的空间利用率,结构化的展示保证了数据可读性.高效.清晰且易用是进行表格设计的原则性要求.本文将从表格的内容组织到交互作一 ...

  6. 全网最简单的C# json数据解析 无敌菜鸟教程 十分钟搞定json数据解析

    全网最简单的C# json数据解析 无敌菜鸟教程 十分钟搞定json数据解析 废话先说一点,算了.直接进入正题吧. 用例子说话: JSON数据: string json: " {" ...

  7. 数据可视化利器D3.js教程 API

    汇智网 http://xc.hubwiz.com/course/54fd40cfe564e50d50dcf284 D3.js 入门系列 - 选择元素和绑定数据 https://www.cnblogs. ...

  8. node爬取app数据_使用node.js如何爬取网站数据

    数据库又不会弄,只能扒扒别人的数据了. 搭建环境: (1).创建一个文件夹,进入并初始化一个package.json文件. npm init -y (2).安装相关依赖: npm install -- ...

  9. android studio使用nodejs本地服务器json数据_使用Node.js的Alexa技巧

    可以使用AlexaLambda函数或RESTAPI端点开发Alexa技能.Lambda函数是Amazon实现AWS中提供的无服务器功能.Amazon建议使用Lambda函数,尽管它们不容易调试.虽然您 ...

  10. vue子组件获取父组件数据_在vue.js中父组件是如何向子组件传递数据的?

    本文只有一个学习点. 父组件如何向子组件传递数据. 一起学习,更多文章请关注我的头条号,我是落笔承冰. 一.先创建一张空白网页index.html,在head标签里设置好vue的链接库. 二.写一个绑 ...

最新文章

  1. 了解Hololens2的硬件信息
  2. Django开发环境准备
  3. 我的世界之史蒂夫生存记
  4. 机器学习知识点(二十五)Java实现隐马尔科夫模型HMM之jahmm库
  5. php stripos 返回值,php函数stripos详解
  6. 要学会Python爬虫都需要什么基础呢?
  7. 使用AWS Lambda在Go中构建RESTful API
  8. leetcode 242. 有效的字母异位词 思考分析
  9. C#多线程之旅(3)——线程池
  10. java table 数据绑定,ireport5.6使用table组件,如何用table显示javaBean数据源
  11. 什么样的合作方式最舒服
  12. 横向扩展 纵向扩展 数据库_扩展数据库–减少扩展的艺术
  13. 全排列---STL方法与递归方法
  14. 一些好用的nginx第三方模块
  15. c#基础系列2---深入理解 String
  16. mac地址扫描源码_ARP-基础-扫描-攻击-防范!
  17. java常用单词及解释_Java常用英语单词
  18. linux练习题十七
  19. 两个路由器+两个主机:简单的网络配置
  20. 动漫培训学费一般多少钱

热门文章

  1. Rhel6服务器日志浅谈
  2. 自定义UITabBarController以及UITabBar的分析
  3. 【Java】反射 Reflection
  4. PHP分类输出代码,PHP无限分类代码,支持数组格式化、直接输出菜单两种方式_php技巧...
  5. adb 安卓模拟器 进程端口_Frida初体验安卓CTF逆向
  6. observable java_RxJava之Observables类型理解
  7. Unix下oracle备份,Linux下Oracle备份与数据迁移
  8. Linux ls按时间排列
  9. JS中的slice和splice
  10. 分布式锁的原理和实现详解