d3-collection
为元素准备的以字符串为键名的灵活数据结构。
Installing
<script src="https://d3js.org/d3-collection.v1.min.js"></script>
<script>
var map = d3.map()
.set("foo", 1)
.set("bar", 2);
</script>
API Reference
Objects
JavaScript中常见的数据类型为associative array(关联数组),或者更简单的说是具有一组named properties(具名属性)的对象。遍历关联数组中的键(或属性名)的标准方法是使用for…in loop。但是注意,遍历的顺序是未定义的。D3提供了几种用数字索引将关联数组转换成标准数组的方法。
提醒一句:使用普通对象作为maps是很诱人的,但这在内置属性名作为键名时(如object["__proto__"] = 42和"hasOwnProperty" in object)会导致意外行为。如果你可以确保map keys和set values是安全的,可以使用maps和sets(或等价的ES6)代替普通对象。
d3.keys(object)
返回一个包含给定对象(关联数组)所有属性名的数组。返回数组的顺序未定义。
d3.values(object)
返回一个包含给定对象(关联数组)所有属性值的数组。返回数组的顺序未定义。
d3.entries(object)
返回一个包含给定对象(关联数组)所有属性名和属性值的数组。每个entry都是带有键和值的对象,如{key: "foo", value: 42}
。返回数组的顺序未定义。
d3.entries({foo: 42, bar: true}); // [{key: "foo", value: 42}, {key: "bar", value: true}]
Maps
类似于ES6 Maps,但也有点不同:
键会强制转换为字符串。
- map.each,不是map.forEach。(同样,没有this参数)
- map.remove,不是map.delete。
- map.entries,返回{key,value}对象数组,不是[key,value]迭代器。
- map.size是方法,不是不是property(属性),map.empty也一样。
d3.map([object[, key]])
创建一个新的map。如果指定了object,则将object中所有可枚举属性复制进此map。给定object也可以是一个数组或其它map。可以指定一个key函数,用来计算数组中每个值的键。例如:
var map = d3.map([{name: "foo"}, {name: "bar"}], function(d) { return d.name; });
map.get("foo"); // {"name": "foo"}
map.get("bar"); // {"name": "bar"}
map.get("baz"); // undefined
另请参阅nests。
map.has(key)
当且仅当此map具有给定key字符串的entry时返回true。注意:该值可能为null或undefined。
map.get(key)
返回给定的key字符串的值。如果此map没有给定key的entry,则返回undefined。
map.set(key, value)
为给定key字符串设置value。如果此map已经有同名key字符串的entry,则将用新值替换原来的entry。返回此map,允许链式调用。例如:
var map = d3.map()
.set("foo", 1)
.set("bar", 2)
.set("baz", 3);
map.get("foo"); // 1
map.remove(key)
如果此map具有给定key字符串的entry,则移除entry并返回true。否则,此方法将什么也不做并返回false。
map.clear()
移除此map的所有entry。
map.keys()
返回此map中每个entry的字符串键数组。返回键的顺序是任意的。
map.values()
返回此map中每个entry的值数组。返回值的顺序是任意的。
map.entries()
返回此map中每个entry的键值对对象数组。返回entries的顺序是任意的。每个entry的键都是字符串,单值可以是任意类型。
map.each(function)
为此map中的每个entry调用给定的function,并传入entry的值、键和其自身作为参数,返回undefined。迭代顺序是任意的。
map.empty()
当且仅当此map没有entries时返回true。
map.size()
返回此map的entry的总数。
Sets
类似于ES6 Sets,但也有点不同:
值会强制转换为字符串。
- set.each,不是set.forEach。(同样,没有this参数)
- set.remove,不是set.delete。
- set.size是一个方法,不是property(属性),set.empty也一样。
d3.set([array[, accessor]])
创建一个新的set。如果指定了array,则将给定的字符串array添加到返回的set中。array也可以是一个set。可以指定accessor函数,相当于在创建set前调用array.map(accessor)。
set.has(value)
当且仅当此set中具有给定字符串value的entry时返回true。
set.add(value)
将给定字符串value添加到此set。返回此set,允许链式调用。例如:
var set = d3.set()
.add("foo")
.add("bar")
.add("baz");
set.has("foo"); // true
set.remove(value)
如果此set包含给定的字符串value,则将其移除并返回true。否则,此方法将什么也不做并返回false。
set.clear()
移除此set中的所有值。
set.values()
返回一个包含此set中所有字符串值的数组。返回值的顺序是任意的。可以用作计算一组字符串的唯一值的简便方法。例如:
d3.set(["foo", "bar", "foo", "baz"]).values(); // "foo", "bar", "baz"
set.each(function)
为此set中的每个值调用给定的function,将值作为前两个参数传入(和map.each相对),然后是set本身。返回undefined。迭代顺序是任意的。
set.empty()
当且仅当此set中没有值时返回true。
set.size()
返回次set中值的总数。
Nests
嵌套可以让数组中的元素分组为一个hierarchical tree structure(分层树状结构);类似于SQL中的GROUP BY运算符,除了其
可以有多层分组,且结果输出的是一个树而不是一个flat table。树中的层级由key函数指定。树的叶子节点可以按值排序,而内部节点可以按键排序。可选的rollup函数会使用summary函数折叠每个叶子节点中的元素。嵌套运算符(由nest返回的对象)是可重用的,并且不会保留对嵌套数据的任何引用。
例如,由如下关于大麦产量的表格数据结构,来源于1931年2月明尼苏达州的各个网站:
var yields = [
{yield: 27.00, variety: "Manchuria", year: 1931, site: "University Farm"},
{yield: 48.87, variety: "Manchuria", year: 1931, site: "Waseca"},
{yield: 27.43, variety: "Manchuria", year: 1931, site: "Morris"},
...
];
为了便于可视化,首先可以按年份对元素进行嵌套,然后按种类,如下所示:
var entries = d3.nest()
.key(function(d) { return d.year; })
.key(function(d) { return d.variety; })
.entries(yields);
这将返回一个嵌套数组。数组外部的每个元素都是一个键值对,列出了不同键的值:
[{key: "1931", values: [
{key: "Manchuria", values: [
{yield: 27.00, variety: "Manchuria", year: 1931, site: "University Farm"},
{yield: 48.87, variety: "Manchuria", year: 1931, site: "Waseca"},
{yield: 27.43, variety: "Manchuria", year: 1931, site: "Morris"}, ...]},
{key: "Glabron", values: [
{yield: 43.07, variety: "Glabron", year: 1931, site: "University Farm"},
{yield: 55.20, variety: "Glabron", year: 1931, site: "Waseca"}, ...]}, ...]},
{key: "1932", values: ...}]
在SVG或HTML中嵌套形式可以轻松的进行迭代及生成层次结构。
更多关于嵌套的介绍,另请参阅:
- Phoebe Bright的D3 Nest Tutorial and examples
- Shan Carter的Mister Nester
d3.nest()
创建一个新的nest运算符。键的初始值为空。
nest.key(key)
注册一个新的key函数。key函数将被输入数组中的每个元素调用,并必须返回一个字符串标识符来将元素分配至其相应的组。通常,函数是一个简单accessor,如上面的年份和种类accessor。(不会传入输入数组的索引。)每次注册一个key时,它都将被加入key的内部数组的末尾,而嵌套运算符会应用一个额外的嵌套级别。
nest.sortKeys(comparator)
用给定的comparator对当前key的值排序,如d3.ascending或d3.descending。如果没有为当前key指定comparator,则键返回的顺序是未定义的。例如,按升序对年份排序,按降序对种类排序:
var entries = d3.nest()
.key(function(d) { return d.year; }).sortKeys(d3.ascending)
.key(function(d) { return d.variety; }).sortKeys(d3.descending)
.entries(yields);
注意,这只会影响nest.entries的结果;不管comparator如何,由nest.map和nest.object返回的键的顺序始终都是未定义的。
nest.sortValues(comparator)
用给定的comparator对叶子元素排序,如d3.ascending或d3.descending。这大致相当于在应用嵌套运算符前对输入数组进行排序;但是,由于每个组较小,所有通常更有效。如果没有指定comparator,则将按照输入数组中出现的顺序返回元素。这适用于nest.map,nest.entries和nest.object。
nest.rollup(function)
指定要应用于每一组叶子元素的rollup函数。rollup函数的返回值会替换由nest.map或nest.object返回的相关数组中的叶子值数组;对于nest.entries,它会使用entry.value替换entry.values。如果指定了叶子comparator,则叶子元素会在调用rollup函数前先排序。
nest.map(array)
将嵌套运算符应用于给定的array,返回嵌套的map。返回map中的每个entry都对应由第一个key函数返回的key值。entry值取决于注册的key函数的数量;如果有额外的key,则值为另一个map;否则,该值是从具有给定键值的输入array中筛选出来的元素数组。如果没有定义key,则返回输入array。
nest.object(array)
将嵌套运算符应用于给定的array,返回嵌套对象。返回的关联数组中的每个entry都对应由第一个key函数返回的key值。entry值取决于注册的key函数的数量;如果有额外的key,则值为另一个map;否则,该值是从具有给定键值的输入array中筛选出来的元素数组。
注意:如果有任何key与JavaScript内置属性冲突,如__proto__
,则此方法是不安全的。如果你不能保证key是安全的,你应该使用nest.map代替。
nest.entries(array)
将嵌套运算符应用于给定的array,返回一个包含键值entries的数组。从概念上讲,这类似于对由nest.map返回的关联数组应用map.entries,它适用于层次结构的每一个层级而不仅仅是第一层(最外层)。返回的关联数组中的每个entry都对应由第一个key函数返回的key值。entry值取决于注册的key函数的数量;如果有额外的key,则值为另一个entries的嵌套数组;否则,该值是从具有给定键值的输入array中筛选出来的元素数组。