c语言sscanf函数的用法是什么
275
2022-09-16
d3js源码解析,selection模块(三),数据是如何绑定到元素上的?
selection模块结构
选择元素修改元素加入数据(本章的内容)处理事件控制流局部变量命名空间
添加数据
这部分开始介绍Join,讲解的两个文章selection.join notebookThinking With Joins
selection.data([data[, key]])
讲述数据数组绑定到元素上,返回绑定成功的selection表示update状态,同时也定义了enter,exit状态在返回的选择器上,数据可以为任意数组(数字,对象数组…)或者一个返回数组函数,存储在选择器的__data__属性中,从而使数据具有“粘滞性”。 结合join、enter、exit、append、remove,可以以数据驱动的方式添加、更新、删除元素,如下例子从matrix中创建html:
const matrix = [ [11975, 5871, 8916, 2868], [ 1951, 10048, 2060, 6171], [ 8010, 16145, 8090, 8045], [ 1013, 990, 940, 6907]];evs.select("body") .append("table") .selectAll("tr") .data(matrix) .join("tr") .selectAll("td") .data(d => d) .join("td") .text(d => d);
再该例子中,通过matrix的长度添加table行数。 如果没有指定key,则按数本身据顺序进行添加,如果key为函数,为每个元素执行该函数返回的字符串添加为当前元素(这里就只源码中的keyValue,类似于一个标记位),并把数据节点合并到enter中。data源码解析如果只看文档真是一头雾水,这里设计的原则就是为选择器添加了几个数组类属性,目前现在可以理解为data、enter、update、exit,当我们data一个数据的时候,会先根据data中的数据分别向这三个数组中添加元素,数据驱动的含义也在这里,update为更新过的数组,即原来的该节点的数据中和新加入的data冲突了,更新原来已有的节点已绑定数据的数据,enter就是data中去掉了更新的那部分剩余的数据,相当于添加新元素节点,exit会存放哪些无法与数据匹配上的,或数据长度就那么多,多余出来的原先存在的节点,相当于删除掉哪些节点了。当然最后作者删掉了update,因为这只是一个过程变量,不需要进行存储了。 你可以简单理解为enter会向原节点添加进去绑定数据,以方便以该数据驱动添加节点,exit数组存储的则为删除与数据不匹配的节点,update就是最后的返回值。源代码:不想看就跳过,但我觉着看一下代码就豁然开朗了:
import {Selection} from "./index.js";import {EnterNode} from "./enter.js";import constant from '../constant.js';var keyPrefix='$'; //防止像__proto__这样的key//不输入key的情况function bindIndex(parent,group,enter,update,exit,data){ var i=0, node, groupLength=group.length, dataLength=data.length; //这里处理可以添加数据的元素,即按传入数据data的长度向元素添加数据 //把非空节点加入update,所以这里update的含义可以说是可以被更新的节点数组 //把空节点加入enter for(;i
例如这个文档:
通过key函数添加数据:
const data = [ {name: "Locke", number: 4}, {name: "Reyes", number: 8}, {name: "Ford", number: 15}, {name: "Jarrah", number: 16}, {name: "Shephard", number: 23}, {name: "Kwon", number: 42}];d3.selectAll("div") .data(data, function(d) { return d ? d.name : this.id; }) .text(d => d.number);
key函数通过判断d是否存在,返回name或id,以为当前选择器元素没有绑定过数据,元素上的数据(datum)即上面代码证d为空,如果元素绑定过了数据,则d为费空。 更新(update)和添加(enter)以数据顺序进行,删除状态(exit)保留原有的顺序,也许在指定了key时选择器中的元素顺序与文档中的元素顺序不一致,此时需要用前面提到的selection.order或sort对文档排序,关于key函数的更多理解Let’s Make a Bar Chart, IIObject Constancy 如果没有指定data,则返回选择器元素的数据数组,该方法不能用来清除绑定数据,使用selection.datum.
selection.join(enter[, update][, exit])
根据之前绑定的数据data,对元素添加、删除、重新排序,是enter、exit、append、remove、oreder的显示替换。代码实现也是封装的这些函数。用法如下
svg.selectAll("circle") .data(data) .join("circle") .attr("fill", "none") .attr("stroke", "black");
并且可以传入函数控制每个操作:
svg.selectAll("circle") .data(data) .join( enter => enter.append("circle").attr("fill", "green"), update => update.attr("fill", "blue") ) .attr("stroke", "black");
换可以通过第三个函数删除,返回值会合并enter和update并返回通过分隔enter和update,以及在data中添加key函数,可以最小化对dom的更改以优化性能。 还可以通过在enter、update、exit中创建过渡来设置动画,为避免破坏方法链用selection.call创建过渡,或返回一个未定义的enter、update组织合并。
selection.enter()
返回选择器的enter状态,对于每个绑定好的数据(datum)没有对应DOM元素的占位符节点,如果没有selection.data掉用后使用,返回值为空。 选择器的enter状态通常用于创建与新数据缺失的元素,如下根据数组数据创建div:
const div = d3.select("body") .selectAll("div") .data([4, 8, 15, 16, 23, 42]) .enter().append("div") .text(d => d);
如果body为空,该程序会创建6个div,根据数组数据的顺序,将其文本内容指定为关联数据(强制为字符串类型)。
从概念上讲,enter桩体的占位符是指向父元素的指针(上面例子中为body),该方法通常用于添加元素,添加后与update状态的选择器合并,使得应用于enter和update两个状态。 enter的实现原理是在enter.js中定义了一个enterNode对象,给选择器添加这个对象,前面提到的进入enter状态,就是返回一个新的选择器,这个选择器构造是传入的是上一条链路选择器的._enter,及其父节点。源码如下
import sparse from './sparse.js'import {Selection} from '.index.js'export default function () { return new Selection(this._enter || this._groups.map(sparse),this._parents);}//在这里定义了enternode对象 这里也是构造函数加原型模式export function EnterNode(parent,datum) { this.ownerDocument = parent.ownerDocument; this.namespaceURI=parent.namespaceURI; this._next = null; this._parent = parent; this.__data__=datum;}EnterNode.prototype={ constructor:EnterNode, appendChild:function(child){ return this._parent.insertBefore(child, this._next); }, insertBefore:function(child,next){ return this._parent.insertBefore(child,next); }, querySelector:function(selector){ return this._parent.querySelector(selector); }, querySelectorAll:function(selector) { return this._parent.querySelectorAll(selector); }};
selection.exit()
返回删除的selection元素,文档中没有被添加数据的节点。通常用于添加新数组前删除旧数据与多余元素。
div = div.data([1, 2, 4, 8, 16, 32], d => d);
data操作根据前面enter中的数据已经传入了[4, 8, 15, 16, 23, 42],新数据重复的有4,8,16,因此update这三个,可以使用enter添加1,2,32三个新元素。
div.enter().append("div").text(d => d);
删除旧数据中的15,23,42:
div.exit().remove();
现在文档是这样:
这里DOM的顺序与数据一致因为新旧数据都是一样的顺序,如果新加入的顺序不同,使用selection.order重新排序。
selection.datum([value])
获取或设置每个元素的绑定数据,这种方法不selection.data不同。不会join,也不影响enter和exit,其内部实现实际上是this.node().__data__直接获取或设置数据。 在指定了value的情况下,如果是常量则赋值,函数的话返回值设置为数据(在每个节点上数据绑定的名称为__data__),为null会删除该元素绑定的数据。 如果没有指定值,返回第一个非空节点绑定的数据,这在只有一个节点时很有用, 此方法在对于H5中的自定义属性非常有效,例如给定如下元素:
通过此方法将元素上绑定的数据设置为内置dataset属性。
selection.datum(function() { return this.dataset; })
总结
这一份是对数据绑定原理的解析,以及数据的几个状态,当我们分析数据时,最有效的几个操作添加数据、删除数据、更新数据,d3的作者用这几个简答的api全部解答了,换绑定到了dom上,使得dom可以根据数据进行同样的添加删除更新。其中基本的原理还视在selection对象上,我们给selection添加了这么几个属性enter(存储添加元素的数据节点数组)、exit(存储删除了的节点数组)、update(这个是根据新数据更新的数据绑定的节点数组)以及__data__(单个节点上的数据属性,保存数据内容)。这几个api中,data是必须的,data后可以对selectin进行enter、exit操作,以及datum查看或设置data值,以及一个抽象出来的join函数,简化enter、exit操作优化了速度。 高层接口:在我使用时就可以直接使用data.enter.进行数据绑定,其他操作在需要时添加即可。
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~