D3.js 中,data绑定数据

使用数据文件:tweets.json

{
    "tweets": [
        {
            "user": "Al",
            "content": "I really love seafood.",
            "timestamp": " Mon Dec 23 2013 21:30 GMT-0800 (PST)",
            "retweets": ["Raj", "Pris", "Roy"],
            "favorites": ["Sam"]
        }, {
            "user": "Al",
            "content": "I take that back, this doesn't taste so good.",
            "timestamp": "Mon Dec 23 2013 21:55 GMT-0800 (PST)",
            "retweets": ["Roy"],
            "favorites": []
        }, {
            "user": "Al",
            "content": "From now on, I'm only eating cheese sandwiches.",
            "timestamp": "Mon Dec 23 2013 22:22 GMT-0800 (PST)",
            "retweets": [],
            "favorites": ["Roy", "Sam"]
        }, {
            "user": "Roy",
            "content": "Great workout!",
            "timestamp": " Mon Dec 23 2013 7:20 GMT-0800 (PST)",
            "retweets": [],
            "favorites": []
        }, {
            "user": "Roy",
            "content": "Spectacular oatmeal!",
            "timestamp": " Mon Dec 23 2013 7:23 GMT-0800 (PST)",
            "retweets": [],
            "favorites ": []}, 
            {
                "user": "Roy",
                "content": "Amazing traffic!",
                "timestamp": " Mon Dec 23 2013 7:47 GMT-0800 (PST)",
                "retweets": [],
                "favorites": []
            },
            {
                "user": "Roy",
                "content": "Just got a ticket for texting and driving!",
                "timestamp": " Mon Dec 23 2013 8:05 GMT-0800 (PST)",
                "retweets": [],
                "favorites": ["Sam", "Sally", "Pris"]
            },
            {
                "user": "Pris",
                "content": "Going to have some boiled eggs.",
                "timestamp": " Mon Dec 23 2013 18:23 GMT-0800 (PST)",
                "retweets": [],
                "favorites": ["Sally"]
            },
            {
                "user": "Pris",
                "content": "Maybe practice some gymnastics.",
                "timestamp": " Mon Dec 23 2013 19:47 GMT-0800 (PST)",
                "retweets": [],
                "favorites": ["Sally"]
            },
            {
                "user": "Sam",
                "content": "@Roy Let's get lunch",
                "timestamp": " Mon Dec 23 2013 11:05 GMT-0800 (PST)",
                "retweets": ["Pris"],
                "favorites": ["Sally", "Pris"]
            }
    ]
}

首先先导入文件,并将文件数据存入变量Data_中。(但是因为导入方法是异步方法,它发送文件请求后就会返回,执行后面的逻辑。所以如果后续逻辑紧接着就是用Data_,可能面临此时数据未返回未赋予Data_从而其值为空的情况,在这里不考虑)。

var Data_;
d3.json('tweets.json',function(d){
    Data_=d;
});

然后,在建立列表,当然此时html页面的body元素中是完全空白的:

d3.select("body").append("ul");
d3.select("ul").selectAll("li").data(Data_.tweets,function(d,i){
    return d.user;
}).enter().append("li").text(d=>d.user);

这里有几个要点

  1. 首先选择了body元素,然后创建(追加一个)ul元素。在此基础上选择所有li元素,显然此时没有li元素,所以.selectAll("li")会返回一个空集。

  2. 在空集基础之上绑定数据,暂且先不管data()。因为此时没有DOM元素(li)可以用来绑定数据,造成情况就是待绑定的数据多余了,这些多余的数据分别被封装为EnterNode类型对象,推入data方法所返回的对象的_enter属性之中,因此后续使用enter()方法时会处理这些多余的数据。

    可以看见,data方法返回的Selection对象中有_enter、_exit、_groups、_parents四个属性,当绑定数据(调用data方法)后又多余数据,这些数据会被封装为EnterNode类型对象,推入_enter中,数据被放在_data_属性之中。当然可以想到,如果绑定数据之后,DOM元素反而多余了,那么这些元素就会被推入_exit属性之中,后面会看到
  3. 调用enter()之后,后面的方法链会被循环调用。此时由于_enter属性中有10个EnterNode对象,则方法链会被调用10次,每一次都会传入EnterNode对象的__data__属性作为数据,在语句.enter().append("li").text(d=>d.user);,会插入一个li元素(append方法是上图中的_parent属性调用的,可见后面有一个[ul],它保存的就是父元素,在父元素上追加一个li子元素),一旦有这样一个li元素生成,那么li元素就会自动创建一个__data__属性,它的值和EnterNode对象的__data__是一致的,可以通过document.getElementsByTag("li")[i]._data_来查看。
    text用来设置元素文本,它的参数是一个函数,这个d当然就是__data__
    另外要注意, 如果忽略了append,直接写成.enter().text(d=>d.user);则不会有任何效果,因为没有实际添加元素,自然也不会有数据被实际绑定。

  4. 回到data方法:

    data(Data_.tweets,function(d,i){
        return d.user;
    })
    

    首先注意,写成Data_.tweets而不能写成Data_,第一个参数是指定被绑定的数据集,它一定要是一个数组类型或类数组类型。在上面的json文件可知,引用Data_后,里面只有一个tweets对象,这显然不合适,需要使用Data_.tweets,它代表数据数组。
    另外,第二个参数是指定主键,如果忽略,那么就按照数据数组的数字下标来充当主键。我们使用一个函数的返回值来充当主键,它是这么工作的:

    • 首先,计算selection中选中的DOM元素(selectAll("li"))的主键,如果有多个DOM结点元素的主键值相同,则多余的DOM结点会被推入_exit_中,供之后的exit()方法连调用。
    • 然后,按照给定的Key函数,基于数据集(Data_.tweets)计算出每一个数据项的主键值。并与DOM元素的主键进行匹配。如果这个主键匹配成功,则该元素可以被用来后续操作;如果匹配不成功(或主键值重复),则说明该数据是多余的,那么它会被封装为EnterNode并被推入_enter中,供enter()之后的方法链调用

    由于第一次使用,会创建li元素并且为其绑定user作为主键值。注意,主键值(也就是函数返回值)必须是数字或者字符串,所以,如果想把一个对象作为主键,需要返回JSON.stringift(obj)或其他定义方法把它变成字符串,否则就会调用Object.prototype.toString().call,这样就会得出[object Object],则显然会造成主键重复

我们来看一个例子。上述代码运行后,会立刻在html页面中创建一个由10个列表项的列表,主键是每一个tweetuser,但是显然主键是有重复的。现在,我们再次运行代码

d3.select("ul").selectAll("li").data(Data_.tweets,function(d,i){
    return d.user;
});

其返回结果


已知,前三个列表项的主键都是'Al'(用户名),所以只有第一个被推入_groups中供后续操作,后面两个li的主键与第一个重复,它们就被推入了_exit中,供exit()调用后操作,同理,因为重复,这两个li所对应的_data_属性数据也被封装并推入_enter_之中。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,076评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,658评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,732评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,493评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,591评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,598评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,601评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,348评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,797评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,114评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,278评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,953评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,585评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,202评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,442评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,180评论 2 367
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,139评论 2 352

推荐阅读更多精彩内容

  • (续jQuery基础(1)) 第5章 DOM节点的复制与替换 (1)DOM拷贝clone() 克隆节点是DOM的常...
    凛0_0阅读 1,333评论 0 8
  • 这篇笔记主要包含 Vue 2 不同于 Vue 1 或者特有的内容,还有我对于 Vue 1.0 印象不深的内容。关于...
    云之外阅读 5,048评论 0 29
  • 总结: 鼠标事件 1.click与dbclick事件$ele.click()$ele.click(handler(...
    阿r阿r阅读 1,603评论 2 10
  • 一个愚蠢的人 一个什么都拖累别人 ,拖累事儿的人 认识到了 压抑在心里 可以改变吗!? 想要改变
    A_fa阅读 133评论 0 0
  • 明年2017,成功步入28,买房,装修,还贷!工作五年,成功将最后一笔存款用在了装修上,银行卡上的数字归零!不知道...
    深蓝2007阅读 302评论 0 0