bar.js 40.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
 *
 */
K
kener 已提交
8 9
define(function (require) {
    var ComponentBase = require('../component/base');
K
kener 已提交
10
    var ChartBase = require('./base');
K
kener 已提交
11
    
K
kener 已提交
12
    // 图形依赖
K
kener 已提交
13
    var RectangleShape = require('zrender/shape/Rectangle');
K
kener 已提交
14 15 16 17
    // 组件依赖
    require('../component/axis');
    require('../component/grid');
    require('../component/dataZoom');
K
kener 已提交
18
    
K
kener 已提交
19 20 21 22 23
    var ecConfig = require('../config');
    var ecData = require('../util/ecData');
    var zrUtil = require('zrender/tool/util');
    var zrColor = require('zrender/tool/color');
    
K
kener 已提交
24 25 26 27 28 29 30
    /**
     * 构造函数
     * @param {Object} messageCenter echart消息中心
     * @param {ZRender} zr zrender实例
     * @param {Object} series 数据
     * @param {Object} component 组件
     */
K
kener 已提交
31
    function Bar(ecTheme, messageCenter, zr, option, myChart){
K
kener 已提交
32
        // 基类
K
kener 已提交
33
        ComponentBase.call(this, ecTheme, messageCenter, zr, option, myChart);
K
kener 已提交
34 35
        // 图表基类
        ChartBase.call(this);
K
kener 已提交
36
        
K
kener 已提交
37
        this.refresh(option);
K
kener 已提交
38 39 40
    }
    
    Bar.prototype = {
41
        type: ecConfig.CHART_TYPE_BAR,
K
kener 已提交
42 43 44
        /**
         * 绘制图形
         */
45
        _buildShape: function () {
L
lang 已提交
46
            this._buildPosition();
K
kener 已提交
47
        },
K
kener 已提交
48 49
        
        _buildNormal: function(seriesArray, maxDataLength, locationMap, xMarkMap, orient) {
K
kener 已提交
50
            var series = this.series;
K
kener 已提交
51 52 53 54
            // 确定类目轴和数值轴,同一方向随便找一个即可
            var seriesIndex = locationMap[0][0];
            var serie = series[seriesIndex];
            var xAxisIndex = serie.xAxisIndex;
K
kener 已提交
55 56 57 58
            var yAxisIndex = serie.yAxisIndex;
            var categoryAxis = orient == 'horizontal' 
                ? this.component.xAxis.getAxis(xAxisIndex)
                : this.component.yAxis.getAxis(yAxisIndex);
K
kener 已提交
59 60
            var valueAxis;  // 数值轴各异

K
kener 已提交
61
            var size = this._mapSize(categoryAxis, locationMap);
K
kener 已提交
62 63 64
            var gap = size.gap;
            var barGap = size.barGap;
            var barWidthMap = size.barWidthMap;
K
kener 已提交
65
            var barMaxWidthMap = size.barMaxWidthMap;
K
kener 已提交
66 67 68
            var barWidth = size.barWidth;                   // 自适应宽度
            var barMinHeightMap = size.barMinHeightMap;
            var barHeight;
K
kener 已提交
69
            var curBarWidth;
K
kener 已提交
70
            var interval = size.interval;
K
kener 已提交
71 72 73

            var x;
            var y;
K
kener 已提交
74 75 76 77
            var lastP; // 正向堆积处理
            var baseP;
            var lastN; // 负向堆积处理
            var baseN;
K
kener 已提交
78 79 80 81
            var barShape;
            var data;
            var value;
            for (var i = 0, l = maxDataLength; i < l; i++) {
82
                if (categoryAxis.getNameByIndex(i) == null) {
K
kener 已提交
83 84 85
                    // 系列数据超出类目轴长度
                    break;
                }
K
kener 已提交
86 87 88
                orient == 'horizontal'
                    ? (x = categoryAxis.getCoordByIndex(i) - gap / 2)
                    : (y = categoryAxis.getCoordByIndex(i) + gap / 2);
K
kener 已提交
89
                for (var j = 0, k = locationMap.length; j < k; j++) {
K
kener 已提交
90
                    // 堆积数据用第一条valueAxis
K
kener 已提交
91
                    yAxisIndex = series[locationMap[j][0]].yAxisIndex || 0;
K
kener 已提交
92 93 94 95 96
                    xAxisIndex = series[locationMap[j][0]].xAxisIndex || 0;
                    valueAxis = orient == 'horizontal' 
                        ? this.component.yAxis.getAxis(yAxisIndex)
                        : this.component.xAxis.getAxis(xAxisIndex);
                    baseP = lastP = baseN = lastN = valueAxis.getCoord(0);
K
kener 已提交
97 98 99 100
                    for (var m = 0, n = locationMap[j].length; m < n; m++) {
                        seriesIndex = locationMap[j][m];
                        serie = series[seriesIndex];
                        data = serie.data[i];
K
Kener 已提交
101
                        value = this.getDataFromOption(data, '-');
K
kener 已提交
102 103
                        xMarkMap[seriesIndex] = xMarkMap[seriesIndex] 
                                                || {
104 105 106 107 108
                                                    min: Number.POSITIVE_INFINITY,
                                                    max: Number.NEGATIVE_INFINITY,
                                                    sum: 0,
                                                    counter: 0,
                                                    average: 0
K
kener 已提交
109
                                                };
110
                        if (value === '-') {
K
kener 已提交
111 112 113 114
                            // 空数据在做完后补充拖拽提示框
                            continue;
                        }
                        if (value > 0) {
K
kener 已提交
115
                            // 正向堆积
116 117
                            barHeight = m > 0 
                                        ? valueAxis.getCoordSize(value)
K
kener 已提交
118 119 120 121 122
                                        : (
                                            orient == 'horizontal'
                                            ? (baseP - valueAxis.getCoord(value))
                                            : (valueAxis.getCoord(value) - baseP)
                                        );
K
kener 已提交
123
                            // 非堆积数据最小高度有效
K
kener 已提交
124
                            if (n === 1 && barMinHeightMap[seriesIndex] > barHeight) {
K
kener 已提交
125 126
                                barHeight = barMinHeightMap[seriesIndex];
                            }
K
kener 已提交
127 128 129 130 131 132 133 134
                            if (orient == 'horizontal') {
                                lastP -= barHeight;
                                y = lastP;
                            }
                            else {
                                x = lastP;
                                lastP += barHeight;
                            }
K
kener 已提交
135 136
                        }
                        else if (value < 0){
K
kener 已提交
137
                            // 负向堆积
138 139
                            barHeight = m > 0 
                                        ? valueAxis.getCoordSize(value)
K
kener 已提交
140 141 142 143 144
                                        : (
                                            orient == 'horizontal'
                                            ? (valueAxis.getCoord(value) - baseN)
                                            : (baseN - valueAxis.getCoord(value))
                                        );
K
kener 已提交
145
                            // 非堆积数据最小高度有效
K
kener 已提交
146
                            if (n === 1 && barMinHeightMap[seriesIndex] > barHeight) {
K
kener 已提交
147 148
                                barHeight = barMinHeightMap[seriesIndex];
                            }
K
kener 已提交
149 150 151 152 153 154 155 156
                            if (orient == 'horizontal') {
                                y = lastN;
                                lastN += barHeight;
                            }
                            else {
                                lastN -= barHeight;
                                x = lastN;
                            }
K
kener 已提交
157 158 159
                        }
                        else {
                            // 0值
K
kener 已提交
160
                            barHeight = 0;
K
kener 已提交
161
                            // 最小高度无效
K
kener 已提交
162 163 164 165 166 167 168 169
                            if (orient == 'horizontal') {
                                lastP -= barHeight;
                                y = lastP;
                            }
                            else {
                                x = lastP;
                                lastP += barHeight;
                            }
K
kener 已提交
170
                        }
L
jshint  
lang 已提交
171
                        var curBarWidth = Math.min(
K
kener 已提交
172 173 174 175
                            barMaxWidthMap[seriesIndex] || Number.MAX_VALUE,
                            barWidthMap[seriesIndex] || barWidth
                        );
                        xMarkMap[seriesIndex][i] = orient == 'horizontal'
L
jshint  
lang 已提交
176 177
                                                   ? (x + curBarWidth / 2) 
                                                   : (y - curBarWidth / 2);
178 179
                        if (xMarkMap[seriesIndex].min > value) {
                            xMarkMap[seriesIndex].min = value;
K
kener 已提交
180 181 182 183 184 185 186 187
                            if (orient == 'horizontal') {
                                xMarkMap[seriesIndex].minY = y;
                                xMarkMap[seriesIndex].minX = xMarkMap[seriesIndex][i];
                            }
                            else {
                                xMarkMap[seriesIndex].minX = x + barHeight;
                                xMarkMap[seriesIndex].minY = xMarkMap[seriesIndex][i];
                            }
188 189 190
                        }
                        if (xMarkMap[seriesIndex].max < value) {
                            xMarkMap[seriesIndex].max = value;
K
kener 已提交
191 192 193 194 195 196 197 198 199
                            if (orient == 'horizontal') {
                                xMarkMap[seriesIndex].maxY = y;
                                xMarkMap[seriesIndex].maxX = xMarkMap[seriesIndex][i];
                            }
                            else {
                                xMarkMap[seriesIndex].maxX = x + barHeight;
                                xMarkMap[seriesIndex].maxY = xMarkMap[seriesIndex][i];
                            }
                            
200 201 202
                        }
                        xMarkMap[seriesIndex].sum += value;
                        xMarkMap[seriesIndex].counter++;
K
kener 已提交
203
                        
K
kener 已提交
204
                        if (i % interval === 0) {
K
kener 已提交
205 206 207
                            barShape = this._getBarItem(
                                seriesIndex, i,
                                categoryAxis.getNameByIndex(i),
K
kener 已提交
208
                                x,
L
jshint  
lang 已提交
209 210 211
                                y - (orient == 'horizontal' ? 0 : curBarWidth),
                                orient == 'horizontal' ? curBarWidth : barHeight,
                                orient == 'horizontal' ? barHeight : curBarWidth,
K
kener 已提交
212
                                orient == 'horizontal' ? 'vertical' : 'horizontal'
K
kener 已提交
213 214 215
                            );
                            this.shapeList.push(new RectangleShape(barShape));
                        }
K
kener 已提交
216 217 218 219 220 221 222
                    }

                    // 补充空数据的拖拽提示框
                    for (var m = 0, n = locationMap[j].length; m < n; m++) {
                        seriesIndex = locationMap[j][m];
                        serie = series[seriesIndex];
                        data = serie.data[i];
K
Kener 已提交
223
                        value = this.getDataFromOption(data, '-');
K
kener 已提交
224 225 226 227 228
                        if (value != '-') {
                            // 只关心空数据
                            continue;
                        }

K
kener 已提交
229
                        if (this.deepQuery([data, serie, this.option], 'calculable')) {
K
kener 已提交
230 231 232 233 234 235 236 237 238
                            if (orient == 'horizontal') {
                                lastP -= this.ecTheme.island.r;
                                y = lastP;
                            }
                            else {
                                x = lastP;
                                lastP += this.ecTheme.island.r;
                            }
                            
L
jshint  
lang 已提交
239
                            curBarWidth = Math.min(
K
kener 已提交
240 241 242
                                barMaxWidthMap[seriesIndex] || Number.MAX_VALUE,
                                barWidthMap[seriesIndex] || barWidth
                            );
K
kener 已提交
243
                            barShape = this._getBarItem(
K
kener 已提交
244 245
                                seriesIndex, i,
                                categoryAxis.getNameByIndex(i),
K
kener 已提交
246
                                x + 0.5,
L
jshint  
lang 已提交
247 248 249
                                y + 0.5 - (orient == 'horizontal' ? 0 : curBarWidth),
                                (orient == 'horizontal' ? curBarWidth : this.ecTheme.island.r) - 1,
                                (orient == 'horizontal' ? this.ecTheme.island.r : curBarWidth) - 1,
K
kener 已提交
250
                                orient == 'horizontal' ? 'vertical' : 'horizontal'
K
kener 已提交
251 252 253
                            );
                            barShape.hoverable = false;
                            barShape.draggable = false;
K
kener 已提交
254
                            barShape.style.lineWidth = 1;
K
kener 已提交
255
                            barShape.style.brushType = 'stroke';
K
kener 已提交
256 257
                            barShape.style.strokeColor = serie.calculableHolderColor
                                                         || this.ecTheme.calculableHolderColor;
K
kener 已提交
258

K
kener 已提交
259
                            this.shapeList.push(new RectangleShape(barShape));
K
kener 已提交
260 261
                        }
                    }
K
kener 已提交
262
                    orient == 'horizontal'
L
jshint  
lang 已提交
263
                        ? (x += (curBarWidth + barGap)) : (y -= (curBarWidth + barGap));
K
kener 已提交
264 265
                }
            }
266
            
K
kener 已提交
267 268 269 270 271 272 273 274 275
            this._calculMarkMapXY(xMarkMap, locationMap, orient == 'horizontal' ? 'y' : 'x');
        },
        /**
         * 构建类目轴为水平方向的柱形图系列
         */
        _buildHorizontal: function (seriesArray, maxDataLength, locationMap, xMarkMap) {
            return this._buildNormal(
                seriesArray, maxDataLength, locationMap, xMarkMap, 'horizontal'
            );
K
kener 已提交
276
        },
K
kener 已提交
277 278 279 280

        /**
         * 构建类目轴为垂直方向的柱形图系列
         */
K
kener 已提交
281
        _buildVertical: function (seriesArray, maxDataLength, locationMap, xMarkMap) {
K
kener 已提交
282 283 284
            return this._buildNormal(
                seriesArray, maxDataLength, locationMap, xMarkMap, 'vertical'
            );
K
kener 已提交
285 286 287 288 289 290 291 292
        },
        
        /**
         * 构建双数值轴柱形图
         */
        _buildOther: function (seriesArray, maxDataLength, locationMap, xMarkMap) {
            var series = this.series;
            
293 294
            for (var j = 0, k = locationMap.length; j < k; j++) {
                for (var m = 0, n = locationMap[j].length; m < n; m++) {
K
kener 已提交
295 296 297 298 299 300 301 302
                    var seriesIndex = locationMap[j][m];
                    var serie = series[seriesIndex];
                    var xAxisIndex = serie.xAxisIndex || 0;
                    var xAxis = this.component.xAxis.getAxis(xAxisIndex);
                    var baseX = xAxis.getCoord(0);
                    var yAxisIndex = serie.yAxisIndex || 0;
                    var yAxis = this.component.yAxis.getAxis(yAxisIndex);
                    var baseY = yAxis.getCoord(0);
K
kener 已提交
303
                    
K
kener 已提交
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
                    xMarkMap[seriesIndex] = xMarkMap[seriesIndex] 
                                            || {
                                                min0: Number.POSITIVE_INFINITY,
                                                min1: Number.POSITIVE_INFINITY,
                                                max0: Number.NEGATIVE_INFINITY,
                                                max1: Number.NEGATIVE_INFINITY,
                                                sum0: 0,
                                                sum1: 0,
                                                counter0: 0,
                                                counter1: 0,
                                                average0: 0,
                                                average1: 0
                                            };

                    for (var i = 0, l = serie.data.length; i < l; i++) {
                        var data = serie.data[i];
K
Kener 已提交
320
                        var value = this.getDataFromOption(data, '-');
K
kener 已提交
321 322 323
                        if (!(value instanceof Array)) {
                            continue;
                        }
324
                        
K
kener 已提交
325 326 327 328 329 330 331
                        var x = xAxis.getCoord(value[0]);
                        var y = yAxis.getCoord(value[1]);
                        
                        var queryTarget = [data, serie];
                        var barWidth = this.deepQuery(queryTarget, 'barWidth') || 10; // 默认柱形
                        var barHeight = this.deepQuery(queryTarget, 'barHeight');
                        var orient;
K
jshint  
kener 已提交
332
                        var barShape;
K
kener 已提交
333 334 335 336 337 338 339 340 341 342 343 344 345 346 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 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 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419
                        
                        if (barHeight != null) {
                            // 条形图
                            orient = 'horizontal';
                            
                            if (value[0] > 0) {
                                // 正向
                                barWidth = x - baseX;
                                x -= barWidth;
                            }
                            else if (value[0] < 0){
                                // 负向
                                barWidth = baseX - x;
                            }
                            else {
                                // 0值
                                barWidth = 0;
                            }
                            
                            barShape = this._getBarItem(
                                seriesIndex, i,
                                value[0],
                                x, 
                                y - barHeight / 2,
                                barWidth,
                                barHeight,
                                orient
                            );
                        }
                        else {
                            // 柱形
                            orient = 'vertical';
                            
                            if (value[1] > 0) {
                            // 正向
                                barHeight = baseY - y;
                            }
                            else if (value[1] < 0){
                                // 负向
                                barHeight = y - baseY;
                                y -= barHeight;
                            }
                            else {
                                // 0值
                                barHeight = 0;
                            }
                            barShape = this._getBarItem(
                                seriesIndex, i,
                                value[0],
                                x - barWidth / 2, 
                                y,
                                barWidth,
                                barHeight,
                                orient
                            );
                        }
                        this.shapeList.push(new RectangleShape(barShape));
                        
                        
                        x = xAxis.getCoord(value[0]);
                        y = yAxis.getCoord(value[1]);
                        if (xMarkMap[seriesIndex].min0 > value[0]) {
                            xMarkMap[seriesIndex].min0 = value[0];
                            xMarkMap[seriesIndex].minY0 = y;
                            xMarkMap[seriesIndex].minX0 = x;
                        }
                        if (xMarkMap[seriesIndex].max0 < value[0]) {
                            xMarkMap[seriesIndex].max0 = value[0];
                            xMarkMap[seriesIndex].maxY0 = y;
                            xMarkMap[seriesIndex].maxX0 = x;
                        }
                        xMarkMap[seriesIndex].sum0 += value[0];
                        xMarkMap[seriesIndex].counter0++;
                        
                        if (xMarkMap[seriesIndex].min1 > value[1]) {
                            xMarkMap[seriesIndex].min1 = value[1];
                            xMarkMap[seriesIndex].minY1 = y;
                            xMarkMap[seriesIndex].minX1 = x;
                        }
                        if (xMarkMap[seriesIndex].max1 < value[1]) {
                            xMarkMap[seriesIndex].max1 = value[1];
                            xMarkMap[seriesIndex].maxY1 = y;
                            xMarkMap[seriesIndex].maxX1 = x;
                        }
                        xMarkMap[seriesIndex].sum1 += value[1];
                        xMarkMap[seriesIndex].counter1++;
                    }
420 421
                }
            }
K
kener 已提交
422 423
            
            this._calculMarkMapXY(xMarkMap, locationMap, 'xy');
K
kener 已提交
424
        },
K
kener 已提交
425
        
K
kener 已提交
426 427 428 429 430
        /**
         * 我真是自找麻烦啊,为啥要允许系列级个性化最小宽度和高度啊!!!
         * @param {CategoryAxis} categoryAxis 类目坐标轴,需要知道类目间隔大小
         * @param {Array} locationMap 整形数据的系列索引
         */
431
        _mapSize: function (categoryAxis, locationMap, ignoreUserDefined) {
K
kener 已提交
432 433 434 435 436 437 438 439 440
            var res = this._findSpecialBarSzie(locationMap, ignoreUserDefined);
            var barWidthMap = res.barWidthMap;
            var barMaxWidthMap = res.barMaxWidthMap;
            var barMinHeightMap = res.barMinHeightMap;
            var sBarWidthCounter = res.sBarWidthCounter;    // 用户指定
            var sBarWidthTotal = res.sBarWidthTotal;        // 用户指定
            var barGap = res.barGap;
            var barCategoryGap = res.barCategoryGap;
            
K
kener 已提交
441 442
            var gap;
            var barWidth;
K
kener 已提交
443
            var interval = 1;
K
kener 已提交
444 445
            if (locationMap.length != sBarWidthCounter) {
                // 至少存在一个自适应宽度的柱形图
K
kener 已提交
446
                if (!ignoreUserDefined) {
K
kener 已提交
447 448 449 450 451 452 453 454 455
                    gap = typeof barCategoryGap === 'string' && barCategoryGap.match(/%$/)
                          // 百分比
                          ? Math.floor(
                              categoryAxis.getGap() 
                              * (100 - parseFloat(barCategoryGap)) 
                              / 100
                            )
                          // 数值
                          : (categoryAxis.getGap() - barCategoryGap);
456
                    if (typeof barGap === 'string' && barGap.match(/%$/)) {
K
kener 已提交
457 458 459 460 461 462 463 464 465 466 467
                        barGap = parseFloat(barGap) / 100;
                        barWidth = Math.floor(
                            (gap - sBarWidthTotal)
                            / ((locationMap.length - 1) * barGap 
                               + locationMap.length - sBarWidthCounter)
                        );
                        barGap = Math.floor(barWidth * barGap);
                    }
                    else {
                        barGap = parseFloat(barGap);
                        barWidth = Math.floor(
K
kener 已提交
468
                            (gap - sBarWidthTotal - barGap * (locationMap.length - 1))
K
kener 已提交
469 470 471
                            / (locationMap.length - sBarWidthCounter)
                        );
                    }
K
kener 已提交
472
                    // 无法满足用户定义的宽度设计,忽略用户宽度,打回重做
K
kener 已提交
473
                    if (barWidth <= 0) {
K
kener 已提交
474
                        return this._mapSize(categoryAxis, locationMap, true);
K
kener 已提交
475 476 477 478 479 480 481 482
                    }
                }
                else {
                    // 忽略用户定义的宽度设定
                    gap = categoryAxis.getGap();
                    barGap = 0;
                    barWidth = Math.floor(gap / locationMap.length);
                    // 已经忽略用户定义的宽度设定依然还无法满足显示,只能硬来了;
K
kener 已提交
483
                    if (barWidth <= 0) {
K
kener 已提交
484
                        interval = Math.floor(locationMap.length / gap);
K
kener 已提交
485 486
                        barWidth = 1;
                    }
K
kener 已提交
487 488 489
                }
            }
            else {
K
kener 已提交
490 491
                // 全是自定义宽度,barGap无效,系列间隔决定barGap
                gap = sBarWidthCounter > 1
K
kener 已提交
492
                      ? (typeof barCategoryGap === 'string' && barCategoryGap.match(/%$/))
K
kener 已提交
493 494 495 496 497 498 499 500 501 502
                          // 百分比
                          ? Math.floor(
                              categoryAxis.getGap() 
                              * (100 - parseFloat(barCategoryGap)) 
                              / 100
                            )
                          // 数值
                          : (categoryAxis.getGap() - barCategoryGap)
                      // 只有一个
                      : sBarWidthTotal;
K
kener 已提交
503
                barWidth = 0;
K
kener 已提交
504
                barGap = sBarWidthCounter > 1 
K
kener 已提交
505
                         ? Math.floor((gap - sBarWidthTotal) / (sBarWidthCounter - 1))
K
kener 已提交
506 507
                         : 0;
                if (barGap < 0) {
K
kener 已提交
508
                    // 无法满足用户定义的宽度设计,忽略用户宽度,打回重做
K
kener 已提交
509
                    return this._mapSize(categoryAxis, locationMap, true);
K
kener 已提交
510 511
                }
            }
K
kener 已提交
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 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581
            
            // 检查是否满足barMaxWidthMap
            
            return this._recheckBarMaxWidth(
                locationMap,
                barWidthMap, barMaxWidthMap, barMinHeightMap,
                gap,   // 总宽度
                barWidth, barGap, interval
            );
        },
        
        /**
         * 计算堆积下用户特殊指定的各种size 
         */
        _findSpecialBarSzie: function(locationMap, ignoreUserDefined) {
            var series = this.series;
            var barWidthMap = {};
            var barMaxWidthMap = {};
            var barMinHeightMap = {};
            var sBarWidth;              // 用户指定
            var sBarMaxWidth;           // 用户指定
            var sBarWidthCounter = 0;   // 用户指定
            var sBarWidthTotal = 0;     // 用户指定
            var barGap;
            var barCategoryGap;
            for (var j = 0, k = locationMap.length; j < k; j++) {
                var hasFound = {
                    barWidth: false,
                    barMaxWidth: false
                };
                for (var m = 0, n = locationMap[j].length; m < n; m++) {
                    var seriesIndex = locationMap[j][m];
                    var queryTarget = series[seriesIndex];
                    if (!ignoreUserDefined) {
                        if (!hasFound.barWidth) {
                            sBarWidth = this.query(queryTarget, 'barWidth');
                            if (sBarWidth != null) {
                                // 同一堆积第一个生效barWidth
                                barWidthMap[seriesIndex] = sBarWidth;
                                sBarWidthTotal += sBarWidth;
                                sBarWidthCounter++;
                                hasFound.barWidth = true;
                                // 复位前面同一堆积但没被定义的
                                for (var ii = 0, ll = m; ii < ll; ii++) {
                                    var pSeriesIndex = locationMap[j][ii];
                                    barWidthMap[pSeriesIndex] = sBarWidth;
                                }
                            }
                        }
                        else {
                            barWidthMap[seriesIndex] = sBarWidth;   // 用找到的一个
                        }
                        
                        if (!hasFound.barMaxWidth) {
                            sBarMaxWidth = this.query(queryTarget, 'barMaxWidth');
                            if (sBarMaxWidth != null) {
                                // 同一堆积第一个生效barMaxWidth
                                barMaxWidthMap[seriesIndex] = sBarMaxWidth;
                                hasFound.barMaxWidth = true;
                                // 复位前面同一堆积但没被定义的
                                for (var ii = 0, ll = m; ii < ll; ii++) {
                                    var pSeriesIndex = locationMap[j][ii];
                                    barMaxWidthMap[pSeriesIndex] = sBarMaxWidth;
                                }
                            }
                        }
                        else {
                            barMaxWidthMap[seriesIndex] = sBarMaxWidth;   // 用找到的一个
                        }
                    }
K
kener 已提交
582

K
kener 已提交
583 584 585 586 587 588 589
                    barMinHeightMap[seriesIndex] = this.query(queryTarget, 'barMinHeight');
                    barGap = barGap != null ? barGap : this.query(queryTarget, 'barGap');
                    barCategoryGap = barCategoryGap != null 
                                     ? barCategoryGap : this.query(queryTarget, 'barCategoryGap');
                }
            }
            
K
kener 已提交
590
            return {
591
                barWidthMap: barWidthMap,
K
kener 已提交
592 593 594 595 596 597 598 599
                barMaxWidthMap: barMaxWidthMap,
                barMinHeightMap: barMinHeightMap,
                sBarWidth: sBarWidth,
                sBarMaxWidth: sBarMaxWidth,
                sBarWidthCounter: sBarWidthCounter,
                sBarWidthTotal: sBarWidthTotal,
                barGap: barGap,
                barCategoryGap: barCategoryGap
L
jshint  
lang 已提交
600
            };
K
kener 已提交
601 602 603 604 605 606 607 608 609 610 611 612
        },
        
        /**
         * 检查是否满足barMaxWidthMap 
         */
        _recheckBarMaxWidth: function(
                locationMap,
                barWidthMap, barMaxWidthMap, barMinHeightMap,
                gap,   // 总宽度
                barWidth, barGap, interval
        ) {
            for (var j = 0, k = locationMap.length; j < k; j++) {
K
kener 已提交
613 614 615 616
                var seriesIndex = locationMap[j][0];
                if (barMaxWidthMap[seriesIndex] && barMaxWidthMap[seriesIndex] < barWidth) {
                    // 不满足最大宽度
                    gap -= barWidth - barMaxWidthMap[seriesIndex]; // 总宽度减少
K
kener 已提交
617 618
                }
            }
K
kener 已提交
619
            
K
kener 已提交
620 621 622
            return {
                barWidthMap: barWidthMap,
                barMaxWidthMap: barMaxWidthMap,
623
                barMinHeightMap: barMinHeightMap ,
K
kener 已提交
624
                gap: gap,   // 总宽度
625 626 627
                barWidth: barWidth,
                barGap: barGap,
                interval: interval
L
jshint  
lang 已提交
628
            };
K
kener 已提交
629
        },
K
kener 已提交
630
        
K
kener 已提交
631 632 633
        /**
         * 生成最终图形数据
         */
634
        _getBarItem: function (seriesIndex, dataIndex, name, x, y, width, height, orient) {
K
kener 已提交
635
            var series = this.series;
K
kener 已提交
636 637 638 639
            var barShape;
            var serie = series[seriesIndex];
            var data = serie.data[dataIndex];
            // 多级控制
K
kener 已提交
640
            var defaultColor = this._sIndex2ColorMap[seriesIndex];
K
kener 已提交
641
            var queryTarget = [data, serie];
K
kener 已提交
642 643 644 645 646
            var normalColor = this.deepQuery(queryTarget, 'itemStyle.normal.color') 
                              || defaultColor;
            var emphasisColor = this.deepQuery(queryTarget, 'itemStyle.emphasis.color');
            
            var normal = this.deepMerge(queryTarget, 'itemStyle.normal');
647
            var normalBorderWidth = normal.barBorderWidth;
K
kener 已提交
648 649
            var emphasis = this.deepMerge(queryTarget, 'itemStyle.emphasis');
            
K
kener 已提交
650
            barShape = {
651 652
                zlevel: this.getZlevelBase(),
                z: this.getZBase(),
K
kener 已提交
653
                clickable: this.deepQuery(queryTarget, 'clickable'),
654 655 656 657 658 659 660 661 662 663
                style: {
                    x: x,
                    y: y,
                    width: width,
                    height: height,
                    brushType: 'both',
                    color: this.getItemStyleColor(normalColor, seriesIndex, dataIndex, data),
                    radius: normal.barBorderRadius,
                    lineWidth: normalBorderWidth,
                    strokeColor: normal.barBorderColor
K
kener 已提交
664
                },
665 666 667 668 669
                highlightStyle: {
                    color: this.getItemStyleColor(emphasisColor, seriesIndex, dataIndex, data),
                    radius: emphasis.barBorderRadius,
                    lineWidth: emphasis.barBorderWidth,
                    strokeColor: emphasis.barBorderColor
K
kener 已提交
670
                },
671
                _orient: orient
K
kener 已提交
672
            };
K
kener 已提交
673
            barShape.highlightStyle.color = barShape.highlightStyle.color
674
                            || (typeof barShape.style.color === 'string'
K
kener 已提交
675 676 677
                                ? zrColor.lift(barShape.style.color, -0.3)
                                : barShape.style.color
                               );
K
kener 已提交
678
            // 考虑线宽的显示优化
K
kener 已提交
679 680
            if (normalBorderWidth > 0
                && barShape.style.height > normalBorderWidth
681
                && barShape.style.width > normalBorderWidth
K
kener 已提交
682
            ) {
683 684 685 686
                barShape.style.y += normalBorderWidth / 2;
                barShape.style.height -= normalBorderWidth;
                barShape.style.x += normalBorderWidth / 2;
                barShape.style.width -= normalBorderWidth;
K
kener 已提交
687 688
            }
            else {
K
kener 已提交
689
                // 太小了或者线宽小于0,废了边线
K
kener 已提交
690 691 692
                barShape.style.brushType = 'fill';
            }
            
K
kener 已提交
693
            barShape.highlightStyle.textColor = barShape.highlightStyle.color;
K
kener 已提交
694
            
K
kener 已提交
695
            barShape = this.addLabel(barShape, serie, data, name, orient);
696 697 698 699
            if (barShape.style.textPosition === 'insideLeft'
                || barShape.style.textPosition === 'insideRight'
                || barShape.style.textPosition === 'insideTop'
                || barShape.style.textPosition === 'insideBottom'
K
kener 已提交
700 701 702
            ) {
                var gap = 5;
                switch (barShape.style.textPosition) {
703
                    case 'insideLeft':
K
kener 已提交
704 705 706 707 708
                        barShape.style.textX = barShape.style.x + gap;
                        barShape.style.textY = barShape.style.y + barShape.style.height / 2;
                        barShape.style.textAlign = 'left';
                        barShape.style.textBaseline = 'middle';
                        break;
709
                    case 'insideRight':
K
kener 已提交
710 711 712 713 714
                        barShape.style.textX = barShape.style.x + barShape.style.width - gap;
                        barShape.style.textY = barShape.style.y + barShape.style.height / 2;
                        barShape.style.textAlign = 'right';
                        barShape.style.textBaseline = 'middle';
                        break;
715
                    case 'insideTop':
K
kener 已提交
716 717 718 719 720
                        barShape.style.textX = barShape.style.x + barShape.style.width / 2;
                        barShape.style.textY = barShape.style.y + gap / 2;
                        barShape.style.textAlign = 'center';
                        barShape.style.textBaseline = 'top';
                        break;
721
                    case 'insideBottom':
K
kener 已提交
722 723 724 725 726 727 728 729 730
                        barShape.style.textX = barShape.style.x + barShape.style.width / 2;
                        barShape.style.textY = barShape.style.y + barShape.style.height - gap / 2;
                        barShape.style.textAlign = 'center';
                        barShape.style.textBaseline = 'bottom';
                        break;
                }
                barShape.style.textPosition = 'specific';
                barShape.style.textColor = barShape.style.textColor || '#fff';
            }
K
kener 已提交
731

K
kener 已提交
732 733
            if (this.deepQuery([data, serie, this.option],'calculable')) {
                this.setCalculable(barShape);
K
kener 已提交
734 735 736 737 738 739
                barShape.draggable = true;
            }

            ecData.pack(
                barShape,
                series[seriesIndex], seriesIndex,
K
kener 已提交
740
                series[seriesIndex].data[dataIndex], dataIndex,
K
kener 已提交
741 742 743 744
                name
            );

            return barShape;
K
kener 已提交
745
        },
K
kener 已提交
746

K
kener 已提交
747
        // 位置转换
748
        getMarkCoord: function (seriesIndex, mpData) {
K
kener 已提交
749 750
            var serie = this.series[seriesIndex];
            var xMarkMap = this.xMarkMap[seriesIndex];
K
kener 已提交
751 752
            var xAxis = this.component.xAxis.getAxis(serie.xAxisIndex);
            var yAxis = this.component.yAxis.getAxis(serie.yAxisIndex);
K
kener 已提交
753 754
            var dataIndex;
            var pos;
755
            if (mpData.type
756
                && (mpData.type === 'max' || mpData.type === 'min' || mpData.type === 'average')
757 758
            ) {
                // 特殊值内置支持
K
kener 已提交
759 760 761 762
                var valueIndex = mpData.valueIndex != null 
                                 ? mpData.valueIndex 
                                 : xMarkMap.maxX0 != null 
                                   ? '1' : '';
763
                pos = [
K
kener 已提交
764 765 766 767
                    xMarkMap[mpData.type + 'X' + valueIndex],
                    xMarkMap[mpData.type + 'Y' + valueIndex],
                    xMarkMap[mpData.type + 'Line' + valueIndex],
                    xMarkMap[mpData.type + valueIndex]
768 769
                ];
            }
K
kener 已提交
770
            else if (xMarkMap.isHorizontal) {
K
kener 已提交
771
                // 横向
772
                dataIndex = typeof mpData.xAxis === 'string' && xAxis.getIndexByName
K
kener 已提交
773 774
                            ? xAxis.getIndexByName(mpData.xAxis)
                            : (mpData.xAxis || 0);
K
kener 已提交
775
                
K
kener 已提交
776
                var x = xMarkMap[dataIndex];
777
                x = x != null
K
kener 已提交
778 779 780 781 782 783
                    ? x 
                    : typeof mpData.xAxis != 'string' && xAxis.getCoordByIndex
                      ? xAxis.getCoordByIndex(mpData.xAxis || 0)
                      : xAxis.getCoord(mpData.xAxis || 0);
                
                pos = [x, yAxis.getCoord(mpData.yAxis || 0)];
K
kener 已提交
784 785 786
            }
            else {
                // 纵向
787
                dataIndex = typeof mpData.yAxis === 'string' && yAxis.getIndexByName
K
kener 已提交
788 789
                            ? yAxis.getIndexByName(mpData.yAxis)
                            : (mpData.yAxis || 0);
K
kener 已提交
790
                
K
kener 已提交
791
                var y = xMarkMap[dataIndex];
792
                y = y != null
K
kener 已提交
793 794 795 796 797 798
                    ? y
                    : typeof mpData.yAxis != 'string' && yAxis.getCoordByIndex
                      ? yAxis.getCoordByIndex(mpData.yAxis || 0)
                      : yAxis.getCoord(mpData.yAxis || 0);
                
                pos = [xAxis.getCoord(mpData.xAxis || 0), y];
K
kener 已提交
799
            }
K
kener 已提交
800
            
K
kener 已提交
801
            return pos;
K
kener 已提交
802
        },
K
kener 已提交
803
        
K
kener 已提交
804 805 806
        /**
         * 刷新
         */
807
        refresh: function (newOption) {
K
kener 已提交
808
            if (newOption) {
K
kener 已提交
809 810
                this.option = newOption;
                this.series = newOption.series;
K
kener 已提交
811
            }
K
kener 已提交
812 813
            
            this.backupShapeList();
K
kener 已提交
814 815
            this._buildShape();
        },
816 817 818 819
        
        /**
         * 动态数据增加动画 
         */
820
        addDataAnimation: function (params) {
K
kener 已提交
821
            var series = this.series;
822 823 824 825 826 827 828 829 830 831 832
            var aniMap = {}; // seriesIndex索引参数
            for (var i = 0, l = params.length; i < l; i++) {
                aniMap[params[i][0]] = params[i];
            }
            var x;
            var dx;
            var y;
            var dy;
            var serie;
            var seriesIndex;
            var dataIndex;
K
kener 已提交
833 834
            for (var i = this.shapeList.length - 1; i >= 0; i--) {
                seriesIndex = ecData.get(this.shapeList[i], 'seriesIndex');
835 836
                if (aniMap[seriesIndex] && !aniMap[seriesIndex][3]) {
                    // 有数据删除才有移动的动画
837
                    if (this.shapeList[i].type === 'rectangle') {
838
                        // 主动画
K
kener 已提交
839
                        dataIndex = ecData.get(this.shapeList[i], 'dataIndex');
840
                        serie = series[seriesIndex];
K
kener 已提交
841
                        if (aniMap[seriesIndex][2] && dataIndex === serie.data.length - 1) {
842
                            // 队头加入删除末尾
K
kener 已提交
843
                            this.zr.delShape(this.shapeList[i].id);
844 845
                            continue;
                        }
K
kener 已提交
846
                        else if (!aniMap[seriesIndex][2] && dataIndex === 0) {
847
                            // 队尾加入删除头部
K
kener 已提交
848
                            this.zr.delShape(this.shapeList[i].id);
849 850
                            continue;
                        }
851
                        if (this.shapeList[i]._orient === 'horizontal') {
852
                            // 条形图
K
kener 已提交
853
                            dy = this.component.yAxis.getAxis(
854 855 856 857 858 859 860
                                    serie.yAxisIndex || 0
                                 ).getGap();
                            y = aniMap[seriesIndex][2] ? -dy : dy;
                            x = 0;
                        }
                        else {
                            // 柱形图
K
kener 已提交
861
                            dx = this.component.xAxis.getAxis(
862 863 864 865 866
                                    serie.xAxisIndex || 0
                                 ).getGap();
                            x = aniMap[seriesIndex][2] ? dx : -dx;
                            y = 0;
                        }
K
kener 已提交
867
                        this.shapeList[i].position = [0, 0];
K
kener 已提交
868
                        this.zr.animate(this.shapeList[i].id, '')
869 870
                            .when(
                                500,
871
                                { position: [x, y] }
872 873 874 875 876
                            )
                            .start();
                    }
                }
            }
K
kener 已提交
877
        }
K
kener 已提交
878
    };
K
kener 已提交
879
    
K
kener 已提交
880
    zrUtil.inherits(Bar, ChartBase);
K
kener 已提交
881 882
    zrUtil.inherits(Bar, ComponentBase);
    
883 884 885
    // 图表注册
    require('../chart').define('bar', Bar);
    
K
kener 已提交
886 887
    return Bar;
});