UNPKG

@d3plus/data

Version:

JavaScript data loading, manipulation, and analysis functions.

81 lines 8.49 kB
/* @d3plus/data v3.0.6 JavaScript data loading, manipulation, and analysis functions. Copyright (c) 2025 D3plus - https://d3plus.org @license MIT */ (e=>{"function"==typeof define&&define.amd?define(e):e()})(function(){if("undefined"!=typeof window){try{if("undefined"==typeof SVGElement||Boolean(SVGElement.prototype.innerHTML))return}catch(e){return}function r(e){switch(e.nodeType){case 1:var t=e,n="";return n+="<"+t.tagName,t.hasAttributes()&&[].forEach.call(t.attributes,function(e){n+=" "+e.name+'="'+e.value+'"'}),n+=">",t.hasChildNodes()&&[].forEach.call(t.childNodes,function(e){n+=r(e)}),n+="</"+t.tagName+">";case 3:return e.textContent.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");case 8:return"\x3c!--"+e.nodeValue+"--\x3e"}}Object.defineProperty(SVGElement.prototype,"innerHTML",{get:function(){var t="";return[].forEach.call(this.childNodes,function(e){t+=r(e)}),t},set:function(e){for(;this.firstChild;)this.removeChild(this.firstChild);try{var t=new DOMParser,n=(t.async=!1,"<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'>"+e+"</svg>"),r=t.parseFromString(n,"text/xml").documentElement;[].forEach.call(r.childNodes,function(e){this.appendChild(this.ownerDocument.importNode(e,!0))}.bind(this))}catch(e){throw new Error("Error parsing markup string")}}}),Object.defineProperty(SVGElement.prototype,"innerSVG",{get:function(){return this.innerHTML},set:function(e){this.innerHTML=e}})}}),((e,t)=>{"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("d3-request"),require("@d3plus/dom"),require("d3-array"),require("d3-collection")):"function"==typeof define&&define.amd?define("@d3plus/data",["exports","d3-request","@d3plus/dom","d3-array","d3-collection"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).d3plus={},e.d3Request,e.dom,e.d3Array,e.d3Collection)})(this,function(e,m,y,d,r){ /** @function isData @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. @param {*} dataItem The value to be tested */var a=e=>"string"==typeof e||"object"==typeof e&&e.url&&e.headers,g=(e,t="data",n="headers")=>e[t].map(r=>e[n].reduce((e,t,n)=>(e[t]=r[n],e),{})),v=(e,r="data")=>e.reduce((e,t)=>{let n=[];return Array.isArray(t)?n=t:t[r]&&(n=t[r]),e.concat(n)},[]); /** @function dataFold @desc Given a JSON object where the data values and headers have been split into separate key lookups, this function will combine the data values with the headers and returns one large array of objects. @param {Object} json A JSON data Object with `data` and `headers` keys. @param {String} [data = "data"] The key used for the flat data array inside of the JSON object. @param {String} [headers = "headers"] The key used for the flat headers array inside of the JSON object. */ /** @function dataLoad @desc Loads data from a filepath or URL, converts it to a valid JSON object, and returns it to a callback function. @param {Array|String} path The path to the file or url to be loaded. Also support array of paths strings. If an Array of objects is passed, the xhr request logic is skipped. @param {Function} [formatter] An optional formatter function that is run on the loaded data. @param {String} [key] The key in the `this` context to save the resulting data to. @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. */function i(o,s,d,l){let u,c=e=>e.reduce((e,t)=>t?e+1:e,0);var t=( // If path param is a not an Array then convert path to a 1 element Array to re-use logic o=o instanceof Array?o:[o]).find(a);let f=new Array(o.length),h=[],p=( // If there is a string I'm assuming is a Array to merge, urls or data t?o.forEach((e,t)=>{a(e)?h.push(e):f[t]=e}):f[0]=o,c(f)); // If there is no data to Load response is immediately if(h.forEach(e=>{let t={},i=e;"object"==typeof e&&(i=e.url,t=e.headers);var n=(u=(e=>{switch(e.slice(e.length-4)){case".csv":return m.csv;case".tsv":return m.tsv;case".txt":return m.text;default:return m.json}})(i))(i);for(let e in t)!{}.hasOwnProperty.call(t,e)||n.header(e,t[e]);n.get((e,t)=>{var n,r,a;(t=e?[]:t)&&!(t instanceof Array)&&t.data&&t.headers&&(t=g(t)),a=e,r=u,n=t,r!==m.json&&!a&&n&&n instanceof Array&&n.forEach(e=>{for(var t in e)isNaN(e[t])?"false"===e[t].toLowerCase()?e[t]=!1:"true"===e[t].toLowerCase()?e[t]=!0:"null"===e[t].toLowerCase()?e[t]=null:"undefined"===e[t].toLowerCase()&&(e[t]=void 0):e[t]=parseFloat(e[t])}),t=n,f[r=i,o.indexOf(r)]=t,c(f)-p===h.length&&( // Format data t=1===c(f)?f[0]:f,this._cache&&this._lrucache.set(d+"_"+i,t),s?(a=s(1===c(f)?f[0]:f),"data"===d&&y.isObject(a)?(t=a.data||[],delete a.data,this.config(a)):t=a||[]):"data"===d&&(t=v(f,"data")),d&&"_"+d in this&&(this["_"+d]=t),l)&&l(e,t)})}),0===h.length){f=f.map(e=>e=e&&!(e instanceof Array)&&e.data&&e.headers?g(e):e); // Format data let e=1===c(f)?f[0]:f;s?(t=s(1===c(f)?f[0]:f),"data"===d&&y.isObject(t)?(e=t.data||[],delete t.data,this.config(t)):e=t||[]):"data"===d&&(e=v(f,"data")),d&&"_"+d in this&&(this["_"+d]=e),l&&l(null,e)}} /** @function isData @desc Adds the provided value to the internal queue to be loaded, if necessary. This is used internally in new d3plus visualizations that fold in additional data sources, like the nodes and links of Network or the topojson of Geomap. @param {Array|String|Object} data The data to be loaded @param {Function} [data] An optional data formatter/callback @param {String} data The internal Viz method to be modified */ /** @function unique @desc ES5 implementation to reduce an Array of values to unique instances. @param {Array} arr The Array of objects to be filtered. @param {Function} [accessor] An optional accessor function used to extract data points from an Array of Objects. @example <caption>this</caption> unique(["apple", "banana", "apple"]); @example <caption>returns this</caption> ["apple", "banana"] */function l(e,n=e=>e){let r=e.map(n).map(e=>e instanceof Date?+e:e);return e.filter((e,t)=>{e=n(e);return r.indexOf(e instanceof Date?+e:e)===t})} /** @function merge @desc Combines an Array of Objects together and returns a new Object. @param {Array} objects The Array of objects to be merged together. @param {Object} aggs An object containing specific aggregation methods (functions) for each key type. By default, numbers are summed and strings are returned as an array of unique values. @example <caption>this</caption> merge([ {id: "foo", group: "A", value: 10, links: [1, 2]}, {id: "bar", group: "A", value: 20, links: [1, 3]} ]); @example <caption>returns this</caption> {id: ["bar", "foo"], group: "A", value: 30, links: [1, 2, 3]} */e.addToQueue=function(e,t,n){var r;(e=e instanceof Array?e:[e]).find(a)?(r=this._queue.find(e=>e[3]===n),t=[i.bind(this),e,t,n],r?this._queue[this._queue.indexOf(r)]=t:this._queue.push(t)):this["_"+n]=e},e.concat=v,e.fold=g,e.isData=a,e.load=i,e.merge=function a(i,o={}){let e=l(d.merge(i.map(e=>Object.keys(e)))),s={};return e.forEach(t=>{let e;var n,r;o[t]?e=o[t](i,e=>e[t]):(r=(n=i.map(e=>e[t])).map(e=>e||!1===e?e.constructor:e).filter(e=>void 0!==e)).length?0<=r.indexOf(Array)?1===(e=l(e=d.merge(n.map(e=>e instanceof Array?e:[e])))).length&&(e=e[0]):0<=r.indexOf(String)?1===(e=l(n)).length&&(e=e[0]):0<=r.indexOf(Number)?e=d.sum(n):0<=r.indexOf(Object)?e=1===(e=l(n.filter(e=>e))).length?e[0]:a(e):1===(e=l(n.filter(e=>void 0!==e))).length&&(e=e[0]):e=void 0,s[t]=e}),s} /** @function nest @summary Extends the base behavior of d3.nest to allow for multiple depth levels. @param {Array} *data* The data array to be nested. @param {Array} *keys* An array of key accessors that signify each nest level. @private */,e.nest=function(e,t){t instanceof Array||(t=[t]);var n=r.nest();for(let e=0;e<t.length;e++)n.key(t[e]); /** Bubbles up values that do not nest to the furthest key. @param {Array} *values* The "values" of a nest object. @private */ return function t(e){return e.map(e=>{if(e.key&&e.values){if("undefined"===e.values[0].key)return e.values[0].values[0];e.values=t(e.values)}return e})}(n.entries(e))},e.unique=l}); //# sourceMappingURL=d3plus-data.js.map