09-D3.js动态增删数据

目前为止,只要更新数据,我们采用的都是“整批整包”的方式:改变数据集数组中的值,然后重新绑定修改后的值,覆盖原始值对 DOM 元素的绑定。

这种方式非常适合所有值都会改变,而且数据集长度(即数据值的数量)不变的情形。可是我们知道,现实中的数据可没那么简单。这就对代码的灵活性提出了更高要求,比如只更新一两个值,或者支持增加值和减少值,等等。

动态增加删除.gif
  • 注意事项:
  • data() 把数据绑定到元素,但也会返回更新元素集。

  • 更新元素集可能包含加入和退出元素集,这两个元素集可以通过 enter() 和 exit() 方法得到。

  • 在数据值比元素多的情况下,加入元素集会引用尚不存在的占位元素。

  • 在元素比数据值多的情况下,退出元素集会引用没有对应数据的元素。

  • 数据联结用于确定数据值怎么与元素匹配。

  • 默认情况下,数据联结按照索引(也就是值在数据集中出现的顺序)进行。

  • 要对数据联结施加更多控制,可以指定键函数。

<p id="add">Add a new data value</p>
<p id="remove">Remove a data value</p>
//Width and height
var w = 600;
var h = 250;

var dataset = [{ key: 0, value: 5 },        //dataset is now an array of objects.
{ key: 1, value: 10 },      //Each object has a 'key' and a 'value'.
{ key: 2, value: 13 },
{ key: 3, value: 19 },
{ key: 4, value: 21 },
{ key: 5, value: 25 },
{ key: 6, value: 22 },
{ key: 7, value: 18 },
{ key: 8, value: 15 },
{ key: 9, value: 13 },
{ key: 10, value: 11 },
{ key: 11, value: 12 },
{ key: 12, value: 15 },
{ key: 13, value: 20 },
{ key: 14, value: 18 },
{ key: 15, value: 17 },
{ key: 16, value: 16 },
{ key: 17, value: 18 },
{ key: 18, value: 23 },
{ key: 19, value: 25 }];

var xScale = d3.scaleBand()
    .domain(d3.range(dataset.length))
    .rangeRound([0, w])
    .paddingInner(0.05);

var yScale = d3.scaleLinear()
    .domain([0, d3.max(dataset, function (d) { return d.value; })])
    .range([0, h]);

//Define key function, to be used when binding data
var key = function (d) {
    return d.key;
};

//Create SVG element
var svg = d3.select("body")
    .append("svg")
    .attr("width", w)
    .attr("height", h);

//Create bars
svg.selectAll("rect")
    .data(dataset, key)
    .enter()
    .append("rect")
    .attr("x", function (d, i) {
        return xScale(i);
    })
    .attr("y", function (d) {
        return h - yScale(d.value);
    })
    .attr("width", xScale.bandwidth())
    .attr("height", function (d) {
        return yScale(d.value);
    })
    .attr("fill", function (d) {
        return "rgb(0, 0, " + (d.value * 10) + ")";
    });

//Create labels
svg.selectAll("text")
    .data(dataset, key)
    .enter()
    .append("text")
    .text(function (d) {
        return d.value;
    })
    .attr("text-anchor", "middle")
    .attr("x", function (d, i) {
        return xScale(i) + xScale.bandwidth() / 2;
    })
    .attr("y", function (d) {
        return h - yScale(d.value) + 14;
    })
    .attr("font-family", "sans-serif")
    .attr("font-size", "11px")
    .attr("fill", "white");




//On click, update with new data            
d3.selectAll("p")
    .on("click", function () {

        //在匿名的监听器函数内部,this 引用被单击的元素(p),因此选择this, 再使用 attr() 就可以取得被单击元素的 ID
        var paragraphID = d3.select(this).attr("id");

        //Decide what to do next
        if (paragraphID == "add") {
            //Add a data value
            var minValue = 2;
            var maxValue = 25 - minValue;
            var newNumber = Math.floor(Math.random() * maxValue) + minValue;
            var lastKeyValue = dataset[dataset.length - 1].key;
            dataset.push({
                key: lastKeyValue + 1,
                value: newNumber
            });
            //如果要同时添加和删除
            // dataset.shift(); 

        } else {
            //Remove a value
            dataset.shift();    //Remove one value from dataset
        }

        //Update scale domains
        xScale.domain(d3.range(dataset.length));
        yScale.domain([0, d3.max(dataset, function (d) { return d.value; })]);

        //Select…
        var bars = svg.selectAll("rect")
            .data(dataset, key);

        //Enter…
        bars.enter()
            .append("rect")
            .attr("x", w)
            .attr("y", function (d) {
                return h - yScale(d.value);
            })
            .attr("width", xScale.bandwidth())
            .attr("height", function (d) {
                return yScale(d.value);
            })
            .attr("fill", function (d) {
                return "rgb(0, 0, " + (d.value * 10) + ")";
            })
            .merge(bars)    //Update…
            .transition()
            .duration(500)
            .attr("x", function (d, i) {
                return xScale(i);
            })
            .attr("y", function (d) {
                return h - yScale(d.value);
            })
            .attr("width", xScale.bandwidth())
            .attr("height", function (d) {
                return yScale(d.value);
            });

        //Exit…
        bars.exit()
            .transition()
            .duration(500)
            .attr("x", -xScale.bandwidth())
            .remove();

        //标签的添加、过渡和删除
        //Select…
        var labels = svg.selectAll("text")
            .data(dataset, key);

        //Exit…
        labels.exit()
            .transition()
            .duration(500)
            .attr("x", -xScale.bandwidth())
            .remove();

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

推荐阅读更多精彩内容