echarts.js 26.4 KB
Newer Older
L
tweak  
lang 已提交
1 2 3 4 5 6 7 8 9 10
/*!
 * ECharts, a javascript interactive chart library.
 *
 * Copyright (c) 2015, Baidu Inc.
 * All rights reserved.
 *
 * LICENSE
 * https://github.com/ecomfe/echarts/blob/master/LICENSE.txt
 */

L
lang 已提交
11
/**
L
lang 已提交
12
 * @module echarts
L
lang 已提交
13
 */
L
lang 已提交
14 15
define(function (require) {

L
lang 已提交
16
    var GlobalModel = require('./model/Global');
L
lang 已提交
17
    var ExtensionAPI = require('./ExtensionAPI');
L
lang 已提交
18
    var CoordinateSystemManager = require('./CoordinateSystem');
L
lang 已提交
19

L
Update  
lang 已提交
20 21 22 23 24 25
    var ComponentModel = require('./model/Component');
    var SeriesModel = require('./model/Series');

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

L
lang 已提交
26
    var zrender = require('zrender');
L
lang 已提交
27
    var zrUtil = require('zrender/core/util');
L
lang 已提交
28 29
    var colorTool = require('zrender/tool/color');
    var env = require('zrender/core/env');
L
lang 已提交
30
    var Eventful = require('zrender/mixin/Eventful');
L
lang 已提交
31

32 33
    var each = zrUtil.each;

34 35
    var VISUAL_CODING_STAGES = ['echarts', 'chart', 'component'];

L
lang 已提交
36
    // TODO Transform first or filter first
L
lang 已提交
37 38
    var PROCESSOR_STAGES = ['transform', 'filter', 'statistic'];

L
lang 已提交
39 40 41 42 43 44 45
    /**
     * @module echarts~MessageCenter
     */
    function MessageCenter() {
        Eventful.call(this);
    }
    zrUtil.mixin(MessageCenter, Eventful);
L
lang 已提交
46 47 48
    /**
     * @module echarts~ECharts
     */
L
lang 已提交
49
    function ECharts (dom, theme, opts) {
L
lang 已提交
50
        opts = opts || {};
L
lang 已提交
51

L
lang 已提交
52 53 54 55 56
        if (theme) {
            each(optionPreprocessorFuncs, function (preProcess) {
                preProcess(theme);
            });
        }
L
lang 已提交
57 58 59 60 61 62 63 64 65
        /**
         * @type {string}
         */
        this.id;
        /**
         * Group id
         * @type {string}
         */
        this.group;
L
lang 已提交
66 67 68 69 70
        /**
         * @type {HTMLDomElement}
         * @private
         */
        this._dom = dom;
L
lang 已提交
71 72 73 74
        /**
         * @type {module:zrender/ZRender}
         * @private
         */
L
lang 已提交
75 76 77
        this._zr = zrender.init(dom, {
            renderer: opts.renderer || 'canvas'
        });
L
lang 已提交
78

L
lang 已提交
79 80 81 82
        /**
         * @type {Object}
         * @private
         */
L
lang 已提交
83
        this._theme = zrUtil.clone(theme, true);
L
lang 已提交
84

L
lang 已提交
85 86 87 88
        /**
         * @type {Array.<module:echarts/view/Chart>}
         * @private
         */
L
lang 已提交
89
        this._chartsList = [];
L
lang 已提交
90 91 92 93 94

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

L
lang 已提交
97 98 99 100
        /**
         * @type {Array.<module:echarts/view/Component>}
         * @private
         */
L
lang 已提交
101
        this._componentsList = [];
L
lang 已提交
102 103 104 105 106

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

L
lang 已提交
109
        /**
L
lang 已提交
110
         * @type {module:echarts/ExtensionAPI}
L
lang 已提交
111 112
         * @private
         */
113
        this._api = new ExtensionAPI(this);
L
lang 已提交
114

L
lang 已提交
115 116 117 118
        /**
         * @type {module:echarts/CoordinateSystem}
         * @private
         */
L
lang 已提交
119
        this._coordinateSystem = new CoordinateSystemManager();
L
lang 已提交
120

L
lang 已提交
121 122
        Eventful.call(this);

L
lang 已提交
123 124 125 126 127 128
        /**
         * @type {module:echarts~MessageCenter}
         * @private
         */
        this._messageCenter = new MessageCenter();

L
lang 已提交
129 130
        // Init mouse events
        this._initEvents();
L
Resize  
lang 已提交
131 132 133

        // In case some people write `window.onresize = chart.resize`
        this.resize = zrUtil.bind(this.resize, this);
L
lang 已提交
134
    }
L
lang 已提交
135

L
tweak  
lang 已提交
136
    var echartsProto = ECharts.prototype;
L
lang 已提交
137

138 139 140
    /**
     * @return {HTMLDomElement}
     */
L
tweak  
lang 已提交
141 142 143
    echartsProto.getDom = function () {
        return this._dom;
    };
L
lang 已提交
144

145 146 147
    /**
     * @return {module:zrender~ZRender}
     */
L
tweak  
lang 已提交
148 149 150
    echartsProto.getZr = function () {
        return this._zr;
    };
L
lang 已提交
151

152 153 154 155 156 157
    /**
     * @param {Object} option
     * @param {boolean} notMerge
     * @param {boolean} [notRefreshImmediately=false]
     */
    echartsProto.setOption = function (option, notMerge, notRefreshImmediately) {
L
tweak  
lang 已提交
158 159
        // PENDING
        option = zrUtil.clone(option, true);
160

L
tweak  
lang 已提交
161 162 163
        each(optionPreprocessorFuncs, function (preProcess) {
            preProcess(option);
        });
L
lang 已提交
164

L
tweak  
lang 已提交
165 166 167 168 169 170 171 172 173
        var ecModel = this._model;
        if (!ecModel || notMerge) {
            ecModel = new GlobalModel(option, null, this._theme);
            this._model = ecModel;
        }
        else {
            ecModel.restoreData();
            ecModel.mergeOption(option);
        }
L
lang 已提交
174

175
        prepareView.call(this, 'component', ecModel);
L
lang 已提交
176

177
        prepareView.call(this, 'chart', ecModel);
L
lang 已提交
178

179
        updateMethods.update.call(this);
L
lang 已提交
180

181
        !notRefreshImmediately && this._zr.refreshImmediately();
L
tweak  
lang 已提交
182
    };
L
lang 已提交
183

L
Tweak  
lang 已提交
184 185 186 187 188 189
    /**
     * @DEPRECATED
     */
    echartsProto.setTheme = function () {
        console.log('ECharts#setTheme() is DEPRECATED in ECharts 3.0');
    };
L
tweak  
lang 已提交
190 191 192 193 194 195
    /**
     * @return {module:echarts/model/Global}
     */
    echartsProto.getModel = function () {
        return this._model;
    };
L
lang 已提交
196

L
tweak  
lang 已提交
197 198 199 200 201 202
    /**
     * @return {number}
     */
    echartsProto.getWidth = function () {
        return this._zr.getWidth();
    };
L
lang 已提交
203

L
tweak  
lang 已提交
204 205 206 207 208 209
    /**
     * @return {number}
     */
    echartsProto.getHeight = function () {
        return this._zr.getHeight();
    };
L
lang 已提交
210

211

212 213 214 215 216 217 218 219
    var updateMethods = {

        /**
         * @param {Object} payload
         * @private
         */
        update: function (payload) {
            console.time && console.time('update');
L
lang 已提交
220

221
            var ecModel = this._model;
L
lang 已提交
222

223 224 225 226 227
            ecModel.restoreData();

            // 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.
P
pah100 已提交
228

229
            processData.call(this, ecModel);
L
lang 已提交
230

231
            stackSeriesData.call(this, ecModel);
L
lang 已提交
232

233
            this._coordinateSystem.update(ecModel, this._api);
L
lang 已提交
234

235
            doLayout.call(this, ecModel, payload);
236

237
            doVisualCoding.call(this, ecModel, payload);
238

239
            doRender.call(this, ecModel, payload);
240

241 242 243 244 245 246 247 248 249
            // Set background
            var backgroundColor = ecModel.get('backgroundColor');
            // In IE8
            if (!env.canvasSupported) {
                var colorArr = colorTool.parse(backgroundColor);
                backgroundColor = colorTool.stringify(colorArr, 'rgb');
                if (colorArr[3] === 0) {
                    backgroundColor = 'transparent';
                }
L
lang 已提交
250
            }
L
lang 已提交
251 252 253 254 255 256 257 258
            if (env.node) {
                this._zr.configLayer(0, {
                    clearColor: backgroundColor
                });
            }
            else {
                backgroundColor && (this._dom.style.backgroundColor = backgroundColor);
            }
L
lang 已提交
259

260 261
            console.time && console.timeEnd('update');
        },
262

263 264 265 266 267 268 269
        // PENDING
        /**
         * @param {Object} payload
         * @private
         */
        updateView: function (payload) {
            var ecModel = this._model;
270

271
            doLayout.call(this, ecModel, payload);
272

273
            doVisualCoding.call(this, ecModel, payload);
274

275 276
            invokeUpdateMethod.call(this, 'updateView', ecModel, payload);
        },
277

278 279 280 281 282 283
        /**
         * @param {Object} payload
         * @private
         */
        updateVisual: function (payload) {
            var ecModel = this._model;
284

285
            doVisualCoding.call(this, ecModel, payload);
286

287 288
            invokeUpdateMethod.call(this, 'updateVisual', ecModel, payload);
        },
289

290 291 292 293 294 295
        /**
         * @param {Object} payload
         * @private
         */
        updateLayout: function (payload) {
            var ecModel = this._model;
296

297
            doLayout.call(this, ecModel, payload);
298

299 300
            invokeUpdateMethod.call(this, 'updateLayout', ecModel, payload);
        },
L
lang 已提交
301

302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
        /**
         * @param {Object} payload
         * @private
         */
        highlight: function (payload) {
            toggleHighlight.call(this, 'highlight', payload);
        },

        /**
         * @param {Object} payload
         * @private
         */
        downplay: function (payload) {
            toggleHighlight.call(this, 'downplay', payload);
        }
317 318 319 320 321 322 323

    };

    /**
     * @param {Object} payload
     * @private
     */
324
    function toggleHighlight(method, payload) {
325
        var ecModel = this._model;
326 327 328

        ecModel.eachComponent(
            {mainType: 'series', query: payload},
P
pah100 已提交
329
            function (seriesModel, index, payloadInfo) {
P
tweak  
pah100 已提交
330
                var chartView = this._chartsMap[seriesModel.id];
331
                if (chartView) {
P
pah100 已提交
332 333 334
                    chartView[method](
                        seriesModel, ecModel, this._api, payloadInfo
                    );
335 336 337 338
                }
            },
            this
        );
339
    }
340

L
Resize  
lang 已提交
341 342 343
    /**
     * Resize the chart
     */
L
tweak  
lang 已提交
344
    echartsProto.resize = function () {
L
Resize  
lang 已提交
345
        this._zr.resize();
L
lang 已提交
346
        updateMethods.update.call(this);
L
lang 已提交
347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373

        // Resize loading effect
        this._loadingFX && this._loadingFX.resize();
    };

    var defaultLoadingEffect = require('./loading/default');
    /**
     * Show loading effect
     * @param  {string} [name='default']
     * @param  {Object} [cfg]
     */
    echartsProto.showLoading = function (name, cfg) {
        if (zrUtil.isObject(name)) {
            cfg = name;
            name = 'default';
        }
        var el = defaultLoadingEffect(this._api, cfg);
        this._loadingFX = el;
        this._zr.add(el);
    };

    /**
     * Hide loading effect
     */
    echartsProto.hideLoading = function () {
        this._zr.remove(this._loadingFX);
        this._loadingFX = null;
L
tweak  
lang 已提交
374
    };
P
pah100 已提交
375

L
lang 已提交
376
    /**
L
Resize  
lang 已提交
377 378
     * @param {Object} eventObj
     * @return {Object}
L
lang 已提交
379 380 381 382 383 384 385
     */
    echartsProto.makeActionFromEvent = function (eventObj) {
        var payload = zrUtil.extend({}, eventObj);
        payload.type = eventActionMap[eventObj.type];
        return payload;
    };

L
tweak  
lang 已提交
386 387 388 389
    /**
     * @pubilc
     * @param {Object} payload
     * @param {string} [payload.type] Action type
P
pah100 已提交
390
     * @param {boolean} [silent=false] Whether trigger event.
L
tweak  
lang 已提交
391 392
     * @param {number} [payload.from] From uid
     */
L
lang 已提交
393
    echartsProto.dispatchAction = function (payload, silent) {
L
tweak  
lang 已提交
394 395
        var actionWrap = actions[payload.type];
        if (actionWrap) {
L
lang 已提交
396 397
            var actionInfo = actionWrap.actionInfo;
            var updateMethod = actionInfo.update || 'update';
L
tweak  
lang 已提交
398
            actionWrap.action(payload, this._model);
399
            updateMethod !== 'none' && updateMethods[updateMethod].call(this, payload);
L
lang 已提交
400

P
pah100 已提交
401 402 403 404 405
            if (!silent) {
                // Emit event outside
                // Convert type to eventType
                var eventObj = zrUtil.extend({}, payload);
                eventObj.type = actionInfo.event || eventObj.type;
L
lang 已提交
406
                this._messageCenter.trigger(eventObj.type, eventObj);
P
pah100 已提交
407
            }
L
tweak  
lang 已提交
408 409
        }
    };
410

L
tweak  
lang 已提交
411 412 413 414
    /**
     * @param {string} methodName
     * @private
     */
415
    function invokeUpdateMethod(methodName, ecModel, payload) {
416
        var api = this._api;
L
lang 已提交
417

L
tweak  
lang 已提交
418 419 420 421
        // Update all components
        each(this._componentsList, function (component) {
            var componentModel = component.__model;
            component[methodName](componentModel, ecModel, api, payload);
422

L
tweak  
lang 已提交
423 424
            updateZ(componentModel, component);
        }, this);
L
lang 已提交
425

L
tweak  
lang 已提交
426 427
        // Upate all charts
        ecModel.eachSeries(function (seriesModel, idx) {
P
tweak  
pah100 已提交
428
            var chart = this._chartsMap[seriesModel.id];
L
tweak  
lang 已提交
429
            chart[methodName](seriesModel, ecModel, api, payload);
430

L
tweak  
lang 已提交
431 432
            updateZ(seriesModel, chart);
        }, this);
433

434
    }
L
lang 已提交
435

L
lang 已提交
436
    /**
L
Tweak  
lang 已提交
437
     * Prepare view instances of charts and components
L
lang 已提交
438 439 440
     * @param  {module:echarts/model/Global} ecModel
     * @private
     */
441
    function prepareView(type, ecModel) {
L
Tweak  
lang 已提交
442 443 444
        var isComponent = type === 'component';
        var viewList = isComponent ? this._componentsList : this._chartsList;
        var viewMap = isComponent ? this._componentsMap : this._chartsMap;
L
tweak  
lang 已提交
445
        var zr = this._zr;
L
lang 已提交
446

L
Tweak  
lang 已提交
447 448
        for (var i = 0; i < viewList.length; i++) {
            viewList[i].__keepAlive = false;
L
tweak  
lang 已提交
449
        }
L
lang 已提交
450

L
Tweak  
lang 已提交
451 452 453 454
        ecModel[isComponent ? 'eachComponent' : 'eachSeries'](function (componentType, model) {
            if (isComponent) {
                if (componentType === 'series') {
                    return;
L
lang 已提交
455
                }
456
            }
L
tweak  
lang 已提交
457
            else {
L
Tweak  
lang 已提交
458
                model = componentType;
L
tweak  
lang 已提交
459 460
            }

P
tweak  
pah100 已提交
461
            var view = viewMap[model.id];
L
Tweak  
lang 已提交
462 463 464
            if (!view) {
                var classType = ComponentModel.parseClassType(model.type);
                var Clazz = isComponent
L
tweak  
lang 已提交
465
                    ? ComponentView.getClass(classType.main, classType.sub)
L
Tweak  
lang 已提交
466
                    : ChartView.getClass(classType.sub);
L
tweak  
lang 已提交
467
                if (Clazz) {
L
Tweak  
lang 已提交
468 469
                    view = new Clazz();
                    view.init(ecModel, this._api);
P
tweak  
pah100 已提交
470
                    viewMap[model.id] = view;
L
Tweak  
lang 已提交
471 472 473 474 475
                    viewList.push(view);
                    zr.add(view.group);
                }
                else {
                    // Error
L
lang 已提交
476
                    return;
L
lang 已提交
477
                }
478
            }
L
Tweak  
lang 已提交
479 480

            view.__keepAlive = true;
P
tweak  
pah100 已提交
481
            view.__id = model.id;
L
Tweak  
lang 已提交
482
            view.__model = model;
L
tweak  
lang 已提交
483 484
        }, this);

L
Tweak  
lang 已提交
485 486 487 488 489 490 491
        for (var i = 0; i < viewList.length;) {
            var view = viewList[i];
            if (!view.__keepAlive) {
                zr.remove(view.group);
                view.dispose(this._api);
                viewList.splice(i, 1);
                delete viewMap[view.__id];
L
tweak  
lang 已提交
492 493 494 495 496
            }
            else {
                i++;
            }
        }
497 498
    }

L
tweak  
lang 已提交
499 500 501 502 503 504
    /**
     * Processor data in each series
     *
     * @param {module:echarts/model/Global} ecModel
     * @private
     */
505
    function processData(ecModel) {
L
tweak  
lang 已提交
506 507 508
        each(PROCESSOR_STAGES, function (stage) {
            each(dataProcessorFuncs[stage] || [], function (process) {
                process(ecModel);
L
lang 已提交
509
            });
L
tweak  
lang 已提交
510
        });
511
    }
L
lang 已提交
512

L
tweak  
lang 已提交
513 514 515
    /**
     * @private
     */
516
    function stackSeriesData(ecModel) {
L
tweak  
lang 已提交
517 518 519 520 521 522 523 524
        var stackedDataMap = {};
        ecModel.eachSeries(function (series) {
            var stack = series.get('stack');
            var data = series.getData();
            if (stack && data.type === 'list') {
                var previousStack = stackedDataMap[stack];
                if (previousStack) {
                    data.stackedOn = previousStack;
L
lang 已提交
525
                }
L
tweak  
lang 已提交
526 527 528
                stackedDataMap[stack] = data;
            }
        });
529
    }
L
lang 已提交
530

L
tweak  
lang 已提交
531
    /**
L
lang 已提交
532
     * Layout before each chart render there series, after visual coding and data processing
L
tweak  
lang 已提交
533 534 535 536
     *
     * @param {module:echarts/model/Global} ecModel
     * @private
     */
537
    function doLayout(ecModel, payload) {
538
        var api = this._api;
L
tweak  
lang 已提交
539 540 541
        each(layoutFuncs, function (layout) {
            layout(ecModel, api, payload);
        });
542
    }
L
lang 已提交
543

L
tweak  
lang 已提交
544 545 546 547 548 549
    /**
     * Code visual infomation from data after data processing
     *
     * @param {module:echarts/model/Global} ecModel
     * @private
     */
550
    function doVisualCoding(ecModel, payload) {
L
tweak  
lang 已提交
551 552 553
        each(VISUAL_CODING_STAGES, function (stage) {
            each(visualCodingFuncs[stage] || [], function (visualCoding) {
                visualCoding(ecModel, payload);
L
lang 已提交
554
            });
L
tweak  
lang 已提交
555
        });
556
    }
L
lang 已提交
557

L
tweak  
lang 已提交
558 559 560 561
    /**
     * Render each chart and component
     * @private
     */
562
    function doRender(ecModel, payload) {
563
        var api = this._api;
L
tweak  
lang 已提交
564 565 566 567 568 569 570 571 572 573 574 575 576 577
        // Render all components
        each(this._componentsList, function (component) {
            var componentModel = component.__model;
            component.render(componentModel, ecModel, api, payload);

            updateZ(componentModel, component);
        }, this);

        each(this._chartsList, function (chart) {
            chart.__keepAlive = false;
        }, this);

        // Render all charts
        ecModel.eachSeries(function (seriesModel, idx) {
P
tweak  
pah100 已提交
578
            var chart = this._chartsMap[seriesModel.id];
L
tweak  
lang 已提交
579 580 581 582 583 584
            chart.__keepAlive = true;
            chart.render(seriesModel, ecModel, api, payload);

            updateZ(seriesModel, chart);
        }, this);

L
lang 已提交
585
        // Remove groups of unrendered charts
L
tweak  
lang 已提交
586 587 588 589 590
        each(this._chartsList, function (chart) {
            if (!chart.__keepAlive) {
                chart.remove(ecModel, api);
            }
        }, this);
591
    }
L
lang 已提交
592

L
lang 已提交
593 594 595 596 597 598 599 600 601 602 603 604 605
    var MOUSE_EVENT_NAMES = [
        'click', 'dblclick', 'mouseover', 'mouseout', 'globalout'
    ];
    /**
     * @private
     */
    echartsProto._initEvents = function () {
        var zr = this._zr;
        each(MOUSE_EVENT_NAMES, function (eveName) {
            zr.on(eveName, function (e) {
                var ecModel = this.getModel();
                var el = e.target;
                if (el && el.dataIndex != null) {
606
                    var hostModel = el.hostModel || ecModel.getSeriesByIndex(el.seriesIndex);
L
lang 已提交
607 608 609 610 611 612 613
                    var params = hostModel && hostModel.getDataParams(el.dataIndex) || {};
                    params.event = e;
                    params.type = eveName;
                    this.trigger(eveName, params);
                }
            }, this);
        }, this);
L
lang 已提交
614 615 616 617 618 619

        zrUtil.each(eventActionMap, function (actionType, eventType) {
            this._messageCenter.on(eventType, function (event) {
                this.trigger(eventType, event);
            }, this);
        }, this);
L
lang 已提交
620 621
    };

L
lang 已提交
622 623 624 625 626 627 628 629 630
    /**
     * @return {boolean]
     */
    echartsProto.isDisposed = function () {
        return this._disposed;
    };
    /**
     * Dispose instance
     */
L
tweak  
lang 已提交
631
    echartsProto.dispose = function () {
L
lang 已提交
632 633
        this._disposed = true;

L
tweak  
lang 已提交
634 635 636 637 638 639
        each(this._components, function (component) {
            component.dispose();
        });
        each(this._charts, function (chart) {
            chart.dispose();
        });
L
lang 已提交
640

L
Tweak  
lang 已提交
641
        this._zr.dispose();
L
lang 已提交
642 643

        instances[this.id] = null;
L
lang 已提交
644 645
    };

L
lang 已提交
646 647
    zrUtil.mixin(ECharts, Eventful);

L
lang 已提交
648 649 650 651 652 653 654 655 656 657 658 659 660 661
    /**
     * @param {module:echarts/model/Series|module:echarts/model/Component} model
     * @param {module:echarts/view/Component|module:echarts/view/Chart} view
     * @return {string}
     */
    function updateZ(model, view) {
        var z = model.get('z');
        var zlevel = model.get('zlevel');
        // Set z and zlevel
        view.group.traverse(function (el) {
            z != null && (el.z = z);
            zlevel != null && (el.zlevel = zlevel);
        });
    }
L
lang 已提交
662 663 664 665
    /**
     * @type {Array.<Function>}
     * @inner
     */
P
pah100 已提交
666 667
    var actions = [];

L
lang 已提交
668
    /**
L
lang 已提交
669
     * Map eventType to actionType
L
lang 已提交
670 671 672 673
     * @type {Object}
     */
    var eventActionMap = {};

L
lang 已提交
674 675 676 677
    /**
     * @type {Array.<Function>}
     * @inner
     */
678 679
    var layoutFuncs = [];

L
lang 已提交
680 681 682 683 684 685 686
    /**
     * Data processor functions of each stage
     * @type {Array.<Object.<string, Function>>}
     * @inner
     */
    var dataProcessorFuncs = {};

687 688 689 690 691 692
    /**
     * @type {Array.<Function>}
     * @inner
     */
    var optionPreprocessorFuncs = [];

L
lang 已提交
693 694 695 696 697
    /**
     * Visual coding functions of each stage
     * @type {Array.<Object.<string, Function>>}
     * @inner
     */
698
    var visualCodingFuncs = {};
L
lang 已提交
699

L
lang 已提交
700 701 702 703 704 705
    var instances = {};
    var connectedGroups = {};

    var idBase = new Date() - 0;
    var groupIdBase = new Date() - 0;
    var DOM_ATTRIBUTE_KEY = '_echarts_instance_';
L
lang 已提交
706
    /**
L
lang 已提交
707
     * @alias module:echarts
L
lang 已提交
708
     */
L
lang 已提交
709 710 711 712 713 714 715 716 717
    var echarts = {
        /**
         * @type {number}
         */
        version: '3.0.0',
        dependencies: {
            zrender: '3.0.0'
        }
    };
L
lang 已提交
718

L
tweak  
lang 已提交
719 720 721 722 723 724
    /**
     * @param {HTMLDomElement} dom
     * @param {Object} [theme]
     * @param {Object} opts
     */
    echarts.init = function (dom, theme, opts) {
L
lang 已提交
725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740
        // Check version
        if ((zrender.version.replace('.', '') - 0) < (echarts.dependencies.zrender.replace('.', '') - 0)) {
            console.error(
                'ZRender ' + zrender.version
                + ' is too old for ECharts ' + echarts.version
                + '. Current version need ZRender '
                + echarts.dependencies.zrender + '+'
            );
        }

        var chart = new ECharts(dom, theme, opts);
        chart.id = idBase++;
        instances[chart.id] = chart;

        // Connecting
        zrUtil.each(eventActionMap, function (actionType, eventType) {
L
lang 已提交
741 742
            // FIXME
            chart._messageCenter.on(eventType, function (event) {
L
lang 已提交
743 744 745
                if (connectedGroups[chart.group]) {
                    chart.__connectedActionDispatching = true;
                    for (var id in instances) {
L
tweak  
lang 已提交
746
                        var action = chart.makeActionFromEvent(event);
L
lang 已提交
747 748
                        var otherChart = instances[id];
                        if (otherChart !== chart && otherChart.group === chart.group) {
L
tweak  
lang 已提交
749
                            if (!otherChart.__connectedActionDispatching) {
L
lang 已提交
750
                                otherChart.dispatchAction(action);
L
tweak  
lang 已提交
751
                            }
L
lang 已提交
752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821
                        }
                    }
                    chart.__connectedActionDispatching = false;
                }
            });
        });

        return chart;
    };

    /**
     * @return {string|Array.<module:echarts~ECharts>} groupId
     */
    echarts.connect = function (groupId) {
        // Is array of charts
        if (zrUtil.isArray(groupId)) {
            var charts = groupId;
            groupId = null;
            // If any chart has group
            zrUtil.each(charts, function (chart) {
                if (chart.group != null) {
                    groupId = chart.group;
                }
            });
            groupId = groupId || groupIdBase++;
            zrUtil.each(charts, function (chart) {
                chart.group = groupId;
            });
        }
        connectedGroups[groupId] = true;
        return groupId;
    };

    /**
     * @return {string} groupId
     */
    echarts.disConnect = function (groupId) {
        connectedGroups[groupId] = false;
    };

    /**
     * Dispose a chart instance
     * @param  {module:echarts~ECharts|HTMLDomElement|string} chart
     */
    echarts.dispose = function (chart) {
        if (zrUtil.isDom(chart)) {
            chart = echarts.getInstanceByDom(chart);
        }
        else if (typeof chart === 'string') {
            chart = instances[chart];
        }
        if ((chart instanceof ECharts) && !chart.isDisposed()) {
            chart.dispose();
        }
    };

    /**
     * @param  {HTMLDomElement} dom
     * @return {echarts~ECharts}
     */
    echarts.getInstanceByDom = function (dom) {
        var key = dom.getAttribute(DOM_ATTRIBUTE_KEY);
        return instances[key];
    };
    /**
     * @param {string} key
     * @return {echarts~ECharts}
     */
    echarts.getInstanceById = function (key) {
        return instances[key];
L
tweak  
lang 已提交
822
    };
L
lang 已提交
823

L
tweak  
lang 已提交
824 825 826 827 828 829 830
    /**
     * Register option preprocessor
     * @param {Function} preprocessorFunc
     */
    echarts.registerPreprocessor = function (preprocessorFunc) {
        optionPreprocessorFuncs.push(preprocessorFunc);
    };
831

L
tweak  
lang 已提交
832 833 834 835 836 837 838 839 840 841 842
    /**
     * @param {string} stage
     * @param {Function} processorFunc
     */
    echarts.registerProcessor = function (stage, processorFunc) {
        if (zrUtil.indexOf(PROCESSOR_STAGES, stage) < 0) {
            throw new Error('stage should be one of ' + PROCESSOR_STAGES);
        }
        var funcs = dataProcessorFuncs[stage] || (dataProcessorFuncs[stage] = []);
        funcs.push(processorFunc);
    };
L
lang 已提交
843

L
tweak  
lang 已提交
844 845 846 847 848 849 850 851 852 853 854
    /**
     * Usage:
     * registerAction('someAction', 'someEvent', function () { ... });
     * registerAction('someAction', function () { ... });
     * registerAction(
     *     {type: 'someAction', event: 'someEvent', update: 'updateView'},
     *     function () { ... }
     * );
     *
     * @param {(string|Object)} actionInfo
     * @param {string} actionInfo.type
L
lang 已提交
855 856 857 858
     * @param {string} [actionInfo.event]
     * @param {string} [actionInfo.update]
     * @param {string} [eventName]
     * @param {Function} action
L
tweak  
lang 已提交
859
     */
L
lang 已提交
860 861 862 863 864
    echarts.registerAction = function (actionInfo, eventName, action) {
        if (typeof eventName === 'function') {
            action = eventName;
            eventName = '';
        }
L
tweak  
lang 已提交
865 866
        var actionType = zrUtil.isObject(actionInfo)
            ? actionInfo.type
L
lang 已提交
867 868 869
            : ([actionInfo, actionInfo = {
                event: eventName
            }][0]);
L
lang 已提交
870 871

        actionInfo.event = actionInfo.event || actionType;
L
lang 已提交
872
        eventName = actionInfo.event;
873

L
tweak  
lang 已提交
874 875 876
        if (!actions[actionType]) {
            actions[actionType] = {action: action, actionInfo: actionInfo};
        }
L
lang 已提交
877
        eventActionMap[eventName] = actionType;
L
tweak  
lang 已提交
878
    };
P
pah100 已提交
879

L
tweak  
lang 已提交
880 881 882 883 884 885 886
    /**
     * @param {string} type
     * @param {*} CoordinateSystem
     */
    echarts.registerCoordinateSystem = function (type, CoordinateSystem) {
        CoordinateSystemManager.register(type, CoordinateSystem);
    };
L
lang 已提交
887

L
tweak  
lang 已提交
888 889 890
    /**
     * @param {*} layout
     */
L
lang 已提交
891
    echarts.registerLayout = function (layout) {
L
tweak  
lang 已提交
892
        // PENDING All functions ?
893 894
        if (zrUtil.indexOf(layoutFuncs, layout) < 0) {
            layoutFuncs.push(layout);
L
tweak  
lang 已提交
895 896
        }
    };
L
lang 已提交
897

L
tweak  
lang 已提交
898 899 900 901 902 903 904 905 906 907 908
    /**
     * @param {string} stage
     * @param {Function} visualCodingFunc
     */
    echarts.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 已提交
909

L
tweak  
lang 已提交
910 911 912 913 914 915
    /**
     * @param {Object} opts
     */
    echarts.extendChartView = function (opts) {
        return ChartView.extend(opts);
    };
L
Update  
lang 已提交
916

L
tweak  
lang 已提交
917 918 919 920 921 922
    /**
     * @param {Object} opts
     */
    echarts.extendComponentModel = function (opts) {
        return ComponentModel.extend(opts);
    };
L
Update  
lang 已提交
923

L
tweak  
lang 已提交
924 925 926 927 928 929
    /**
     * @param {Object} opts
     */
    echarts.extendSeriesModel = function (opts) {
        return SeriesModel.extend(opts);
    };
P
pah100 已提交
930

L
tweak  
lang 已提交
931 932 933 934 935
    /**
     * @param {Object} opts
     */
    echarts.extendComponentView = function (opts) {
        return ComponentView.extend(opts);
L
lang 已提交
936 937
    };

938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957
    /**
     * ZRender need a canvas context to do measureText.
     * But in node environment canvas may be created by node-canvas.
     * So we need to specify how to create a canvas instead of using document.createElement('canvas')
     *
     * Be careful of using it in the browser.
     *
     * @param {Function} creator
     * @example
     *     var Canvas = require('canvas');
     *     var echarts = require('echarts');
     *     echarts.setCanvasCreator(function () {
     *         // Small size is enough.
     *         return new Canvas(32, 32);
     *     });
     */
    echarts.setCanvasCreator = function (creator) {
        zrUtil.createCanvas = creator;
    };

L
lang 已提交
958 959 960
    echarts.registerVisualCoding('echarts', zrUtil.curry(
        require('./visual/seriesColor'), '', 'itemStyle'
    ));
961 962
    echarts.registerPreprocessor(require('./preprocessor/backwardCompat'));

963 964 965 966 967 968 969 970 971 972 973 974
    // Default action
    echarts.registerAction({
        type: 'highlight',
        event: 'highlight',
        update: 'highlight'
    }, zrUtil.noop);
    echarts.registerAction({
        type: 'downplay',
        event: 'downplay',
        update: 'downplay'
    }, zrUtil.noop);

L
lang 已提交
975 976
    return echarts;
});