List.js 13.1 KB
Newer Older
L
lang 已提交
1 2
// TODO entry.getLon(), entry.getLat()
// List supported for cartesian, polar coordinateSystem
L
lang 已提交
3 4 5 6
define(function(require) {
    'use strict';

    var zrUtil = require('zrender/core/util');
L
lang 已提交
7
    var Model = require('../model/Model');
L
lang 已提交
8
    var DataDiffer = require('./DataDiffer');
L
lang 已提交
9

L
lang 已提交
10 11 12 13 14 15 16 17 18 19 20 21 22
    var POSSIBLE_DIMENSIONS = ['x', 'y', 'z', 'value', 'radius', 'angle'];

    /**
     * Check if two entries has same xIndex, yIndex, zIndex, valueIndex, etc.
     * @param {module:echarts/data/List~Entry} entry1
     * @param {module:echarts/data/List~Entry} entry2
     * @inner
     */
    function isEntrySameShape(entry1, entry2) {
        for (var i = 0; i < POSSIBLE_DIMENSIONS.length; i++) {
            var key = POSSIBLE_DIMENSIONS[i] + 'Index';
            if (entry1[key] !== entry2[key]) {
                return false;
L
lang 已提交
23
            }
L
lang 已提交
24 25
        }
        return true;
L
lang 已提交
26
    }
P
pah100 已提交
27

L
lang 已提交
28 29 30
    /**
     * @name echarts/data/List~Entry
     * @extends {module:echarts/model/Model}
31 32 33 34 35 36
     *
     * @param {Object} option
     * @param {module:echarts/model/Model} parentModel
     * @param {number} dataIndex
     * @param {Array.<string>} [independentVar=['x']]
     * @param {Array.<string>} [dependentVar='y']
L
lang 已提交
37
     */
L
lang 已提交
38 39 40 41
    var Entry = Model.extend({

        layout: null,

42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
        /**
         * @type {number}
         * @protected
         */
        xIndex: 0,

        /**
         * @type {number}
         * @protected
         */
        yIndex: 1,

        /**
         * @type {number}
         * @protected
         */
        zIndex: -1,

L
lang 已提交
60 61 62 63 64 65 66 67 68 69 70 71
        /**
         * @type {number}
         * @protected
         */
        radiusIndex: 0,

        /**
         * @type {number}
         * @protected
         */
        angleIndex: 1,

72 73 74 75 76
        /**
         * @type {number}
         * @protected
         */
        valueIndex: 1,
L
lang 已提交
77

L
lang 已提交
78 79 80 81 82
        /**
         * @type {module:echarts/data/List~Entry}
         */
        stackedOn: null,

P
pah100 已提交
83
        init: function (option, parentModel, rawDataIndex, independentVar, dependentVar) {
L
lang 已提交
84 85 86 87 88 89

            /**
             * @type {string}
             * @memeberOf module:echarts/data/List~Entry
             * @public
             */
L
lang 已提交
90 91
            this.name = option.name || '';

P
pah100 已提交
92 93 94 95 96 97 98
            /**
             * this.option **MUST NOT** be modified in List!
             * Different lists might share this option instance.
             *
             * @readOnly
             * @type {*}
             */
L
lang 已提交
99
            this.option = option;
L
lang 已提交
100

101 102
            var value = option.value == null ? option : option.value;

L
lang 已提交
103 104 105 106 107
            if (value === '-' || value == null) {
                value = [rawDataIndex, null];
            }
            else if (!isNaN(value)) {
                value = [rawDataIndex, +value];
P
pah100 已提交
108 109 110 111 112 113 114 115
                /**
                 * If dataIndex is persistent in entry, it should be udpated when modifying list.
                 * So use this.dataIndexIndex to mark that.
                 *
                 * @readOnly
                 * @type {number}
                 */
                this.dataIndexIndex = 0;
116 117
            }

L
lang 已提交
118 119 120
            if (independentVar) {
                for (var i = 0; i < independentVar.length; i++) {
                    this[independentVar[i] + 'Index'] = i;
121 122 123
                }
                this.valueIndex = value.length - 1;

L
lang 已提交
124
                this[dependentVar + 'Index'] = this.valueIndex;
125 126
            }

L
lang 已提交
127
            /**
P
pah100 已提交
128 129 130 131
             * All of the content **MUST NOT** be modified,
             * (because they are the same instance with option.value)
             * except this._value[this.dataIndexIndex].
             *
132
             * @type {Array.<number>}
L
lang 已提交
133 134 135
             * @memeberOf module:echarts/data/List~Entry
             * @private
             */
136
            this._value = value;
L
lang 已提交
137

L
lang 已提交
138
            /**
P
pah100 已提交
139 140
             * Data index before modifying list (filterSelf).
             *
L
lang 已提交
141 142
             * @readOnly
             */
P
pah100 已提交
143
            this.rawDataIndex = rawDataIndex;
L
lang 已提交
144 145
        },

L
lang 已提交
146 147 148
        setDataIndex: function (index) {
            if (this.dataIndexIndex != null) {
                this._value[this.dataIndexIndex] = index;
L
lang 已提交
149
            }
L
lang 已提交
150 151
        },

L
lang 已提交
152 153
        clone: function (dataIndex) {
            var entry = new Entry(this.option, this.parentModel, dataIndex);
L
lang 已提交
154
            entry.name = this.name;
L
lang 已提交
155
            entry.stackedOn = this.stackedOn;
L
lang 已提交
156

L
lang 已提交
157 158
            for (var i = 0; i < POSSIBLE_DIMENSIONS.length; i++) {
                var key = POSSIBLE_DIMENSIONS[i] + 'Index';
L
lang 已提交
159 160 161
                if (this.hasOwnProperty(key)) {
                    entry[key] = this[key];
                }
L
lang 已提交
162
            }
L
lang 已提交
163
            return entry;
L
lang 已提交
164 165 166
        }
    });

L
lang 已提交
167
    zrUtil.each(POSSIBLE_DIMENSIONS, function (dim) {
168 169
        var capitalized = dim[0].toUpperCase() + dim.substr(1);
        var indexKey = dim + 'Index';
L
lang 已提交
170 171
        var getterName = 'get' + capitalized;
        Entry.prototype[getterName] = function (stack) {
172 173
            var index = this[indexKey];
            if (index >= 0) {
L
lang 已提交
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
                var val = this._value[index];
                var stackedOn = this.stackedOn;

                // Normalize empty value
                if (val === '-' || val == null) {
                    val = null;
                }
                if (val != null
                    // Has stack
                    && stack && stackedOn
                    // Is getValue
                    && index === this.valueIndex
                    // Has same dimensions shape on stack
                    // PENDING If check the two stacking entries have same shape
                    && isEntrySameShape(this, stackedOn)
                ) {
                    var stackValue = stackedOn[getterName](stack);
                    if (
                        // Positive stack
                        val > 0 && stackValue > 0
                        // Negative stack
                        || (val < 0 && stackValue < 0)
                    ) {
                        val += stackValue;
                    }
                }
                return val;
201
            }
P
pah100 已提交
202
        };
203
    });
L
lang 已提交
204

L
lang 已提交
205
    function List(dimensions, value) {
P
pah100 已提交
206 207 208 209
        /**
         * @readOnly
         * @type {Array}
         */
L
lang 已提交
210
        this.elements = [];
L
lang 已提交
211 212 213 214 215 216 217 218 219 220 221 222

        /**
         * @readOnly
         * @type {Array.<string>}
         */
        this.dimensions = dimensions || ['x']

        /**
         * @readOnly
         * @type {string}
         */
        this.value = value || 'y';
L
lang 已提交
223 224 225 226 227 228
    }

    List.prototype = {

        constructor: List,

L
lang 已提交
229 230
        type: 'list',

L
lang 已提交
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
        /**
         * @type {module:echarts/data/List~Entry}
         */
        at: function (idx) {
            return this.elements[idx];
        },

        /**
         * Create and add a new entry
         * @param {Object} option
         * @param {module:echarts/model/Series} seriesModel
         * @return {module:echarts/data/List~Entry}
         */
        add: function (option, seriesModel) {
            var elements = this.elements;
            var entry = new Entry(option, seriesModel, elements.length, this.dimensions, this.value);
            elements.push(entry);
            return entry;
        },

        /**
         * Get elements count
         * @return {number}
         */
P
pah100 已提交
255 256 257 258
        count: function () {
            return this.elements.length;
        },

L
lang 已提交
259 260 261 262 263
        /**
         * Iterate each element
         * @param {Function} cb
         * @param {*} context
         */
L
lang 已提交
264
        each: function (cb, context) {
P
pah100 已提交
265
            zrUtil.each(this.elements, cb, context || this);
L
lang 已提交
266 267
        },

L
lang 已提交
268
        /**
L
lang 已提交
269 270 271
         * Map elemements to a new created array
         * @param {Function} cb
         * @param {*} context
L
lang 已提交
272 273 274
         */
        map: function (cb, context) {
            var ret = [];
P
pah100 已提交
275
            context = context || this;
L
lang 已提交
276
            this.each(function (item, idx) {
P
pah100 已提交
277
                ret.push(cb && cb.call(context, item));
L
lang 已提交
278 279 280 281
            }, context);
            return ret;
        },

L
lang 已提交
282 283 284 285 286
        /**
         * Filter elements in place
         * @param {Function} cb
         * @param {*} context
         */
P
pah100 已提交
287 288
        filterSelf: function (cb, context) {
            this.elements = zrUtil.filter(this.elements, cb, context || this);
L
lang 已提交
289
            this.each(this._setEntryDataIndex);
P
pah100 已提交
290 291
        },

L
lang 已提交
292 293
        _setEntryDataIndex: function (entry, dataIndex) {
            entry.setDataIndex(dataIndex);
L
lang 已提交
294 295
        },

L
lang 已提交
296 297 298 299 300 301 302 303 304 305
        /**
         * @return {module:echarts/data/List~Entry}
         */
        getByName: function (name) {
            var elements = this.elements;
            for (var i = 0; i < elements.length; i++) {
                if (elements[i].name === name) {
                    return elements[i];
                }
            }
L
lang 已提交
306 307
        },

L
lang 已提交
308 309 310 311 312 313 314 315 316 317 318 319
        /**
         * @param {string} name
         * @param {*} option
         */
        append: function (name, option) {
            var elements = this.elements;
            var el = new Entry(option, null, elements.length);
            el.name = name;
            elements.push(el);
            return el;
        },

L
lang 已提交
320 321 322 323 324 325 326 327 328 329 330
        /**
         * Get the diff result with the old list data
         * @param {module:echarts/data/List} oldList
         * @return {module:echarts/data/DataDiffer}
         * @example
         *  data.diff(this._data)
         *      .add(function (item) { // Add a new shape})
         *      .update(function (newItem, oldItem) { // Update the shape})
         *      .remove(function (item) { // Remove unused shape})
         *      .execute()
         */
L
lang 已提交
331 332 333 334
        diff: function (oldList) {
            return new DataDiffer(oldList ? oldList.elements : [], this.elements);
        },

L
lang 已提交
335 336 337 338
        /**
         * Clone a new list and all its' entries
         * @return {module:echarts/data/List}
         */
L
lang 已提交
339
        clone: function () {
L
lang 已提交
340 341 342 343
            var list = new List(this.dimensions, this.value);
            list.elements = zrUtil.map(this.elements, function (el, i) {
                return el.clone(i);
            });
L
lang 已提交
344
            return list;
L
lang 已提交
345 346 347
        }
    };

L
lang 已提交
348 349 350 351
    zrUtil.each(POSSIBLE_DIMENSIONS, function (dim) {
        var capitalized = dim[0].toUpperCase() + dim.substr(1);

        List.prototype['each' + capitalized] = function (cb, stack, context) {
L
lang 已提交
352
            this.each(function (item, idx) {
L
lang 已提交
353
                cb && cb.call(context || this, item['get' + capitalized](stack));
L
lang 已提交
354 355 356
            }, context);
        };

L
lang 已提交
357
        List.prototype['map' + capitalized] = function (cb, stack, context) {
L
lang 已提交
358 359
            var ret = [];
            this.each(function (item) {
L
lang 已提交
360
                ret.push(cb && cb.call(context || this, item['get' + capitalized](stack)));
L
lang 已提交
361 362 363
            }, context);
            return ret;
        };
L
lang 已提交
364 365
    });

366
    List.fromArray = function (data, seriesModel, ecModel) {
L
lang 已提交
367
        var coordinateSystem = seriesModel.get('coordinateSystem');
368 369 370
        var independentVar;
        var dependentVar;

L
lang 已提交
371 372 373 374 375 376
        // FIXME
        // 这里 List 跟几个坐标系和坐标系 Model 耦合了
        if (coordinateSystem === 'cartesian2d') {
            var xAxisModel = ecModel.getComponent('xAxis', seriesModel.get('xAxisIndex'));
            var yAxisModel = ecModel.getComponent('yAxis', seriesModel.get('yAxisIndex'));
            if (xAxisModel.get('type') === 'category') {
L
lang 已提交
377 378 379
                independentVar = ['x'];
                dependentVar = 'y';
            }
L
lang 已提交
380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397
            else if (yAxisModel.get('type') === 'category') {
                independentVar = ['y'];
                dependentVar = 'x';
            }
            else {
                // PENDING
                var dim = data[0] && data[0].length;
                if (dim === 2) {
                    independentVar = ['x'];
                    dependentVar = 'y';
                }
                else if (dim === 3) {
                    independentVar = ['x', 'y'];
                    dependentVar = 'z';
                }
            }
        }
        else if (coordinateSystem === 'polar') {
L
lang 已提交
398
            var axisFinder = function (axisModel) {
L
lang 已提交
399
                return axisModel.get('polarIndex') === polarIndex;
P
pah100 已提交
400
            }
L
lang 已提交
401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422
            var polarIndex = seriesModel.get('polarIndex') || 0;
            var angleAxisModel = ecModel.findComponent('angleAxis', axisFinder);
            var radiusAxisModel = ecModel.findComponent('radiusAxis', axisFinder);

            if (angleAxisModel.get('type') === 'category') {
                independentVar = ['angle'];
                dependentVar = 'radius';
            }
            else if (radiusAxisModel.get('type') === 'category') {
                independentVar = ['radius'];
                dependentVar = 'angle';
            }
            else {
                var dim = data[0] && data[0].length;
                if (dim === 2) {
                    independentVar = ['radius'];
                    dependentVar = 'angle';
                }
                else if (dim === 3) {
                    independentVar = ['radius', 'angle'];
                    dependentVar = 'value';
                }
L
lang 已提交
423 424
            }
        }
425

L
lang 已提交
426
        var list = new List(independentVar, dependentVar);
427

L
lang 已提交
428
        // Normalize data
L
lang 已提交
429 430
        zrUtil.each(data, function (dataItem, index) {
            var entry = list.add(dataItem, seriesModel);
L
lang 已提交
431
            // FIXME
L
lang 已提交
432 433 434
            if (! dataItem.name) {
                entry.name = index;
            }
L
lang 已提交
435
            return entry;
L
lang 已提交
436 437
        });
        return list;
L
lang 已提交
438 439 440
    };

    List.Entry = Entry;
L
lang 已提交
441 442 443

    return List;
});