legend.js 37.6 KB
Newer Older
K
kener 已提交
1 2 3 4
/**
 * echarts组件:图例
 *
 * @desc echarts基于Canvas,纯Javascript图表库,提供直观,生动,可交互,可个性化定制的数据统计图表。
K
kener 已提交
5
 * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)
K
kener 已提交
6 7 8
 *
 */
define(function (require) {
K
kener 已提交
9 10 11
    var Base = require('./base');
    
    // 图形依赖
K
kener 已提交
12 13
    var TextShape = require('zrender/shape/Text');
    var RectangleShape = require('zrender/shape/Rectangle');
K
kener 已提交
14
    var SectorShape = require('zrender/shape/Sector');
K
kener 已提交
15
    //var BeziercurveShape = require('zrender/shape/Beziercurve');
K
kener 已提交
16
    var IconShape = require('../util/shape/Icon');
K
kener 已提交
17
    var CandleShape = require('../util/shape/Candle');
K
kener 已提交
18
    
K
kener 已提交
19
    var ecConfig = require('../config');
K
Kener 已提交
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
     // 图例
    ecConfig.legend = {
        zlevel: 0,                  // 一级层叠
        z: 4,                       // 二级层叠
        show: true,
        orient: 'horizontal',      // 布局方式,默认为水平布局,可选为:
                                   // 'horizontal' ¦ 'vertical'
        x: 'center',               // 水平安放位置,默认为全图居中,可选为:
                                   // 'center' ¦ 'left' ¦ 'right'
                                   // ¦ {number}(x坐标,单位px)
        y: 'top',                  // 垂直安放位置,默认为全图顶端,可选为:
                                   // 'top' ¦ 'bottom' ¦ 'center'
                                   // ¦ {number}(y坐标,单位px)
        backgroundColor: 'rgba(0,0,0,0)',
        borderColor: '#ccc',       // 图例边框颜色
        borderWidth: 0,            // 图例边框线宽,单位px,默认为0(无边框)
        padding: 5,                // 图例内边距,单位px,默认各方向内边距为5,
                                   // 接受数组分别设定上右下左边距,同css
        itemGap: 10,               // 各个item之间的间隔,单位px,默认为10,
                                   // 横向布局时为水平间隔,纵向布局时为纵向间隔
        itemWidth: 20,             // 图例图形宽度
        itemHeight: 14,            // 图例图形高度
        textStyle: {
            color: '#333'          // 图例文字颜色
        },
        selectedMode: true         // 选择模式,默认开启图例开关
        // selected: null,         // 配置默认选中状态,可配合LEGEND.SELECTED事件做动态数据载入
        // data: [],               // 图例内容(详见legend.data,数组中每一项代表一个item
    };

K
kener 已提交
50 51 52
    var zrUtil = require('zrender/tool/util');
    var zrArea = require('zrender/tool/area');

K
kener 已提交
53 54 55 56 57 58
    /**
     * 构造函数
     * @param {Object} messageCenter echart消息中心
     * @param {ZRender} zr zrender实例
     * @param {Object} option 图表参数
     */
K
kener 已提交
59 60
    function Legend(ecTheme, messageCenter, zr, option, myChart) {
        if (!this.query(option, 'legend.data')) {
K
jshint  
kener 已提交
61
            console.error('option.legend.data has not been defined.');
K
kener 已提交
62 63 64 65
            return;
        }
        
        Base.call(this, ecTheme, messageCenter, zr, option, myChart);
K
kener 已提交
66
        
K
jshint  
kener 已提交
67 68 69 70
        var self = this;
        self._legendSelected = function (param) {
            self.__legendSelected(param);
        };
K
kener 已提交
71 72 73
        self._dispatchHoverLink = function(param) {
            return self.__dispatchHoverLink(param);
        };
K
jshint  
kener 已提交
74
        
K
kener 已提交
75 76 77
        this._colorIndex = 0;
        this._colorMap = {};
        this._selectedMap = {};
78
        this._hasDataMap = {};
K
kener 已提交
79 80
        
        this.refresh(option);
K
kener 已提交
81 82 83
    }
    
    Legend.prototype = {
84 85
        type: ecConfig.COMPONENT_TYPE_LEGEND,
        _buildShape: function () {
K
kener 已提交
86 87 88
            if (!this.legendOption.show) {
                return;
            }
K
kener 已提交
89
            // 图例元素组的位置参数,通过计算所得x, y, width, height
K
kener 已提交
90
            this._itemGroupLocation = this._getItemGroupLocation();
K
kener 已提交
91

K
kener 已提交
92 93
            this._buildBackground();
            this._buildItem();
K
kener 已提交
94

K
kener 已提交
95 96
            for (var i = 0, l = this.shapeList.length; i < l; i++) {
                this.zr.addShape(this.shapeList[i]);
K
kener 已提交
97
            }
K
kener 已提交
98
        },
K
kener 已提交
99 100 101 102

        /**
         * 构建所有图例元素
         */
103
        _buildItem: function () {
K
kener 已提交
104
            var data = this.legendOption.data;
K
kener 已提交
105 106 107 108 109
            var dataLength = data.length;
            var itemName;
            var itemType;
            var itemShape;
            var textShape;
K
kener 已提交
110
            var textStyle  = this.legendOption.textStyle;
111 112
            var dataTextStyle;
            var dataFont;
K
jshint  
kener 已提交
113
            var formattedName;
K
kener 已提交
114

K
kener 已提交
115 116 117 118 119 120 121
            var zrWidth = this.zr.getWidth();
            var zrHeight = this.zr.getHeight();
            var lastX = this._itemGroupLocation.x;
            var lastY = this._itemGroupLocation.y;
            var itemWidth = this.legendOption.itemWidth;
            var itemHeight = this.legendOption.itemHeight;
            var itemGap = this.legendOption.itemGap;
K
kener 已提交
122 123
            var color;

124
            if (this.legendOption.orient === 'vertical' && this.legendOption.x === 'right') {
K
kener 已提交
125 126
                lastX = this._itemGroupLocation.x
                        + this._itemGroupLocation.width
K
kener 已提交
127 128 129 130
                        - itemWidth;
            }

            for (var i = 0; i < dataLength; i++) {
131 132
                dataTextStyle = zrUtil.merge(
                    data[i].textStyle || {},
K
kener 已提交
133
                    textStyle
134
                );
K
kener 已提交
135
                dataFont = this.getFont(dataTextStyle);
136
                
K
kener 已提交
137
                itemName = this._getName(data[i]);
K
jshint  
kener 已提交
138
                formattedName = this._getFormatterName(itemName);
139 140
                if (itemName === '') { // 别帮我代码优化
                    if (this.legendOption.orient === 'horizontal') {
K
kener 已提交
141
                        lastX = this._itemGroupLocation.x;
K
kener 已提交
142 143 144
                        lastY += itemHeight + itemGap;
                    }
                    else {
145
                        this.legendOption.x === 'right'
K
kener 已提交
146 147
                            ? lastX -= this._itemGroupLocation.maxWidth + itemGap
                            : lastX += this._itemGroupLocation.maxWidth + itemGap;
K
kener 已提交
148
                        lastY = this._itemGroupLocation.y;
K
kener 已提交
149 150 151
                    }
                    continue;
                }
K
kener 已提交
152
                itemType = data[i].icon || this._getSomethingByName(itemName).type;
K
kener 已提交
153
                
K
kener 已提交
154
                color = this.getColor(itemName);
K
kener 已提交
155

156
                if (this.legendOption.orient === 'horizontal') {
K
kener 已提交
157
                    if (zrWidth - lastX < 200   // 最后200px做分行预判
F
fanlia 已提交
158
                        && (itemWidth + 5 + zrArea.getTextWidth(formattedName, dataFont)
K
kener 已提交
159
                            // 分行的最后一个不用算itemGap
160
                            + (i === dataLength - 1 || data[i + 1] === '' ? 0 : itemGap)
K
kener 已提交
161
                           ) >= zrWidth - lastX
K
kener 已提交
162
                    ) {
K
kener 已提交
163
                        lastX = this._itemGroupLocation.x;
K
kener 已提交
164 165 166
                        lastY += itemHeight + itemGap;
                    }
                }
K
kener 已提交
167 168 169 170
                else {
                    if (zrHeight - lastY < 200   // 最后200px做分行预判
                        && (itemHeight
                            // 分行的最后一个不用算itemGap
171 172 173
                            + (i === dataLength - 1 || data[i + 1] === '' ? 0 : itemGap)
                           ) 
                           >= zrHeight - lastY
K
kener 已提交
174
                    ) {
175
                        this.legendOption.x === 'right'
K
kener 已提交
176 177 178
                        ? lastX -= this._itemGroupLocation.maxWidth + itemGap
                        : lastX += this._itemGroupLocation.maxWidth + itemGap;
                        lastY = this._itemGroupLocation.y;
K
kener 已提交
179 180
                    }
                }
K
kener 已提交
181 182

                // 图形
K
kener 已提交
183
                itemShape = this._getItemShapeByType(
K
kener 已提交
184 185
                    lastX, lastY,
                    itemWidth, itemHeight,
186
                    (this._selectedMap[itemName] && this._hasDataMap[itemName] ? color : '#ccc'),
187 188
                    itemType,
                    color
K
kener 已提交
189 190
                );
                itemShape._name = itemName;
K
kener 已提交
191
                itemShape = new IconShape(itemShape);
K
kener 已提交
192 193 194

                // 文字
                textShape = {
195
                    // shape: 'text',
196 197
                    zlevel: this.getZlevelBase(),
                    z: this.getZBase(),
198 199 200 201
                    style: {
                        x: lastX + itemWidth + 5,
                        y: lastY + itemHeight / 2,
                        color: this._selectedMap[itemName]
202
                                ? (dataTextStyle.color === 'auto' ? color : dataTextStyle.color)
K
kener 已提交
203
                                : '#ccc',
F
fanlia 已提交
204
                        text: formattedName,
205
                        textFont: dataFont,
K
kener 已提交
206
                        textBaseline: 'middle'
K
kener 已提交
207
                    },
208 209
                    highlightStyle: {
                        color: color,
210 211
                        brushType: 'fill'
                    },
212 213
                    hoverable: !!this.legendOption.selectedMode,
                    clickable: !!this.legendOption.selectedMode
K
kener 已提交
214 215
                };

216 217
                if (this.legendOption.orient === 'vertical'
                    && this.legendOption.x === 'right'
K
kener 已提交
218 219 220 221 222 223
                ) {
                    textShape.style.x -= (itemWidth + 10);
                    textShape.style.textAlign = 'right';
                }

                textShape._name = itemName;
K
kener 已提交
224 225
                textShape = new TextShape(textShape);
                
K
kener 已提交
226
                if (this.legendOption.selectedMode) {
K
jshint  
kener 已提交
227
                    itemShape.onclick = textShape.onclick = this._legendSelected;
K
kener 已提交
228
                    itemShape.onmouseover =  textShape.onmouseover = this._dispatchHoverLink;
K
kener 已提交
229 230
                    itemShape.hoverConnect = textShape.id;
                    textShape.hoverConnect = itemShape.id;
231
                }
K
kener 已提交
232 233
                this.shapeList.push(itemShape);
                this.shapeList.push(textShape);
K
kener 已提交
234

235
                if (this.legendOption.orient === 'horizontal') {
K
kener 已提交
236
                    lastX += itemWidth + 5
F
fanlia 已提交
237
                             + zrArea.getTextWidth(formattedName, dataFont)
K
kener 已提交
238 239 240 241 242 243
                             + itemGap;
                }
                else {
                    lastY += itemHeight + itemGap;
                }
            }
K
kener 已提交
244
        
245 246
            if (this.legendOption.orient === 'horizontal'
                && this.legendOption.x === 'center'
K
kener 已提交
247
                && lastY != this._itemGroupLocation.y
K
kener 已提交
248 249
            ) {
                // 多行橫排居中优化
K
kener 已提交
250
                this._mLineOptimize();
K
kener 已提交
251
            }
K
kener 已提交
252
        },
K
kener 已提交
253
        
254
        _getName: function(data) {
K
kener 已提交
255 256
            return typeof data.name != 'undefined' ? data.name : data;
        },
F
fanlia 已提交
257 258 259 260

        _getFormatterName: function(itemName) {
            var formatter = this.legendOption.formatter;
            var formattedName;
261
            if (typeof formatter === 'function') {
F
fanlia 已提交
262 263
                formattedName = formatter.call(this.myChart, itemName);
            }
264
            else if (typeof formatter === 'string') {
F
fanlia 已提交
265 266 267 268 269 270 271 272 273 274 275 276
                formattedName = formatter.replace('{name}', itemName);
            }
            else {
                formattedName = itemName;
            }
            return formattedName;
        },

        _getFormatterNameFromData: function(data) {
            var itemName = this._getName(data);
            return this._getFormatterName(itemName);
        },
K
kener 已提交
277
        
K
kener 已提交
278
        // 多行橫排居中优化
279
        _mLineOptimize: function () {
K
kener 已提交
280
            var lineOffsetArray = []; // 每行宽度
K
kener 已提交
281 282
            var lastX = this._itemGroupLocation.x;
            for (var i = 2, l = this.shapeList.length; i < l; i++) {
283
                if (this.shapeList[i].style.x === lastX) {
K
kener 已提交
284 285
                    lineOffsetArray.push(
                        (
K
kener 已提交
286
                            this._itemGroupLocation.width 
K
kener 已提交
287
                            - (
K
kener 已提交
288
                                this.shapeList[i - 1].style.x
K
kener 已提交
289
                                + zrArea.getTextWidth(
K
kener 已提交
290 291
                                      this.shapeList[i - 1].style.text,
                                      this.shapeList[i - 1].style.textFont
K
kener 已提交
292 293 294 295 296
                                  )
                                - lastX
                            )
                        ) / 2
                    );
K
kener 已提交
297
                }
298
                else if (i === l - 1) {
K
kener 已提交
299 300
                    lineOffsetArray.push(
                        (
K
kener 已提交
301
                            this._itemGroupLocation.width 
K
kener 已提交
302
                            - (
K
kener 已提交
303
                                this.shapeList[i].style.x
K
kener 已提交
304
                                + zrArea.getTextWidth(
K
kener 已提交
305 306
                                      this.shapeList[i].style.text,
                                      this.shapeList[i].style.textFont
K
kener 已提交
307 308 309 310 311 312 313 314
                                  )
                                - lastX
                            )
                        ) / 2
                    );
                }
            }
            var curLineIndex = -1;
K
kener 已提交
315
            for (var i = 1, l = this.shapeList.length; i < l; i++) {
316
                if (this.shapeList[i].style.x === lastX) {
K
kener 已提交
317 318 319 320 321 322
                    curLineIndex++;
                }
                if (lineOffsetArray[curLineIndex] === 0) {
                    continue;
                }
                else {
K
kener 已提交
323
                    this.shapeList[i].style.x += lineOffsetArray[curLineIndex];
K
kener 已提交
324 325
                }
            }
K
kener 已提交
326
        },
K
kener 已提交
327

328
        _buildBackground: function () {
K
kener 已提交
329
            var padding = this.reformCssArray(this.legendOption.padding);
K
kener 已提交
330

K
kener 已提交
331
            this.shapeList.push(new RectangleShape({
332 333
                zlevel: this.getZlevelBase(),
                z: this.getZBase(),
K
kener 已提交
334
                hoverable :false,
335
                style: {
K
kener 已提交
336 337 338 339
                    x: this._itemGroupLocation.x - padding[3],
                    y: this._itemGroupLocation.y - padding[0],
                    width: this._itemGroupLocation.width + padding[3] + padding[1],
                    height: this._itemGroupLocation.height + padding[0] + padding[2],
340 341 342 343
                    brushType: this.legendOption.borderWidth === 0 ? 'fill' : 'both',
                    color: this.legendOption.backgroundColor,
                    strokeColor: this.legendOption.borderColor,
                    lineWidth: this.legendOption.borderWidth
K
kener 已提交
344
                }
K
kener 已提交
345
            }));
K
kener 已提交
346
        },
K
kener 已提交
347 348 349 350

        /**
         * 根据选项计算图例实体的位置坐标
         */
351
        _getItemGroupLocation: function () {
K
kener 已提交
352
            var data = this.legendOption.data;
K
kener 已提交
353
            var dataLength = data.length;
K
kener 已提交
354 355 356 357 358
            var itemGap = this.legendOption.itemGap;
            var itemWidth = this.legendOption.itemWidth + 5; // 5px是图形和文字的间隔,不可配
            var itemHeight = this.legendOption.itemHeight;
            var textStyle  = this.legendOption.textStyle;
            var font = this.getFont(textStyle);
K
kener 已提交
359 360
            var totalWidth = 0;
            var totalHeight = 0;
K
kener 已提交
361
            var padding = this.reformCssArray(this.legendOption.padding);
K
kener 已提交
362 363
            var zrWidth = this.zr.getWidth() - padding[1] - padding[3];
            var zrHeight = this.zr.getHeight() - padding[0] - padding[2];
K
kener 已提交
364 365 366
            
            var temp = 0; // 宽高计算,用于多行判断
            var maxWidth = 0; // 垂直布局有用
367
            if (this.legendOption.orient === 'horizontal') {
K
kener 已提交
368
                // 水平布局,计算总宽度
K
kener 已提交
369
                totalHeight = itemHeight;
K
kener 已提交
370
                for (var i = 0; i < dataLength; i++) {
K
kener 已提交
371
                    if (this._getName(data[i]) === '') {
K
kener 已提交
372
                        temp -= itemGap;
K
Kener 已提交
373
                        totalWidth = Math.max(totalWidth, temp);
K
kener 已提交
374 375 376 377
                        totalHeight += itemHeight + itemGap;
                        temp = 0;
                        continue;
                    }
K
Kener 已提交
378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397
                    var tempTextWidth = zrArea.getTextWidth(
                        this._getFormatterNameFromData(data[i]),
                        data[i].textStyle 
                        ? this.getFont(zrUtil.merge(
                            data[i].textStyle || {},
                            textStyle
                          ))
                        : font
                    );
                    if (temp + itemWidth + tempTextWidth + itemGap > zrWidth) {
                        // new line
                        temp -= itemGap;  // 减去最后一个的itemGap
                        totalWidth = Math.max(totalWidth, temp);
                        totalHeight += itemHeight + itemGap;
                        temp = 0;
                    }
                    else {
                        temp += itemWidth + tempTextWidth + itemGap;
                        totalWidth = Math.max(totalWidth, temp - itemGap);
                    }
K
kener 已提交
398 399 400 401 402 403 404 405
                }
            }
            else {
                // 垂直布局,计算总高度
                for (var i = 0; i < dataLength; i++) {
                    maxWidth = Math.max(
                        maxWidth,
                        zrArea.getTextWidth(
F
fanlia 已提交
406
                            this._getFormatterNameFromData(data[i]),
407
                            data[i].textStyle 
K
kener 已提交
408
                            ? this.getFont(zrUtil.merge(
409
                                  data[i].textStyle || {},
K
kener 已提交
410
                                  textStyle
411 412
                              ))
                            : font
K
kener 已提交
413 414 415
                        )
                    );
                }
K
kener 已提交
416 417 418
                maxWidth += itemWidth;
                totalWidth = maxWidth;
                for (var i = 0; i < dataLength; i++) {
K
kener 已提交
419
                    if (this._getName(data[i]) === '') {
K
kener 已提交
420
                        totalWidth += maxWidth + itemGap;
K
Kener 已提交
421 422
                        temp -= itemGap;  // 减去最后一个的itemGap
                        totalHeight = Math.max(totalHeight, temp);
K
kener 已提交
423 424 425
                        temp = 0;
                        continue;
                    }
K
Kener 已提交
426 427 428 429 430 431 432 433 434 435 436
                    if (temp + itemHeight + itemGap > zrHeight) {
                        // new line
                        totalWidth += maxWidth + itemGap;
                        temp -= itemGap;  // 减去最后一个的itemGap
                        totalHeight = Math.max(totalHeight, temp);
                        temp = 0;
                    }
                    else {
                        temp += itemHeight + itemGap;
                        totalHeight = Math.max(totalHeight, temp - itemGap);
                    }
K
kener 已提交
437
                }
K
kener 已提交
438 439
            }

K
kener 已提交
440 441
            zrWidth = this.zr.getWidth();
            zrHeight = this.zr.getHeight();
K
kener 已提交
442
            var x;
K
kener 已提交
443
            switch (this.legendOption.x) {
K
kener 已提交
444 445 446 447
                case 'center' :
                    x = Math.floor((zrWidth - totalWidth) / 2);
                    break;
                case 'left' :
K
kener 已提交
448
                    x = padding[3] + this.legendOption.borderWidth;
K
kener 已提交
449 450 451 452
                    break;
                case 'right' :
                    x = zrWidth
                        - totalWidth
K
kener 已提交
453 454
                        - padding[1]
                        - padding[3]
K
kener 已提交
455
                        - this.legendOption.borderWidth * 2;
K
kener 已提交
456 457
                    break;
                default :
K
kener 已提交
458
                    x = this.parsePercent(this.legendOption.x, zrWidth);
K
kener 已提交
459 460
                    break;
            }
K
kener 已提交
461
            
K
kener 已提交
462
            var y;
K
kener 已提交
463
            switch (this.legendOption.y) {
K
kener 已提交
464
                case 'top' :
K
kener 已提交
465
                    y = padding[0] + this.legendOption.borderWidth;
K
kener 已提交
466 467 468 469
                    break;
                case 'bottom' :
                    y = zrHeight
                        - totalHeight
K
kener 已提交
470 471
                        - padding[0]
                        - padding[2]
K
kener 已提交
472
                        - this.legendOption.borderWidth * 2;
K
kener 已提交
473 474 475 476 477
                    break;
                case 'center' :
                    y = Math.floor((zrHeight - totalHeight) / 2);
                    break;
                default :
K
kener 已提交
478
                    y = this.parsePercent(this.legendOption.y, zrHeight);
K
kener 已提交
479 480 481 482
                    break;
            }

            return {
483 484 485 486 487
                x: x,
                y: y,
                width: totalWidth,
                height: totalHeight,
                maxWidth: maxWidth
K
kener 已提交
488
            };
K
kener 已提交
489
        },
K
kener 已提交
490 491

        /**
K
kener 已提交
492
         * 根据名称返回series数据或data
K
kener 已提交
493
         */
494
        _getSomethingByName: function (name) {
K
kener 已提交
495
            var series = this.option.series;
K
kener 已提交
496
            var data;
K
kener 已提交
497
            for (var i = 0, l = series.length; i < l; i++) {
498
                if (series[i].name === name) {
K
kener 已提交
499
                    // 系列名称优先
K
kener 已提交
500
                    return {
501 502 503 504 505
                        type: series[i].type,
                        series: series[i],
                        seriesIndex: i,
                        data: null,
                        dataIndex: -1
K
kener 已提交
506
                    };
K
kener 已提交
507 508
                }

K
kener 已提交
509
                if (
510 511 512 513 514
                    series[i].type === ecConfig.CHART_TYPE_PIE 
                    || series[i].type === ecConfig.CHART_TYPE_RADAR
                    || series[i].type === ecConfig.CHART_TYPE_CHORD
                    || series[i].type === ecConfig.CHART_TYPE_FORCE
                    || series[i].type === ecConfig.CHART_TYPE_FUNNEL
K
kener 已提交
515
                ) {
516 517
                    data = series[i].categories || series[i].data || series[i].nodes;

K
kener 已提交
518
                    for (var j = 0, k = data.length; j < k; j++) {
519
                        if (data[j].name === name) {
K
kener 已提交
520
                            return {
521 522 523 524 525
                                type: series[i].type,
                                series: series[i],
                                seriesIndex: i,
                                data: data[j],
                                dataIndex: j
K
kener 已提交
526
                            };
K
kener 已提交
527 528
                        }
                    }
K
kener 已提交
529
                }
K
kener 已提交
530
            }
K
kener 已提交
531
            return {
532 533 534 535 536
                type: 'bar',
                series: null,
                seriesIndex: -1,
                data: null,
                dataIndex: -1
K
kener 已提交
537
            };
K
kener 已提交
538
        },
K
kener 已提交
539
        
540
        _getItemShapeByType: function (x, y, width, height, color, itemType, defaultColor) {
K
kener 已提交
541
            var highlightColor = color === '#ccc' ? defaultColor : color;
542
            var itemShape = {
543 544
                zlevel: this.getZlevelBase(),
                z: this.getZBase(),
545 546 547 548 549 550 551 552 553
                style: {
                    iconType: 'legendicon' + itemType,
                    x: x,
                    y: y,
                    width: width,
                    height: height,
                    color: color,
                    strokeColor: color,
                    lineWidth: 2
554 555
                },
                highlightStyle: {
556 557 558
                    color: highlightColor,
                    strokeColor: highlightColor,
                    lineWidth: 1
559
                },
560 561
                hoverable: this.legendOption.selectedMode,
                clickable: this.legendOption.selectedMode
562
            };
K
kener 已提交
563 564 565 566 567 568 569 570
            
            var imageLocation;
            if (itemType.match('image')) {
                var imageLocation = itemType.replace(
                    new RegExp('^image:\\/\\/'), ''
                );
                itemType = 'image';
            }
571
            // 特殊设置
K
kener 已提交
572
            switch (itemType) {
573
                case 'line':
574
                    itemShape.style.brushType = 'stroke';
575 576
                    itemShape.highlightStyle.lineWidth = 3;
                    break;
577
                case 'radar':
L
loutongbing 已提交
578
                case 'venn':
579
                case 'scatter':
580
                    itemShape.highlightStyle.lineWidth = 3;
581
                    break;
582
                case 'k':
583
                    itemShape.style.brushType = 'both';
584 585
                    itemShape.highlightStyle.lineWidth = 3;
                    itemShape.highlightStyle.color =
K
Kener 已提交
586 587 588
                    itemShape.style.color = this.deepQuery(
                        [this.ecTheme, ecConfig], 'k.itemStyle.normal.color'
                    ) || '#fff';
589
                    itemShape.style.strokeColor = color != '#ccc' 
K
Kener 已提交
590 591 592 593 594
                        ? (
                            this.deepQuery(
                                [this.ecTheme, ecConfig], 'k.itemStyle.normal.lineStyle.color'
                            ) || '#ff3200'
                        )
595
                        : color;
K
kener 已提交
596
                    break;
597
                case 'image':
K
kener 已提交
598 599 600 601 602 603
                    itemShape.style.iconType = 'image';
                    itemShape.style.image = imageLocation;
                    if (color === '#ccc') {
                        itemShape.style.opacity = 0.5;
                    }
                    break;
K
kener 已提交
604
            }
605
            return itemShape;
K
kener 已提交
606
        },
K
kener 已提交
607

608
        __legendSelected: function (param) {
K
kener 已提交
609
            var itemName = param.target._name;
K
kener 已提交
610 611 612
            if (this.legendOption.selectedMode === 'single') {
                for (var k in this._selectedMap) {
                    this._selectedMap[k] = false;
K
kener 已提交
613 614
                }
            }
K
kener 已提交
615 616
            this._selectedMap[itemName] = !this._selectedMap[itemName];
            this.messageCenter.dispatch(
K
kener 已提交
617 618
                ecConfig.EVENT.LEGEND_SELECTED,
                param.event,
K
kener 已提交
619
                {
620 621
                    selected: this._selectedMap,
                    target: itemName
K
kener 已提交
622 623
                },
                this.myChart
K
kener 已提交
624
            );
K
kener 已提交
625
        },
K
kener 已提交
626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641
        
        /**
         * 产生hover link事件 
         */
        __dispatchHoverLink : function(param) {
            this.messageCenter.dispatch(
                ecConfig.EVENT.LEGEND_HOVERLINK,
                param.event,
                {
                    target: param.target._name
                },
                this.myChart
            );
            return;
        },
        
K
kener 已提交
642 643 644
        /**
         * 刷新
         */
645
        refresh: function (newOption) {
K
kener 已提交
646
            if (newOption) {
K
kener 已提交
647
                this.option = newOption || this.option;
K
kener 已提交
648
                this.option.legend = this.reformOption(this.option.legend);
K
kener 已提交
649 650 651 652 653 654 655
                this.legendOption = this.option.legend;
                
                var data = this.legendOption.data || [];
                var itemName;
                var something;
                var color;
                var queryTarget;
K
kener 已提交
656 657 658 659 660 661 662
                if (this.legendOption.selected) {
                    for (var k in this.legendOption.selected) {
                        this._selectedMap[k] = typeof this._selectedMap[k] != 'undefined'
                                               ? this._selectedMap[k]
                                               : this.legendOption.selected[k];
                    }
                }
K
kener 已提交
663
                for (var i = 0, dataLength = data.length; i < dataLength; i++) {
K
kener 已提交
664
                    itemName = this._getName(data[i]);
K
kener 已提交
665 666 667 668 669
                    if (itemName === '') {
                        continue;
                    }
                    something = this._getSomethingByName(itemName);
                    if (!something.series) {
670
                        this._hasDataMap[itemName] = false;
K
kener 已提交
671 672
                    } 
                    else {
673
                        this._hasDataMap[itemName] = true;
K
kener 已提交
674
                        if (something.data
675 676 677
                            && (something.type === ecConfig.CHART_TYPE_PIE
                                || something.type === ecConfig.CHART_TYPE_FORCE
                                || something.type === ecConfig.CHART_TYPE_FUNNEL)
K
kener 已提交
678 679 680 681 682 683 684 685
                        ) {
                            queryTarget = [something.data, something.series];
                        }
                        else {
                            queryTarget = [something.series];
                        }
                        
                        color = this.getItemStyleColor(
K
kener 已提交
686
                            this.deepQuery(queryTarget, 'itemStyle.normal.color'),
K
kener 已提交
687 688 689 690 691 692 693
                            something.seriesIndex,
                            something.dataIndex,
                            something.data
                        );
                        if (color && something.type != ecConfig.CHART_TYPE_K) {
                            this.setColor(itemName, color);
                        }
K
kener 已提交
694
                        this._selectedMap[itemName] = 
695
                            this._selectedMap[itemName] != null
K
kener 已提交
696
                            ? this._selectedMap[itemName] : true; 
K
kener 已提交
697 698
                    }
                }
K
kener 已提交
699
            }
K
kener 已提交
700 701 702
            this.clear();
            this._buildShape();
        },
K
kener 已提交
703
        
704
        getRelatedAmount: function(name) {
K
kener 已提交
705 706 707 708
            var amount = 0;
            var series = this.option.series;
            var data;
            for (var i = 0, l = series.length; i < l; i++) {
709
                if (series[i].name === name) {
K
kener 已提交
710 711 712 713 714
                    // 系列名称优先
                    amount++;
                }

                if (
715 716 717 718 719
                    series[i].type === ecConfig.CHART_TYPE_PIE 
                    || series[i].type === ecConfig.CHART_TYPE_RADAR
                    || series[i].type === ecConfig.CHART_TYPE_CHORD
                    || series[i].type === ecConfig.CHART_TYPE_FORCE
                    || series[i].type === ecConfig.CHART_TYPE_FUNNEL
K
kener 已提交
720 721 722 723 724
                ) {
                    data = series[i].type != ecConfig.CHART_TYPE_FORCE
                           ? series[i].data         // 饼图、雷达图、和弦图得查找里面的数据名字
                           : series[i].categories;  // 力导布局查找categories配置
                    for (var j = 0, k = data.length; j < k; j++) {
725
                        if (data[j].name === name && data[j].value != '-') {
K
kener 已提交
726
                            amount++;
K
kener 已提交
727 728 729 730 731 732
                        }
                    }
                }
            }
            return amount;
        },
K
kener 已提交
733

734
        setColor: function (legendName, color) {
K
kener 已提交
735 736
            this._colorMap[legendName] = color;
        },
K
kener 已提交
737

738
        getColor: function (legendName) {
K
kener 已提交
739 740
            if (!this._colorMap[legendName]) {
                this._colorMap[legendName] = this.zr.getColor(this._colorIndex++);
K
kener 已提交
741
            }
K
kener 已提交
742 743
            return this._colorMap[legendName];
        },
K
kener 已提交
744
        
745
        hasColor: function (legendName) {
K
kener 已提交
746 747
            return this._colorMap[legendName] ? this._colorMap[legendName] : false;
        },
K
kener 已提交
748

749
        add: function (name, color){
K
kener 已提交
750 751
            var data = this.legendOption.data;
            for (var i = 0, dataLength = data.length; i < dataLength; i++) {
752
                if (this._getName(data[i]) === name) {
K
kener 已提交
753 754 755 756
                    // 已有就不重复加了
                    return;
                }
            }
K
kener 已提交
757 758 759
            this.legendOption.data.push(name);
            this.setColor(name,color);
            this._selectedMap[name] = true;
760
            this._hasDataMap[name] = true;
K
kener 已提交
761
        },
K
kener 已提交
762

763
        del: function (name){
K
kener 已提交
764
            var data = this.legendOption.data;
K
kener 已提交
765
            for (var i = 0, dataLength = data.length; i < dataLength; i++) {
766
                if (this._getName(data[i]) === name) {
K
kener 已提交
767
                    return this.legendOption.data.splice(i, 1);
K
kener 已提交
768 769
                }
            }
K
kener 已提交
770
        },
771 772 773 774 775 776
        
        /**
         * 特殊图形元素回调设置
         * @param {Object} name
         * @param {Object} itemShape
         */
777 778
        getItemShape: function (name) {
            if (name == null) {
K
kener 已提交
779 780
                return;
            }
781
            var shape;
K
kener 已提交
782 783
            for (var i = 0, l = this.shapeList.length; i < l; i++) {
                shape = this.shapeList[i];
784
                if (shape._name === name && shape.type != 'text') {
785 786 787
                    return shape;
                }
            }
K
kener 已提交
788
        },
789 790 791 792 793 794
        
        /**
         * 特殊图形元素回调设置
         * @param {Object} name
         * @param {Object} itemShape
         */
795
        setItemShape: function (name, itemShape) {
796
            var shape;
K
kener 已提交
797 798
            for (var i = 0, l = this.shapeList.length; i < l; i++) {
                shape = this.shapeList[i];
799
                if (shape._name === name && shape.type != 'text') {
K
kener 已提交
800
                    if (!this._selectedMap[name]) {
801 802 803
                        itemShape.style.color = '#ccc';
                        itemShape.style.strokeColor = '#ccc';
                    }
K
kener 已提交
804
                    this.zr.modShape(shape.id, itemShape);
805 806
                }
            }
K
kener 已提交
807
        },
K
kener 已提交
808

809
        isSelected: function (itemName) {
K
kener 已提交
810 811
            if (typeof this._selectedMap[itemName] != 'undefined') {
                return this._selectedMap[itemName];
K
kener 已提交
812 813 814 815 816
            }
            else {
                // 没在legend里定义的都为true啊~
                return true;
            }
K
kener 已提交
817
        },
K
kener 已提交
818
        
819
        getSelectedMap: function () {
K
kener 已提交
820 821
            return this._selectedMap;
        },
K
kener 已提交
822
        
823
        setSelected: function(itemName, selectStatus) {
K
kener 已提交
824 825 826 827 828 829 830 831
            if (this.legendOption.selectedMode === 'single') {
                for (var k in this._selectedMap) {
                    this._selectedMap[k] = false;
                }
            }
            this._selectedMap[itemName] = selectStatus;
            this.messageCenter.dispatch(
                ecConfig.EVENT.LEGEND_SELECTED,
K
kener 已提交
832
                null,
K
kener 已提交
833
                {
834 835
                    selected: this._selectedMap,
                    target: itemName
K
kener 已提交
836 837
                },
                this.myChart
K
kener 已提交
838 839 840
            );
        },
        
K
kener 已提交
841 842 843
        /**
         * 图例选择
         */
844
        onlegendSelected: function (param, status) {
K
kener 已提交
845
            var legendSelected = param.selected;
K
kener 已提交
846
            for (var itemName in legendSelected) {
K
kener 已提交
847
                if (this._selectedMap[itemName] != legendSelected[itemName]) {
K
kener 已提交
848 849 850
                    // 有一项不一致都需要重绘
                    status.needRefresh = true;
                }
K
kener 已提交
851
                this._selectedMap[itemName] = legendSelected[itemName];
K
kener 已提交
852 853 854
            }
            return;
        }
K
jshint  
kener 已提交
855
    };
856 857
    
    var legendIcon = {
858
        line: function (ctx, style) {
859 860 861 862
            var dy = style.height / 2;
            ctx.moveTo(style.x,     style.y + dy);
            ctx.lineTo(style.x + style.width,style.y + dy);
        },
K
kener 已提交
863
        
864
        pie: function (ctx, style) {
865 866 867 868
            var x = style.x;
            var y = style.y;
            var width = style.width;
            var height = style.height;
K
kener 已提交
869
            SectorShape.prototype.buildPath(ctx, {
870 871
                x: x + width / 2,
                y: y + height + 2,
K
kener 已提交
872
                r: height,
873 874 875
                r0: 6,
                startAngle: 45,
                endAngle: 135
876
            });
K
kener 已提交
877
        },
K
kener 已提交
878 879
        
        eventRiver: function (ctx, style) {
K
kener 已提交
880 881 882 883 884
            var x = style.x;
            var y = style.y;
            var width = style.width;
            var height = style.height;
            ctx.moveTo(x, y + height);
K
kener 已提交
885 886 887
            ctx.bezierCurveTo(
                x + width, y + height, x, y + 4, x + width, y + 4
            );
K
kener 已提交
888
            ctx.lineTo(x + width, y);
K
kener 已提交
889 890 891
            ctx.bezierCurveTo(
                x, y, x + width, y + height - 4, x, y + height - 4
            );
K
kener 已提交
892 893
            ctx.lineTo(x, y + height);
        },
K
kener 已提交
894
        
895
        k: function (ctx, style) {
896 897 898 899
            var x = style.x;
            var y = style.y;
            var width = style.width;
            var height = style.height;
K
kener 已提交
900
            CandleShape.prototype.buildPath(ctx, {
901 902 903
                x: x + width / 2,
                y: [y + 1, y + 1, y + height - 6, y + height],
                width: width - 6
904 905
            });
        },
K
kener 已提交
906
        
907
        bar: function (ctx, style) {
K
kener 已提交
908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928
            var x = style.x;
            var y = style.y +1;
            var width = style.width;
            var height = style.height - 2;
            var r = 3;
            
            ctx.moveTo(x + r, y);
            ctx.lineTo(x + width - r, y);
            ctx.quadraticCurveTo(
                x + width, y, x + width, y + r
            );
            ctx.lineTo(x + width, y + height - r);
            ctx.quadraticCurveTo(
                x + width, y + height, x + width - r, y + height
            );
            ctx.lineTo(x + r, y + height);
            ctx.quadraticCurveTo(
                x, y + height, x, y + height - r
            );
            ctx.lineTo(x, y + r);
            ctx.quadraticCurveTo(x, y, x + r, y);
K
kener 已提交
929
        },
K
kener 已提交
930
        
931
        force: function (ctx, style) {
K
kener 已提交
932
            IconShape.prototype.iconLibrary.circle(ctx, style);
K
kener 已提交
933
        },
K
kener 已提交
934
        
K
kener 已提交
935
        radar: function (ctx, style) {
K
kener 已提交
936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952
            var n = 6;
            var x = style.x + style.width / 2;
            var y = style.y + style.height / 2;
            var r = style.height / 2;

            var dStep = 2 * Math.PI / n;
            var deg = -Math.PI / 2;
            var xStart = x + r * Math.cos(deg);
            var yStart = y + r * Math.sin(deg);
            
            ctx.moveTo(xStart, yStart);
            deg += dStep;
            for (var i = 0, end = n - 1; i < end; i ++) {
                ctx.lineTo(x + r * Math.cos(deg), y + r * Math.sin(deg));
                deg += dStep;
            }
            ctx.lineTo(xStart, yStart);
953
        }
K
kener 已提交
954
    };
K
kener 已提交
955 956
    legendIcon.chord = legendIcon.pie;
    legendIcon.map = legendIcon.bar;
957
    
K
kener 已提交
958 959 960 961
    for (var k in legendIcon) {
        IconShape.prototype.iconLibrary['legendicon' + k] = legendIcon[k];
    }
    
K
kener 已提交
962 963
    zrUtil.inherits(Legend, Base);
    
964 965
    require('../component').define('legend', Legend);
    
K
kener 已提交
966 967 968 969
    return Legend;
});