@d3plus/data 3.0.11 → 3.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  /*
2
- @d3plus/data v3.0.11
2
+ @d3plus/data v3.0.13
3
3
  JavaScript data loading, manipulation, and analysis functions.
4
4
  Copyright (c) 2025 D3plus - https://d3plus.org
5
5
  @license MIT
@@ -117,380 +117,7 @@
117
117
  @function isData
118
118
  @desc Returns true/false whether the argument provided to the function should be loaded using an internal XHR request. Valid data can either be a string URL or an Object with "url" and "headers" keys.
119
119
  @param {*} dataItem The value to be tested
120
- */ var isData = ((dataItem)=>typeof dataItem === "string" || typeof dataItem === "object" && dataItem.url && dataItem.headers);
121
-
122
- var prefix = "$";
123
- function Map() {}
124
- Map.prototype = map.prototype = {
125
- constructor: Map,
126
- has: function(key) {
127
- return prefix + key in this;
128
- },
129
- get: function(key) {
130
- return this[prefix + key];
131
- },
132
- set: function(key, value) {
133
- this[prefix + key] = value;
134
- return this;
135
- },
136
- remove: function(key) {
137
- var property = prefix + key;
138
- return property in this && delete this[property];
139
- },
140
- clear: function() {
141
- for(var property in this)if (property[0] === prefix) delete this[property];
142
- },
143
- keys: function() {
144
- var keys = [];
145
- for(var property in this)if (property[0] === prefix) keys.push(property.slice(1));
146
- return keys;
147
- },
148
- values: function() {
149
- var values = [];
150
- for(var property in this)if (property[0] === prefix) values.push(this[property]);
151
- return values;
152
- },
153
- entries: function() {
154
- var entries = [];
155
- for(var property in this)if (property[0] === prefix) entries.push({
156
- key: property.slice(1),
157
- value: this[property]
158
- });
159
- return entries;
160
- },
161
- size: function() {
162
- var size = 0;
163
- for(var property in this)if (property[0] === prefix) ++size;
164
- return size;
165
- },
166
- empty: function() {
167
- for(var property in this)if (property[0] === prefix) return false;
168
- return true;
169
- },
170
- each: function(f) {
171
- for(var property in this)if (property[0] === prefix) f(this[property], property.slice(1), this);
172
- }
173
- };
174
- function map(object, f) {
175
- var map = new Map;
176
- // Copy constructor.
177
- if (object instanceof Map) object.each(function(value, key) {
178
- map.set(key, value);
179
- });
180
- else if (Array.isArray(object)) {
181
- var i = -1, n = object.length, o;
182
- if (f == null) while(++i < n)map.set(i, object[i]);
183
- else while(++i < n)map.set(f(o = object[i], i, object), o);
184
- } else if (object) for(var key in object)map.set(key, object[key]);
185
- return map;
186
- }
187
-
188
- function nest$1() {
189
- var keys = [], sortKeys = [], sortValues, rollup, nest;
190
- function apply(array, depth, createResult, setResult) {
191
- if (depth >= keys.length) {
192
- if (sortValues != null) array.sort(sortValues);
193
- return rollup != null ? rollup(array) : array;
194
- }
195
- var i = -1, n = array.length, key = keys[depth++], keyValue, value, valuesByKey = map(), values, result = createResult();
196
- while(++i < n){
197
- if (values = valuesByKey.get(keyValue = key(value = array[i]) + "")) {
198
- values.push(value);
199
- } else {
200
- valuesByKey.set(keyValue, [
201
- value
202
- ]);
203
- }
204
- }
205
- valuesByKey.each(function(values, key) {
206
- setResult(result, key, apply(values, depth, createResult, setResult));
207
- });
208
- return result;
209
- }
210
- function entries(map, depth) {
211
- if (++depth > keys.length) return map;
212
- var array, sortKey = sortKeys[depth - 1];
213
- if (rollup != null && depth >= keys.length) array = map.entries();
214
- else array = [], map.each(function(v, k) {
215
- array.push({
216
- key: k,
217
- values: entries(v, depth)
218
- });
219
- });
220
- return sortKey != null ? array.sort(function(a, b) {
221
- return sortKey(a.key, b.key);
222
- }) : array;
223
- }
224
- return nest = {
225
- object: function(array) {
226
- return apply(array, 0, createObject, setObject);
227
- },
228
- map: function(array) {
229
- return apply(array, 0, createMap, setMap);
230
- },
231
- entries: function(array) {
232
- return entries(apply(array, 0, createMap, setMap), 0);
233
- },
234
- key: function(d) {
235
- keys.push(d);
236
- return nest;
237
- },
238
- sortKeys: function(order) {
239
- sortKeys[keys.length - 1] = order;
240
- return nest;
241
- },
242
- sortValues: function(order) {
243
- sortValues = order;
244
- return nest;
245
- },
246
- rollup: function(f) {
247
- rollup = f;
248
- return nest;
249
- }
250
- };
251
- }
252
- function createObject() {
253
- return {};
254
- }
255
- function setObject(object, key, value) {
256
- object[key] = value;
257
- }
258
- function createMap() {
259
- return map();
260
- }
261
- function setMap(map, key, value) {
262
- map.set(key, value);
263
- }
264
-
265
- function Set() {}
266
- var proto = map.prototype;
267
- Set.prototype = {
268
- constructor: Set,
269
- has: proto.has,
270
- add: function(value) {
271
- value += "";
272
- this[prefix + value] = value;
273
- return this;
274
- },
275
- remove: proto.remove,
276
- clear: proto.clear,
277
- values: proto.keys,
278
- size: proto.size,
279
- empty: proto.empty,
280
- each: proto.each
281
- };
282
-
283
- var noop = {
284
- value: function() {}
285
- };
286
- function dispatch() {
287
- for(var i = 0, n = arguments.length, _ = {}, t; i < n; ++i){
288
- if (!(t = arguments[i] + "") || t in _ || /[\s.]/.test(t)) throw new Error("illegal type: " + t);
289
- _[t] = [];
290
- }
291
- return new Dispatch(_);
292
- }
293
- function Dispatch(_) {
294
- this._ = _;
295
- }
296
- function parseTypenames(typenames, types) {
297
- return typenames.trim().split(/^|\s+/).map(function(t) {
298
- var name = "", i = t.indexOf(".");
299
- if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
300
- if (t && !types.hasOwnProperty(t)) throw new Error("unknown type: " + t);
301
- return {
302
- type: t,
303
- name: name
304
- };
305
- });
306
- }
307
- Dispatch.prototype = dispatch.prototype = {
308
- constructor: Dispatch,
309
- on: function(typename, callback) {
310
- var _ = this._, T = parseTypenames(typename + "", _), t, i = -1, n = T.length;
311
- // If no callback was specified, return the callback of the given type and name.
312
- if (arguments.length < 2) {
313
- while(++i < n)if ((t = (typename = T[i]).type) && (t = get(_[t], typename.name))) return t;
314
- return;
315
- }
316
- // If a type was specified, set the callback for the given type and name.
317
- // Otherwise, if a null callback was specified, remove callbacks of the given name.
318
- if (callback != null && typeof callback !== "function") throw new Error("invalid callback: " + callback);
319
- while(++i < n){
320
- if (t = (typename = T[i]).type) _[t] = set(_[t], typename.name, callback);
321
- else if (callback == null) for(t in _)_[t] = set(_[t], typename.name, null);
322
- }
323
- return this;
324
- },
325
- copy: function() {
326
- var copy = {}, _ = this._;
327
- for(var t in _)copy[t] = _[t].slice();
328
- return new Dispatch(copy);
329
- },
330
- call: function(type, that) {
331
- if ((n = arguments.length - 2) > 0) for(var args = new Array(n), i = 0, n, t; i < n; ++i)args[i] = arguments[i + 2];
332
- if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type);
333
- for(t = this._[type], i = 0, n = t.length; i < n; ++i)t[i].value.apply(that, args);
334
- },
335
- apply: function(type, that, args) {
336
- if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type);
337
- for(var t = this._[type], i = 0, n = t.length; i < n; ++i)t[i].value.apply(that, args);
338
- }
339
- };
340
- function get(type, name) {
341
- for(var i = 0, n = type.length, c; i < n; ++i){
342
- if ((c = type[i]).name === name) {
343
- return c.value;
344
- }
345
- }
346
- }
347
- function set(type, name, callback) {
348
- for(var i = 0, n = type.length; i < n; ++i){
349
- if (type[i].name === name) {
350
- type[i] = noop, type = type.slice(0, i).concat(type.slice(i + 1));
351
- break;
352
- }
353
- }
354
- if (callback != null) type.push({
355
- name: name,
356
- value: callback
357
- });
358
- return type;
359
- }
360
-
361
- function request(url, callback) {
362
- var request, event = dispatch("beforesend", "progress", "load", "error"), mimeType, headers = map(), xhr = new XMLHttpRequest, user = null, password = null, response, responseType, timeout = 0;
363
- // If IE does not support CORS, use XDomainRequest.
364
- if (typeof XDomainRequest !== "undefined" && !("withCredentials" in xhr) && /^(http(s)?:)?\/\//.test(url)) xhr = new XDomainRequest;
365
- "onload" in xhr ? xhr.onload = xhr.onerror = xhr.ontimeout = respond : xhr.onreadystatechange = function(o) {
366
- xhr.readyState > 3 && respond(o);
367
- };
368
- function respond(o) {
369
- var status = xhr.status, result;
370
- if (!status && hasResponse(xhr) || status >= 200 && status < 300 || status === 304) {
371
- if (response) {
372
- try {
373
- result = response.call(request, xhr);
374
- } catch (e) {
375
- event.call("error", request, e);
376
- return;
377
- }
378
- } else {
379
- result = xhr;
380
- }
381
- event.call("load", request, result);
382
- } else {
383
- event.call("error", request, o);
384
- }
385
- }
386
- xhr.onprogress = function(e) {
387
- event.call("progress", request, e);
388
- };
389
- request = {
390
- header: function(name, value) {
391
- name = (name + "").toLowerCase();
392
- if (arguments.length < 2) return headers.get(name);
393
- if (value == null) headers.remove(name);
394
- else headers.set(name, value + "");
395
- return request;
396
- },
397
- // If mimeType is non-null and no Accept header is set, a default is used.
398
- mimeType: function(value) {
399
- if (!arguments.length) return mimeType;
400
- mimeType = value == null ? null : value + "";
401
- return request;
402
- },
403
- // Specifies what type the response value should take;
404
- // for instance, arraybuffer, blob, document, or text.
405
- responseType: function(value) {
406
- if (!arguments.length) return responseType;
407
- responseType = value;
408
- return request;
409
- },
410
- timeout: function(value) {
411
- if (!arguments.length) return timeout;
412
- timeout = +value;
413
- return request;
414
- },
415
- user: function(value) {
416
- return arguments.length < 1 ? user : (user = value == null ? null : value + "", request);
417
- },
418
- password: function(value) {
419
- return arguments.length < 1 ? password : (password = value == null ? null : value + "", request);
420
- },
421
- // Specify how to convert the response content to a specific type;
422
- // changes the callback value on "load" events.
423
- response: function(value) {
424
- response = value;
425
- return request;
426
- },
427
- // Alias for send("GET", …).
428
- get: function(data, callback) {
429
- return request.send("GET", data, callback);
430
- },
431
- // Alias for send("POST", …).
432
- post: function(data, callback) {
433
- return request.send("POST", data, callback);
434
- },
435
- // If callback is non-null, it will be used for error and load events.
436
- send: function(method, data, callback) {
437
- xhr.open(method, url, true, user, password);
438
- if (mimeType != null && !headers.has("accept")) headers.set("accept", mimeType + ",*/*");
439
- if (xhr.setRequestHeader) headers.each(function(value, name) {
440
- xhr.setRequestHeader(name, value);
441
- });
442
- if (mimeType != null && xhr.overrideMimeType) xhr.overrideMimeType(mimeType);
443
- if (responseType != null) xhr.responseType = responseType;
444
- if (timeout > 0) xhr.timeout = timeout;
445
- if (callback == null && typeof data === "function") callback = data, data = null;
446
- if (callback != null && callback.length === 1) callback = fixCallback(callback);
447
- if (callback != null) request.on("error", callback).on("load", function(xhr) {
448
- callback(null, xhr);
449
- });
450
- event.call("beforesend", request, xhr);
451
- xhr.send(data == null ? null : data);
452
- return request;
453
- },
454
- abort: function() {
455
- xhr.abort();
456
- return request;
457
- },
458
- on: function() {
459
- var value = event.on.apply(event, arguments);
460
- return value === event ? request : value;
461
- }
462
- };
463
- return request;
464
- }
465
- function fixCallback(callback) {
466
- return function(error, xhr) {
467
- callback(error == null ? xhr : null);
468
- };
469
- }
470
- function hasResponse(xhr) {
471
- var type = xhr.responseType;
472
- return type && type !== "text" ? xhr.response // null on error
473
- : xhr.responseText; // "" on error
474
- }
475
-
476
- function type(defaultMimeType, response) {
477
- return function(url, callback) {
478
- var r = request(url).mimeType(defaultMimeType).response(response);
479
- if (callback != null) {
480
- if (typeof callback !== "function") throw new Error("invalid callback: " + callback);
481
- return r.get(callback);
482
- }
483
- return r;
484
- };
485
- }
486
-
487
- var json = type("application/json", function(xhr) {
488
- return JSON.parse(xhr.responseText);
489
- });
490
-
491
- var text = type("text/plain", function(xhr) {
492
- return xhr.responseText;
493
- });
120
+ */ var isData = ((dataItem)=>typeof dataItem === "string" || typeof dataItem === "object" && dataItem.url);
494
121
 
495
122
  var EOL = {}, EOF = {}, QUOTE = 34, NEWLINE = 10, RETURN = 13;
496
123
  function objectConverter(columns) {
@@ -527,7 +154,7 @@
527
154
  var hours = date.getUTCHours(), minutes = date.getUTCMinutes(), seconds = date.getUTCSeconds(), milliseconds = date.getUTCMilliseconds();
528
155
  return isNaN(date) ? "Invalid Date" : formatYear(date.getUTCFullYear()) + "-" + pad(date.getUTCMonth() + 1, 2) + "-" + pad(date.getUTCDate(), 2) + (milliseconds ? "T" + pad(hours, 2) + ":" + pad(minutes, 2) + ":" + pad(seconds, 2) + "." + pad(milliseconds, 3) + "Z" : seconds ? "T" + pad(hours, 2) + ":" + pad(minutes, 2) + ":" + pad(seconds, 2) + "Z" : minutes || hours ? "T" + pad(hours, 2) + ":" + pad(minutes, 2) + "Z" : "");
529
156
  }
530
- function dsv$1(delimiter) {
157
+ function dsvFormat(delimiter) {
531
158
  var reFormat = new RegExp("[\"" + delimiter + "\n\r]"), DELIMITER = delimiter.charCodeAt(0);
532
159
  function parse(text, f) {
533
160
  var convert, columns, rows = parseRows(text, function(row, i) {
@@ -614,32 +241,39 @@
614
241
  };
615
242
  }
616
243
 
617
- var csv$1 = dsv$1(",");
244
+ var csv$1 = dsvFormat(",");
618
245
  var csvParse = csv$1.parse;
619
246
 
620
- var tsv$1 = dsv$1("\t");
247
+ var tsv$1 = dsvFormat("\t");
621
248
  var tsvParse = tsv$1.parse;
622
249
 
623
- function dsv(defaultMimeType, parse) {
624
- return function(url, row, callback) {
625
- if (arguments.length < 3) callback = row, row = null;
626
- var r = request(url).mimeType(defaultMimeType);
627
- r.row = function(_) {
628
- return arguments.length ? r.response(responseOf(parse, row = _)) : row;
629
- };
630
- r.row(row);
631
- return callback ? r.get(callback) : r;
632
- };
250
+ function responseText(response) {
251
+ if (!response.ok) throw new Error(response.status + " " + response.statusText);
252
+ return response.text();
633
253
  }
634
- function responseOf(parse, row) {
635
- return function(request) {
636
- return parse(request.responseText, row);
637
- };
254
+ function text(input, init) {
255
+ return fetch(input, init).then(responseText);
638
256
  }
639
257
 
640
- var csv = dsv("text/csv", csvParse);
258
+ function dsvParse(parse) {
259
+ return function(input, init, row) {
260
+ if (arguments.length === 2 && typeof init === "function") row = init, init = undefined;
261
+ return text(input, init).then(function(response) {
262
+ return parse(response, row);
263
+ });
264
+ };
265
+ }
266
+ var csv = dsvParse(csvParse);
267
+ var tsv = dsvParse(tsvParse);
641
268
 
642
- var tsv = dsv("text/tab-separated-values", tsvParse);
269
+ function responseJson(response) {
270
+ if (!response.ok) throw new Error(response.status + " " + response.statusText);
271
+ if (response.status === 204 || response.status === 205) return;
272
+ return response.json();
273
+ }
274
+ function json(input, init) {
275
+ return fetch(input, init).then(responseJson);
276
+ }
643
277
 
644
278
  /**
645
279
  @function isObject
@@ -696,22 +330,21 @@
696
330
  @param {String} [key] The key in the `this` context to save the resulting data to.
697
331
  @param {Function} [callback] A function that is called when the final data is loaded. It is passed 2 variables, any error present and the data loaded.
698
332
  */ function load(path, formatter, key, callback) {
699
- let parser;
700
- const getParser = (path)=>{
333
+ const fetchData = (path, init = {})=>{
701
334
  const ext = path.slice(path.length - 4);
702
335
  switch(ext){
703
336
  case ".csv":
704
- return csv;
337
+ return csv(path, init);
705
338
  case ".tsv":
706
- return tsv;
339
+ return tsv(path, init);
707
340
  case ".txt":
708
- return text;
341
+ return text(path, init);
709
342
  default:
710
- return json;
343
+ return json(path, init);
711
344
  }
712
345
  };
713
- const validateData = (err, parser, data)=>{
714
- if (parser !== json && !err && data && data instanceof Array) {
346
+ const validateData = (data)=>{
347
+ if (data && data instanceof Array) {
715
348
  data.forEach((d)=>{
716
349
  for(const k in d){
717
350
  if (!isNaN(d[k])) d[k] = parseFloat(d[k]);
@@ -725,7 +358,6 @@
725
358
  return data;
726
359
  };
727
360
  const loadedLength = (loadedArray)=>loadedArray.reduce((prev, current)=>current ? prev + 1 : prev, 0);
728
- const getPathIndex = (url, array)=>array.indexOf(url);
729
361
  // If path param is a not an Array then convert path to a 1 element Array to re-use logic
730
362
  if (!(path instanceof Array)) path = [
731
363
  path
@@ -745,23 +377,16 @@
745
377
  // Load all urls an combine them with data arrays
746
378
  const alreadyLoaded = loadedLength(loaded);
747
379
  toLoad.forEach((dataItem)=>{
748
- let headers = {}, url = dataItem;
749
- if (typeof dataItem === "object") {
380
+ let url = dataItem, init = {};
381
+ if (typeof dataItem === "object" && dataItem.url) {
750
382
  url = dataItem.url;
751
- headers = dataItem.headers;
752
- }
753
- parser = getParser(url);
754
- const request = parser(url);
755
- for(const key in headers){
756
- if (({}).hasOwnProperty.call(headers, key)) {
757
- request.header(key, headers[key]);
758
- }
383
+ init = dataItem;
759
384
  }
760
- request.get((err, data)=>{
761
- data = err ? [] : data;
762
- if (data && !(data instanceof Array) && data.data && data.headers) data = fold(data);
763
- data = validateData(err, parser, data);
764
- loaded[getPathIndex(url, path)] = data;
385
+ fetchData(url, init).then((data)=>{
386
+ if (!(data instanceof Array) && data.data && data.headers) data = fold(data);
387
+ data = validateData(data);
388
+ loaded[path.findIndex((d)=>JSON.stringify(d) == JSON.stringify(dataItem))] = data;
389
+ // All urls loaded
765
390
  if (loadedLength(loaded) - alreadyLoaded === toLoad.length) {
766
391
  // Format data
767
392
  data = loadedLength(loaded) === 1 ? loaded[0] : loaded;
@@ -777,8 +402,11 @@
777
402
  data = concat(loaded, "data");
778
403
  }
779
404
  if (key && `_${key}` in this) this[`_${key}`] = data;
780
- if (callback) callback(err, data);
405
+ if (callback) callback(undefined, data);
781
406
  }
407
+ }).catch((err)=>{
408
+ console.log(err);
409
+ if (callback) callback(err, undefined);
782
410
  });
783
411
  });
784
412
  // If there is no data to Load response is immediately
@@ -811,15 +439,15 @@
811
439
  @param {Function} [data] An optional data formatter/callback
812
440
  @param {String} data The internal Viz method to be modified
813
441
  */ function addToQueue(_, f, key) {
814
- if (!(_ instanceof Array)) _ = [
442
+ const paths = _ instanceof Array ? _ : [
815
443
  _
816
444
  ];
817
- const needToLoad = _.find(isData);
445
+ const needToLoad = paths.find(isData);
818
446
  if (needToLoad) {
819
447
  const prev = this._queue.find((q)=>q[3] === key);
820
448
  const d = [
821
449
  load.bind(this),
822
- _,
450
+ paths,
823
451
  f,
824
452
  key
825
453
  ];
@@ -913,6 +541,167 @@
913
541
  return newObject;
914
542
  }
915
543
 
544
+ var prefix = "$";
545
+ function Map() {}
546
+ Map.prototype = map.prototype = {
547
+ constructor: Map,
548
+ has: function(key) {
549
+ return prefix + key in this;
550
+ },
551
+ get: function(key) {
552
+ return this[prefix + key];
553
+ },
554
+ set: function(key, value) {
555
+ this[prefix + key] = value;
556
+ return this;
557
+ },
558
+ remove: function(key) {
559
+ var property = prefix + key;
560
+ return property in this && delete this[property];
561
+ },
562
+ clear: function() {
563
+ for(var property in this)if (property[0] === prefix) delete this[property];
564
+ },
565
+ keys: function() {
566
+ var keys = [];
567
+ for(var property in this)if (property[0] === prefix) keys.push(property.slice(1));
568
+ return keys;
569
+ },
570
+ values: function() {
571
+ var values = [];
572
+ for(var property in this)if (property[0] === prefix) values.push(this[property]);
573
+ return values;
574
+ },
575
+ entries: function() {
576
+ var entries = [];
577
+ for(var property in this)if (property[0] === prefix) entries.push({
578
+ key: property.slice(1),
579
+ value: this[property]
580
+ });
581
+ return entries;
582
+ },
583
+ size: function() {
584
+ var size = 0;
585
+ for(var property in this)if (property[0] === prefix) ++size;
586
+ return size;
587
+ },
588
+ empty: function() {
589
+ for(var property in this)if (property[0] === prefix) return false;
590
+ return true;
591
+ },
592
+ each: function(f) {
593
+ for(var property in this)if (property[0] === prefix) f(this[property], property.slice(1), this);
594
+ }
595
+ };
596
+ function map(object, f) {
597
+ var map = new Map;
598
+ // Copy constructor.
599
+ if (object instanceof Map) object.each(function(value, key) {
600
+ map.set(key, value);
601
+ });
602
+ else if (Array.isArray(object)) {
603
+ var i = -1, n = object.length, o;
604
+ if (f == null) while(++i < n)map.set(i, object[i]);
605
+ else while(++i < n)map.set(f(o = object[i], i, object), o);
606
+ } else if (object) for(var key in object)map.set(key, object[key]);
607
+ return map;
608
+ }
609
+
610
+ function nest$1() {
611
+ var keys = [], sortKeys = [], sortValues, rollup, nest;
612
+ function apply(array, depth, createResult, setResult) {
613
+ if (depth >= keys.length) {
614
+ if (sortValues != null) array.sort(sortValues);
615
+ return rollup != null ? rollup(array) : array;
616
+ }
617
+ var i = -1, n = array.length, key = keys[depth++], keyValue, value, valuesByKey = map(), values, result = createResult();
618
+ while(++i < n){
619
+ if (values = valuesByKey.get(keyValue = key(value = array[i]) + "")) {
620
+ values.push(value);
621
+ } else {
622
+ valuesByKey.set(keyValue, [
623
+ value
624
+ ]);
625
+ }
626
+ }
627
+ valuesByKey.each(function(values, key) {
628
+ setResult(result, key, apply(values, depth, createResult, setResult));
629
+ });
630
+ return result;
631
+ }
632
+ function entries(map, depth) {
633
+ if (++depth > keys.length) return map;
634
+ var array, sortKey = sortKeys[depth - 1];
635
+ if (rollup != null && depth >= keys.length) array = map.entries();
636
+ else array = [], map.each(function(v, k) {
637
+ array.push({
638
+ key: k,
639
+ values: entries(v, depth)
640
+ });
641
+ });
642
+ return sortKey != null ? array.sort(function(a, b) {
643
+ return sortKey(a.key, b.key);
644
+ }) : array;
645
+ }
646
+ return nest = {
647
+ object: function(array) {
648
+ return apply(array, 0, createObject, setObject);
649
+ },
650
+ map: function(array) {
651
+ return apply(array, 0, createMap, setMap);
652
+ },
653
+ entries: function(array) {
654
+ return entries(apply(array, 0, createMap, setMap), 0);
655
+ },
656
+ key: function(d) {
657
+ keys.push(d);
658
+ return nest;
659
+ },
660
+ sortKeys: function(order) {
661
+ sortKeys[keys.length - 1] = order;
662
+ return nest;
663
+ },
664
+ sortValues: function(order) {
665
+ sortValues = order;
666
+ return nest;
667
+ },
668
+ rollup: function(f) {
669
+ rollup = f;
670
+ return nest;
671
+ }
672
+ };
673
+ }
674
+ function createObject() {
675
+ return {};
676
+ }
677
+ function setObject(object, key, value) {
678
+ object[key] = value;
679
+ }
680
+ function createMap() {
681
+ return map();
682
+ }
683
+ function setMap(map, key, value) {
684
+ map.set(key, value);
685
+ }
686
+
687
+ function Set() {}
688
+ var proto = map.prototype;
689
+ Set.prototype = {
690
+ constructor: Set,
691
+ has: proto.has,
692
+ add: function(value) {
693
+ value += "";
694
+ this[prefix + value] = value;
695
+ return this;
696
+ },
697
+ remove: proto.remove,
698
+ clear: proto.clear,
699
+ values: proto.keys,
700
+ size: proto.size,
701
+ empty: proto.empty,
702
+ each: proto.each
703
+ };
704
+
916
705
  /**
917
706
  @function nest
918
707
  @summary Extends the base behavior of d3.nest to allow for multiple depth levels.