UNPKG

dc

Version:

A multi-dimensional charting library built to work natively with crossfilter and rendered using d3.js

1,729 lines (1,547 loc) 94.7 kB
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.crossfilter = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){ module.exports = require("./src/crossfilter").crossfilter; },{"./src/crossfilter":6}],2:[function(require,module,exports){ (function (global){ /** * lodash (Custom Build) <https://lodash.com/> * Build: `lodash modularize exports="npm" -o ./` * Copyright jQuery Foundation and other contributors <https://jquery.org/> * Released under MIT license <https://lodash.com/license> * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE> * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors */ /** Used as the `TypeError` message for "Functions" methods. */ var FUNC_ERROR_TEXT = 'Expected a function'; /** Used to stand-in for `undefined` hash values. */ var HASH_UNDEFINED = '__lodash_hash_undefined__'; /** Used as references for various `Number` constants. */ var INFINITY = 1 / 0; /** `Object#toString` result references. */ var funcTag = '[object Function]', genTag = '[object GeneratorFunction]', symbolTag = '[object Symbol]'; /** Used to match property names within property paths. */ var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/, reIsPlainProp = /^\w*$/, reLeadingDot = /^\./, rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g; /** * Used to match `RegExp` * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns). */ var reRegExpChar = /[\\^$.*+?()[\]{}|]/g; /** Used to match backslashes in property paths. */ var reEscapeChar = /\\(\\)?/g; /** Used to detect host constructors (Safari). */ var reIsHostCtor = /^\[object .+?Constructor\]$/; /** Detect free variable `global` from Node.js. */ var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; /** Detect free variable `self`. */ var freeSelf = typeof self == 'object' && self && self.Object === Object && self; /** Used as a reference to the global object. */ var root = freeGlobal || freeSelf || Function('return this')(); /** * Gets the value at `key` of `object`. * * @private * @param {Object} [object] The object to query. * @param {string} key The key of the property to get. * @returns {*} Returns the property value. */ function getValue(object, key) { return object == null ? undefined : object[key]; } /** * Checks if `value` is a host object in IE < 9. * * @private * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a host object, else `false`. */ function isHostObject(value) { // Many host objects are `Object` objects that can coerce to strings // despite having improperly defined `toString` methods. var result = false; if (value != null && typeof value.toString != 'function') { try { result = !!(value + ''); } catch (e) {} } return result; } /** Used for built-in method references. */ var arrayProto = Array.prototype, funcProto = Function.prototype, objectProto = Object.prototype; /** Used to detect overreaching core-js shims. */ var coreJsData = root['__core-js_shared__']; /** Used to detect methods masquerading as native. */ var maskSrcKey = (function() { var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || ''); return uid ? ('Symbol(src)_1.' + uid) : ''; }()); /** Used to resolve the decompiled source of functions. */ var funcToString = funcProto.toString; /** Used to check objects for own properties. */ var hasOwnProperty = objectProto.hasOwnProperty; /** * Used to resolve the * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) * of values. */ var objectToString = objectProto.toString; /** Used to detect if a method is native. */ var reIsNative = RegExp('^' + funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&') .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' ); /** Built-in value references. */ var Symbol = root.Symbol, splice = arrayProto.splice; /* Built-in method references that are verified to be native. */ var Map = getNative(root, 'Map'), nativeCreate = getNative(Object, 'create'); /** Used to convert symbols to primitives and strings. */ var symbolProto = Symbol ? Symbol.prototype : undefined, symbolToString = symbolProto ? symbolProto.toString : undefined; /** * Creates a hash object. * * @private * @constructor * @param {Array} [entries] The key-value pairs to cache. */ function Hash(entries) { var index = -1, length = entries ? entries.length : 0; this.clear(); while (++index < length) { var entry = entries[index]; this.set(entry[0], entry[1]); } } /** * Removes all key-value entries from the hash. * * @private * @name clear * @memberOf Hash */ function hashClear() { this.__data__ = nativeCreate ? nativeCreate(null) : {}; } /** * Removes `key` and its value from the hash. * * @private * @name delete * @memberOf Hash * @param {Object} hash The hash to modify. * @param {string} key The key of the value to remove. * @returns {boolean} Returns `true` if the entry was removed, else `false`. */ function hashDelete(key) { return this.has(key) && delete this.__data__[key]; } /** * Gets the hash value for `key`. * * @private * @name get * @memberOf Hash * @param {string} key The key of the value to get. * @returns {*} Returns the entry value. */ function hashGet(key) { var data = this.__data__; if (nativeCreate) { var result = data[key]; return result === HASH_UNDEFINED ? undefined : result; } return hasOwnProperty.call(data, key) ? data[key] : undefined; } /** * Checks if a hash value for `key` exists. * * @private * @name has * @memberOf Hash * @param {string} key The key of the entry to check. * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. */ function hashHas(key) { var data = this.__data__; return nativeCreate ? data[key] !== undefined : hasOwnProperty.call(data, key); } /** * Sets the hash `key` to `value`. * * @private * @name set * @memberOf Hash * @param {string} key The key of the value to set. * @param {*} value The value to set. * @returns {Object} Returns the hash instance. */ function hashSet(key, value) { var data = this.__data__; data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value; return this; } // Add methods to `Hash`. Hash.prototype.clear = hashClear; Hash.prototype['delete'] = hashDelete; Hash.prototype.get = hashGet; Hash.prototype.has = hashHas; Hash.prototype.set = hashSet; /** * Creates an list cache object. * * @private * @constructor * @param {Array} [entries] The key-value pairs to cache. */ function ListCache(entries) { var index = -1, length = entries ? entries.length : 0; this.clear(); while (++index < length) { var entry = entries[index]; this.set(entry[0], entry[1]); } } /** * Removes all key-value entries from the list cache. * * @private * @name clear * @memberOf ListCache */ function listCacheClear() { this.__data__ = []; } /** * Removes `key` and its value from the list cache. * * @private * @name delete * @memberOf ListCache * @param {string} key The key of the value to remove. * @returns {boolean} Returns `true` if the entry was removed, else `false`. */ function listCacheDelete(key) { var data = this.__data__, index = assocIndexOf(data, key); if (index < 0) { return false; } var lastIndex = data.length - 1; if (index == lastIndex) { data.pop(); } else { splice.call(data, index, 1); } return true; } /** * Gets the list cache value for `key`. * * @private * @name get * @memberOf ListCache * @param {string} key The key of the value to get. * @returns {*} Returns the entry value. */ function listCacheGet(key) { var data = this.__data__, index = assocIndexOf(data, key); return index < 0 ? undefined : data[index][1]; } /** * Checks if a list cache value for `key` exists. * * @private * @name has * @memberOf ListCache * @param {string} key The key of the entry to check. * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. */ function listCacheHas(key) { return assocIndexOf(this.__data__, key) > -1; } /** * Sets the list cache `key` to `value`. * * @private * @name set * @memberOf ListCache * @param {string} key The key of the value to set. * @param {*} value The value to set. * @returns {Object} Returns the list cache instance. */ function listCacheSet(key, value) { var data = this.__data__, index = assocIndexOf(data, key); if (index < 0) { data.push([key, value]); } else { data[index][1] = value; } return this; } // Add methods to `ListCache`. ListCache.prototype.clear = listCacheClear; ListCache.prototype['delete'] = listCacheDelete; ListCache.prototype.get = listCacheGet; ListCache.prototype.has = listCacheHas; ListCache.prototype.set = listCacheSet; /** * Creates a map cache object to store key-value pairs. * * @private * @constructor * @param {Array} [entries] The key-value pairs to cache. */ function MapCache(entries) { var index = -1, length = entries ? entries.length : 0; this.clear(); while (++index < length) { var entry = entries[index]; this.set(entry[0], entry[1]); } } /** * Removes all key-value entries from the map. * * @private * @name clear * @memberOf MapCache */ function mapCacheClear() { this.__data__ = { 'hash': new Hash, 'map': new (Map || ListCache), 'string': new Hash }; } /** * Removes `key` and its value from the map. * * @private * @name delete * @memberOf MapCache * @param {string} key The key of the value to remove. * @returns {boolean} Returns `true` if the entry was removed, else `false`. */ function mapCacheDelete(key) { return getMapData(this, key)['delete'](key); } /** * Gets the map value for `key`. * * @private * @name get * @memberOf MapCache * @param {string} key The key of the value to get. * @returns {*} Returns the entry value. */ function mapCacheGet(key) { return getMapData(this, key).get(key); } /** * Checks if a map value for `key` exists. * * @private * @name has * @memberOf MapCache * @param {string} key The key of the entry to check. * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. */ function mapCacheHas(key) { return getMapData(this, key).has(key); } /** * Sets the map `key` to `value`. * * @private * @name set * @memberOf MapCache * @param {string} key The key of the value to set. * @param {*} value The value to set. * @returns {Object} Returns the map cache instance. */ function mapCacheSet(key, value) { getMapData(this, key).set(key, value); return this; } // Add methods to `MapCache`. MapCache.prototype.clear = mapCacheClear; MapCache.prototype['delete'] = mapCacheDelete; MapCache.prototype.get = mapCacheGet; MapCache.prototype.has = mapCacheHas; MapCache.prototype.set = mapCacheSet; /** * Gets the index at which the `key` is found in `array` of key-value pairs. * * @private * @param {Array} array The array to inspect. * @param {*} key The key to search for. * @returns {number} Returns the index of the matched value, else `-1`. */ function assocIndexOf(array, key) { var length = array.length; while (length--) { if (eq(array[length][0], key)) { return length; } } return -1; } /** * The base implementation of `_.isNative` without bad shim checks. * * @private * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a native function, * else `false`. */ function baseIsNative(value) { if (!isObject(value) || isMasked(value)) { return false; } var pattern = (isFunction(value) || isHostObject(value)) ? reIsNative : reIsHostCtor; return pattern.test(toSource(value)); } /** * The base implementation of `_.toString` which doesn't convert nullish * values to empty strings. * * @private * @param {*} value The value to process. * @returns {string} Returns the string. */ function baseToString(value) { // Exit early for strings to avoid a performance hit in some environments. if (typeof value == 'string') { return value; } if (isSymbol(value)) { return symbolToString ? symbolToString.call(value) : ''; } var result = (value + ''); return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; } /** * Casts `value` to a path array if it's not one. * * @private * @param {*} value The value to inspect. * @returns {Array} Returns the cast property path array. */ function castPath(value) { return isArray(value) ? value : stringToPath(value); } /** * Gets the data for `map`. * * @private * @param {Object} map The map to query. * @param {string} key The reference key. * @returns {*} Returns the map data. */ function getMapData(map, key) { var data = map.__data__; return isKeyable(key) ? data[typeof key == 'string' ? 'string' : 'hash'] : data.map; } /** * Gets the native function at `key` of `object`. * * @private * @param {Object} object The object to query. * @param {string} key The key of the method to get. * @returns {*} Returns the function if it's native, else `undefined`. */ function getNative(object, key) { var value = getValue(object, key); return baseIsNative(value) ? value : undefined; } /** * Checks if `value` is a property name and not a property path. * * @private * @param {*} value The value to check. * @param {Object} [object] The object to query keys on. * @returns {boolean} Returns `true` if `value` is a property name, else `false`. */ function isKey(value, object) { if (isArray(value)) { return false; } var type = typeof value; if (type == 'number' || type == 'symbol' || type == 'boolean' || value == null || isSymbol(value)) { return true; } return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || (object != null && value in Object(object)); } /** * Checks if `value` is suitable for use as unique object key. * * @private * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is suitable, else `false`. */ function isKeyable(value) { var type = typeof value; return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean') ? (value !== '__proto__') : (value === null); } /** * Checks if `func` has its source masked. * * @private * @param {Function} func The function to check. * @returns {boolean} Returns `true` if `func` is masked, else `false`. */ function isMasked(func) { return !!maskSrcKey && (maskSrcKey in func); } /** * Converts `string` to a property path array. * * @private * @param {string} string The string to convert. * @returns {Array} Returns the property path array. */ var stringToPath = memoize(function(string) { string = toString(string); var result = []; if (reLeadingDot.test(string)) { result.push(''); } string.replace(rePropName, function(match, number, quote, string) { result.push(quote ? string.replace(reEscapeChar, '$1') : (number || match)); }); return result; }); /** * Converts `value` to a string key if it's not a string or symbol. * * @private * @param {*} value The value to inspect. * @returns {string|symbol} Returns the key. */ function toKey(value) { if (typeof value == 'string' || isSymbol(value)) { return value; } var result = (value + ''); return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; } /** * Converts `func` to its source code. * * @private * @param {Function} func The function to process. * @returns {string} Returns the source code. */ function toSource(func) { if (func != null) { try { return funcToString.call(func); } catch (e) {} try { return (func + ''); } catch (e) {} } return ''; } /** * Creates a function that memoizes the result of `func`. If `resolver` is * provided, it determines the cache key for storing the result based on the * arguments provided to the memoized function. By default, the first argument * provided to the memoized function is used as the map cache key. The `func` * is invoked with the `this` binding of the memoized function. * * **Note:** The cache is exposed as the `cache` property on the memoized * function. Its creation may be customized by replacing the `_.memoize.Cache` * constructor with one whose instances implement the * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object) * method interface of `delete`, `get`, `has`, and `set`. * * @static * @memberOf _ * @since 0.1.0 * @category Function * @param {Function} func The function to have its output memoized. * @param {Function} [resolver] The function to resolve the cache key. * @returns {Function} Returns the new memoized function. * @example * * var object = { 'a': 1, 'b': 2 }; * var other = { 'c': 3, 'd': 4 }; * * var values = _.memoize(_.values); * values(object); * // => [1, 2] * * values(other); * // => [3, 4] * * object.a = 2; * values(object); * // => [1, 2] * * // Modify the result cache. * values.cache.set(object, ['a', 'b']); * values(object); * // => ['a', 'b'] * * // Replace `_.memoize.Cache`. * _.memoize.Cache = WeakMap; */ function memoize(func, resolver) { if (typeof func != 'function' || (resolver && typeof resolver != 'function')) { throw new TypeError(FUNC_ERROR_TEXT); } var memoized = function() { var args = arguments, key = resolver ? resolver.apply(this, args) : args[0], cache = memoized.cache; if (cache.has(key)) { return cache.get(key); } var result = func.apply(this, args); memoized.cache = cache.set(key, result); return result; }; memoized.cache = new (memoize.Cache || MapCache); return memoized; } // Assign cache to `_.memoize`. memoize.Cache = MapCache; /** * Performs a * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) * comparison between two values to determine if they are equivalent. * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to compare. * @param {*} other The other value to compare. * @returns {boolean} Returns `true` if the values are equivalent, else `false`. * @example * * var object = { 'a': 1 }; * var other = { 'a': 1 }; * * _.eq(object, object); * // => true * * _.eq(object, other); * // => false * * _.eq('a', 'a'); * // => true * * _.eq('a', Object('a')); * // => false * * _.eq(NaN, NaN); * // => true */ function eq(value, other) { return value === other || (value !== value && other !== other); } /** * Checks if `value` is classified as an `Array` object. * * @static * @memberOf _ * @since 0.1.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is an array, else `false`. * @example * * _.isArray([1, 2, 3]); * // => true * * _.isArray(document.body.children); * // => false * * _.isArray('abc'); * // => false * * _.isArray(_.noop); * // => false */ var isArray = Array.isArray; /** * Checks if `value` is classified as a `Function` object. * * @static * @memberOf _ * @since 0.1.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a function, else `false`. * @example * * _.isFunction(_); * // => true * * _.isFunction(/abc/); * // => false */ function isFunction(value) { // The use of `Object#toString` avoids issues with the `typeof` operator // in Safari 8-9 which returns 'object' for typed array and other constructors. var tag = isObject(value) ? objectToString.call(value) : ''; return tag == funcTag || tag == genTag; } /** * Checks if `value` is the * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) * * @static * @memberOf _ * @since 0.1.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is an object, else `false`. * @example * * _.isObject({}); * // => true * * _.isObject([1, 2, 3]); * // => true * * _.isObject(_.noop); * // => true * * _.isObject(null); * // => false */ function isObject(value) { var type = typeof value; return !!value && (type == 'object' || type == 'function'); } /** * Checks if `value` is object-like. A value is object-like if it's not `null` * and has a `typeof` result of "object". * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is object-like, else `false`. * @example * * _.isObjectLike({}); * // => true * * _.isObjectLike([1, 2, 3]); * // => true * * _.isObjectLike(_.noop); * // => false * * _.isObjectLike(null); * // => false */ function isObjectLike(value) { return !!value && typeof value == 'object'; } /** * Checks if `value` is classified as a `Symbol` primitive or object. * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a symbol, else `false`. * @example * * _.isSymbol(Symbol.iterator); * // => true * * _.isSymbol('abc'); * // => false */ function isSymbol(value) { return typeof value == 'symbol' || (isObjectLike(value) && objectToString.call(value) == symbolTag); } /** * Converts `value` to a string. An empty string is returned for `null` * and `undefined` values. The sign of `-0` is preserved. * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to process. * @returns {string} Returns the string. * @example * * _.toString(null); * // => '' * * _.toString(-0); * // => '-0' * * _.toString([1, 2, 3]); * // => '1,2,3' */ function toString(value) { return value == null ? '' : baseToString(value); } /** * This method is like `_.get` except that if the resolved value is a * function it's invoked with the `this` binding of its parent object and * its result is returned. * * @static * @since 0.1.0 * @memberOf _ * @category Object * @param {Object} object The object to query. * @param {Array|string} path The path of the property to resolve. * @param {*} [defaultValue] The value returned for `undefined` resolved values. * @returns {*} Returns the resolved value. * @example * * var object = { 'a': [{ 'b': { 'c1': 3, 'c2': _.constant(4) } }] }; * * _.result(object, 'a[0].b.c1'); * // => 3 * * _.result(object, 'a[0].b.c2'); * // => 4 * * _.result(object, 'a[0].b.c3', 'default'); * // => 'default' * * _.result(object, 'a[0].b.c3', _.constant('default')); * // => 'default' */ function result(object, path, defaultValue) { path = isKey(path, object) ? [path] : castPath(path); var index = -1, length = path.length; // Ensure the loop is entered when path is empty. if (!length) { object = undefined; length = 1; } while (++index < length) { var value = object == null ? undefined : object[toKey(path[index])]; if (value === undefined) { index = length; value = defaultValue; } object = isFunction(value) ? value.call(object) : value; } return object; } module.exports = result; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{}],3:[function(require,module,exports){ module.exports={"version":"1.4.7"} },{}],4:[function(require,module,exports){ if (typeof Uint8Array !== "undefined") { var crossfilter_array8 = function(n) { return new Uint8Array(n); }; var crossfilter_array16 = function(n) { return new Uint16Array(n); }; var crossfilter_array32 = function(n) { return new Uint32Array(n); }; var crossfilter_arrayLengthen = function(array, length) { if (array.length >= length) return array; var copy = new array.constructor(length); copy.set(array); return copy; }; var crossfilter_arrayWiden = function(array, width) { var copy; switch (width) { case 16: copy = crossfilter_array16(array.length); break; case 32: copy = crossfilter_array32(array.length); break; default: throw new Error("invalid array width!"); } copy.set(array); return copy; }; } function crossfilter_arrayUntyped(n) { var array = new Array(n), i = -1; while (++i < n) array[i] = 0; return array; } function crossfilter_arrayLengthenUntyped(array, length) { var n = array.length; while (n < length) array[n++] = 0; return array; } function crossfilter_arrayWidenUntyped(array, width) { if (width > 32) throw new Error("invalid array width!"); return array; } // An arbitrarily-wide array of bitmasks function crossfilter_bitarray(n) { this.length = n; this.subarrays = 1; this.width = 8; this.masks = { 0: 0 } this[0] = crossfilter_array8(n); } crossfilter_bitarray.prototype.lengthen = function(n) { var i, len; for (i = 0, len = this.subarrays; i < len; ++i) { this[i] = crossfilter_arrayLengthen(this[i], n); } this.length = n; }; // Reserve a new bit index in the array, returns {offset, one} crossfilter_bitarray.prototype.add = function() { var m, w, one, i, len; for (i = 0, len = this.subarrays; i < len; ++i) { m = this.masks[i]; w = this.width - (32 * i); one = ~m & -~m; if (w >= 32 && !one) { continue; } if (w < 32 && (one & (1 << w))) { // widen this subarray this[i] = crossfilter_arrayWiden(this[i], w <<= 1); this.width = 32 * i + w; } this.masks[i] |= one; return { offset: i, one: one }; } // add a new subarray this[this.subarrays] = crossfilter_array8(this.length); this.masks[this.subarrays] = 1; this.width += 8; return { offset: this.subarrays++, one: 1 }; }; // Copy record from index src to index dest crossfilter_bitarray.prototype.copy = function(dest, src) { var i, len; for (i = 0, len = this.subarrays; i < len; ++i) { this[i][dest] = this[i][src]; } }; // Truncate the array to the given length crossfilter_bitarray.prototype.truncate = function(n) { var i, len; for (i = 0, len = this.subarrays; i < len; ++i) { for (var j = this.length - 1; j >= n; j--) { this[i][j] = 0; } this[i].length = n; } this.length = n; }; // Checks that all bits for the given index are 0 crossfilter_bitarray.prototype.zero = function(n) { var i, len; for (i = 0, len = this.subarrays; i < len; ++i) { if (this[i][n]) { return false; } } return true; }; // Checks that all bits for the given index are 0 except for possibly one crossfilter_bitarray.prototype.zeroExcept = function(n, offset, zero) { var i, len; for (i = 0, len = this.subarrays; i < len; ++i) { if (i === offset ? this[i][n] & zero : this[i][n]) { return false; } } return true; }; // Checks that all bits for the given indez are 0 except for the specified mask. // The mask should be an array of the same size as the filter subarrays width. crossfilter_bitarray.prototype.zeroExceptMask = function(n, mask) { var i, len; for (i = 0, len = this.subarrays; i < len; ++i) { if (this[i][n] & mask[i]) { return false; } } return true; } // Checks that only the specified bit is set for the given index crossfilter_bitarray.prototype.only = function(n, offset, one) { var i, len; for (i = 0, len = this.subarrays; i < len; ++i) { if (this[i][n] != (i === offset ? one : 0)) { return false; } } return true; }; // Checks that only the specified bit is set for the given index except for possibly one other crossfilter_bitarray.prototype.onlyExcept = function(n, offset, zero, onlyOffset, onlyOne) { var mask; var i, len; for (i = 0, len = this.subarrays; i < len; ++i) { mask = this[i][n]; if (i === offset) mask &= zero; if (mask != (i === onlyOffset ? onlyOne : 0)) { return false; } } return true; }; module.exports = { array8: crossfilter_arrayUntyped, array16: crossfilter_arrayUntyped, array32: crossfilter_arrayUntyped, arrayLengthen: crossfilter_arrayLengthenUntyped, arrayWiden: crossfilter_arrayWidenUntyped, bitarray: crossfilter_bitarray }; },{}],5:[function(require,module,exports){ 'use strict'; var crossfilter_identity = require('./identity'); function bisect_by(f) { // Locate the insertion point for x in a to maintain sorted order. The // arguments lo and hi may be used to specify a subset of the array which // should be considered; by default the entire array is used. If x is already // present in a, the insertion point will be before (to the left of) any // existing entries. The return value is suitable for use as the first // argument to `array.splice` assuming that a is already sorted. // // The returned insertion point i partitions the array a into two halves so // that all v < x for v in a[lo:i] for the left side and all v >= x for v in // a[i:hi] for the right side. function bisectLeft(a, x, lo, hi) { while (lo < hi) { var mid = lo + hi >>> 1; if (f(a[mid]) < x) lo = mid + 1; else hi = mid; } return lo; } // Similar to bisectLeft, but returns an insertion point which comes after (to // the right of) any existing entries of x in a. // // The returned insertion point i partitions the array into two halves so that // all v <= x for v in a[lo:i] for the left side and all v > x for v in // a[i:hi] for the right side. function bisectRight(a, x, lo, hi) { while (lo < hi) { var mid = lo + hi >>> 1; if (x < f(a[mid])) hi = mid; else lo = mid + 1; } return lo; } bisectRight.right = bisectRight; bisectRight.left = bisectLeft; return bisectRight; } module.exports = bisect_by(crossfilter_identity); module.exports.by = bisect_by; // assign the raw function to the export as well },{"./identity":10}],6:[function(require,module,exports){ 'use strict'; var xfilterArray = require('./array'); var xfilterFilter = require('./filter'); var crossfilter_identity = require('./identity'); var crossfilter_null = require('./null'); var crossfilter_zero = require('./zero'); var xfilterHeapselect = require('./heapselect'); var xfilterHeap = require('./heap'); var bisect = require('./bisect'); var insertionsort = require('./insertionsort'); var permute = require('./permute'); var quicksort = require('./quicksort'); var xfilterReduce = require('./reduce'); var packageJson = require('./../package.json'); // require own package.json for the version field var result = require('lodash.result'); // constants var REMOVED_INDEX = -1; // expose API exports exports.crossfilter = crossfilter; exports.crossfilter.heap = xfilterHeap; exports.crossfilter.heapselect = xfilterHeapselect; exports.crossfilter.bisect = bisect; exports.crossfilter.insertionsort = insertionsort; exports.crossfilter.permute = permute; exports.crossfilter.quicksort = quicksort; exports.crossfilter.version = packageJson.version; // please note use of "package-json-versionify" transform function crossfilter() { var crossfilter = { add: add, remove: removeData, dimension: dimension, groupAll: groupAll, size: size, all: all, allFiltered: allFiltered, onChange: onChange, isElementFiltered: isElementFiltered }; var data = [], // the records n = 0, // the number of records; data.length filters, // 1 is filtered out filterListeners = [], // when the filters change dataListeners = [], // when data is added removeDataListeners = [], // when data is removed callbacks = []; filters = new xfilterArray.bitarray(0); // Adds the specified new records to this crossfilter. function add(newData) { var n0 = n, n1 = newData.length; // If there's actually new data to add… // Merge the new data into the existing data. // Lengthen the filter bitset to handle the new records. // Notify listeners (dimensions and groups) that new data is available. if (n1) { data = data.concat(newData); filters.lengthen(n += n1); dataListeners.forEach(function(l) { l(newData, n0, n1); }); triggerOnChange('dataAdded'); } return crossfilter; } // Removes all records that match the current filters, or if a predicate function is passed, // removes all records matching the predicate (ignoring filters). function removeData(predicate) { var // Mapping from old record indexes to new indexes (after records removed) newIndex = crossfilter_index(n, n), removed = [], usePred = typeof predicate === 'function', shouldRemove = function (i) { return usePred ? predicate(data[i], i) : filters.zero(i) }; for (var index1 = 0, index2 = 0; index1 < n; ++index1) { if ( shouldRemove(index1) ) { removed.push(index1); newIndex[index1] = REMOVED_INDEX; } else { newIndex[index1] = index2++; } } // Remove all matching records from groups. filterListeners.forEach(function(l) { l(-1, -1, [], removed, true); }); // Update indexes. removeDataListeners.forEach(function(l) { l(newIndex); }); // Remove old filters and data by overwriting. for (var index3 = 0, index4 = 0; index3 < n; ++index3) { if ( newIndex[index3] !== REMOVED_INDEX ) { if (index3 !== index4) filters.copy(index4, index3), data[index4] = data[index3]; ++index4; } } data.length = n = index4; filters.truncate(index4); triggerOnChange('dataRemoved'); } function maskForDimensions(dimensions) { var n, d, len, id, mask = Array(filters.subarrays); for (n = 0; n < filters.subarrays; n++) { mask[n] = ~0; } for (d = 0, len = dimensions.length; d < len; d++) { // The top bits of the ID are the subarray offset and the lower bits are the bit // offset of the "one" mask. id = dimensions[d].id(); mask[id >> 7] &= ~(0x1 << (id & 0x3f)); } return mask; } // Return true if the data element at index i is filtered IN. // Optionally, ignore the filters of any dimensions in the ignore_dimensions list. function isElementFiltered(i, ignore_dimensions) { var mask = maskForDimensions(ignore_dimensions || []); return filters.zeroExceptMask(i,mask); } // Adds a new dimension with the specified value accessor function. function dimension(value, iterable) { if (typeof value === 'string') { var accessorPath = value; value = function(d) { return result(d, accessorPath); }; } var dimension = { filter: filter, filterExact: filterExact, filterRange: filterRange, filterFunction: filterFunction, filterAll: filterAll, currentFilter: currentFilter, hasCurrentFilter: hasCurrentFilter, top: top, bottom: bottom, group: group, groupAll: groupAll, dispose: dispose, remove: dispose, // for backwards-compatibility accessor: value, id: function() { return id; } }; var one, // lowest unset bit as mask, e.g., 00001000 zero, // inverted one, e.g., 11110111 offset, // offset into the filters arrays id, // unique ID for this dimension (reused when dimensions are disposed) values, // sorted, cached array index, // maps sorted value index -> record index (in data) newValues, // temporary array storing newly-added values newIndex, // temporary array storing newly-added index iterablesIndexCount, newIterablesIndexCount, iterablesIndexFilterStatus, newIterablesIndexFilterStatus, iterablesEmptyRows = [], sort = quicksort.by(function(i) { return newValues[i]; }), refilter = xfilterFilter.filterAll, // for recomputing filter refilterFunction, // the custom filter function in use filterValue, // the value used for filtering (value, array, function or undefined) filterValuePresent, // true if filterValue contains something indexListeners = [], // when data is added dimensionGroups = [], lo0 = 0, hi0 = 0, t = 0, k; // Updating a dimension is a two-stage process. First, we must update the // associated filters for the newly-added records. Once all dimensions have // updated their filters, the groups are notified to update. dataListeners.unshift(preAdd); dataListeners.push(postAdd); removeDataListeners.push(removeData); // Add a new dimension in the filter bitmap and store the offset and bitmask. var tmp = filters.add(); offset = tmp.offset; one = tmp.one; zero = ~one; // Create a unique ID for the dimension // IDs will be re-used if dimensions are disposed. // For internal use the ID is the subarray offset shifted left 7 bits or'd with the // bit offset of the set bit in the dimension's "one" mask. id = (offset << 7) | (Math.log(one) / Math.log(2)); preAdd(data, 0, n); postAdd(data, 0, n); // Incorporates the specified new records into this dimension. // This function is responsible for updating filters, values, and index. function preAdd(newData, n0, n1) { if (iterable){ // Count all the values t = 0; j = 0; k = []; for (var i0 = 0; i0 < newData.length; i0++) { for(j = 0, k = value(newData[i0]); j < k.length; j++) { t++; } } newValues = []; newIterablesIndexCount = crossfilter_range(newData.length); newIterablesIndexFilterStatus = crossfilter_index(t,1); var unsortedIndex = crossfilter_range(t); for (var l = 0, index1 = 0; index1 < newData.length; index1++) { k = value(newData[index1]) // if(!k.length){ newIterablesIndexCount[index1] = 0; iterablesEmptyRows.push(index1 + n0); continue; } newIterablesIndexCount[index1] = k.length for (j = 0; j < k.length; j++) { newValues.push(k[j]); unsortedIndex[l] = index1; l++; } } // Create the Sort map used to sort both the values and the valueToData indices var sortMap = sort(crossfilter_range(t), 0, t); // Use the sortMap to sort the newValues newValues = permute(newValues, sortMap); // Use the sortMap to sort the unsortedIndex map // newIndex should be a map of sortedValue -> crossfilterData newIndex = permute(unsortedIndex, sortMap) } else{ // Permute new values into natural order using a standard sorted index. newValues = newData.map(value); newIndex = sort(crossfilter_range(n1), 0, n1); newValues = permute(newValues, newIndex); } if(iterable) { n1 = t; } // Bisect newValues to determine which new records are selected. var bounds = refilter(newValues), lo1 = bounds[0], hi1 = bounds[1]; if (refilterFunction) { for (var index2 = 0; index2 < n1; ++index2) { if (!refilterFunction(newValues[index2], index2)) { filters[offset][newIndex[index2] + n0] |= one; if(iterable) newIterablesIndexFilterStatus[index2] = 1; } } } else { for (var index3 = 0; index3 < lo1; ++index3) { filters[offset][newIndex[index3] + n0] |= one; if(iterable) newIterablesIndexFilterStatus[index3] = 1; } for (var index4 = hi1; index4 < n1; ++index4) { filters[offset][newIndex[index4] + n0] |= one; if(iterable) newIterablesIndexFilterStatus[index4] = 1; } } // If this dimension previously had no data, then we don't need to do the // more expensive merge operation; use the new values and index as-is. if (!n0) { values = newValues; index = newIndex; iterablesIndexCount = newIterablesIndexCount; iterablesIndexFilterStatus = newIterablesIndexFilterStatus; lo0 = lo1; hi0 = hi1; return; } var oldValues = values, oldIndex = index, oldIterablesIndexFilterStatus = iterablesIndexFilterStatus, old_n0, i1 = 0; i0 = 0; if(iterable){ old_n0 = n0 n0 = oldValues.length; n1 = t } // Otherwise, create new arrays into which to merge new and old. values = iterable ? new Array(n0 + n1) : new Array(n); index = iterable ? new Array(n0 + n1) : crossfilter_index(n, n); if(iterable) iterablesIndexFilterStatus = crossfilter_index(n0 + n1, 1); // Concatenate the newIterablesIndexCount onto the old one. if(iterable) { var oldiiclength = iterablesIndexCount.length; iterablesIndexCount = xfilterArray.arrayLengthen(iterablesIndexCount, n); for(var j=0; j+oldiiclength < n; j++) { iterablesIndexCount[j+oldiiclength] = newIterablesIndexCount[j]; } } // Merge the old and new sorted values, and old and new index. var index5 = 0; for (; i0 < n0 && i1 < n1; ++index5) { if (oldValues[i0] < newValues[i1]) { values[index5] = oldValues[i0]; if(iterable) iterablesIndexFilterStatus[index5] = oldIterablesIndexFilterStatus[i0]; index[index5] = oldIndex[i0++]; } else { values[index5] = newValues[i1]; if(iterable) iterablesIndexFilterStatus[index5] = newIterablesIndexFilterStatus[i1]; index[index5] = newIndex[i1++] + (iterable ? old_n0 : n0); } } // Add any remaining old values. for (; i0 < n0; ++i0, ++index5) { values[index5] = oldValues[i0]; if(iterable) iterablesIndexFilterStatus[index5] = oldIterablesIndexFilterStatus[i0]; index[index5] = oldIndex[i0]; } // Add any remaining new values. for (; i1 < n1; ++i1, ++index5) { values[index5] = newValues[i1]; if(iterable) iterablesIndexFilterStatus[index5] = newIterablesIndexFilterStatus[i1]; index[index5] = newIndex[i1] + (iterable ? old_n0 : n0); } // Bisect again to recompute lo0 and hi0. bounds = refilter(values), lo0 = bounds[0], hi0 = bounds[1]; } // When all filters have updated, notify index listeners of the new values. function postAdd(newData, n0, n1) { indexListeners.forEach(function(l) { l(newValues, newIndex, n0, n1); }); newValues = newIndex = null; } function removeData(reIndex) { if (iterable) { for (var i0 = 0, i1 = 0; i0 < iterablesEmptyRows.length; i0++) { if (reIndex[iterablesEmptyRows[i0]] !== REMOVED_INDEX) { iterablesEmptyRows[i1] = reIndex[iterablesEmptyRows[i0]]; i1++; } } iterablesEmptyRows.length = i1; for (i0 = 0, i1 = 0; i0 < n; i0++) { if (reIndex[i0] !== REMOVED_INDEX) { if (i1 !== i0) iterablesIndexCount[i1] = iterablesIndexCount[i0]; i1++; } } iterablesIndexCount.length = i1; } // Rewrite our index, overwriting removed values var n0 = values.length; for (var i = 0, j = 0, oldDataIndex; i < n0; ++i) { oldDataIndex = index[i]; if (reIndex[oldDataIndex] !== REMOVED_INDEX) { if (i !== j) values[j] = values[i]; index[j] = reIndex[oldDataIndex]; if (iterable) { iterablesIndexFilterStatus[j] = iterablesIndexFilterStatus[i]; } ++j; } } values.length = j; if (iterable) iterablesIndexFilterStatus.length = j; while (j < n0) index[j++] = 0; // Bisect again to recompute lo0 and hi0. var bounds = refilter(values); lo0 = bounds[0], hi0 = bounds[1]; } // Updates the selected values based on the specified bounds [lo, hi]. // This implementation is used by all the public filter methods. function filterIndexBounds(bounds) { var lo1 = bounds[0], hi1 = bounds[1]; if (refilterFunction) { refilterFunction = null; filterIndexFunction(function(d, i) { return lo1 <= i && i < hi1; }, bounds[0] === 0 && bounds[1] === values.length); lo0 = lo1; hi0 = hi1; return dimension; } var i, j, k, added = [], removed = [], valueIndexAdded = [], valueIndexRemoved = []; // Fast incremental update based on previous lo index. if (lo1 < lo0) { for (i = lo1, j = Math.min(lo0, hi1); i < j; ++i) { added.push(index[i]); valueIndexAdded.push(i); } } else if (lo1 > lo0) { for (i = lo0, j = Math.min(lo1, hi0); i < j; ++i) { removed.push(index[i]); valueIndexRemoved.push(i); } } // Fast incremental update based on previous hi index. if (hi1 > hi0) { for (i = Math.max(lo1, hi0), j = hi1; i < j; ++i) { added.push(index[i]); valueIndexAdded.push(i); } } else if (hi1 < hi0) { for (i = Math.max(lo0, hi1), j = hi0; i < j; ++i) { removed.push(index[i]); valueIndexRemoved.push(i); } } if(!iterable) { // Flip filters normally. for(i=0; i<added.length; i++) { filters[offset][added[i]] ^= one; } for(i=0; i<removed.length; i++) { filters[offset][removed[i]] ^= one; } } else { // For iterables, we need to figure out if the row has been completely removed vs partially included // Only count a row as added if it is not already being aggregated. Only count a row // as removed if the last element being aggregated is removed. var newAdded = []; var newRemoved = []; for (i = 0; i < added.length; i++) { iterablesIndexCount[added[i]]++ iterablesIndexFilterStatus[valueIndexAdded[i]] = 0; if(iterablesIndexCount[added[i]] === 1) { filters[offset][added[i]] ^= one; newAdded.push(added[i]); } } for (i = 0; i < removed.length; i++) { iterablesIndexCount[removed[i]]-- iterablesIndexFilterStatus[valueIndexRemoved[i]] = 1; if(iterablesIndexCount[removed[i]] === 0) { filters[offset][removed[i]] ^= one; newRemoved.push(removed[i]); } } added = newAdded; removed = newRemoved; // Now handle empty rows. if(bounds[0] === 0 && bounds[1] === values.length) { for(i = 0; i < iterablesEmptyRows.length; i++) { if((filters[offset][k = iterablesEmptyRows[i]] & one)) { // Was not in the filter, so set the filter and add filters[offset][k] ^= one; added.push(k); } } } else { // filter in place - remove empty rows if necessary for(i = 0; i < iterablesEmptyRows.length; i++) { if(!(filters[offset][k = iterablesEmptyRows[i]] & one)) { // Was in the filter, so set the filter and remove filters[offset][k] ^= one; removed.push(k); } } } } lo0 = lo1; hi0 = hi1; filterListeners.forEach(function(l) { l(one, offset, added, removed); }); triggerOnChange('filtered'); return dimension; } // Filters this dimension using the specified range, value, or null. // If the range is null, this is equivalent to filterAll. // If the range is an array, this is equivalent to filterRange. // Otherwise, this is equivalent to filterExact. function filter(range) { return range == null ? filterAll() : Array.isArray(range) ? filterRange(range) : typeof range === "function" ? filterFunction(range) : filterExact(range); } // Filters this dimension to select the exact value. function filterExact(value) { filterValue = value; filterValuePresent = true; return filterIndexBounds((refilter = xfilterFilter.filterExact(bisect, value))(values)); } // Filters this dimension to select the specified range [lo, hi]. // The lower bound is inclusive, and the upper bound is exclusive. function filterRange(range) { filterValue = range; filterValuePresent = true; return filterIndexBounds((refilter = xfilterFilter.filterRange(bisect, range))(values)); } // Clears any fi