bar.js 42.0 KB
Newer Older
K
kener 已提交
1 2 3 4 5 6 7
/**
 * echarts图表类:柱形图
 *
 * @desc echarts基于Canvas,纯Javascript图表库,提供直观,生动,可交互,可个性化定制的数据统计图表。
 * @author Kener (@Kener-林峰, linzhifeng@baidu.com)
 *
 */
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 () {
K
kener 已提交
46
            this._bulidPosition();
K
kener 已提交
47
        },
K
kener 已提交
48 49 50 51

        /**
         * 构建类目轴为水平方向的柱形图系列
         */
K
kener 已提交
52
        _buildHorizontal: function (seriesArray, maxDataLength, locationMap, xMarkMap) {
K
kener 已提交
53
            var series = this.series;
K
kener 已提交
54 55 56 57
            // 确定类目轴和数值轴,同一方向随便找一个即可
            var seriesIndex = locationMap[0][0];
            var serie = series[seriesIndex];
            var xAxisIndex = serie.xAxisIndex;
K
kener 已提交
58
            var categoryAxis = this.component.xAxis.getAxis(xAxisIndex);
K
kener 已提交
59 60 61
            var yAxisIndex; // 数值轴各异
            var valueAxis;  // 数值轴各异

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

            var x;
            var y;
K
kener 已提交
73
            var lastYP; // 正向堆积处理
K
kener 已提交
74
            var baseYP;
K
kener 已提交
75
            var lastYN; // 负向堆积处理
K
kener 已提交
76 77 78 79 80
            var baseYN;
            var barShape;
            var data;
            var value;
            for (var i = 0, l = maxDataLength; i < l; i++) {
81
                if (categoryAxis.getNameByIndex(i) == null) {
K
kener 已提交
82 83 84 85 86
                    // 系列数据超出类目轴长度
                    break;
                }
                x = categoryAxis.getCoordByIndex(i) - gap / 2;
                for (var j = 0, k = locationMap.length; j < k; j++) {
K
kener 已提交
87
                    // 堆积数据用第一条valueAxis
K
kener 已提交
88
                    yAxisIndex = series[locationMap[j][0]].yAxisIndex || 0;
K
kener 已提交
89
                    valueAxis = this.component.yAxis.getAxis(yAxisIndex);
K
kener 已提交
90
                    baseYP = lastYP = baseYN = lastYN = valueAxis.getCoord(0);
K
kener 已提交
91 92 93 94
                    for (var m = 0, n = locationMap[j].length; m < n; m++) {
                        seriesIndex = locationMap[j][m];
                        serie = series[seriesIndex];
                        data = serie.data[i];
95 96
                        value = data != null
                                ? (data.value != null
K
kener 已提交
97 98 99
                                  ? data.value
                                  : data)
                                : '-';
K
kener 已提交
100 101
                        xMarkMap[seriesIndex] = xMarkMap[seriesIndex] 
                                                || {
102 103 104 105 106
                                                    min: Number.POSITIVE_INFINITY,
                                                    max: Number.NEGATIVE_INFINITY,
                                                    sum: 0,
                                                    counter: 0,
                                                    average: 0
K
kener 已提交
107
                                                };
108
                        if (value === '-') {
K
kener 已提交
109 110 111
                            // 空数据在做完后补充拖拽提示框
                            continue;
                        }
112
                        //y = valueAxis.getCoord(value);
K
kener 已提交
113
                        if (value > 0) {
K
kener 已提交
114
                            // 正向堆积
115 116 117 118
                            //barHeight = baseYP - y;
                            barHeight = m > 0 
                                        ? valueAxis.getCoordSize(value)
                                        : (baseYP - valueAxis.getCoord(value));
K
kener 已提交
119
                            // 非堆积数据最小高度有效
K
kener 已提交
120
                            if (n === 1 && barMinHeightMap[seriesIndex] > barHeight) {
K
kener 已提交
121 122 123 124 125 126
                                barHeight = barMinHeightMap[seriesIndex];
                            }
                            lastYP -= barHeight;
                            y = lastYP;
                        }
                        else if (value < 0){
K
kener 已提交
127
                            // 负向堆积
128 129 130 131
                            //barHeight = y - baseYN;
                            barHeight = m > 0 
                                        ? valueAxis.getCoordSize(value)
                                        : (valueAxis.getCoord(value) - baseYN);
K
kener 已提交
132
                            // 非堆积数据最小高度有效
K
kener 已提交
133
                            if (n === 1 && barMinHeightMap[seriesIndex] > barHeight) {
K
kener 已提交
134 135 136 137 138 139 140
                                barHeight = barMinHeightMap[seriesIndex];
                            }
                            y = lastYN;
                            lastYN += barHeight;
                        }
                        else {
                            // 0值
141
                            barHeight = 0;//baseYP - y;
K
kener 已提交
142 143 144 145
                            // 最小高度无效
                            lastYP -= barHeight;
                            y = lastYP;
                        }
K
kener 已提交
146 147
                        xMarkMap[seriesIndex][i] = 
                            x + (barWidthMap[seriesIndex] || barWidth) / 2;
148 149 150 151 152 153 154 155 156 157 158 159
                        if (xMarkMap[seriesIndex].min > value) {
                            xMarkMap[seriesIndex].min = value;
                            xMarkMap[seriesIndex].minY = y;
                            xMarkMap[seriesIndex].minX = xMarkMap[seriesIndex][i];
                        }
                        if (xMarkMap[seriesIndex].max < value) {
                            xMarkMap[seriesIndex].max = value;
                            xMarkMap[seriesIndex].maxY = y;
                            xMarkMap[seriesIndex].maxX = xMarkMap[seriesIndex][i];
                        }
                        xMarkMap[seriesIndex].sum += value;
                        xMarkMap[seriesIndex].counter++;
K
kener 已提交
160
                        
K
kener 已提交
161
                        if (i % interval === 0) {
K
kener 已提交
162 163 164 165 166 167 168 169 170 171
                            barShape = this._getBarItem(
                                seriesIndex, i,
                                categoryAxis.getNameByIndex(i),
                                x, y,
                                barWidthMap[seriesIndex] || barWidth,
                                barHeight,
                                'vertical'
                            );
                            this.shapeList.push(new RectangleShape(barShape));
                        }
K
kener 已提交
172 173 174 175 176 177 178
                    }

                    // 补充空数据的拖拽提示框
                    for (var m = 0, n = locationMap[j].length; m < n; m++) {
                        seriesIndex = locationMap[j][m];
                        serie = series[seriesIndex];
                        data = serie.data[i];
179 180
                        value = data != null
                                ? (data.value != null
K
kener 已提交
181 182 183 184 185 186 187 188
                                  ? data.value
                                  : data)
                                : '-';
                        if (value != '-') {
                            // 只关心空数据
                            continue;
                        }

K
kener 已提交
189
                        if (this.deepQuery([data, serie, this.option], 'calculable')) {
K
kener 已提交
190
                            lastYP -= this.ecTheme.island.r;
K
kener 已提交
191 192
                            y = lastYP;

K
kener 已提交
193
                            barShape = this._getBarItem(
K
kener 已提交
194 195
                                seriesIndex, i,
                                categoryAxis.getNameByIndex(i),
K
kener 已提交
196 197
                                x + 0.5, y + 0.5,
                                (barWidthMap[seriesIndex] || barWidth) - 1,
K
kener 已提交
198
                                this.ecTheme.island.r - 1,
K
kener 已提交
199
                                'vertical'
K
kener 已提交
200 201 202
                            );
                            barShape.hoverable = false;
                            barShape.draggable = false;
K
kener 已提交
203
                            barShape.style.lineWidth = 1;
K
kener 已提交
204
                            barShape.style.brushType = 'stroke';
K
kener 已提交
205 206
                            barShape.style.strokeColor = serie.calculableHolderColor
                                                         || this.ecTheme.calculableHolderColor;
K
kener 已提交
207

K
kener 已提交
208
                            this.shapeList.push(new RectangleShape(barShape));
K
kener 已提交
209 210 211 212 213 214
                        }
                    }

                    x += ((barWidthMap[seriesIndex] || barWidth) + barGap);
                }
            }
215
            
K
kener 已提交
216
            this._calculMarkMapXY(xMarkMap, locationMap, 'y');
K
kener 已提交
217
        },
K
kener 已提交
218 219 220 221

        /**
         * 构建类目轴为垂直方向的柱形图系列
         */
K
kener 已提交
222
        _buildVertical: function (seriesArray, maxDataLength, locationMap, xMarkMap) {
K
kener 已提交
223
            var series = this.series;
K
kener 已提交
224 225 226 227
            // 确定类目轴和数值轴,同一方向随便找一个即可
            var seriesIndex = locationMap[0][0];
            var serie = series[seriesIndex];
            var yAxisIndex = serie.yAxisIndex;
K
kener 已提交
228
            var categoryAxis = this.component.yAxis.getAxis(yAxisIndex);
K
kener 已提交
229 230 231
            var xAxisIndex; // 数值轴各异
            var valueAxis;  // 数值轴各异

K
kener 已提交
232
            var size = this._mapSize(categoryAxis, locationMap);
K
kener 已提交
233 234 235 236 237 238
            var gap = size.gap;
            var barGap = size.barGap;
            var barWidthMap = size.barWidthMap;
            var barWidth = size.barWidth;                   // 自适应宽度
            var barMinHeightMap = size.barMinHeightMap;
            var barHeight;
K
kener 已提交
239
            var interval = size.interval;
K
kener 已提交
240 241 242

            var x;
            var y;
K
kener 已提交
243
            var lastXP; // 正向堆积处理
K
kener 已提交
244
            var baseXP;
K
kener 已提交
245
            var lastXN; // 负向堆积处理
K
kener 已提交
246 247 248 249 250
            var baseXN;
            var barShape;
            var data;
            var value;
            for (var i = 0, l = maxDataLength; i < l; i++) {
251
                if (categoryAxis.getNameByIndex(i) == null) {
K
kener 已提交
252 253 254 255 256
                    // 系列数据超出类目轴长度
                    break;
                }
                y = categoryAxis.getCoordByIndex(i) + gap / 2;
                for (var j = 0, k = locationMap.length; j < k; j++) {
K
kener 已提交
257
                    // 堆积数据用第一条valueAxis
K
kener 已提交
258
                    xAxisIndex = series[locationMap[j][0]].xAxisIndex || 0;
K
kener 已提交
259
                    valueAxis = this.component.xAxis.getAxis(xAxisIndex);
K
kener 已提交
260
                    baseXP = lastXP = baseXN = lastXN = valueAxis.getCoord(0);
K
kener 已提交
261 262 263 264
                    for (var m = 0, n = locationMap[j].length; m < n; m++) {
                        seriesIndex = locationMap[j][m];
                        serie = series[seriesIndex];
                        data = serie.data[i];
265 266
                        value = data != null
                                ? (data.value != null
K
kener 已提交
267 268 269
                                  ? data.value
                                  : data)
                                : '-';
K
kener 已提交
270 271
                        xMarkMap[seriesIndex] = xMarkMap[seriesIndex] 
                                                || {
272 273 274 275 276
                                                    min: Number.POSITIVE_INFINITY,
                                                    max: Number.NEGATIVE_INFINITY,
                                                    sum: 0,
                                                    counter: 0,
                                                    average: 0
K
kener 已提交
277
                                                };
278
                        if (value === '-') {
K
kener 已提交
279 280 281
                            // 空数据在做完后补充拖拽提示框
                            continue;
                        }
282
                        //x = valueAxis.getCoord(value);
K
kener 已提交
283
                        if (value > 0) {
K
kener 已提交
284
                            // 正向堆积
285 286 287 288
                            //barHeight = x - baseXP;
                            barHeight = m > 0 
                                        ? valueAxis.getCoordSize(value)
                                        : (valueAxis.getCoord(value) - baseXP);
K
kener 已提交
289
                            // 非堆积数据最小高度有效
K
kener 已提交
290
                            if (n === 1 && barMinHeightMap[seriesIndex] > barHeight) {
K
kener 已提交
291 292 293 294 295 296
                                barHeight = barMinHeightMap[seriesIndex];
                            }
                            x = lastXP;
                            lastXP += barHeight;
                        }
                        else if (value < 0){
K
kener 已提交
297
                            // 负向堆积
298 299 300 301
                            //barHeight = baseXN - x;
                            barHeight = m > 0 
                                        ? valueAxis.getCoordSize(value)
                                        : (baseXN - valueAxis.getCoord(value));
K
kener 已提交
302
                            // 非堆积数据最小高度有效
K
kener 已提交
303
                            if (n === 1 && barMinHeightMap[seriesIndex] > barHeight) {
K
kener 已提交
304 305 306 307 308 309 310
                                barHeight = barMinHeightMap[seriesIndex];
                            }
                            lastXN -= barHeight;
                            x = lastXN;
                        }
                        else {
                            // 0值
311
                            barHeight = 0;//x - baseXP;
K
kener 已提交
312 313 314 315 316
                            // 最小高度无效
                            x = lastXP;
                            lastXP += barHeight;
                        }

K
kener 已提交
317
                        xMarkMap[seriesIndex][i] = y - (barWidthMap[seriesIndex] || barWidth) / 2;
318 319 320 321 322 323 324 325 326 327 328 329
                        if (xMarkMap[seriesIndex].min > value) {
                            xMarkMap[seriesIndex].min = value;
                            xMarkMap[seriesIndex].minX = x + barHeight;
                            xMarkMap[seriesIndex].minY = xMarkMap[seriesIndex][i];
                        }
                        if (xMarkMap[seriesIndex].max < value) {
                            xMarkMap[seriesIndex].max = value;
                            xMarkMap[seriesIndex].maxX = x + barHeight;
                            xMarkMap[seriesIndex].maxY = xMarkMap[seriesIndex][i];
                        }
                        xMarkMap[seriesIndex].sum += value;
                        xMarkMap[seriesIndex].counter++;
K
kener 已提交
330
                        
K
kener 已提交
331
                        if (i % interval === 0) {
K
kener 已提交
332 333 334 335 336 337 338 339 340 341
                            barShape = this._getBarItem(
                                seriesIndex, i,
                                categoryAxis.getNameByIndex(i),
                                x, y - (barWidthMap[seriesIndex] || barWidth),
                                barHeight,
                                barWidthMap[seriesIndex] || barWidth,
                                'horizontal'
                            );
                            this.shapeList.push(new RectangleShape(barShape));
                        }
K
kener 已提交
342 343 344 345 346 347 348
                    }

                    // 补充空数据的拖拽提示框
                    for (var m = 0, n = locationMap[j].length; m < n; m++) {
                        seriesIndex = locationMap[j][m];
                        serie = series[seriesIndex];
                        data = serie.data[i];
349 350
                        value = data != null
                                ? (data.value != null
K
kener 已提交
351 352 353 354 355 356 357 358
                                  ? data.value
                                  : data)
                                : '-';
                        if (value != '-') {
                            // 只关心空数据
                            continue;
                        }

K
kener 已提交
359
                        if (this.deepQuery([data, serie, this.option], 'calculable')) {
K
kener 已提交
360
                            x = lastXP;
K
kener 已提交
361
                            lastXP += this.ecTheme.island.r;
K
kener 已提交
362

K
kener 已提交
363
                            barShape = this._getBarItem(
K
kener 已提交
364 365 366
                                seriesIndex,
                                i,
                                categoryAxis.getNameByIndex(i),
K
kener 已提交
367
                                x + 0.5, y + 0.5 - (barWidthMap[seriesIndex] || barWidth),
K
kener 已提交
368
                                this.ecTheme.island.r - 1,
K
kener 已提交
369
                                (barWidthMap[seriesIndex] || barWidth) - 1,
K
kener 已提交
370
                                'horizontal'
K
kener 已提交
371 372 373
                            );
                            barShape.hoverable = false;
                            barShape.draggable = false;
K
kener 已提交
374
                            barShape.style.lineWidth = 1;
K
kener 已提交
375
                            barShape.style.brushType = 'stroke';
K
kener 已提交
376 377
                            barShape.style.strokeColor = serie.calculableHolderColor
                                                         || this.ecTheme.calculableHolderColor;
K
kener 已提交
378

K
kener 已提交
379
                            this.shapeList.push(new RectangleShape(barShape));
K
kener 已提交
380 381 382 383 384 385
                        }
                    }

                    y -= ((barWidthMap[seriesIndex] || barWidth) + barGap);
                }
            }
386
            
K
kener 已提交
387 388 389 390 391 392 393 394 395
            this._calculMarkMapXY(xMarkMap, locationMap, 'x');
        },
        
        /**
         * 构建双数值轴柱形图
         */
        _buildOther: function (seriesArray, maxDataLength, locationMap, xMarkMap) {
            var series = this.series;
            
396 397
            for (var j = 0, k = locationMap.length; j < k; j++) {
                for (var m = 0, n = locationMap[j].length; m < n; m++) {
K
kener 已提交
398 399 400 401 402 403 404 405
                    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 已提交
406
                    
K
kener 已提交
407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430
                    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];
                        var value = data != null
                                    ? (data.value != null
                                      ? data.value
                                      : data)
                                    : '-';
                        if (!(value instanceof Array)) {
                            continue;
                        }
431
                        
K
kener 已提交
432 433 434 435 436 437 438
                        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 已提交
439
                        var barShape;
K
kener 已提交
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
                        
                        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++;
                    }
527 528
                }
            }
K
kener 已提交
529 530
            
            this._calculMarkMapXY(xMarkMap, locationMap, 'xy');
K
kener 已提交
531
        },
K
kener 已提交
532
        
K
kener 已提交
533 534 535 536 537
        /**
         * 我真是自找麻烦啊,为啥要允许系列级个性化最小宽度和高度啊!!!
         * @param {CategoryAxis} categoryAxis 类目坐标轴,需要知道类目间隔大小
         * @param {Array} locationMap 整形数据的系列索引
         */
538
        _mapSize: function (categoryAxis, locationMap, ignoreUserDefined) {
K
kener 已提交
539
            var series = this.series;
K
kener 已提交
540
            var seriesIndex;
K
kener 已提交
541 542 543 544 545
            var barWidthMap = {};
            var barMinHeightMap = {};
            var sBarWidth;
            var sBarWidthCounter = 0;
            var sBarWidthTotal = 0;
K
kener 已提交
546 547
            var barGap;
            var barCategoryGap;
K
kener 已提交
548
            var hasFound;
K
kener 已提交
549
            var queryTarget;
K
kener 已提交
550
            var interval = 1;
K
kener 已提交
551 552

            for (var j = 0, k = locationMap.length; j < k; j++) {
K
kener 已提交
553
                hasFound = false;   // 同一堆积第一个barWidth生效
K
kener 已提交
554 555
                for (var m = 0, n = locationMap[j].length; m < n; m++) {
                    seriesIndex = locationMap[j][m];
K
kener 已提交
556
                    queryTarget = series[seriesIndex];
K
kener 已提交
557 558
                    if (!ignoreUserDefined) {
                        if (!hasFound) {
K
kener 已提交
559
                            sBarWidth = this.query(queryTarget, 'barWidth');
560
                            if (sBarWidth != null) {
K
kener 已提交
561
                                // 同一堆积第一个生效barWidth
K
kener 已提交
562 563 564 565
                                barWidthMap[seriesIndex] = sBarWidth;
                                sBarWidthTotal += sBarWidth;
                                sBarWidthCounter++;
                                hasFound = true;
K
kener 已提交
566
                                // 复位前面同一堆积但没被定义的
K
kener 已提交
567 568 569 570
                                for (var ii = 0, ll = m; ii < ll; ii++) {
                                    var pSeriesIndex = locationMap[j][ii];
                                    barWidthMap[pSeriesIndex] = sBarWidth;
                                }
K
kener 已提交
571 572 573 574 575 576
                            }
                        } else {
                            barWidthMap[seriesIndex] = sBarWidth;   // 用找到的一个
                        }
                    }

577 578 579 580
                    barMinHeightMap[seriesIndex] = this.query(queryTarget, 'barMinHeight');
                    barGap = barGap != null ? barGap : this.query(queryTarget, 'barGap');
                    barCategoryGap = barCategoryGap != null 
                                     ? barCategoryGap : this.query(queryTarget, 'barCategoryGap');
K
kener 已提交
581 582 583 584 585 586 587
                }
            }

            var gap;
            var barWidth;
            if (locationMap.length != sBarWidthCounter) {
                // 至少存在一个自适应宽度的柱形图
K
kener 已提交
588
                if (!ignoreUserDefined) {
K
kener 已提交
589 590 591 592 593 594 595 596 597
                    gap = typeof barCategoryGap === 'string' && barCategoryGap.match(/%$/)
                          // 百分比
                          ? Math.floor(
                              categoryAxis.getGap() 
                              * (100 - parseFloat(barCategoryGap)) 
                              / 100
                            )
                          // 数值
                          : (categoryAxis.getGap() - barCategoryGap);
598
                    if (typeof barGap === 'string' && barGap.match(/%$/)) {
K
kener 已提交
599 600 601 602 603 604 605 606 607 608 609
                        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 已提交
610
                            (gap - sBarWidthTotal - barGap * (locationMap.length - 1))
K
kener 已提交
611 612 613
                            / (locationMap.length - sBarWidthCounter)
                        );
                    }
K
kener 已提交
614
                    // 无法满足用户定义的宽度设计,忽略用户宽度,打回重做
K
kener 已提交
615
                    if (barWidth <= 0) {
K
kener 已提交
616
                        return this._mapSize(categoryAxis, locationMap, true);
K
kener 已提交
617 618 619 620 621 622 623 624
                    }
                }
                else {
                    // 忽略用户定义的宽度设定
                    gap = categoryAxis.getGap();
                    barGap = 0;
                    barWidth = Math.floor(gap / locationMap.length);
                    // 已经忽略用户定义的宽度设定依然还无法满足显示,只能硬来了;
K
kener 已提交
625
                    if (barWidth <= 0) {
K
kener 已提交
626
                        interval = Math.floor(locationMap.length / gap);
K
kener 已提交
627 628
                        barWidth = 1;
                    }
K
kener 已提交
629 630 631
                }
            }
            else {
K
kener 已提交
632 633
                // 全是自定义宽度,barGap无效,系列间隔决定barGap
                gap = sBarWidthCounter > 1
K
kener 已提交
634
                      ? (typeof barCategoryGap === 'string' && barCategoryGap.match(/%$/))
K
kener 已提交
635 636 637 638 639 640 641 642 643 644
                          // 百分比
                          ? Math.floor(
                              categoryAxis.getGap() 
                              * (100 - parseFloat(barCategoryGap)) 
                              / 100
                            )
                          // 数值
                          : (categoryAxis.getGap() - barCategoryGap)
                      // 只有一个
                      : sBarWidthTotal;
K
kener 已提交
645
                barWidth = 0;
K
kener 已提交
646
                barGap = sBarWidthCounter > 1 
K
kener 已提交
647
                         ? Math.floor((gap - sBarWidthTotal) / (sBarWidthCounter - 1))
K
kener 已提交
648 649
                         : 0;
                if (barGap < 0) {
K
kener 已提交
650
                    // 无法满足用户定义的宽度设计,忽略用户宽度,打回重做
K
kener 已提交
651
                    return this._mapSize(categoryAxis, locationMap, true);
K
kener 已提交
652 653 654 655
                }
            }

            return {
656 657 658 659 660 661
                barWidthMap: barWidthMap,
                barMinHeightMap: barMinHeightMap ,
                gap: gap,
                barWidth: barWidth,
                barGap: barGap,
                interval: interval
K
kener 已提交
662
            };
K
kener 已提交
663
        },
K
kener 已提交
664 665 666 667

        /**
         * 生成最终图形数据
         */
668
        _getBarItem: function (seriesIndex, dataIndex, name, x, y, width, height, orient) {
K
kener 已提交
669
            var series = this.series;
K
kener 已提交
670 671 672 673
            var barShape;
            var serie = series[seriesIndex];
            var data = serie.data[dataIndex];
            // 多级控制
K
kener 已提交
674
            var defaultColor = this._sIndex2ColorMap[seriesIndex];
K
kener 已提交
675
            var queryTarget = [data, serie];
K
kener 已提交
676 677 678 679 680
            var normalColor = this.deepQuery(queryTarget, 'itemStyle.normal.color') 
                              || defaultColor;
            var emphasisColor = this.deepQuery(queryTarget, 'itemStyle.emphasis.color');
            
            var normal = this.deepMerge(queryTarget, 'itemStyle.normal');
681
            var normalBorderWidth = normal.barBorderWidth;
K
kener 已提交
682 683
            var emphasis = this.deepMerge(queryTarget, 'itemStyle.emphasis');
            
K
kener 已提交
684
            barShape = {
685
                zlevel: this._zlevelBase,
K
kener 已提交
686
                clickable: this.deepQuery(queryTarget, 'clickable'),
687 688 689 690 691 692 693 694 695 696
                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 已提交
697
                },
698 699 700 701 702
                highlightStyle: {
                    color: this.getItemStyleColor(emphasisColor, seriesIndex, dataIndex, data),
                    radius: emphasis.barBorderRadius,
                    lineWidth: emphasis.barBorderWidth,
                    strokeColor: emphasis.barBorderColor
K
kener 已提交
703
                },
704
                _orient: orient
K
kener 已提交
705
            };
K
kener 已提交
706
            barShape.highlightStyle.color = barShape.highlightStyle.color
707
                            || (typeof barShape.style.color === 'string'
K
kener 已提交
708 709 710
                                ? zrColor.lift(barShape.style.color, -0.3)
                                : barShape.style.color
                               );
K
kener 已提交
711
            // 考虑线宽的显示优化
K
kener 已提交
712 713
            if (normalBorderWidth > 0
                && barShape.style.height > normalBorderWidth
714
                && barShape.style.width > normalBorderWidth
K
kener 已提交
715
            ) {
716 717 718 719
                barShape.style.y += normalBorderWidth / 2;
                barShape.style.height -= normalBorderWidth;
                barShape.style.x += normalBorderWidth / 2;
                barShape.style.width -= normalBorderWidth;
K
kener 已提交
720 721
            }
            else {
K
kener 已提交
722
                // 太小了或者线宽小于0,废了边线
K
kener 已提交
723 724 725
                barShape.style.brushType = 'fill';
            }
            
K
kener 已提交
726
            barShape.highlightStyle.textColor = barShape.highlightStyle.color;
K
kener 已提交
727
            
K
kener 已提交
728
            barShape = this.addLabel(barShape, serie, data, name, orient);
729 730 731 732
            if (barShape.style.textPosition === 'insideLeft'
                || barShape.style.textPosition === 'insideRight'
                || barShape.style.textPosition === 'insideTop'
                || barShape.style.textPosition === 'insideBottom'
K
kener 已提交
733 734 735
            ) {
                var gap = 5;
                switch (barShape.style.textPosition) {
736
                    case 'insideLeft':
K
kener 已提交
737 738 739 740 741
                        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;
742
                    case 'insideRight':
K
kener 已提交
743 744 745 746 747
                        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;
748
                    case 'insideTop':
K
kener 已提交
749 750 751 752 753
                        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;
754
                    case 'insideBottom':
K
kener 已提交
755 756 757 758 759 760 761 762 763
                        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 已提交
764

K
kener 已提交
765 766
            if (this.deepQuery([data, serie, this.option],'calculable')) {
                this.setCalculable(barShape);
K
kener 已提交
767 768 769 770 771 772
                barShape.draggable = true;
            }

            ecData.pack(
                barShape,
                series[seriesIndex], seriesIndex,
K
kener 已提交
773
                series[seriesIndex].data[dataIndex], dataIndex,
K
kener 已提交
774 775 776 777
                name
            );

            return barShape;
K
kener 已提交
778
        },
K
kener 已提交
779

K
kener 已提交
780
        // 位置转换
781
        getMarkCoord: function (seriesIndex, mpData) {
K
kener 已提交
782 783
            var serie = this.series[seriesIndex];
            var xMarkMap = this.xMarkMap[seriesIndex];
K
kener 已提交
784 785
            var xAxis = this.component.xAxis.getAxis(serie.xAxisIndex);
            var yAxis = this.component.yAxis.getAxis(serie.yAxisIndex);
K
kener 已提交
786 787
            var dataIndex;
            var pos;
788
            if (mpData.type
789
                && (mpData.type === 'max' || mpData.type === 'min' || mpData.type === 'average')
790 791
            ) {
                // 特殊值内置支持
K
kener 已提交
792 793 794 795
                var valueIndex = mpData.valueIndex != null 
                                 ? mpData.valueIndex 
                                 : xMarkMap.maxX0 != null 
                                   ? '1' : '';
796
                pos = [
K
kener 已提交
797 798 799 800
                    xMarkMap[mpData.type + 'X' + valueIndex],
                    xMarkMap[mpData.type + 'Y' + valueIndex],
                    xMarkMap[mpData.type + 'Line' + valueIndex],
                    xMarkMap[mpData.type + valueIndex]
801 802
                ];
            }
K
kener 已提交
803
            else if (xMarkMap.isHorizontal) {
K
kener 已提交
804
                // 横向
805
                dataIndex = typeof mpData.xAxis === 'string' && xAxis.getIndexByName
K
kener 已提交
806 807
                            ? xAxis.getIndexByName(mpData.xAxis)
                            : (mpData.xAxis || 0);
K
kener 已提交
808
                
K
kener 已提交
809
                var x = xMarkMap[dataIndex];
810
                x = x != null
K
kener 已提交
811 812 813 814 815 816
                    ? 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 已提交
817 818 819
            }
            else {
                // 纵向
820
                dataIndex = typeof mpData.yAxis === 'string' && yAxis.getIndexByName
K
kener 已提交
821 822
                            ? yAxis.getIndexByName(mpData.yAxis)
                            : (mpData.yAxis || 0);
K
kener 已提交
823
                
K
kener 已提交
824
                var y = xMarkMap[dataIndex];
825
                y = y != null
K
kener 已提交
826 827 828 829 830 831
                    ? 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 已提交
832
            }
K
kener 已提交
833
            
K
kener 已提交
834
            return pos;
K
kener 已提交
835
        },
K
kener 已提交
836
        
K
kener 已提交
837 838 839
        /**
         * 刷新
         */
840
        refresh: function (newOption) {
K
kener 已提交
841
            if (newOption) {
K
kener 已提交
842 843
                this.option = newOption;
                this.series = newOption.series;
K
kener 已提交
844
            }
K
kener 已提交
845 846
            
            this.backupShapeList();
K
kener 已提交
847 848
            this._buildShape();
        },
849 850 851 852
        
        /**
         * 动态数据增加动画 
         */
853
        addDataAnimation: function (params) {
K
kener 已提交
854
            var series = this.series;
855 856 857 858 859 860 861 862 863 864 865
            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 已提交
866 867
            for (var i = this.shapeList.length - 1; i >= 0; i--) {
                seriesIndex = ecData.get(this.shapeList[i], 'seriesIndex');
868 869
                if (aniMap[seriesIndex] && !aniMap[seriesIndex][3]) {
                    // 有数据删除才有移动的动画
870
                    if (this.shapeList[i].type === 'rectangle') {
871
                        // 主动画
K
kener 已提交
872
                        dataIndex = ecData.get(this.shapeList[i], 'dataIndex');
873
                        serie = series[seriesIndex];
K
kener 已提交
874
                        if (aniMap[seriesIndex][2] && dataIndex === serie.data.length - 1) {
875
                            // 队头加入删除末尾
K
kener 已提交
876
                            this.zr.delShape(this.shapeList[i].id);
877 878
                            continue;
                        }
K
kener 已提交
879
                        else if (!aniMap[seriesIndex][2] && dataIndex === 0) {
880
                            // 队尾加入删除头部
K
kener 已提交
881
                            this.zr.delShape(this.shapeList[i].id);
882 883
                            continue;
                        }
884
                        if (this.shapeList[i]._orient === 'horizontal') {
885
                            // 条形图
K
kener 已提交
886
                            dy = this.component.yAxis.getAxis(
887 888 889 890 891 892 893
                                    serie.yAxisIndex || 0
                                 ).getGap();
                            y = aniMap[seriesIndex][2] ? -dy : dy;
                            x = 0;
                        }
                        else {
                            // 柱形图
K
kener 已提交
894
                            dx = this.component.xAxis.getAxis(
895 896 897 898 899
                                    serie.xAxisIndex || 0
                                 ).getGap();
                            x = aniMap[seriesIndex][2] ? dx : -dx;
                            y = 0;
                        }
K
kener 已提交
900
                        this.shapeList[i].position = [0, 0];
K
kener 已提交
901
                        this.zr.animate(this.shapeList[i].id, '')
902 903
                            .when(
                                500,
904
                                { position: [x, y] }
905 906 907 908 909
                            )
                            .start();
                    }
                }
            }
K
kener 已提交
910
        }
K
kener 已提交
911
    };
K
kener 已提交
912
    
K
kener 已提交
913
    zrUtil.inherits(Bar, ChartBase);
K
kener 已提交
914 915
    zrUtil.inherits(Bar, ComponentBase);
    
916 917 918
    // 图表注册
    require('../chart').define('bar', Bar);
    
K
kener 已提交
919 920
    return Bar;
});