calculableBase.js 23.6 KB
Newer Older
K
kener 已提交
1
/**
K
kener 已提交
2
 * echarts可计算特性基类
K
kener 已提交
3 4 5 6 7
 *
 * @desc echarts基于Canvas,纯Javascript图表库,提供直观,生动,可交互,可个性化定制的数据统计图表。
 * @author Kener (@Kener-林峰, linzhifeng@baidu.com)
 *
 */
K
kener 已提交
8
define(function (require) {
K
kener 已提交
9
    var ecConfig = require('../config');
K
kener 已提交
10 11 12 13 14
    var ecData = require('../util/ecData');
    var accMath = require('../util/accMath');
    var zrUtil = require('zrender/tool/util');
    
    function Base(){
K
kener 已提交
15
        var self = this;
K
kener 已提交
16 17 18
        this.selectedMap = {};
        this.shapeHandler = {
            onclick : function () {
K
kener 已提交
19 20
                self.isClick = true;
            },
K
kener 已提交
21
            
K
kener 已提交
22 23
            ondragover : function (param) {
                // 返回触发可计算特性的图形提示
K
kener 已提交
24
                var calculableShape = param.target;
K
kener 已提交
25 26
                calculableShape.highlightStyle = calculableShape.highlightStyle || {};
                
K
kener 已提交
27
                // 备份特出特性
K
kener 已提交
28
                var highlightStyle = calculableShape.highlightStyle;
K
kener 已提交
29 30 31 32 33 34 35 36
                var brushType = highlightStyle.brushTyep;
                var strokeColor = highlightStyle.strokeColor;
                var lineWidth = highlightStyle.lineWidth;
                
                highlightStyle.brushType = 'stroke';
                highlightStyle.strokeColor = self.ecTheme.calculableColor;
                highlightStyle.lineWidth = calculableShape.type == 'icon' ? 30 : 10;
                
K
kener 已提交
37
                self.zr.addHoverShape(calculableShape);
K
kener 已提交
38
                
K
kener 已提交
39
                setTimeout(function (){
K
kener 已提交
40 41 42 43 44 45
                    // 复位
                    if (calculableShape.highlightStyle) {
                        calculableShape.highlightStyle.brushType = brushType;
                        calculableShape.highlightStyle.strokeColor = strokeColor;
                        calculableShape.highlightStyle.lineWidth = lineWidth;
                    }
K
kener 已提交
46
                },20);
K
kener 已提交
47
            },
K
kener 已提交
48
            
K
kener 已提交
49 50 51 52 53 54
            ondrop : function (param) {
                // 排除一些非数据的拖拽进入
                if (typeof ecData.get(param.dragged, 'data') != 'undefined') {
                    self.isDrop = true;
                }
            },
K
kener 已提交
55
            
K
kener 已提交
56 57 58 59
            ondragend : function () {
                self.isDragend = true;
            }
        }
K
kener 已提交
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
    }
    
    /**
     * 基类方法
     */
    Base.prototype = {
        /**
         * 图形拖拽特性 
         */
        setCalculable : function (shape) {
            shape.dragEnableTime = this.ecTheme.DRAG_ENABLE_TIME;
            shape.ondragover = this.shapeHandler.ondragover;
            shape.ondragend = this.shapeHandler.ondragend;
            shape.ondrop = this.shapeHandler.ondrop;
            return shape;
        },
K
kener 已提交
76 77 78 79

        /**
         * 数据项被拖拽进来
         */
K
kener 已提交
80 81
        ondrop : function (param, status) {
            if (!this.isDrop || !param.target) {
K
kener 已提交
82 83 84 85 86 87 88 89 90 91
                // 没有在当前实例上发生拖拽行为则直接返回
                return;
            }

            var target = param.target;      // 拖拽安放目标
            var dragged = param.dragged;    // 当前被拖拽的图形对象

            var seriesIndex = ecData.get(target, 'seriesIndex');
            var dataIndex = ecData.get(target, 'dataIndex');

K
kener 已提交
92
            // 落到数据item上,数据被拖拽到某个数据项上,数据修改
K
kener 已提交
93
            var data = this.option.series[seriesIndex].data[dataIndex] || '-';
K
kener 已提交
94 95
            if (data.value) {
                if (data.value != '-') {
K
kener 已提交
96
                    this.option.series[seriesIndex].data[dataIndex].value = 
K
kener 已提交
97
                        accMath.accAdd(
K
kener 已提交
98
                            this.option.series[seriesIndex].data[dataIndex].value,
K
kener 已提交
99 100
                            ecData.get(dragged, 'value')
                        );
K
kener 已提交
101 102
                }
                else {
K
kener 已提交
103
                    this.option.series[seriesIndex].data[dataIndex].value =
K
kener 已提交
104 105 106 107 108
                        ecData.get(dragged, 'value');
                }
            }
            else {
                if (data != '-') {
K
kener 已提交
109
                    this.option.series[seriesIndex].data[dataIndex] = 
K
kener 已提交
110
                        accMath.accAdd(
K
kener 已提交
111
                            this.option.series[seriesIndex].data[dataIndex],
K
kener 已提交
112 113
                            ecData.get(dragged, 'value')
                        );
K
kener 已提交
114 115
                }
                else {
K
kener 已提交
116
                    this.option.series[seriesIndex].data[dataIndex] =
K
kener 已提交
117 118 119 120 121 122 123 124
                        ecData.get(dragged, 'value');
                }
            }

            // 别status = {}赋值啊!!
            status.dragIn = status.dragIn || true;

            // 处理完拖拽事件后复位
K
kener 已提交
125
            this.isDrop = false;
K
kener 已提交
126 127

            return;
K
kener 已提交
128
        },
K
kener 已提交
129 130 131 132

        /**
         * 数据项被拖拽出去
         */
K
kener 已提交
133 134
        ondragend : function (param, status) {
            if (!this.isDragend || !param.target) {
K
kener 已提交
135 136 137 138 139 140 141 142 143
                // 没有在当前实例上发生拖拽行为则直接返回
                return;
            }
            var target = param.target;      // 被拖拽图形元素

            var seriesIndex = ecData.get(target, 'seriesIndex');
            var dataIndex = ecData.get(target, 'dataIndex');

            // 被拖拽的图形是折线图bar,删除被拖拽走的数据
K
kener 已提交
144
            this.option.series[seriesIndex].data[dataIndex] = '-';
K
kener 已提交
145 146 147 148 149 150

            // 别status = {}赋值啊!!
            status.dragOut = true;
            status.needRefresh = true;

            // 处理完拖拽事件后复位
K
kener 已提交
151
            this.isDragend = false;
K
kener 已提交
152 153

            return;
K
kener 已提交
154
        },
K
kener 已提交
155 156 157 158

        /**
         * 图例选择
         */
K
kener 已提交
159
        onlegendSelected : function (param, status) {
K
kener 已提交
160
            var legendSelected = param.selected;
K
kener 已提交
161 162
            for (var itemName in this.selectedMap) {
                if (this.selectedMap[itemName] != legendSelected[itemName]) {
K
kener 已提交
163 164 165
                    // 有一项不一致都需要重绘
                    status.needRefresh = true;
                }
K
kener 已提交
166
                this.selectedMap[itemName] = legendSelected[itemName];
K
kener 已提交
167
            }
K
kener 已提交
168
            return;
K
kener 已提交
169 170
        },
        
K
kener 已提交
171
        backupShapeList : function () {
K
kener 已提交
172 173 174 175 176 177 178 179 180
            if (this.shapeList && this.shapeList.length > 0) {
                this.lastShapeList = this.shapeList;
                this.shapeList = [];
            }
            else {
                this.lastShapeList = [];
            }
        },
        
K
kener 已提交
181
        addShapeList : function () {
K
kener 已提交
182
            var maxLenth = this.option.animationThreshold / (this.canvasSupported ? 1 : 2);
K
kener 已提交
183 184
            var lastShapeList = this.lastShapeList;
            var shapeList = this.shapeList;
K
kener 已提交
185 186 187
            var duration = lastShapeList.length > 0
                           ? 500 : this.query(this.option, 'animationDuration');
            var easing = this.query(this.option, 'animationEasing');
K
kener 已提交
188 189 190
            var key;
            var oldMap = {};
            var newMap = {};
K
kener 已提交
191 192 193
            if (this.option.animation 
                && !this.option.renderAsImage 
                && shapeList.length < maxLenth
K
kener 已提交
194
                && !this.motionlessOnce
K
kener 已提交
195
            ) {
K
kener 已提交
196
                // 通过已有的shape做动画过渡
K
kener 已提交
197
                for (var i = 0, l = lastShapeList.length; i < l; i++) {
K
kener 已提交
198
                    key = ecData.get(lastShapeList[i], 'seriesIndex') + '_'
K
kener 已提交
199 200 201 202
                          + ecData.get(lastShapeList[i], 'dataIndex')
                          + (this.type == ecConfig.CHART_TYPE_RADAR
                             ? ecData.get(lastShapeList[i], 'special')
                             : '');
K
kener 已提交
203 204 205 206 207 208 209 210
                    if (key.match('undefined') || lastShapeList[i]._mark) {
                        this.zr.delShape(lastShapeList[i].id); // 非关键元素直接删除
                    }
                    else {
                        key += lastShapeList[i].type;
                        oldMap[key] = lastShapeList[i];
                    }
                }
K
kener 已提交
211
                for (var i = 0, l = shapeList.length; i < l; i++) {
K
kener 已提交
212
                    key = ecData.get(shapeList[i], 'seriesIndex') + '_'
K
kener 已提交
213 214 215 216
                          + ecData.get(shapeList[i], 'dataIndex')
                          + (this.type == ecConfig.CHART_TYPE_RADAR
                             ? ecData.get(shapeList[i], 'special')
                             : '');
K
kener 已提交
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
                    if (key.match('undefined') || shapeList[i]._mark) {
                        this.zr.addShape(shapeList[i]); // 非关键元素直接添加
                    }
                    else {
                        key += shapeList[i].type;
                        newMap[key] = shapeList[i];
                    }
                }
                for (key in oldMap) {
                    if (!newMap[key]) {
                        // 新的没有 删除
                        this.zr.delShape(oldMap[key].id);
                    }
                }
                for (key in newMap) {
                    if (oldMap[key]) {
                        // 新旧都有 动画过渡
                        this.zr.delShape(oldMap[key].id);
K
kener 已提交
235
                        this._animateMod(oldMap[key], newMap[key], duration, easing);
K
kener 已提交
236 237 238
                    }
                    else {
                        // 新有旧没有  添加并动画过渡
K
kener 已提交
239
                        this._animateAdd(newMap[key], duration, easing);
K
kener 已提交
240 241
                    }
                }
K
kener 已提交
242
                this.animationMark(duration, easing);
K
kener 已提交
243 244
            }
            else {
K
kener 已提交
245
                this.motionlessOnce = false;
K
kener 已提交
246 247
                // clear old
                this.zr.delShape(lastShapeList);
K
kener 已提交
248
                // 直接添加
K
kener 已提交
249
                for (var i = 0, l = shapeList.length; i < l; i++) {
K
kener 已提交
250 251 252 253 254
                    this.zr.addShape(shapeList[i]);
                }
            }
        },
        
K
kener 已提交
255
        _animateMod : function (oldShape, newShape, duration, easing) {
K
kener 已提交
256
            switch (newShape.type) {
K
kener 已提交
257 258
                case 'broken-line' :
                case 'half-smooth-polygon' :
K
kener 已提交
259
                    this._animationPointList(oldShape, newShape, duration, easing);
K
kener 已提交
260 261
                    break;
                case 'rectangle' :
K
kener 已提交
262
                case 'icon' :
K
kener 已提交
263
                    this._animationRectangle(oldShape, newShape, duration, easing);
K
kener 已提交
264
                    break;
K
kener 已提交
265
                case 'candle' :
K
kener 已提交
266
                    if (duration > 500) {
K
kener 已提交
267
                        this._animationCandle(oldShape, newShape, duration, easing);
K
kener 已提交
268 269 270 271
                    }
                    else {
                        this.zr.addShape(newShape);
                    }
K
kener 已提交
272
                    break;
K
kener 已提交
273 274 275 276 277 278 279 280 281 282 283 284 285 286
                case 'ring' :
                case 'sector' :
                case 'circle' :
                    if (duration > 500) {
                        this._animationRing(
                            oldShape,
                            newShape, 
                            duration + ((ecData.get(newShape, 'dataIndex') || 0) % 20 * 100), 
                            easing
                        );
                    }
                    else if (newShape.type == 'sector') {
                        this._animationSector(oldShape, newShape, duration, easing);
                    }
K
kener 已提交
287 288 289
                    else {
                        this.zr.addShape(newShape);
                    }
K
kener 已提交
290 291 292 293
                    break;
                case 'text' :
                    this._animationText(oldShape, newShape, duration, easing);
                    break;
K
kener 已提交
294 295 296 297 298 299 300 301
                case 'polygon' :
                    if (duration > 500) {
                        this._animationPolygon(oldShape, newShape, duration, easing);
                    }
                    else {
                        this._animationPointList(oldShape, newShape, duration, easing);
                    }
                    break;
K
kener 已提交
302 303 304
                case 'chord' :
                    this._animationChord(oldShape, newShape, duration, easing);
                    break;
K
kener 已提交
305 306 307 308 309 310
                default :
                    this.zr.addShape(newShape);
                    break;
            }
        },
        
K
kener 已提交
311
        _animateAdd : function (newShape, duration, easing) {
K
kener 已提交
312 313 314 315 316 317 318 319
            switch (newShape.type) {
                case 'broken-line' :
                case 'half-smooth-polygon' :
                    var newPointList = [];
                    var len = newShape.style.pointList.length;
                    if (newShape._orient != 'vertical') {
                        var y = newShape.style.pointList[0][1];
                        for (var i = 0; i < len; i++) {
K
kener 已提交
320
                            newPointList[i] = [newShape.style.pointList[i][0], y];
K
kener 已提交
321 322 323 324 325
                        };
                    }
                    else {
                        var x = newShape.style.pointList[0][0];
                        for (var i = 0; i < len; i++) {
K
kener 已提交
326
                            newPointList[i] = [x, newShape.style.pointList[i][1]];
K
kener 已提交
327 328 329 330 331 332 333 334
                        };
                    }
                    if (newShape.type == 'half-smooth-polygon') {
                        newPointList[len - 1] = zrUtil.clone(newShape.style.pointList[len - 1]);
                        newPointList[len - 2] = zrUtil.clone(newShape.style.pointList[len - 2]);
                    }
                    this._animateMod(
                        {
K
kener 已提交
335
                            style : { pointList : newPointList }
K
kener 已提交
336
                        },
K
kener 已提交
337 338 339
                        newShape,
                        duration,
                        easing
K
kener 已提交
340 341 342
                    );
                    break;
                case 'rectangle' :
K
kener 已提交
343
                case 'icon' :
K
kener 已提交
344 345 346 347 348 349 350 351 352 353 354
                    this._animateMod(
                        {
                            style : {
                                x : newShape.style.x,
                                y : newShape._orient == 'vertical'
                                    ? newShape.style.y + newShape.style.height
                                    : newShape.style.y,
                                width: 0,
                                height: 0
                            }
                        },
K
kener 已提交
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370
                        newShape,
                        duration,
                        easing
                    );
                    break;
                case 'candle' :
                    var y = newShape.style.y;
                    this._animateMod(
                        {
                            style : {
                                y : [y[0], y[0], y[0], y[0]]
                            }
                        },
                        newShape,
                        duration,
                        easing
K
kener 已提交
371 372
                    );
                    break;
K
kener 已提交
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400
                case 'sector' :
                    this._animateMod(
                        {
                            style : {
                                startAngle : newShape.style.startAngle,
                                endAngle : newShape.style.startAngle
                            }
                        },
                        newShape,
                        duration,
                        easing
                    );
                    break;
                case 'text' :
                    this._animateMod(
                        {
                            style : {
                                x : newShape.style.textAlign == 'left' 
                                    ? newShape.style.x + 100
                                    : newShape.style.x - 100,
                                y : newShape.style.y
                            }
                        },
                        newShape,
                        duration,
                        easing
                    );
                    break;
K
kener 已提交
401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417
                case 'polygon' :
                    var rect = require('zrender/shape/Polygon').prototype.getRect(newShape.style);
                    var x = rect.x + rect.width / 2;
                    var y = rect.y + rect.height / 2;
                    var newPointList = [];
                    for (var i = 0, len = newShape.style.pointList.length; i < len; i++) {
                        newPointList.push([x + i, y + i]);
                    }
                    this._animateMod(
                        {
                            style : { pointList : newPointList }
                        },
                        newShape,
                        duration,
                        easing
                    );
                    break;
K
kener 已提交
418 419 420 421 422 423 424 425 426 427 428 429 430 431 432
                case 'chord' :
                    this._animateMod(
                        {
                            style : {
                                source0 : 0,
                                source1 : 360,
                                target0 : 0,
                                target1 : 360
                            }
                        },
                        newShape,
                        duration,
                        easing
                    );
                    break;
K
kener 已提交
433
                default :
K
kener 已提交
434
                    this._animateMod({}, newShape, duration, easing);
K
kener 已提交
435 436
                    break;
            }
K
kener 已提交
437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563
        },
        
        _animationPointList : function (oldShape, newShape, duration, easing) {
            var newPointList = newShape.style.pointList;
            if (oldShape.style.pointList.length == newPointList.length) {
                newShape.style.pointList = oldShape.style.pointList;
            }
            else if (oldShape.style.pointList.length < newPointList.length) {
                // 原来短,新的长,补全
                newShape.style.pointList = oldShape.style.pointList.concat(
                    newPointList.slice(oldShape.style.pointList.length)
                )
            }
            else {
                // 原来长,新的短,截断
                newShape.style.pointList = oldShape.style.pointList.slice(
                    0, newPointList.length
                );
            }
            this.zr.addShape(newShape);
            this.zr.animate(newShape.id, 'style')
                .when(
                    duration,
                    { pointList: newPointList }
                )
                .start(easing);
        },
        
        _animationRectangle : function (oldShape, newShape, duration, easing) {
            var newX = newShape.style.x;
            var newY = newShape.style.y;
            var newWidth = newShape.style.width;
            var newHeight = newShape.style.height;
            newShape.style.x = oldShape.style.x;
            newShape.style.y = oldShape.style.y;
            newShape.style.width = oldShape.style.width;
            newShape.style.height = oldShape.style.height;
            this.zr.addShape(newShape);
            this.zr.animate(newShape.id, 'style')
                .when(
                    duration,
                    {
                        x: newX,
                        y: newY,
                        width: newWidth,
                        height: newHeight
                    }
                )
                .start(easing);
        },
        
        _animationCandle : function (oldShape, newShape, duration, easing) {
            var newY = newShape.style.y;
            newShape.style.y = oldShape.style.y;
            this.zr.addShape(newShape);
            this.zr.animate(newShape.id, 'style')
                .when(
                    duration,
                    { y: newY }
                )
                .start(easing);
        },
        
        _animationRing : function (oldShape, newShape, duration, easing) {
            var x = newShape.style.x;
            var y = newShape.style.y;
            var r0 = newShape.style.r0;
            var r = newShape.style.r;
            
            newShape.style.r0 = 0;
            newShape.style.r = 0;
            newShape.rotation = [Math.PI*2, x, y];
            
            this.zr.addShape(newShape);
            this.zr.animate(newShape.id, 'style')
                .when(
                    duration,
                    {
                        r0 : r0,
                        r : r
                    }
                )
                .start(easing);
            this.zr.animate(newShape.id, '')
                .when(
                    Math.round(duration / 3 * 2),
                    { rotation : [0, x, y] }
                )
                .start(easing);
        },
        
        _animationSector : function (oldShape, newShape, duration, easing) {
            var startAngle = newShape.style.startAngle;
            var endAngle = newShape.style.endAngle;
            
            newShape.style.startAngle = oldShape.style.startAngle;
            newShape.style.endAngle = oldShape.style.endAngle;
            
            this.zr.addShape(newShape);
            this.zr.animate(newShape.id, 'style')
                .when(
                    duration,
                    {
                        startAngle : startAngle,
                        endAngle : endAngle
                    }
                )
                .start(easing);
        },
        
        _animationText : function (oldShape, newShape, duration, easing) {
            var x = newShape.style.x;
            var y = newShape.style.y;
            
            newShape.style.x = oldShape.style.x;
            newShape.style.y = oldShape.style.y;
            
            this.zr.addShape(newShape);
            this.zr.animate(newShape.id, 'style')
                .when(
                    duration,
                    {
                        x : x,
                        y : y
                    }
                )
                .start(easing);
K
kener 已提交
564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581
        },
        
        _animationPolygon : function (oldShape, newShape, duration, easing) {
            var rect = require('zrender/shape/Polygon').prototype.getRect(newShape.style);
            var x = rect.x + rect.width / 2;
            var y = rect.y + rect.height / 2;
            
            newShape.scale = [0.1, 0.1, x, y];
            
            this.zr.addShape(newShape);
            this.zr.animate(newShape.id, '')
                .when(
                    duration,
                    {
                        scale : [1, 1, x, y]
                    }
                )
                .start(easing);
K
kener 已提交
582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609
        },
        
        _animationChord : function (oldShape, newShape, duration, easing) {
            //var rect = require('zrender/shape/Polygon').prototype.getRect(newShape.style);
            var source0 = newShape.style.source0;
            var source1 = newShape.style.source1;
            var target0 = newShape.style.target0;
            var target1 = newShape.style.target1;
            
            if (oldShape.style) {
                newShape.style.source0 = oldShape.style.source0;
                newShape.style.source1 = oldShape.style.source1;
                newShape.style.target0 = oldShape.style.target0;
                newShape.style.target1 = oldShape.style.target1;
            }
            
            this.zr.addShape(newShape);
            this.zr.animate(newShape.id, 'style')
                .when(
                    duration,
                    {
                        source0 : source0,
                        source1 : source1,
                        target0 : target0,
                        target1 : target1
                    }
                )
                .start(easing);
K
kener 已提交
610 611 612 613 614
        }
    }

    return Base;
});