diff --git a/src/data/List.js b/src/data/List.js index 114416324f040081da245ec009fac8ad9ae1f694..01ac002916df3eb9f631ab141cca4b40502b4b3f 100644 --- a/src/data/List.js +++ b/src/data/List.js @@ -663,49 +663,53 @@ define(function (require) { return result; }; - /** - * Data mapping to a new List with given dimensions - * @param {string|Array.} dimensions - * @param {Function} cb - * @param {boolean} [stack=false] - * @param {*} [context=this] - * @return {Array} - */ - listProto.map = function (dimensions, cb, stack, context) { - dimensions = zrUtil.map( - normalizeDimensions(dimensions), this.getDimension, this - ); - + function cloneListForMapAndSample(original, excludeDimensions) { var allDimensions = this.dimensions; var list = new List( zrUtil.map(allDimensions, this.getDimensionInfo, this), this.hostModel ); - - // Following properties are all immutable. - // So we can reference to the same value - var indices = list.indices = this.indices; - // FIXME If needs stackedOn, value may already been stacked - transferImmuProperties(list, this, this._wrappedMethods); + transferImmuProperties(list, original, original._wrappedMethods); var storage = list._storage = {}; - var thisStorage = this._storage; - + var originalStorage = original._storage; // Init storage for (var i = 0; i < allDimensions.length; i++) { var dim = allDimensions[i]; - var dimStore = thisStorage[dim]; - if (zrUtil.indexOf(dimensions, dim) >= 0) { + var dimStore = originalStorage[dim]; + if (zrUtil.indexOf(excludeDimensions, dim) >= 0) { storage[dim] = new dimStore.constructor( - thisStorage[dim].length + originalStorage[dim].length ); } else { - // Direct copy for other dimensions - storage[dim] = thisStorage[dim]; + // Direct reference for other dimensions + storage[dim] = originalStorage[dim]; } } + return list; + } + + /** + * Data mapping to a new List with given dimensions + * @param {string|Array.} dimensions + * @param {Function} cb + * @param {boolean} [stack=false] + * @param {*} [context=this] + * @return {Array} + */ + listProto.map = function (dimensions, cb, stack, context) { + dimensions = zrUtil.map( + normalizeDimensions(dimensions), this.getDimension, this + ); + + var list = cloneListForMapAndSample(this, dimensions); + // Following properties are all immutable. + // So we can reference to the same value + var indices = list.indices = this.indices; + + var storage = list._storage; var tmpRetValue = []; this.each(dimensions, function () { @@ -731,11 +735,50 @@ define(function (require) { return list; }; - // Since temporate model is shared by all data items. So we must make sure it can't be write. - // PENDING may cause any performance problem? - // if (Object.freeze) { - // Object.freeze(temporaryModel); - // } + /** + * Large data down sampling on given dimension + * @param {string} dimension + * @param {number} rate + * @param {Function} sampleValue + * @param {Function} sampleIndex Sample index for name and id + */ + listProto.downSample = function (dimension, rate, sampleValue, sampleIndex) { + var list = cloneListForMapAndSample(this, [dimension]); + var storage = this._storage; + var targetStorage = list._storage; + + var originalIndices = this.indices; + var indices = list.indices = []; + + var frameValues = []; + var frameIndices = []; + var frameSize = Math.floor(1 / rate); + + var dimStore = targetStorage[dimension]; + var len = this.count(); + // Copy data from original data + for (var i = 0; i < storage[dimension].length; i++) { + targetStorage[dimension][i] = storage[dimension][i]; + } + 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++) { + frameValues[k] = dimStore[i + k]; + frameIndices[k] = originalIndices[i + k]; + } + var value = sampleValue(frameValues); + var idx = frameIndices[sampleIndex(frameValues, value) || 0]; + // Only write value on the filtered data + dimStore[idx] = value; + indices.push(idx); + } + return list; + }; + /** * Get model of one data item. *