echarts.js 14.2 KB
Newer Older
L
lang 已提交
1
/**
L
tweak  
lang 已提交
2
 * TODO visualCoding 的优先级
L
lang 已提交
3
 *      setTheme
4
 *      axis position 统一处理
L
lang 已提交
5
 *      规范 Symbol 配置和绘制, customPath
L
lang 已提交
6 7
 *
 *      每次 update 只刷新 model 变化的那些 component(需要做依赖收集)
L
lang 已提交
8
 */
L
lang 已提交
9 10
define(function (require) {

L
lang 已提交
11
    var GlobalModel = require('./model/Global');
L
lang 已提交
12
    var ExtensionAPI = require('./ExtensionAPI');
L
lang 已提交
13
    var CoordinateSystemManager = require('./CoordinateSystem');
L
lang 已提交
14

L
Update  
lang 已提交
15 16 17 18 19 20
    var ComponentModel = require('./model/Component');
    var SeriesModel = require('./model/Series');

    var ComponentView = require('./view/Component');
    var ChartView = require('./view/Chart');

L
lang 已提交
21
    var zrender = require('zrender');
L
lang 已提交
22
    var zrUtil = require('zrender/core/util');
L
lang 已提交
23

24 25
    var VISUAL_CODING_STAGES = ['echarts', 'chart', 'component'];

L
lang 已提交
26 27 28
    /**
     * @module echarts~ECharts
     */
L
lang 已提交
29 30
    var ECharts = function (dom, theme, opts) {
        opts = opts || {};
L
lang 已提交
31

L
lang 已提交
32 33 34 35 36
        /**
         * @type {HTMLDomElement}
         * @private
         */
        this._dom = dom;
L
lang 已提交
37 38 39 40
        /**
         * @type {module:zrender/ZRender}
         * @private
         */
L
lang 已提交
41 42 43
        this._zr = zrender.init(dom, {
            renderer: opts.renderer || 'canvas'
        });
L
lang 已提交
44

L
lang 已提交
45 46 47 48
        /**
         * @type {Object}
         * @private
         */
L
lang 已提交
49
        this._theme = zrUtil.clone(theme);
L
lang 已提交
50

L
lang 已提交
51 52 53 54
        /**
         * @type {Array.<module:echarts/view/Chart>}
         * @private
         */
L
lang 已提交
55
        this._chartsList = [];
L
lang 已提交
56 57 58 59 60

        /**
         * @type {Object.<string, module:echarts/view/Chart>}
         * @private
         */
L
lang 已提交
61 62
        this._chartsMap = {};

L
lang 已提交
63 64 65 66
        /**
         * @type {Array.<module:echarts/view/Component>}
         * @private
         */
L
lang 已提交
67
        this._componentsList = [];
L
lang 已提交
68 69 70 71 72

        /**
         * @type {Object.<string, module:echarts/view/Component>}
         * @private
         */
L
lang 已提交
73 74
        this._componentsMap = {};

L
lang 已提交
75
        /**
L
lang 已提交
76
         * @type {module:echarts/ExtensionAPI}
L
lang 已提交
77 78
         * @private
         */
L
lang 已提交
79
        this._extensionAPI = new ExtensionAPI(this);
L
lang 已提交
80

L
lang 已提交
81 82 83 84
        /**
         * @type {module:echarts/CoordinateSystem}
         * @private
         */
L
lang 已提交
85
        this._coordinateSystem = new CoordinateSystemManager();
L
lang 已提交
86

L
lang 已提交
87 88 89 90 91
        /**
         * Layout instances
         * @type {Array}
         * @private
         */
L
lang 已提交
92 93 94
        this._layouts = zrUtil.map(layoutClasses, function (Layout) {
            return new Layout();
        });
L
lang 已提交
95 96 97 98 99 100 101 102 103 104 105 106

        /**
         * @type {boolean}
         * @private
         */
        this._needsUpdate = false;

        this._zr.animation.on('frame', function () {
            if (this._needsUpdate) {
                this.updateImmediately();
            }
        }, this);
L
lang 已提交
107 108 109 110
    };

    ECharts.prototype = {

L
lang 已提交
111 112 113 114
        getDom: function () {
            return this._dom;
        },

L
lang 已提交
115 116 117 118
        getZr: function () {
            return this._zr;
        },

L
lang 已提交
119
        setOption: function (option, notMerge) {
L
lang 已提交
120
            // PENDING
L
lang 已提交
121
            option = zrUtil.clone(option, true);
L
lang 已提交
122

L
lang 已提交
123 124 125 126 127 128 129 130
            var ecModel = this._model;
            if (! ecModel || notMerge) {
                ecModel = new GlobalModel(option, null, this._theme);
                this._model = ecModel;
            }
            else {
                ecModel.mergeOption(option);
            }
L
lang 已提交
131

L
lang 已提交
132
            this._prepareComponents(ecModel);
L
lang 已提交
133

L
lang 已提交
134
            this._prepareCharts(ecModel);
L
lang 已提交
135 136

            this.updateImmediately();
L
lang 已提交
137 138
        },

L
lang 已提交
139 140 141 142 143 144 145
        setTheme: function (theme) {

        },

        /**
         * @return {number}
         */
L
lang 已提交
146 147 148
        getWidth: function () {
            return this._zr.getWidth();
        },
L
lang 已提交
149

L
lang 已提交
150 151 152
        /**
         * @return {number}
         */
L
lang 已提交
153 154 155 156 157
        getHeight: function () {
            return this._zr.getHeight();
        },

        update: function () {
L
lang 已提交
158
            this._needsUpdate = true;
L
lang 已提交
159 160
        },

P
pah100 已提交
161
        updateImmediately: function (event) {
L
lang 已提交
162
            console.time('update');
163

L
lang 已提交
164 165
            var ecModel = this._model;

P
pah100 已提交
166
            ecModel.restoreData();
L
lang 已提交
167

P
pah100 已提交
168 169 170 171
            // TODO
            // Save total ecModel here for undo/redo (after restoring data and before processing data).
            // Undo (restoration of total ecModel) can be carried out in 'action' or outside API call.

L
lang 已提交
172
            this._processData(ecModel);
L
lang 已提交
173

L
lang 已提交
174 175
            this._stackSeriesData(ecModel);

L
lang 已提交
176
            this._coordinateSystem.update(ecModel, this._extensionAPI);
L
lang 已提交
177

P
pah100 已提交
178
            this._doLayout(ecModel, event);
L
lang 已提交
179

180 181
            this._doVisualCoding(ecModel);

P
pah100 已提交
182
            this._doRender(ecModel, event);
L
lang 已提交
183 184

            this._needsUpdate = false;
185

L
lang 已提交
186
            console.timeEnd('update');
L
lang 已提交
187 188
        },

L
lang 已提交
189
        resize: function () {
L
lang 已提交
190
            // var ecModel = this._model;
L
lang 已提交
191

L
lang 已提交
192
            // this._coordinateSystem.resize(ecModel, this._extensionAPI);
L
lang 已提交
193

L
lang 已提交
194
            // this._doVisualCoding(ecModel);
L
lang 已提交
195

L
lang 已提交
196 197 198 199 200
            // this._doLayout(ecModel);

            // this._doRender(ecModel);

            this.updateImmediately();
L
lang 已提交
201 202
        },

P
pah100 已提交
203 204 205 206 207 208 209 210 211 212 213 214 215 216
        /**
         * @pubilc
         * @param {Object} event
         * @param {string} [event.type] Event type
         * @param {number} [event.from] From uid
         */
        dispatch: function (event) {
            var action = actions[event.type];
            if (action) {
                action(event, this._model);
                this.updateImmediately(event);
            }
        },

L
lang 已提交
217
        _prepareCharts: function (ecModel) {
L
lang 已提交
218

L
lang 已提交
219 220
            var chartsList = this._chartsList;
            var chartsMap = this._chartsMap;
L
lang 已提交
221
            var zr = this._zr;
L
lang 已提交
222 223 224 225 226 227

            for (var i = 0; i < chartsList.length; i++) {
                chartsList[i].__keepAlive = false;
            }

            ecModel.eachSeries(function (seriesModel, idx) {
P
pah100 已提交
228
                var id = seriesModel.uid;
L
lang 已提交
229 230

                var chart = chartsMap[id];
231 232
                if (!chart) {
                    var Clazz = ChartView.getClass(
233 234
                        ComponentModel.parseComponentType(seriesModel.type).sub
                    );
235 236
                    if (Clazz) {
                        chart = new Clazz();
L
lang 已提交
237
                        chart.init(ecModel, this._extensionAPI);
L
lang 已提交
238 239
                        chartsMap[id] = chart;
                        chartsList.push(chart);
L
lang 已提交
240
                        zr.add(chart.group);
L
lang 已提交
241 242 243 244 245 246
                    }
                    else {
                        // Error
                    }
                }

L
lang 已提交
247 248
                chart.__keepAlive = true;
                chart.__id = id;
L
lang 已提交
249 250
            }, this);

L
lang 已提交
251 252 253
            for (var i = 0; i < chartsList.length;) {
                var chart = chartsList[i];
                if (! chart.__keepAlive) {
L
lang 已提交
254
                    zr.remove(chart.group);
L
lang 已提交
255
                    chart.dispose(this._extensionAPI);
L
lang 已提交
256 257
                    chartsList.splice(i, 1);
                    delete chartsMap[chart.__id];
L
lang 已提交
258 259 260 261
                }
                else {
                    i++;
                }
262
            }
L
lang 已提交
263 264
        },

L
lang 已提交
265
        _prepareComponents: function (ecModel) {
L
lang 已提交
266 267 268 269 270 271 272 273

            var componentsMap = this._componentsMap;
            var componentsList = this._componentsList;

            for (var i = 0; i < componentsList.length; i++) {
                componentsList[i].__keepAlive = true;
            }

P
pah100 已提交
274
            ecModel.eachComponent(function (componentType, componentModel) {
275 276 277 278
                if (componentType === 'series') {
                    return;
                }

P
pah100 已提交
279
                var id = componentModel.uid;
280 281 282
                var component = componentsMap[id];
                if (!component) {
                    // Create and add component
P
pah100 已提交
283 284 285
                    var Clazz = ComponentView.getClass(
                        componentType, componentModel.option.type
                    );
L
lang 已提交
286

287 288
                    if (Clazz) {
                        component = new Clazz();
L
lang 已提交
289
                        component.init(ecModel, this._extensionAPI);
L
lang 已提交
290
                        componentsMap[id] = component;
L
lang 已提交
291
                        componentsList.push(component);
L
lang 已提交
292 293

                        this._zr.add(component.group);
L
lang 已提交
294
                    }
295 296 297 298 299
                }
                component.__id = id;
                component.__keepAlive = true;
                // Used in rendering
                component.__model = componentModel;
L
lang 已提交
300 301 302 303 304 305
            }, this);

            for (var i = 0; i < componentsList.length;) {
                var component = componentsList[i];
                if (! component.__keepAlive) {
                    this._zr.remove(component.group);
L
lang 已提交
306
                    component.dispose(this._extensionAPI);
L
lang 已提交
307 308
                    componentsList.splice(i, 1);
                    delete componentsMap[component.__id];
L
lang 已提交
309 310
                }
                else {
L
lang 已提交
311
                    i++;
L
lang 已提交
312
                }
313
            }
L
lang 已提交
314 315
        },

L
lang 已提交
316 317 318 319 320 321
        /**
         * Processor data in each series
         *
         * @param {module:echarts/model/Global} ecModel
         * @private
         */
L
lang 已提交
322
        _processData: function (ecModel) {
L
lang 已提交
323
            zrUtil.each(dataProcessorFuncs, function (processor) {
L
lang 已提交
324 325
                processor(ecModel);
            });
L
lang 已提交
326 327
        },

L
lang 已提交
328 329 330 331 332 333 334 335
        /**
         * @private
         */
        _stackSeriesData: function (ecModel) {
            var stackedDataMap = {};
            ecModel.eachSeries(function (series) {
                var stack = series.get('stack');
                var data = series.getData();
L
lang 已提交
336
                if (stack && data.type === 'list') {
L
lang 已提交
337 338
                    var previousStack = stackedDataMap[stack];
                    if (previousStack) {
L
lang 已提交
339
                        data.stackedOn = previousStack;
L
lang 已提交
340 341 342 343 344 345
                    }
                    stackedDataMap[stack] = data;
                }
            });
        },

L
lang 已提交
346 347 348 349 350 351
        /**
         * Layout before each chart render there series after visual coding and data processing
         *
         * @param {module:echarts/model/Global} ecModel
         * @private
         */
P
pah100 已提交
352
        _doLayout: function (ecModel, event) {
L
lang 已提交
353
            zrUtil.each(this._layouts, function (layout) {
P
merge  
pah100 已提交
354
                layout.update(ecModel, event);
355 356
            });
            zrUtil.each(layoutFuncs, function (layout) {
P
pah100 已提交
357
                layout(ecModel, event);
L
lang 已提交
358 359 360 361 362 363 364 365 366 367
            });
        },

        /**
         * Code visual infomation from data after data processing
         *
         * @param {module:echarts/model/Global} ecModel
         * @private
         */
        _doVisualCoding: function (ecModel) {
368 369 370 371
            zrUtil.each(VISUAL_CODING_STAGES, function (stage) {
                zrUtil.each(visualCodingFuncs[stage] || [], function (visualCoding) {
                    visualCoding(ecModel);
                });
L
lang 已提交
372 373 374 375 376 377
            });
        },

        /**
         * Render each chart and component
         */
P
pah100 已提交
378
        _doRender: function (ecModel, event) {
L
lang 已提交
379
            var api = this._extensionAPI;
L
lang 已提交
380
            // Render all components
L
lang 已提交
381
            zrUtil.each(this._componentsList, function (component) {
P
pah100 已提交
382
                component.render(component.__model, ecModel, api, event);
L
lang 已提交
383
            }, this);
P
pah100 已提交
384

L
lang 已提交
385
            zrUtil.each(this._chartsList, function (chart) {
386
                chart.__keepAlive = false;
L
lang 已提交
387
            }, this);
P
pah100 已提交
388

L
lang 已提交
389
            // Render all charts
L
lang 已提交
390
            ecModel.eachSeries(function (seriesModel, idx) {
P
pah100 已提交
391
                var id = seriesModel.uid;
L
lang 已提交
392
                var chart = this._chartsMap[id];
393
                chart.__keepAlive = true;
P
pah100 已提交
394
                chart.render(seriesModel, ecModel, api, event);
L
lang 已提交
395
            }, this);
P
pah100 已提交
396

397 398 399 400 401 402
            // Remove groups of charts
            zrUtil.each(this._chartsList, function (chart) {
                if (!chart.__keepAlive) {
                    chart.remove();
                }
            }, this);
L
lang 已提交
403 404 405 406 407 408 409 410 411 412 413 414 415 416 417
        },

        dispose: function () {
            zrUtil.each(this._components, function (component) {
                component.dispose();
            });
            zrUtil.each(this._charts, function (chart) {
                chart.dispose();
            });

            this.zr.dispose();
        }
    };


L
lang 已提交
418
    var dataProcessorFuncs = [];
L
lang 已提交
419

P
pah100 已提交
420 421
    var actions = [];

L
lang 已提交
422 423
    var layoutClasses = [];

424 425
    var layoutFuncs = [];

426
    var visualCodingFuncs = {};
L
lang 已提交
427

L
lang 已提交
428 429 430 431 432
    /**
     * @module echarts
     */
    var echarts = {

L
lang 已提交
433 434
        init: function (dom, theme, opts) {
            return new ECharts(dom, theme, opts);
L
lang 已提交
435 436
        },

L
lang 已提交
437 438 439 440 441 442
        /**
         * @param {Function}
         */
        registerProcessor: function (processorFunc) {
            if (zrUtil.indexOf(dataProcessorFuncs, processorFunc) < 0) {
                dataProcessorFuncs.push(processorFunc);
L
lang 已提交
443
            }
L
lang 已提交
444 445
        },

P
pah100 已提交
446 447 448 449 450 451 452 453 454
        /**
         * @param {Function}
         */
        registerAction: function (actionName, action) {
            if (!actions[actionName]) {
                actions[actionName] = action;
            }
        },

L
lang 已提交
455 456 457 458
        /**
         * @param {string} type
         * @param {*} CoordinateSystem
         */
L
lang 已提交
459
        registerCoordinateSystem: function (type, CoordinateSystem) {
L
lang 已提交
460 461 462
            CoordinateSystemManager.register(type, CoordinateSystem);
        },

L
lang 已提交
463 464 465
        /**
         * @param {*} layout
         */
466
        registerLayout: function (layout, isFactory) {
L
tweak  
lang 已提交
467
            // PENDING All functions ?
468 469 470 471 472 473 474 475 476
            if (isFactory) {
                if (zrUtil.indexOf(layoutClasses, layout) < 0) {
                    layoutClasses.push(layout);
                }
            }
            else {
                if (zrUtil.indexOf(layoutFuncs, layout) < 0) {
                    layoutFuncs.push(layout);
                }
L
lang 已提交
477 478 479
            }
        },

480 481 482 483 484 485
        registerVisualCoding: function (stage, visualCodingFunc) {
            if (zrUtil.indexOf(VISUAL_CODING_STAGES, stage) < 0) {
                throw new Error('stage should be one of ' + VISUAL_CODING_STAGES);
            }
            var funcs = visualCodingFuncs[stage] || (visualCodingFuncs[stage] = []);
            funcs.push(visualCodingFunc);
L
Update  
lang 已提交
486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501
        },

        /**
         * @param {Object} opts
         */
        extendChartView: function (opts) {
            return ChartView.extend(opts);
        },

        /**
         * @param {Object} opts
         */
        extendComponentModel: function (opts) {
            return ComponentModel.extend(opts);
        },

P
pah100 已提交
502 503 504 505 506 507 508
        /**
         * @param {Object} opts
         */
        extendSeriesModel: function (opts) {
            return SeriesModel.extend(opts);
        },

L
Update  
lang 已提交
509 510 511 512 513
        /**
         * @param {Object} opts
         */
        extendComponentView: function (opts) {
            return ComponentView.extend(opts);
L
lang 已提交
514
        }
L
lang 已提交
515 516
    };

517
    echarts.registerVisualCoding('echarts', require('./visual/defaultColor'));
L
lang 已提交
518

L
lang 已提交
519 520
    return echarts;
});