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'));
posted @ 2020-09-18 11:17  猫神甜辣酱  阅读(537)  评论(0编辑  收藏  举报