美文网首页
d3源码部分笔记-data

d3源码部分笔记-data

作者: 9吧和9说9话 | 来源:发表于2020-11-17 17:44 被阅读0次

    数据驱动核心实现 data方法

    返回值是update选择集合

    export default function(value, key) {
     // 没有value的话 就是取值器
      if (!value) {
        data = new Array(this.size()), j = -1;
        this.each(function(d) { data[++j] = d; });
        return data;
      }
      ....
    
      
      update = new Selection(update, parents);
      update._enter = enter;
      update._exit = exit;
      // 返回update
      return update;
    }
    

    bindKey bingIndex

    export default function(value, key) {
      if (!value) {
        data = new Array(this.size()), j = -1;
        this.each(function(d) { data[++j] = d; });
        return data;
      }
    
      var bind = key ? bindKey : bindIndex,
          parents = this._parents,
          groups = this._groups;
    
      if (typeof value !== "function") value = constant(value);
    
      // 遍历所有的groups
      for (var m = groups.length, update = new Array(m), enter = new Array(m), exit = new Array(m), j = 0; j < m; ++j) {
        var parent = parents[j],
            group = groups[j],
            groupLength = group.length,
            data = value.call(parent, parent && parent.__data__, j, parents),
            dataLength = data.length,
            enterGroup = enter[j] = new Array(dataLength),
            updateGroup = update[j] = new Array(dataLength),
            exitGroup = exit[j] = new Array(groupLength);
    
    
        bind(parent, group, enterGroup, updateGroup, exitGroup, data, key);
        ...
      }
    
      update = new Selection(update, parents);
      update._enter = enter;
      update._exit = exit;
      return update;
    }
    
    

    bindIndex实现

    三种情况:

    1. data数据项大于原来的nodelist
    2. data数据项等于原来的nodelist
    3. data数据项小于原来的nodelist

    最终的逻辑,等于原来nodelist长度的data数据项 全部都是属于update集合,
    超过nodelist长度的data数据项属于enter集合,超过data数据项长度的nodelist部分 属于exit集合。

    function bindIndex(parent, group, enter, update, exit, data) {
      var i = 0,
          node,
          groupLength = group.length,
          dataLength = data.length;
    
      // Put any non-null nodes that fit into update.
      // Put any null nodes into enter.
      // Put any remaining data into enter.
      // 遍历data新的数据源
      for (; i < dataLength; ++i) {
        // 如果当前group中存在 则是update操作
        if (node = group[i]) {
          node.__data__ = data[i];
          update[i] = node;
        } else {
          // 否则就是新增
          enter[i] = new EnterNode(parent, data[i]);
        }
      }
    
      // Put any non-null nodes that don’t fit into exit.
      // 如果dom节点数量比 data数量多 那么后面的都是需要删除的
      for (; i < groupLength; ++i) {
        if (node = group[i]) {
          exit[i] = node;
        }
      }
    }
    
    

    bingKey的实现

    整个逻辑:

    1. 先遍历nodelist 获取每一个node的key 并且缓存,如果有多个node拥有相同的key,则把重复的node 放到exit集合中
    2. 遍历data数据源,获取数据源的每一项的key,如果整个key在上一步的nodelist的key中存在,就把node放到update集合中(并且会把缓存的node的key清空);其他的情况:数据项的key在node缓存的key中不存在或者是重复的key,都会被放到enter集合中。
    3. 原来nodelist中的node的key在新的数据源中不存在了,那么这些node属于exit集合。
    function bindKey(parent, group, enter, update, exit, data, key) {
      var i,
          node,
          nodeByKeyValue = {},
          groupLength = group.length,
          dataLength = data.length,
          keyValues = new Array(groupLength),
          keyValue;
    
      // Compute the key for each node.
      // If multiple nodes have the same key, the duplicates are added to exit.
      for (i = 0; i < groupLength; ++i) {
        // 如果dom节点不为空
        if (node = group[i]) {
          // 获取当前node节点的keyvalue 并且缓存在keyValues数组中
          keyValues[i] = keyValue = keyPrefix + key.call(node, node.__data__, i, group);
          // 多个dom节点有相同的key 就会将后面的添加到exit数组中
          if (keyValue in nodeByKeyValue) {
            exit[i] = node;
          } else {
          // 缓存dom节点和他对应的keyValue
            nodeByKeyValue[keyValue] = node;
          }
        }
      }
    
      // Compute the key for each datum.
      // If there a node associated with this key, join and add it to update.
      // If there is not (or the key is a duplicate), add it to enter.
      // 遍历数据data
      for (i = 0; i < dataLength; ++i) {
        // 获取数据的key
        keyValue = keyPrefix + key.call(parent, data[i], i, data);
        // 如果之前缓存的dom节点key中存在当前的数据源中的key
        // 就添加到update 更新数组结合中
        // 并且吧dom节点key在缓存中 清楚
        if (node = nodeByKeyValue[keyValue]) {
          update[i] = node;
          node.__data__ = data[i];
          nodeByKeyValue[keyValue] = null;
        } else {
          // 如果当前数据中的key 在 node keyValue缓存中 没有
          // 新增node到enter数组中
          enter[i] = new EnterNode(parent, data[i]);
        }
      }
    
      // Add any remaining nodes that were not bound to data to exit.
      for (i = 0; i < groupLength; ++i) {
        if ((node = group[i]) && (nodeByKeyValue[keyValues[i]] === node)) {
          exit[i] = node;
        }
      }
    }
    
    

    相关文章

      网友评论

          本文标题:d3源码部分笔记-data

          本文链接:https://www.haomeiwen.com/subject/ugbwlktx.html