|   | 
| /* | 
| * Licensed to the Apache Software Foundation (ASF) under one | 
| * or more contributor license agreements.  See the NOTICE file | 
| * distributed with this work for additional information | 
| * regarding copyright ownership.  The ASF licenses this file | 
| * to you under the Apache License, Version 2.0 (the | 
| * "License"); you may not use this file except in compliance | 
| * with the License.  You may obtain a copy of the License at | 
| * | 
| *   http://www.apache.org/licenses/LICENSE-2.0 | 
| * | 
| * Unless required by applicable law or agreed to in writing, | 
| * software distributed under the License is distributed on an | 
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | 
| * KIND, either express or implied.  See the License for the | 
| * specific language governing permissions and limitations | 
| * under the License. | 
| */ | 
|   | 
|   | 
| /** | 
|  * AUTO-GENERATED FILE. DO NOT MODIFY. | 
|  */ | 
|   | 
| /* | 
| * Licensed to the Apache Software Foundation (ASF) under one | 
| * or more contributor license agreements.  See the NOTICE file | 
| * distributed with this work for additional information | 
| * regarding copyright ownership.  The ASF licenses this file | 
| * to you under the Apache License, Version 2.0 (the | 
| * "License"); you may not use this file except in compliance | 
| * with the License.  You may obtain a copy of the License at | 
| * | 
| *   http://www.apache.org/licenses/LICENSE-2.0 | 
| * | 
| * Unless required by applicable law or agreed to in writing, | 
| * software distributed under the License is distributed on an | 
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | 
| * KIND, either express or implied.  See the License for the | 
| * specific language governing permissions and limitations | 
| * under the License. | 
| */ | 
| import { assert, clone, createHashMap, isFunction, keys, map, reduce } from 'zrender/lib/core/util.js'; | 
| import { parseDataValue } from './helper/dataValueHelper.js'; | 
| import { shouldRetrieveDataByName } from './Source.js'; | 
| var UNDEFINED = 'undefined'; | 
| /* global Float64Array, Int32Array, Uint32Array, Uint16Array */ | 
| // Caution: MUST not use `new CtorUint32Array(arr, 0, len)`, because the Ctor of array is | 
| // different from the Ctor of typed array. | 
| export var CtorUint32Array = typeof Uint32Array === UNDEFINED ? Array : Uint32Array; | 
| export var CtorUint16Array = typeof Uint16Array === UNDEFINED ? Array : Uint16Array; | 
| export var CtorInt32Array = typeof Int32Array === UNDEFINED ? Array : Int32Array; | 
| export var CtorFloat64Array = typeof Float64Array === UNDEFINED ? Array : Float64Array; | 
| /** | 
|  * Multi dimensional data store | 
|  */ | 
| var dataCtors = { | 
|   'float': CtorFloat64Array, | 
|   'int': CtorInt32Array, | 
|   // Ordinal data type can be string or int | 
|   'ordinal': Array, | 
|   'number': Array, | 
|   'time': CtorFloat64Array | 
| }; | 
| var defaultDimValueGetters; | 
| function getIndicesCtor(rawCount) { | 
|   // The possible max value in this._indicies is always this._rawCount despite of filtering. | 
|   return rawCount > 65535 ? CtorUint32Array : CtorUint16Array; | 
| } | 
| ; | 
| function getInitialExtent() { | 
|   return [Infinity, -Infinity]; | 
| } | 
| ; | 
| function cloneChunk(originalChunk) { | 
|   var Ctor = originalChunk.constructor; | 
|   // Only shallow clone is enough when Array. | 
|   return Ctor === Array ? originalChunk.slice() : new Ctor(originalChunk); | 
| } | 
| function prepareStore(store, dimIdx, dimType, end, append) { | 
|   var DataCtor = dataCtors[dimType || 'float']; | 
|   if (append) { | 
|     var oldStore = store[dimIdx]; | 
|     var oldLen = oldStore && oldStore.length; | 
|     if (!(oldLen === end)) { | 
|       var newStore = new DataCtor(end); | 
|       // The cost of the copy is probably inconsiderable | 
|       // within the initial chunkSize. | 
|       for (var j = 0; j < oldLen; j++) { | 
|         newStore[j] = oldStore[j]; | 
|       } | 
|       store[dimIdx] = newStore; | 
|     } | 
|   } else { | 
|     store[dimIdx] = new DataCtor(end); | 
|   } | 
| } | 
| ; | 
| /** | 
|  * Basically, DataStore API keep immutable. | 
|  */ | 
| var DataStore = /** @class */function () { | 
|   function DataStore() { | 
|     this._chunks = []; | 
|     // It will not be calculated until needed. | 
|     this._rawExtent = []; | 
|     this._extent = []; | 
|     this._count = 0; | 
|     this._rawCount = 0; | 
|     this._calcDimNameToIdx = createHashMap(); | 
|   } | 
|   /** | 
|    * Initialize from data | 
|    */ | 
|   DataStore.prototype.initData = function (provider, inputDimensions, dimValueGetter) { | 
|     if (process.env.NODE_ENV !== 'production') { | 
|       assert(isFunction(provider.getItem) && isFunction(provider.count), 'Invalid data provider.'); | 
|     } | 
|     this._provider = provider; | 
|     // Clear | 
|     this._chunks = []; | 
|     this._indices = null; | 
|     this.getRawIndex = this._getRawIdxIdentity; | 
|     var source = provider.getSource(); | 
|     var defaultGetter = this.defaultDimValueGetter = defaultDimValueGetters[source.sourceFormat]; | 
|     // Default dim value getter | 
|     this._dimValueGetter = dimValueGetter || defaultGetter; | 
|     // Reset raw extent. | 
|     this._rawExtent = []; | 
|     var willRetrieveDataByName = shouldRetrieveDataByName(source); | 
|     this._dimensions = map(inputDimensions, function (dim) { | 
|       if (process.env.NODE_ENV !== 'production') { | 
|         if (willRetrieveDataByName) { | 
|           assert(dim.property != null); | 
|         } | 
|       } | 
|       return { | 
|         // Only pick these two props. Not leak other properties like orderMeta. | 
|         type: dim.type, | 
|         property: dim.property | 
|       }; | 
|     }); | 
|     this._initDataFromProvider(0, provider.count()); | 
|   }; | 
|   DataStore.prototype.getProvider = function () { | 
|     return this._provider; | 
|   }; | 
|   /** | 
|    * Caution: even when a `source` instance owned by a series, the created data store | 
|    * may still be shared by different sereis (the source hash does not use all `source` | 
|    * props, see `sourceManager`). In this case, the `source` props that are not used in | 
|    * hash (like `source.dimensionDefine`) probably only belongs to a certain series and | 
|    * thus should not be fetch here. | 
|    */ | 
|   DataStore.prototype.getSource = function () { | 
|     return this._provider.getSource(); | 
|   }; | 
|   /** | 
|    * @caution Only used in dataStack. | 
|    */ | 
|   DataStore.prototype.ensureCalculationDimension = function (dimName, type) { | 
|     var calcDimNameToIdx = this._calcDimNameToIdx; | 
|     var dimensions = this._dimensions; | 
|     var calcDimIdx = calcDimNameToIdx.get(dimName); | 
|     if (calcDimIdx != null) { | 
|       if (dimensions[calcDimIdx].type === type) { | 
|         return calcDimIdx; | 
|       } | 
|     } else { | 
|       calcDimIdx = dimensions.length; | 
|     } | 
|     dimensions[calcDimIdx] = { | 
|       type: type | 
|     }; | 
|     calcDimNameToIdx.set(dimName, calcDimIdx); | 
|     this._chunks[calcDimIdx] = new dataCtors[type || 'float'](this._rawCount); | 
|     this._rawExtent[calcDimIdx] = getInitialExtent(); | 
|     return calcDimIdx; | 
|   }; | 
|   DataStore.prototype.collectOrdinalMeta = function (dimIdx, ordinalMeta) { | 
|     var chunk = this._chunks[dimIdx]; | 
|     var dim = this._dimensions[dimIdx]; | 
|     var rawExtents = this._rawExtent; | 
|     var offset = dim.ordinalOffset || 0; | 
|     var len = chunk.length; | 
|     if (offset === 0) { | 
|       // We need to reset the rawExtent if collect is from start. | 
|       // Because this dimension may be guessed as number and calcuating a wrong extent. | 
|       rawExtents[dimIdx] = getInitialExtent(); | 
|     } | 
|     var dimRawExtent = rawExtents[dimIdx]; | 
|     // Parse from previous data offset. len may be changed after appendData | 
|     for (var i = offset; i < len; i++) { | 
|       var val = chunk[i] = ordinalMeta.parseAndCollect(chunk[i]); | 
|       if (!isNaN(val)) { | 
|         dimRawExtent[0] = Math.min(val, dimRawExtent[0]); | 
|         dimRawExtent[1] = Math.max(val, dimRawExtent[1]); | 
|       } | 
|     } | 
|     dim.ordinalMeta = ordinalMeta; | 
|     dim.ordinalOffset = len; | 
|     dim.type = 'ordinal'; // Force to be ordinal | 
|   }; | 
|   DataStore.prototype.getOrdinalMeta = function (dimIdx) { | 
|     var dimInfo = this._dimensions[dimIdx]; | 
|     var ordinalMeta = dimInfo.ordinalMeta; | 
|     return ordinalMeta; | 
|   }; | 
|   DataStore.prototype.getDimensionProperty = function (dimIndex) { | 
|     var item = this._dimensions[dimIndex]; | 
|     return item && item.property; | 
|   }; | 
|   /** | 
|    * Caution: Can be only called on raw data (before `this._indices` created). | 
|    */ | 
|   DataStore.prototype.appendData = function (data) { | 
|     if (process.env.NODE_ENV !== 'production') { | 
|       assert(!this._indices, 'appendData can only be called on raw data.'); | 
|     } | 
|     var provider = this._provider; | 
|     var start = this.count(); | 
|     provider.appendData(data); | 
|     var end = provider.count(); | 
|     if (!provider.persistent) { | 
|       end += start; | 
|     } | 
|     if (start < end) { | 
|       this._initDataFromProvider(start, end, true); | 
|     } | 
|     return [start, end]; | 
|   }; | 
|   DataStore.prototype.appendValues = function (values, minFillLen) { | 
|     var chunks = this._chunks; | 
|     var dimensions = this._dimensions; | 
|     var dimLen = dimensions.length; | 
|     var rawExtent = this._rawExtent; | 
|     var start = this.count(); | 
|     var end = start + Math.max(values.length, minFillLen || 0); | 
|     for (var i = 0; i < dimLen; i++) { | 
|       var dim = dimensions[i]; | 
|       prepareStore(chunks, i, dim.type, end, true); | 
|     } | 
|     var emptyDataItem = []; | 
|     for (var idx = start; idx < end; idx++) { | 
|       var sourceIdx = idx - start; | 
|       // Store the data by dimensions | 
|       for (var dimIdx = 0; dimIdx < dimLen; dimIdx++) { | 
|         var dim = dimensions[dimIdx]; | 
|         var val = defaultDimValueGetters.arrayRows.call(this, values[sourceIdx] || emptyDataItem, dim.property, sourceIdx, dimIdx); | 
|         chunks[dimIdx][idx] = val; | 
|         var dimRawExtent = rawExtent[dimIdx]; | 
|         val < dimRawExtent[0] && (dimRawExtent[0] = val); | 
|         val > dimRawExtent[1] && (dimRawExtent[1] = val); | 
|       } | 
|     } | 
|     this._rawCount = this._count = end; | 
|     return { | 
|       start: start, | 
|       end: end | 
|     }; | 
|   }; | 
|   DataStore.prototype._initDataFromProvider = function (start, end, append) { | 
|     var provider = this._provider; | 
|     var chunks = this._chunks; | 
|     var dimensions = this._dimensions; | 
|     var dimLen = dimensions.length; | 
|     var rawExtent = this._rawExtent; | 
|     var dimNames = map(dimensions, function (dim) { | 
|       return dim.property; | 
|     }); | 
|     for (var i = 0; i < dimLen; i++) { | 
|       var dim = dimensions[i]; | 
|       if (!rawExtent[i]) { | 
|         rawExtent[i] = getInitialExtent(); | 
|       } | 
|       prepareStore(chunks, i, dim.type, end, append); | 
|     } | 
|     if (provider.fillStorage) { | 
|       provider.fillStorage(start, end, chunks, rawExtent); | 
|     } else { | 
|       var dataItem = []; | 
|       for (var idx = start; idx < end; idx++) { | 
|         // NOTICE: Try not to write things into dataItem | 
|         dataItem = provider.getItem(idx, dataItem); | 
|         // Each data item is value | 
|         // [1, 2] | 
|         // 2 | 
|         // Bar chart, line chart which uses category axis | 
|         // only gives the 'y' value. 'x' value is the indices of category | 
|         // Use a tempValue to normalize the value to be a (x, y) value | 
|         // Store the data by dimensions | 
|         for (var dimIdx = 0; dimIdx < dimLen; dimIdx++) { | 
|           var dimStorage = chunks[dimIdx]; | 
|           // PENDING NULL is empty or zero | 
|           var val = this._dimValueGetter(dataItem, dimNames[dimIdx], idx, dimIdx); | 
|           dimStorage[idx] = val; | 
|           var dimRawExtent = rawExtent[dimIdx]; | 
|           val < dimRawExtent[0] && (dimRawExtent[0] = val); | 
|           val > dimRawExtent[1] && (dimRawExtent[1] = val); | 
|         } | 
|       } | 
|     } | 
|     if (!provider.persistent && provider.clean) { | 
|       // Clean unused data if data source is typed array. | 
|       provider.clean(); | 
|     } | 
|     this._rawCount = this._count = end; | 
|     // Reset data extent | 
|     this._extent = []; | 
|   }; | 
|   DataStore.prototype.count = function () { | 
|     return this._count; | 
|   }; | 
|   /** | 
|    * Get value. Return NaN if idx is out of range. | 
|    */ | 
|   DataStore.prototype.get = function (dim, idx) { | 
|     if (!(idx >= 0 && idx < this._count)) { | 
|       return NaN; | 
|     } | 
|     var dimStore = this._chunks[dim]; | 
|     return dimStore ? dimStore[this.getRawIndex(idx)] : NaN; | 
|   }; | 
|   DataStore.prototype.getValues = function (dimensions, idx) { | 
|     var values = []; | 
|     var dimArr = []; | 
|     if (idx == null) { | 
|       idx = dimensions; | 
|       // TODO get all from store? | 
|       dimensions = []; | 
|       // All dimensions | 
|       for (var i = 0; i < this._dimensions.length; i++) { | 
|         dimArr.push(i); | 
|       } | 
|     } else { | 
|       dimArr = dimensions; | 
|     } | 
|     for (var i = 0, len = dimArr.length; i < len; i++) { | 
|       values.push(this.get(dimArr[i], idx)); | 
|     } | 
|     return values; | 
|   }; | 
|   /** | 
|    * @param dim concrete dim | 
|    */ | 
|   DataStore.prototype.getByRawIndex = function (dim, rawIdx) { | 
|     if (!(rawIdx >= 0 && rawIdx < this._rawCount)) { | 
|       return NaN; | 
|     } | 
|     var dimStore = this._chunks[dim]; | 
|     return dimStore ? dimStore[rawIdx] : NaN; | 
|   }; | 
|   /** | 
|    * Get sum of data in one dimension | 
|    */ | 
|   DataStore.prototype.getSum = function (dim) { | 
|     var dimData = this._chunks[dim]; | 
|     var sum = 0; | 
|     if (dimData) { | 
|       for (var i = 0, len = this.count(); i < len; i++) { | 
|         var value = this.get(dim, i); | 
|         if (!isNaN(value)) { | 
|           sum += value; | 
|         } | 
|       } | 
|     } | 
|     return sum; | 
|   }; | 
|   /** | 
|    * Get median of data in one dimension | 
|    */ | 
|   DataStore.prototype.getMedian = function (dim) { | 
|     var dimDataArray = []; | 
|     // map all data of one dimension | 
|     this.each([dim], function (val) { | 
|       if (!isNaN(val)) { | 
|         dimDataArray.push(val); | 
|       } | 
|     }); | 
|     // TODO | 
|     // Use quick select? | 
|     var sortedDimDataArray = dimDataArray.sort(function (a, b) { | 
|       return a - b; | 
|     }); | 
|     var len = this.count(); | 
|     // calculate median | 
|     return len === 0 ? 0 : len % 2 === 1 ? sortedDimDataArray[(len - 1) / 2] : (sortedDimDataArray[len / 2] + sortedDimDataArray[len / 2 - 1]) / 2; | 
|   }; | 
|   /** | 
|    * Retrieve the index with given raw data index. | 
|    */ | 
|   DataStore.prototype.indexOfRawIndex = function (rawIndex) { | 
|     if (rawIndex >= this._rawCount || rawIndex < 0) { | 
|       return -1; | 
|     } | 
|     if (!this._indices) { | 
|       return rawIndex; | 
|     } | 
|     // Indices are ascending | 
|     var indices = this._indices; | 
|     // If rawIndex === dataIndex | 
|     var rawDataIndex = indices[rawIndex]; | 
|     if (rawDataIndex != null && rawDataIndex < this._count && rawDataIndex === rawIndex) { | 
|       return rawIndex; | 
|     } | 
|     var left = 0; | 
|     var right = this._count - 1; | 
|     while (left <= right) { | 
|       var mid = (left + right) / 2 | 0; | 
|       if (indices[mid] < rawIndex) { | 
|         left = mid + 1; | 
|       } else if (indices[mid] > rawIndex) { | 
|         right = mid - 1; | 
|       } else { | 
|         return mid; | 
|       } | 
|     } | 
|     return -1; | 
|   }; | 
|   /** | 
|    * Retrieve the index of nearest value. | 
|    * @param dim | 
|    * @param value | 
|    * @param [maxDistance=Infinity] | 
|    * @return If and only if multiple indices have | 
|    *         the same value, they are put to the result. | 
|    */ | 
|   DataStore.prototype.indicesOfNearest = function (dim, value, maxDistance) { | 
|     var chunks = this._chunks; | 
|     var dimData = chunks[dim]; | 
|     var nearestIndices = []; | 
|     if (!dimData) { | 
|       return nearestIndices; | 
|     } | 
|     if (maxDistance == null) { | 
|       maxDistance = Infinity; | 
|     } | 
|     var minDist = Infinity; | 
|     var minDiff = -1; | 
|     var nearestIndicesLen = 0; | 
|     // Check the test case of `test/ut/spec/data/SeriesData.js`. | 
|     for (var i = 0, len = this.count(); i < len; i++) { | 
|       var dataIndex = this.getRawIndex(i); | 
|       var diff = value - dimData[dataIndex]; | 
|       var dist = Math.abs(diff); | 
|       if (dist <= maxDistance) { | 
|         // When the `value` is at the middle of `this.get(dim, i)` and `this.get(dim, i+1)`, | 
|         // we'd better not push both of them to `nearestIndices`, otherwise it is easy to | 
|         // get more than one item in `nearestIndices` (more specifically, in `tooltip`). | 
|         // So we choose the one that `diff >= 0` in this case. | 
|         // But if `this.get(dim, i)` and `this.get(dim, j)` get the same value, both of them | 
|         // should be push to `nearestIndices`. | 
|         if (dist < minDist || dist === minDist && diff >= 0 && minDiff < 0) { | 
|           minDist = dist; | 
|           minDiff = diff; | 
|           nearestIndicesLen = 0; | 
|         } | 
|         if (diff === minDiff) { | 
|           nearestIndices[nearestIndicesLen++] = i; | 
|         } | 
|       } | 
|     } | 
|     nearestIndices.length = nearestIndicesLen; | 
|     return nearestIndices; | 
|   }; | 
|   DataStore.prototype.getIndices = function () { | 
|     var newIndices; | 
|     var indices = this._indices; | 
|     if (indices) { | 
|       var Ctor = indices.constructor; | 
|       var thisCount = this._count; | 
|       // `new Array(a, b, c)` is different from `new Uint32Array(a, b, c)`. | 
|       if (Ctor === Array) { | 
|         newIndices = new Ctor(thisCount); | 
|         for (var i = 0; i < thisCount; i++) { | 
|           newIndices[i] = indices[i]; | 
|         } | 
|       } else { | 
|         newIndices = new Ctor(indices.buffer, 0, thisCount); | 
|       } | 
|     } else { | 
|       var Ctor = getIndicesCtor(this._rawCount); | 
|       newIndices = new Ctor(this.count()); | 
|       for (var i = 0; i < newIndices.length; i++) { | 
|         newIndices[i] = i; | 
|       } | 
|     } | 
|     return newIndices; | 
|   }; | 
|   /** | 
|    * Data filter. | 
|    */ | 
|   DataStore.prototype.filter = function (dims, cb) { | 
|     if (!this._count) { | 
|       return this; | 
|     } | 
|     var newStore = this.clone(); | 
|     var count = newStore.count(); | 
|     var Ctor = getIndicesCtor(newStore._rawCount); | 
|     var newIndices = new Ctor(count); | 
|     var value = []; | 
|     var dimSize = dims.length; | 
|     var offset = 0; | 
|     var dim0 = dims[0]; | 
|     var chunks = newStore._chunks; | 
|     for (var i = 0; i < count; i++) { | 
|       var keep = void 0; | 
|       var rawIdx = newStore.getRawIndex(i); | 
|       // Simple optimization | 
|       if (dimSize === 0) { | 
|         keep = cb(i); | 
|       } else if (dimSize === 1) { | 
|         var val = chunks[dim0][rawIdx]; | 
|         keep = cb(val, i); | 
|       } else { | 
|         var k = 0; | 
|         for (; k < dimSize; k++) { | 
|           value[k] = chunks[dims[k]][rawIdx]; | 
|         } | 
|         value[k] = i; | 
|         keep = cb.apply(null, value); | 
|       } | 
|       if (keep) { | 
|         newIndices[offset++] = rawIdx; | 
|       } | 
|     } | 
|     // Set indices after filtered. | 
|     if (offset < count) { | 
|       newStore._indices = newIndices; | 
|     } | 
|     newStore._count = offset; | 
|     // Reset data extent | 
|     newStore._extent = []; | 
|     newStore._updateGetRawIdx(); | 
|     return newStore; | 
|   }; | 
|   /** | 
|    * Select data in range. (For optimization of filter) | 
|    * (Manually inline code, support 5 million data filtering in data zoom.) | 
|    */ | 
|   DataStore.prototype.selectRange = function (range) { | 
|     var newStore = this.clone(); | 
|     var len = newStore._count; | 
|     if (!len) { | 
|       return this; | 
|     } | 
|     var dims = keys(range); | 
|     var dimSize = dims.length; | 
|     if (!dimSize) { | 
|       return this; | 
|     } | 
|     var originalCount = newStore.count(); | 
|     var Ctor = getIndicesCtor(newStore._rawCount); | 
|     var newIndices = new Ctor(originalCount); | 
|     var offset = 0; | 
|     var dim0 = dims[0]; | 
|     var min = range[dim0][0]; | 
|     var max = range[dim0][1]; | 
|     var storeArr = newStore._chunks; | 
|     var quickFinished = false; | 
|     if (!newStore._indices) { | 
|       // Extreme optimization for common case. About 2x faster in chrome. | 
|       var idx = 0; | 
|       if (dimSize === 1) { | 
|         var dimStorage = storeArr[dims[0]]; | 
|         for (var i = 0; i < len; i++) { | 
|           var val = dimStorage[i]; | 
|           // NaN will not be filtered. Consider the case, in line chart, empty | 
|           // value indicates the line should be broken. But for the case like | 
|           // scatter plot, a data item with empty value will not be rendered, | 
|           // but the axis extent may be effected if some other dim of the data | 
|           // item has value. Fortunately it is not a significant negative effect. | 
|           if (val >= min && val <= max || isNaN(val)) { | 
|             newIndices[offset++] = idx; | 
|           } | 
|           idx++; | 
|         } | 
|         quickFinished = true; | 
|       } else if (dimSize === 2) { | 
|         var dimStorage = storeArr[dims[0]]; | 
|         var dimStorage2 = storeArr[dims[1]]; | 
|         var min2 = range[dims[1]][0]; | 
|         var max2 = range[dims[1]][1]; | 
|         for (var i = 0; i < len; i++) { | 
|           var val = dimStorage[i]; | 
|           var val2 = dimStorage2[i]; | 
|           // Do not filter NaN, see comment above. | 
|           if ((val >= min && val <= max || isNaN(val)) && (val2 >= min2 && val2 <= max2 || isNaN(val2))) { | 
|             newIndices[offset++] = idx; | 
|           } | 
|           idx++; | 
|         } | 
|         quickFinished = true; | 
|       } | 
|     } | 
|     if (!quickFinished) { | 
|       if (dimSize === 1) { | 
|         for (var i = 0; i < originalCount; i++) { | 
|           var rawIndex = newStore.getRawIndex(i); | 
|           var val = storeArr[dims[0]][rawIndex]; | 
|           // Do not filter NaN, see comment above. | 
|           if (val >= min && val <= max || isNaN(val)) { | 
|             newIndices[offset++] = rawIndex; | 
|           } | 
|         } | 
|       } else { | 
|         for (var i = 0; i < originalCount; i++) { | 
|           var keep = true; | 
|           var rawIndex = newStore.getRawIndex(i); | 
|           for (var k = 0; k < dimSize; k++) { | 
|             var dimk = dims[k]; | 
|             var val = storeArr[dimk][rawIndex]; | 
|             // Do not filter NaN, see comment above. | 
|             if (val < range[dimk][0] || val > range[dimk][1]) { | 
|               keep = false; | 
|             } | 
|           } | 
|           if (keep) { | 
|             newIndices[offset++] = newStore.getRawIndex(i); | 
|           } | 
|         } | 
|       } | 
|     } | 
|     // Set indices after filtered. | 
|     if (offset < originalCount) { | 
|       newStore._indices = newIndices; | 
|     } | 
|     newStore._count = offset; | 
|     // Reset data extent | 
|     newStore._extent = []; | 
|     newStore._updateGetRawIdx(); | 
|     return newStore; | 
|   }; | 
|   // /** | 
|   //  * Data mapping to a plain array | 
|   //  */ | 
|   // mapArray(dims: DimensionIndex[], cb: MapArrayCb): any[] { | 
|   //     const result: any[] = []; | 
|   //     this.each(dims, function () { | 
|   //         result.push(cb && (cb as MapArrayCb).apply(null, arguments)); | 
|   //     }); | 
|   //     return result; | 
|   // } | 
|   /** | 
|    * Data mapping to a new List with given dimensions | 
|    */ | 
|   DataStore.prototype.map = function (dims, cb) { | 
|     // TODO only clone picked chunks. | 
|     var target = this.clone(dims); | 
|     this._updateDims(target, dims, cb); | 
|     return target; | 
|   }; | 
|   /** | 
|    * @caution Danger!! Only used in dataStack. | 
|    */ | 
|   DataStore.prototype.modify = function (dims, cb) { | 
|     this._updateDims(this, dims, cb); | 
|   }; | 
|   DataStore.prototype._updateDims = function (target, dims, cb) { | 
|     var targetChunks = target._chunks; | 
|     var tmpRetValue = []; | 
|     var dimSize = dims.length; | 
|     var dataCount = target.count(); | 
|     var values = []; | 
|     var rawExtent = target._rawExtent; | 
|     for (var i = 0; i < dims.length; i++) { | 
|       rawExtent[dims[i]] = getInitialExtent(); | 
|     } | 
|     for (var dataIndex = 0; dataIndex < dataCount; dataIndex++) { | 
|       var rawIndex = target.getRawIndex(dataIndex); | 
|       for (var k = 0; k < dimSize; k++) { | 
|         values[k] = targetChunks[dims[k]][rawIndex]; | 
|       } | 
|       values[dimSize] = dataIndex; | 
|       var retValue = cb && cb.apply(null, values); | 
|       if (retValue != null) { | 
|         // a number or string (in oridinal dimension)? | 
|         if (typeof retValue !== 'object') { | 
|           tmpRetValue[0] = retValue; | 
|           retValue = tmpRetValue; | 
|         } | 
|         for (var i = 0; i < retValue.length; i++) { | 
|           var dim = dims[i]; | 
|           var val = retValue[i]; | 
|           var rawExtentOnDim = rawExtent[dim]; | 
|           var dimStore = targetChunks[dim]; | 
|           if (dimStore) { | 
|             dimStore[rawIndex] = val; | 
|           } | 
|           if (val < rawExtentOnDim[0]) { | 
|             rawExtentOnDim[0] = val; | 
|           } | 
|           if (val > rawExtentOnDim[1]) { | 
|             rawExtentOnDim[1] = val; | 
|           } | 
|         } | 
|       } | 
|     } | 
|   }; | 
|   /** | 
|    * Large data down sampling using largest-triangle-three-buckets | 
|    * @param {string} valueDimension | 
|    * @param {number} targetCount | 
|    */ | 
|   DataStore.prototype.lttbDownSample = function (valueDimension, rate) { | 
|     var target = this.clone([valueDimension], true); | 
|     var targetStorage = target._chunks; | 
|     var dimStore = targetStorage[valueDimension]; | 
|     var len = this.count(); | 
|     var sampledIndex = 0; | 
|     var frameSize = Math.floor(1 / rate); | 
|     var currentRawIndex = this.getRawIndex(0); | 
|     var maxArea; | 
|     var area; | 
|     var nextRawIndex; | 
|     var newIndices = new (getIndicesCtor(this._rawCount))(Math.min((Math.ceil(len / frameSize) + 2) * 2, len)); | 
|     // First frame use the first data. | 
|     newIndices[sampledIndex++] = currentRawIndex; | 
|     for (var i = 1; i < len - 1; i += frameSize) { | 
|       var nextFrameStart = Math.min(i + frameSize, len - 1); | 
|       var nextFrameEnd = Math.min(i + frameSize * 2, len); | 
|       var avgX = (nextFrameEnd + nextFrameStart) / 2; | 
|       var avgY = 0; | 
|       for (var idx = nextFrameStart; idx < nextFrameEnd; idx++) { | 
|         var rawIndex = this.getRawIndex(idx); | 
|         var y = dimStore[rawIndex]; | 
|         if (isNaN(y)) { | 
|           continue; | 
|         } | 
|         avgY += y; | 
|       } | 
|       avgY /= nextFrameEnd - nextFrameStart; | 
|       var frameStart = i; | 
|       var frameEnd = Math.min(i + frameSize, len); | 
|       var pointAX = i - 1; | 
|       var pointAY = dimStore[currentRawIndex]; | 
|       maxArea = -1; | 
|       nextRawIndex = frameStart; | 
|       var firstNaNIndex = -1; | 
|       var countNaN = 0; | 
|       // Find a point from current frame that construct a triangle with largest area with previous selected point | 
|       // And the average of next frame. | 
|       for (var idx = frameStart; idx < frameEnd; idx++) { | 
|         var rawIndex = this.getRawIndex(idx); | 
|         var y = dimStore[rawIndex]; | 
|         if (isNaN(y)) { | 
|           countNaN++; | 
|           if (firstNaNIndex < 0) { | 
|             firstNaNIndex = rawIndex; | 
|           } | 
|           continue; | 
|         } | 
|         // Calculate triangle area over three buckets | 
|         area = Math.abs((pointAX - avgX) * (y - pointAY) - (pointAX - idx) * (avgY - pointAY)); | 
|         if (area > maxArea) { | 
|           maxArea = area; | 
|           nextRawIndex = rawIndex; // Next a is this b | 
|         } | 
|       } | 
|       if (countNaN > 0 && countNaN < frameEnd - frameStart) { | 
|         // Append first NaN point in every bucket. | 
|         // It is necessary to ensure the correct order of indices. | 
|         newIndices[sampledIndex++] = Math.min(firstNaNIndex, nextRawIndex); | 
|         nextRawIndex = Math.max(firstNaNIndex, nextRawIndex); | 
|       } | 
|       newIndices[sampledIndex++] = nextRawIndex; | 
|       currentRawIndex = nextRawIndex; // This a is the next a (chosen b) | 
|     } | 
|     // First frame use the last data. | 
|     newIndices[sampledIndex++] = this.getRawIndex(len - 1); | 
|     target._count = sampledIndex; | 
|     target._indices = newIndices; | 
|     target.getRawIndex = this._getRawIdx; | 
|     return target; | 
|   }; | 
|   /** | 
|    * Large data down sampling using min-max | 
|    * @param {string} valueDimension | 
|    * @param {number} rate | 
|    */ | 
|   DataStore.prototype.minmaxDownSample = function (valueDimension, rate) { | 
|     var target = this.clone([valueDimension], true); | 
|     var targetStorage = target._chunks; | 
|     var frameSize = Math.floor(1 / rate); | 
|     var dimStore = targetStorage[valueDimension]; | 
|     var len = this.count(); | 
|     // Each frame results in 2 data points, one for min and one for max | 
|     var newIndices = new (getIndicesCtor(this._rawCount))(Math.ceil(len / frameSize) * 2); | 
|     var offset = 0; | 
|     for (var i = 0; i < len; i += frameSize) { | 
|       var minIndex = i; | 
|       var minValue = dimStore[this.getRawIndex(minIndex)]; | 
|       var maxIndex = i; | 
|       var maxValue = dimStore[this.getRawIndex(maxIndex)]; | 
|       var thisFrameSize = frameSize; | 
|       // Handle final smaller frame | 
|       if (i + frameSize > len) { | 
|         thisFrameSize = len - i; | 
|       } | 
|       // Determine min and max within the current frame | 
|       for (var k = 0; k < thisFrameSize; k++) { | 
|         var rawIndex = this.getRawIndex(i + k); | 
|         var value = dimStore[rawIndex]; | 
|         if (value < minValue) { | 
|           minValue = value; | 
|           minIndex = i + k; | 
|         } | 
|         if (value > maxValue) { | 
|           maxValue = value; | 
|           maxIndex = i + k; | 
|         } | 
|       } | 
|       var rawMinIndex = this.getRawIndex(minIndex); | 
|       var rawMaxIndex = this.getRawIndex(maxIndex); | 
|       // Set the order of the min and max values, based on their ordering in the frame | 
|       if (minIndex < maxIndex) { | 
|         newIndices[offset++] = rawMinIndex; | 
|         newIndices[offset++] = rawMaxIndex; | 
|       } else { | 
|         newIndices[offset++] = rawMaxIndex; | 
|         newIndices[offset++] = rawMinIndex; | 
|       } | 
|     } | 
|     target._count = offset; | 
|     target._indices = newIndices; | 
|     target._updateGetRawIdx(); | 
|     return target; | 
|   }; | 
|   /** | 
|    * Large data down sampling on given dimension | 
|    * @param sampleIndex Sample index for name and id | 
|    */ | 
|   DataStore.prototype.downSample = function (dimension, rate, sampleValue, sampleIndex) { | 
|     var target = this.clone([dimension], true); | 
|     var targetStorage = target._chunks; | 
|     var frameValues = []; | 
|     var frameSize = Math.floor(1 / rate); | 
|     var dimStore = targetStorage[dimension]; | 
|     var len = this.count(); | 
|     var rawExtentOnDim = target._rawExtent[dimension] = getInitialExtent(); | 
|     var newIndices = new (getIndicesCtor(this._rawCount))(Math.ceil(len / frameSize)); | 
|     var offset = 0; | 
|     for (var i = 0; i < len; i += frameSize) { | 
|       // Last frame | 
|       if (frameSize > len - i) { | 
|         frameSize = len - i; | 
|         frameValues.length = frameSize; | 
|       } | 
|       for (var k = 0; k < frameSize; k++) { | 
|         var dataIdx = this.getRawIndex(i + k); | 
|         frameValues[k] = dimStore[dataIdx]; | 
|       } | 
|       var value = sampleValue(frameValues); | 
|       var sampleFrameIdx = this.getRawIndex(Math.min(i + sampleIndex(frameValues, value) || 0, len - 1)); | 
|       // Only write value on the filtered data | 
|       dimStore[sampleFrameIdx] = value; | 
|       if (value < rawExtentOnDim[0]) { | 
|         rawExtentOnDim[0] = value; | 
|       } | 
|       if (value > rawExtentOnDim[1]) { | 
|         rawExtentOnDim[1] = value; | 
|       } | 
|       newIndices[offset++] = sampleFrameIdx; | 
|     } | 
|     target._count = offset; | 
|     target._indices = newIndices; | 
|     target._updateGetRawIdx(); | 
|     return target; | 
|   }; | 
|   /** | 
|    * Data iteration | 
|    * @param ctx default this | 
|    * @example | 
|    *  list.each('x', function (x, idx) {}); | 
|    *  list.each(['x', 'y'], function (x, y, idx) {}); | 
|    *  list.each(function (idx) {}) | 
|    */ | 
|   DataStore.prototype.each = function (dims, cb) { | 
|     if (!this._count) { | 
|       return; | 
|     } | 
|     var dimSize = dims.length; | 
|     var chunks = this._chunks; | 
|     for (var i = 0, len = this.count(); i < len; i++) { | 
|       var rawIdx = this.getRawIndex(i); | 
|       // Simple optimization | 
|       switch (dimSize) { | 
|         case 0: | 
|           cb(i); | 
|           break; | 
|         case 1: | 
|           cb(chunks[dims[0]][rawIdx], i); | 
|           break; | 
|         case 2: | 
|           cb(chunks[dims[0]][rawIdx], chunks[dims[1]][rawIdx], i); | 
|           break; | 
|         default: | 
|           var k = 0; | 
|           var value = []; | 
|           for (; k < dimSize; k++) { | 
|             value[k] = chunks[dims[k]][rawIdx]; | 
|           } | 
|           // Index | 
|           value[k] = i; | 
|           cb.apply(null, value); | 
|       } | 
|     } | 
|   }; | 
|   /** | 
|    * Get extent of data in one dimension | 
|    */ | 
|   DataStore.prototype.getDataExtent = function (dim) { | 
|     // Make sure use concrete dim as cache name. | 
|     var dimData = this._chunks[dim]; | 
|     var initialExtent = getInitialExtent(); | 
|     if (!dimData) { | 
|       return initialExtent; | 
|     } | 
|     // Make more strict checkings to ensure hitting cache. | 
|     var currEnd = this.count(); | 
|     // Consider the most cases when using data zoom, `getDataExtent` | 
|     // happened before filtering. We cache raw extent, which is not | 
|     // necessary to be cleared and recalculated when restore data. | 
|     var useRaw = !this._indices; | 
|     var dimExtent; | 
|     if (useRaw) { | 
|       return this._rawExtent[dim].slice(); | 
|     } | 
|     dimExtent = this._extent[dim]; | 
|     if (dimExtent) { | 
|       return dimExtent.slice(); | 
|     } | 
|     dimExtent = initialExtent; | 
|     var min = dimExtent[0]; | 
|     var max = dimExtent[1]; | 
|     for (var i = 0; i < currEnd; i++) { | 
|       var rawIdx = this.getRawIndex(i); | 
|       var value = dimData[rawIdx]; | 
|       value < min && (min = value); | 
|       value > max && (max = value); | 
|     } | 
|     dimExtent = [min, max]; | 
|     this._extent[dim] = dimExtent; | 
|     return dimExtent; | 
|   }; | 
|   /** | 
|    * Get raw data item | 
|    */ | 
|   DataStore.prototype.getRawDataItem = function (idx) { | 
|     var rawIdx = this.getRawIndex(idx); | 
|     if (!this._provider.persistent) { | 
|       var val = []; | 
|       var chunks = this._chunks; | 
|       for (var i = 0; i < chunks.length; i++) { | 
|         val.push(chunks[i][rawIdx]); | 
|       } | 
|       return val; | 
|     } else { | 
|       return this._provider.getItem(rawIdx); | 
|     } | 
|   }; | 
|   /** | 
|    * Clone shallow. | 
|    * | 
|    * @param clonedDims Determine which dims to clone. Will share the data if not specified. | 
|    */ | 
|   DataStore.prototype.clone = function (clonedDims, ignoreIndices) { | 
|     var target = new DataStore(); | 
|     var chunks = this._chunks; | 
|     var clonedDimsMap = clonedDims && reduce(clonedDims, function (obj, dimIdx) { | 
|       obj[dimIdx] = true; | 
|       return obj; | 
|     }, {}); | 
|     if (clonedDimsMap) { | 
|       for (var i = 0; i < chunks.length; i++) { | 
|         // Not clone if dim is not picked. | 
|         target._chunks[i] = !clonedDimsMap[i] ? chunks[i] : cloneChunk(chunks[i]); | 
|       } | 
|     } else { | 
|       target._chunks = chunks; | 
|     } | 
|     this._copyCommonProps(target); | 
|     if (!ignoreIndices) { | 
|       target._indices = this._cloneIndices(); | 
|     } | 
|     target._updateGetRawIdx(); | 
|     return target; | 
|   }; | 
|   DataStore.prototype._copyCommonProps = function (target) { | 
|     target._count = this._count; | 
|     target._rawCount = this._rawCount; | 
|     target._provider = this._provider; | 
|     target._dimensions = this._dimensions; | 
|     target._extent = clone(this._extent); | 
|     target._rawExtent = clone(this._rawExtent); | 
|   }; | 
|   DataStore.prototype._cloneIndices = function () { | 
|     if (this._indices) { | 
|       var Ctor = this._indices.constructor; | 
|       var indices = void 0; | 
|       if (Ctor === Array) { | 
|         var thisCount = this._indices.length; | 
|         indices = new Ctor(thisCount); | 
|         for (var i = 0; i < thisCount; i++) { | 
|           indices[i] = this._indices[i]; | 
|         } | 
|       } else { | 
|         indices = new Ctor(this._indices); | 
|       } | 
|       return indices; | 
|     } | 
|     return null; | 
|   }; | 
|   DataStore.prototype._getRawIdxIdentity = function (idx) { | 
|     return idx; | 
|   }; | 
|   DataStore.prototype._getRawIdx = function (idx) { | 
|     if (idx < this._count && idx >= 0) { | 
|       return this._indices[idx]; | 
|     } | 
|     return -1; | 
|   }; | 
|   DataStore.prototype._updateGetRawIdx = function () { | 
|     this.getRawIndex = this._indices ? this._getRawIdx : this._getRawIdxIdentity; | 
|   }; | 
|   DataStore.internalField = function () { | 
|     function getDimValueSimply(dataItem, property, dataIndex, dimIndex) { | 
|       return parseDataValue(dataItem[dimIndex], this._dimensions[dimIndex]); | 
|     } | 
|     defaultDimValueGetters = { | 
|       arrayRows: getDimValueSimply, | 
|       objectRows: function (dataItem, property, dataIndex, dimIndex) { | 
|         return parseDataValue(dataItem[property], this._dimensions[dimIndex]); | 
|       }, | 
|       keyedColumns: getDimValueSimply, | 
|       original: function (dataItem, property, dataIndex, dimIndex) { | 
|         // Performance sensitive, do not use modelUtil.getDataItemValue. | 
|         // If dataItem is an plain object with no value field, the let `value` | 
|         // will be assigned with the object, but it will be tread correctly | 
|         // in the `convertValue`. | 
|         var value = dataItem && (dataItem.value == null ? dataItem : dataItem.value); | 
|         return parseDataValue(value instanceof Array ? value[dimIndex] | 
|         // If value is a single number or something else not array. | 
|         : value, this._dimensions[dimIndex]); | 
|       }, | 
|       typedArray: function (dataItem, property, dataIndex, dimIndex) { | 
|         return dataItem[dimIndex]; | 
|       } | 
|     }; | 
|   }(); | 
|   return DataStore; | 
| }(); | 
| export default DataStore; |