c语言sscanf函数的用法是什么
248
2022-09-04
数据可视化,仿写d3-selection,核心模块选择器(二)
这部分承接上一篇,介绍d3-selection模块中的修改元素节点部分和命名空间。
selection模块结构
选择元素修改元素(本章的内容)加入数据处理事件控制流局部变量命名空间(本章的内容)
选择元素
选择元素后,设置文档的不同属性,例如设置a的name和color:
evs.select("a") .attr("name", "fred") .style("color", "red");
可以直接去d3js.org官网在控制台中做实验。
selection.attr(name[, value]) :
如果指定了value,则将为name的attribute设置为value,并返回选择器,value为常量,则对应属性都设置为该值,如果为函数,会传入数据(d)、索引(i)、当前节点(node),使用返回值来设置属性,空值会删除对应属性。 如果未指定value,返回选择器中第一个非空元素的指定属性的值。 其中name可能会包含命名空间前缀,如xlink:href,参阅evs.spacenames,额外命名空间也可添加。 代码实现中,首先单个参数会直接返回对应属性,封装的getAttribute和getAttributeNS,传入两个参数时,value为null直接删除,封装removeAttribute,传入函数的情况又用到了闭包,在外部使用this.each(callback)传递。
function attrFunction(name, value) { return function() { var v = value.apply(this, arguments); if (v == null) this.removeAttribute(name); else this.setAttribute(name, v); };}
selection.classed(names[, value])
如果指定了value,在该选择器元素下可以将names添加或删除,修改classList属性吗,例如将类foo和bar添加到选择器。
selection.classed("foo bar", true);
如果value为true,所有选择器中元素会添加指定的类,否则不会添加。若value为函数,计算返回值判断是否添加,例如foo类随机数大于0.5时添加
selection.classed("foo", () => Math.random() > 0.5);
没指定value时,对第一个非空的节点进行判断,返回true或false。 代码实现中:防止不支持classList作者自定义了一个对象ClassList,以及对classList的添加删除包含操作,代码如下:
function ClassList(node) { this._node = node; this._names = classArray(node.getAttribute("class") || "");}ClassList.prototype = { add: function(name) { var i = this._names.indexOf(name); if (i < 0) { this._names.push(name); this._node.setAttribute("class", this._names.join(" ")); } }, remove: function(name) { var i = this._names.indexOf(name); if (i >= 0) { this._names.splice(i, 1); this._node.setAttribute("class", this._names.join(" ")); } }, contains: function(name) { return this._names.indexOf(name) >= 0; }};
selection.style(name[, value[, priority]])
设置选择器元素的style属性,value为常数则全部设置为此值,同样可以为函数,按返回值设置是否添加该项,同时可以设置优先级null/important. 未指定value,返回第一个非空元素的属性,如果存在会先否会inline样式,否则返回计算样式。注意:svg中设置3px与3是不同的,某些浏览器会自动添加,ie不会。 代码实现同样用到了Selection的each每个元素进行操作,传入闭包函数。
export default function(name, value, priority) { return arguments.length > 1 ? this.each((value == null ? styleRemove : typeof value === "function"//value传入null,将其style-name删除 ? styleFunction//传入函数 : styleConstant)(name, value, priority == null ? "" : priority))//常量时设置这个值 : styleValue(this.node(), name);//参数一个时返回其对应样式属性}
selection.property(name[, value])| selection.text([value])| selection.html([value])
第一个方法对些些无法寻址找到的属性修改,如表单字段文本,checkbox的checked的boolean值。使用方法与selection.class相同,后面就是改变文本和html,实现上他们封装的方法分别是[]、textContent、innerHTML. 在d3中完全可以利用selection.append/insert去创建数据驱动的内部节点,该html方法是不支持svg的,可以尝试XMLSerializerinnersvg polyfill这两个方法使得innerHTML支持svg以上这些方法attr、classed、style、property、text、html,都是对selection的属性、文本、html进行更改
selection.append(type)
如果type是字符串,为添加为选择器元素的最后一个子元素,或根据绑定的数据来添加元素(如果在enter selection中),并可以通过selection.order调整顺序。 如果为函数,传入d,i,nodes,并将返回的节点作为添加元素,例如讲div添加到p中:
d3.selectAll("p").append("div");//value为字符串d3.selectAll("p").append(() => document.createElement("div"));//value为函数
与下面结果相同:
d3.selectAll("p").select(function() { return this.appendChild(document.createElement("div"));});
这里也是支持包含命名空间的元素的情况。 源码部分使用了create去保存命名空间,或得到父节点的命名空间,然后调用selection.select(function):
import creator from '../creator.js'export default function(name){ var create = typeof name === "function" ? name:creator(name);// return this.select(function(){ return this.appendChild(create.apply(this,arguments));//这里传出去的仍是闭包,相当于调用select(f)的arguments仍是在select.js中出入的 })}
selection.insert(type[, before])
type为字符串时,在指定的选择器before前添加元素,无before时为默认为null。 type和before也可以都是函数,type返回要出入的节点,before返回要插入元素的子元素,下面这个例子是向p中插入div。
d3.selectAll("p").insert("div");d3.selectAll("p").insert(() => document.createElement("div"));//函数
效果与下面相同:
d3.selectAll("p").select(function() { return this.insertBefore(document.createElement("div"), null);});
返回值同样是新选择器以及具有一样的命名空间搜索与定义机制。其内部封装insertBefore,并且复用了selector。
selection.remove()
删除文档中的当前这个选择器中的元素并返回,当前换没有api可以添加回dom,但是可以将返回值传给append、insert重新添加。
function remove(){ var parent=this.parentNode; if(parent) parent.removeChild(this);}export default function () { return this.each(remove);}
代码实现中通过获取父节点,删除该子节点,调用each为每个元素执行该方法,each的返回值正好是元素。
selection.clone([deep])
向选择器插入当前选择器的克隆,返回添加后的选择器,deep为真时也会克隆后代节点。 其代码实现封装了cloneNode(true/flase).
selection.sort(compare)
根据compare函数对选择器中元素的拷贝的数据排序,后返回新选择器,默认为升序。源码如下:
export default function (compare) { if(!compare) compare=ascending; function compareNode(a,b){ return a && b ? compare(a.__data__,b.__data__):!a-!b; } for(var groups=this._groups,m=groups.length,sortgroups=new Array(m),j=0;j
排序函数值红处理空值的函数非常简洁!a-!b保持原来的节点顺序,最后返回时应用order方法,因为这里只是在选择器中数据排序,并没有应用到文档上。
selection.order()
将元素重新插入doucment,相当于调用selection.sort,如果已经排序,速度快很多。
export default function () { for(var groups = this._proups,j=-1,m=gourps.length;++j
selection.raise()
重新插入元素,作为父节点的最后一个子节点,内部使用each方法添加子节点,与下面结果一致:
selection.each(function() { this.parentNode.appendChild(this);});
selection.lower()
与上面相反,添加为父节点的第一个孩子。相当于
selection.each(function() { this.parentNode.insertBefore(this, this.parentNode.firstChild);});
d3.create(name)
创建一个docuemnt下的分离元素name.内部使用select创建,因为返回的是匿名函数,this为其调用时的 开始看还很纠结,他没有删除原节点,怎么又添加了一遍,但appenChild的dom操作是直接把节点移动到最后了。
d3.creator(name)
创建一个元素,实际上就是封装了createElement/NS,组合了命名空间,下面用法相同:
selection.append("div");selection.append(d3.creator("div"));
命名空间namespace
XML中使用相同元素时是需要添加命名空间的。否则会造成冲突,元素的命名空间格式为
xmlns="namespaceURI"
evs.namespace(name)
根据name判断该名称有没有命名空间,如果包含冒号,冒号前解析为空间前缀,后面解析为本地属性,只要该前缀在evs.namespaces中注册了,就会返回
d3.namespace("svg:text"); // {space: "local: "text"}
这里xmlns比较特殊,因为xmlns属性可以在文档中定义一个或多个可供选择的命名空间,所以如果是xmlns,也会返回name不含冒号,也会直接返回名称。
evs.namespaces
已注册名称命名空间的映射。 初始值是:
{ svg: " xhtml: " xlink: " xml: " xmlns: "简单使用时最频繁的还是attr、style、text以及append,设置节点的属性,以及向选择器中添加节点,就能解决大多数问题。
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~