D3.js从源码分析到精通(一)
npm install d3 -S
npm install @types/d3 -D
import * as d3 from 'd3'
d3-selection
select 方法
selectAll 方法
// 第一个
d3.select('.box').style('background','red')
// 多个
d3.selectAll('.box').style('background','red')
下面两种是操作dom的
d3-selectorAll
// 这个函数最优价值的点是把类数组包含到里面去啦
function array$1(x) {
return typeof x === "object" && "length" in x
? x
// Array, TypedArray, NodeList, array-like
// 数组 类型化数组 节点列表 类数组
: Array.from(x); // Map, Set, iterable, string, 或者其他的
}
TypedArray 看源码的时候蒙蔽这是啥,在mdn查查下
类型化数组对象描述一个底层二进制数据缓冲区的一个类数组视图
跟数组的通用方法类型
const typedArray1=new Int8Array(2) typedArray1[0]=11; console.log(typedArray1); // Int8Array(2) [ 11, 0 ]
function selectorAll(selector) {
return selector == null ? [] : function() {
return this.querySelectorAll(selector);
};
}
简单的分析,selectorAll就是方法
querySelectorAll
selector
function selector(selector) {
return selector == null ? none : function() {
return this.querySelector(selector);
};
}
本质就是
document.querySelector
方法
slection.filter
过滤器
d3.selectAll("tr").filter(":nth-child(even)");
下面也是可以的
d3.selectAll(".aaa:nth-child(even)").style('background','red')
函数的写法
d3.selectAll(".aaa").filter((v,i)=>i%2)
attr
selection_attr
因为设计到SVG的判断有点复杂,我在mdn实现的时候发现无效,就去掉SVG这部分代码
function selection_attr(name, value) {
if (arguments.length < 3) {
// 获取dom节点
let node=this.node()
return node.getActiveAttrib(name)
}
return this.each(
// 如果为null/undefined 就删除这个属性
value==null?attrRemove:
typeof value==='function'?attrFunction:
attrConstant
)(name,value)
}
// 删除这个属性
function attrRemove(name) {
return function() {
this.removeAttribute(name);
};
}
// 设置属性和值
function attrConstant(name, value) {
return function() {
this.setAttribute(name, value);
};
}
// 如果是函数
function attrFunction(name, value) {
return function() {
var v = value.apply(this, arguments);
if (v == null) this.removeAttribute(name);
else this.setAttribute(name, v);
};
}
this.each 的含义是算多个节点的操作
function node_each(callback, that) {
let index = -1;
for (const node of this) {
callback.call(that, node, ++index, this);
}
return this;
}
深入理解其中的用法
// 添加 d3.select('#ccc').attr('name','333') // 函数添加 d3.select('#ccc').attr('name',()=>{ return 'eee' }) // 多个添加,起到作用的是 this.each d3.selectAll('.ccc').attr('name','333') // 删除 null/undefined d3.selectAll('.ccc').attr('name',null)
classed()
classList 相关操作
function classArray(string) {
return string.trim().split(/^|\s+/);
}
// classArray('aaa bbb ccc')
// => ['aaa','bbb','ccc']
// 查看dom的classList
function classList(node) {
return node.classList || new ClassList(node);
}
// 如果没有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;
}
};
// 查找所有属性,遍历添加
function classedAdd(node, names) {
var list = classList(node), i = -1, n = names.length;
while (++i < n) list.add(names[i]);
}
// 查找所有属性,遍历删除
function classedRemove(node, names) {
var list = classList(node), i = -1, n = names.length;
while (++i < n) list.remove(names[i]);
}
理解源码后
单个参数
类型 contains 查询是否有这个属性有true 否则false
d3.selectr('.aaa').classed('bbb') // true/false
多个参数
d3.selectr('.aaa').classed('bbb',ture) //添加(没有添加,有就不变)
d3.selectr('.aaa').classed('bbb',false)// 删除 (有则删除,没有则不变)
// 批量添加和删除
d3.selectAll('.aaa').classed('bbb',true)
// 函数的方式
<div class="aaa"></div>
<div class="aaa"></div>
<div class="aaa">
<div class="ccc"></div>
</div>
console.log(d3.selectAll('.aaa').classed('bbb',(v,i)=>{
// 子dom 索引
console.log(v,i);
return true
}));
style
getPropertyPriority
判断是否设置
important
优先级如果有
!important
就表示为important
否则为'', 记得是内联的样式
<div class="aaa" id="box" style="background: #00230b!important;"></div>
// 记得比如你们跟我一样喜欢用ts,记得加上别名限制
//let a = document.querySelector('#box') as HTMLElement;
let a = document.querySelector('#box');
console.log(a.style.getPropertyPriority('background'));
// important
getPropertyValue
查询单个值
<div class="aaa" id="box" style="background: #00230b"></div>
let a = document.querySelector('#box') as HTMLElement;
// 第一种
let b = a.style.getPropertyValue('background');
console.log(b);
// rgb(0, 35, 11)
// 第二种
console.log(getComputedStyle(a).getPropertyValue('background'));
//rgb(0, 35, 11) none repeat scroll 0% 0% / auto padding-box border-box
源码
1602行
function styleValue(node, name) {
return node.style.getPropertyValue(name)
|| defaultView(node).getComputedStyle(node, null).getPropertyValue(name);
}
删除
<div class="aaa" id="box" style="background: #00230b"></div>
let a=document.querySelector('.aaa')
a.style.removeProperty('background')
// 返回''
function styleRemove(name) {
return function() {
this.style.removeProperty(name);
};
}
设置
setProperty
参数 属性,值, 优先级
优先级(important) 默认为''
let a=document.querySelector('.aaa')
a.style.setProperty('border','3px solid red','important')
源码
function styleConstant(name, value, priority) {
return function() {
this.style.setProperty(name, value, priority);
};
}
value 为函数
function styleFunction(name, value, priority) {
return function() {
var v = value.apply(this, arguments);
if (v == null) this.style.removeProperty(name);
else this.style.setProperty(name, v, priority);
};
}
从源码上看我们可以删除或者设置默认属性
实际操作的代码可以是
// 删除默认内置css
d3.select('.aaa').style('margin',()=>{
return null // undefined
})
如果有值
d3.select('.aaa').style('margin',()=>{
return '30px'
},'important')
// important 是可以默认写入的
最后我们看看默认整合的代码
export default function(name, value, priority) {
return arguments.length > 1
? this.each((value == null
? styleRemove : typeof value === "function"
? styleFunction
: styleConstant)(name, value, priority == null ? "" : priority))
: styleValue(this.node(), name);
}
我们可以整合全部完整的实例
arguments的长度为1 执行styleValue方法
也就是查询功能
console.log(d3.select('.aaa').style('font-size'));
this.each 是一个进行多个赋值的操作
当第二个参数是==null就是删除操作 还是undefined也是
d3.select('.aaa').style('font-size',null)
当第二个参数是函数
d3.select('.aaa').style('margin',()=>{
return '30px'
},'important')
否则就是最简单的复制操作
console.log(d3.select('.aaa').style('font-size','40px'));
决定自己的高度的是你的态度,而不是你的才能
记得我们是终身初学者和学习者
总有一天我也能成为大佬