| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141 | /** * echarts图表类:饼图 * * @desc echarts基于Canvas,纯Javascript图表库,提供直观,生动,可交互,可个性化定制的数据统计图表。 * @author Kener (@Kener-林峰, kener.linfeng@gmail.com) * */define(function (require) {    var ChartBase = require('./base');    // 图形依赖    var TextShape = require('zrender/shape/Text');    var RingShape = require('zrender/shape/Ring');    var CircleShape = require('zrender/shape/Circle');    var SectorShape = require('zrender/shape/Sector');    var PolylineShape = require('zrender/shape/Polyline');    var ecConfig = require('../config');    // 饼图默认参数    ecConfig.pie = {        zlevel: 0,                  // 一级层叠        z: 2,                       // 二级层叠        clickable: true,        legendHoverLink: true,        center: ['50%', '50%'],     // 默认全局居中        radius: [0, '75%'],        clockWise: true,            // 默认顺时针        startAngle: 90,        minAngle: 0,                // 最小角度改为0        selectedOffset: 10,         // 选中是扇区偏移量        // selectedMode: false,     // 选择模式,默认关闭,可选single,multiple        // roseType: null,          // 南丁格尔玫瑰图模式,'radius'(半径) | 'area'(面积)        itemStyle: {            normal: {                // color: 各异,                borderColor: 'rgba(0,0,0,0)',                borderWidth: 1,                label: {                    show: true,                    position: 'outer'                    // formatter: 标签文本格式器,同Tooltip.formatter,不支持异步回调                    // textStyle: null      // 默认使用全局文本样式,详见TEXTSTYLE                    // distance: 当position为inner时有效,为label位置到圆心的距离与圆半径(环状图为内外半径和)的比例系数                },                labelLine: {                    show: true,                    length: 20,                    lineStyle: {                        // color: 各异,                        width: 1,                        type: 'solid'                    }                }            },            emphasis: {                // color: 各异,                borderColor: 'rgba(0,0,0,0)',                borderWidth: 1,                label: {                    show: false                    // position: 'outer'                    // formatter: 标签文本格式器,同Tooltip.formatter,不支持异步回调                    // textStyle: null      // 默认使用全局文本样式,详见TEXTSTYLE                    // distance: 当position为inner时有效,为label位置到圆心的距离与圆半径(环状图为内外半径和)的比例系数                },                labelLine: {                    show: false,                    length: 20,                    lineStyle: {                        // color: 各异,                        width: 1,                        type: 'solid'                    }                }            }        }    };    var ecData = require('../util/ecData');    var zrUtil = require('zrender/tool/util');    var zrMath = require('zrender/tool/math');    var zrColor = require('zrender/tool/color');    /**     * 构造函数     * @param {Object} messageCenter echart消息中心     * @param {ZRender} zr zrender实例     * @param {Object} series 数据     * @param {Object} component 组件     */    function Pie(ecTheme, messageCenter, zr, option, myChart){        // 图表基类        ChartBase.call(this, ecTheme, messageCenter, zr, option, myChart);        var self = this;        /**         * 输出动态视觉引导线         */        self.shapeHandler.onmouseover = function (param) {            var shape = param.target;            var seriesIndex = ecData.get(shape, 'seriesIndex');            var dataIndex = ecData.get(shape, 'dataIndex');            var percent = ecData.get(shape, 'special');            var center = [shape.style.x, shape.style.y];            var startAngle = shape.style.startAngle;            var endAngle = shape.style.endAngle;            var midAngle = ((endAngle + startAngle) / 2 + 360) % 360; // 中值            var defaultColor = shape.highlightStyle.color;            // 文本标签,需要显示则会有返回            var label = self.getLabel(                    seriesIndex, dataIndex, percent,                    center, midAngle, defaultColor,                    true                );            if (label) {                self.zr.addHoverShape(label);            }            // 文本标签视觉引导线,需要显示则会有返回            var labelLine = self.getLabelLine(                    seriesIndex, dataIndex,                    center, shape.style.r0, shape.style.r,                    midAngle, defaultColor,                    true                );            if (labelLine) {                self.zr.addHoverShape(labelLine);            }        };        this.refresh(option);    }    Pie.prototype = {        type: ecConfig.CHART_TYPE_PIE,        /**         * 绘制图形         */        _buildShape: function () {            var series = this.series;            var legend = this.component.legend;            this.selectedMap = {};            this._selected = {};            var center;            var radius;            var pieCase;        // 饼图箱子            this._selectedMode = false;            var serieName;            for (var i = 0, l = series.length; i < l; i++) {                if (series[i].type === ecConfig.CHART_TYPE_PIE) {                    series[i] = this.reformOption(series[i]);                    this.legendHoverLink = series[i].legendHoverLink || this.legendHoverLink;                    serieName = series[i].name || '';                    // 系列图例开关                    this.selectedMap[serieName] = legend ? legend.isSelected(serieName) : true;                    if (!this.selectedMap[serieName]) {                        continue;                    }                    center = this.parseCenter(this.zr, series[i].center);                    radius = this.parseRadius(this.zr, series[i].radius);                    this._selectedMode = this._selectedMode || series[i].selectedMode;                    this._selected[i] = [];                    if (this.deepQuery([series[i], this.option], 'calculable')) {                        pieCase = {                            zlevel: series[i].zlevel,                            z: series[i].z,                            hoverable: false,                            style: {                                x: center[0],          // 圆心横坐标                                y: center[1],          // 圆心纵坐标                                // 圆环内外半径                                r0: radius[0] <= 10 ? 0 : radius[0] - 10,                                r: radius[1] + 10,                                brushType: 'stroke',                                lineWidth: 1,                                strokeColor: series[i].calculableHolderColor                                             || this.ecTheme.calculableHolderColor                                             || ecConfig.calculableHolderColor                            }                        };                        ecData.pack(pieCase, series[i], i, undefined, -1);                        this.setCalculable(pieCase);                        pieCase = radius[0] <= 10                                  ? new CircleShape(pieCase)                                  : new RingShape(pieCase);                        this.shapeList.push(pieCase);                    }                    this._buildSinglePie(i);                    this.buildMark(i);                }            }            this.addShapeList();        },        /**         * 构建单个饼图         *         * @param {number} seriesIndex 系列索引         */        _buildSinglePie: function (seriesIndex) {            var series = this.series;            var serie = series[seriesIndex];            var data = serie.data;            var legend = this.component.legend;            var itemName;            var totalSelected = 0;               // 迭代累计选中且非0个数            var totalSelectedValue0 = 0;         // 迭代累计选中0只个数            var totalValue = 0;                  // 迭代累计            var maxValue = Number.NEGATIVE_INFINITY;            var singleShapeList = [];            // 计算需要显示的个数和总值            for (var i = 0, l = data.length; i < l; i++) {                itemName = data[i].name;                this.selectedMap[itemName] = legend ? legend.isSelected(itemName) : true;                if (this.selectedMap[itemName] && !isNaN(data[i].value)) {                    if (+data[i].value !== 0) {                        totalSelected++;                    }                    else {                        totalSelectedValue0++;                    }                    totalValue += +data[i].value;                    maxValue = Math.max(maxValue, +data[i].value);                }            }            if (totalValue === 0) {                return;            }            var percent = 100;            var clockWise = serie.clockWise;            var startAngle = (serie.startAngle.toFixed(2) - 0 + 360) % 360;            var endAngle;            var minAngle = serie.minAngle || 0.01; // #bugfixed            var totalAngle = 360 - (minAngle * totalSelected) - 0.01 * totalSelectedValue0;            var defaultColor;            var roseType = serie.roseType;            var center;            var radius;            var r0;     // 扇形内半径            var r1;     // 扇形外半径            for (var i = 0, l = data.length; i < l; i++) {                itemName = data[i].name;                if (!this.selectedMap[itemName] || isNaN(data[i].value)) {                    continue;                }                // 默认颜色策略,有图例则从图例中获取颜色定义,没有就全局颜色定义                defaultColor = legend ? legend.getColor(itemName) : this.zr.getColor(i);                percent = data[i].value / totalValue;                if (roseType != 'area') {                    endAngle = clockWise                        ? (startAngle - percent * totalAngle - (percent !== 0 ? minAngle : 0.01))                        : (percent * totalAngle + startAngle + (percent !== 0 ? minAngle : 0.01));                }                else {                    endAngle = clockWise                        ? (startAngle - 360 / l)                        : (360 / l + startAngle);                }                endAngle = endAngle.toFixed(2) - 0;                percent = (percent * 100).toFixed(2);                center = this.parseCenter(this.zr, serie.center);                radius = this.parseRadius(this.zr, serie.radius);                r0 = +radius[0];                r1 = +radius[1];                if (roseType === 'radius') {                    r1 = data[i].value / maxValue * (r1 - r0) * 0.8 + (r1 - r0) * 0.2 + r0;                }                else if (roseType === 'area') {                    r1 = Math.sqrt(data[i].value / maxValue) * (r1 - r0) + r0;                }                if (clockWise) {                    var temp;                    temp = startAngle;                    startAngle = endAngle;                    endAngle = temp;                }                this._buildItem(                    singleShapeList,                    seriesIndex, i, percent,                    data[i].selected,                    center, r0, r1,                    startAngle, endAngle, defaultColor                );                if (!clockWise) {                    startAngle = endAngle;                }            }            this._autoLabelLayout(singleShapeList, center, r1);            for (var i = 0, l = singleShapeList.length; i < l; i++) {                this.shapeList.push(singleShapeList[i]);            }            singleShapeList = null;        },        /**         * 构建单个扇形及指标         */        _buildItem: function (            singleShapeList,            seriesIndex, dataIndex, percent,            isSelected,            center, r0, r1,            startAngle, endAngle, defaultColor        ) {            var series = this.series;            var midAngle = ((endAngle + startAngle) / 2 + 360) % 360; // 中值            // 扇形            var sector = this.getSector(                    seriesIndex, dataIndex, percent, isSelected,                    center, r0, r1,                    startAngle, endAngle, defaultColor                );            // 图形需要附加的私有数据            ecData.pack(                sector,                series[seriesIndex], seriesIndex,                series[seriesIndex].data[dataIndex], dataIndex,                series[seriesIndex].data[dataIndex].name,                percent            );            singleShapeList.push(sector);            // 文本标签,需要显示则会有返回            var label = this.getLabel(                    seriesIndex, dataIndex, percent,                    center, midAngle, defaultColor,                    false                );            // 文本标签视觉引导线,需要显示则会有返回            var labelLine = this.getLabelLine(                    seriesIndex, dataIndex,                    center, r0, r1,                    midAngle, defaultColor,                    false                );            if (labelLine) {                ecData.pack(                    labelLine,                    series[seriesIndex], seriesIndex,                    series[seriesIndex].data[dataIndex], dataIndex,                    series[seriesIndex].data[dataIndex].name,                    percent                );                singleShapeList.push(labelLine);            }            if (label) {                ecData.pack(                    label,                    series[seriesIndex], seriesIndex,                    series[seriesIndex].data[dataIndex], dataIndex,                    series[seriesIndex].data[dataIndex].name,                    percent                );                label._labelLine = labelLine;                singleShapeList.push(label);            }        },        /**         * 构建扇形         */        getSector: function (            seriesIndex, dataIndex, percent, isSelected,            center, r0, r1,            startAngle, endAngle, defaultColor        ) {            var series = this.series;            var serie = series[seriesIndex];            var data = serie.data[dataIndex];            var queryTarget = [data, serie];            // 多级控制            var normal = this.deepMerge(                queryTarget,                'itemStyle.normal'            ) || {};            var emphasis = this.deepMerge(                queryTarget,                'itemStyle.emphasis'            ) || {};            var normalColor = this.getItemStyleColor(normal.color, seriesIndex, dataIndex, data)                              || defaultColor;            var emphasisColor = this.getItemStyleColor(emphasis.color, seriesIndex, dataIndex, data)                || (typeof normalColor === 'string'                    ? zrColor.lift(normalColor, -0.2)                    : normalColor                );            var sector = {                zlevel: serie.zlevel,                z: serie.z,                clickable: this.deepQuery(queryTarget, 'clickable'),                style: {                    x: center[0],          // 圆心横坐标                    y: center[1],          // 圆心纵坐标                    r0: r0,         // 圆环内半径                    r: r1,          // 圆环外半径                    startAngle: startAngle,                    endAngle: endAngle,                    brushType: 'both',                    color: normalColor,                    lineWidth: normal.borderWidth,                    strokeColor: normal.borderColor,                    lineJoin: 'round'                },                highlightStyle: {                    color: emphasisColor,                    lineWidth: emphasis.borderWidth,                    strokeColor: emphasis.borderColor,                    lineJoin: 'round'                },                _seriesIndex: seriesIndex,                _dataIndex: dataIndex            };            if (isSelected) {                var midAngle =                    ((sector.style.startAngle + sector.style.endAngle) / 2).toFixed(2) - 0;                sector.style._hasSelected = true;                sector.style._x = sector.style.x;                sector.style._y = sector.style.y;                var offset = this.query(serie, 'selectedOffset');                sector.style.x += zrMath.cos(midAngle, true) * offset;                sector.style.y -= zrMath.sin(midAngle, true) * offset;                this._selected[seriesIndex][dataIndex] = true;            }            else {                this._selected[seriesIndex][dataIndex] = false;            }            if (this._selectedMode) {                sector.onclick = this.shapeHandler.onclick;            }            if (this.deepQuery([data, serie, this.option], 'calculable')) {                this.setCalculable(sector);                sector.draggable = true;            }            // “emphasis显示”添加事件响应            if (this._needLabel(serie, data, true)          // emphasis下显示文本                || this._needLabelLine(serie, data, true)   // emphasis下显示引导线            ) {                sector.onmouseover = this.shapeHandler.onmouseover;            }            sector = new SectorShape(sector);            return sector;        },        /**         * 需要显示则会有返回构建好的shape,否则返回undefined         */        getLabel: function (            seriesIndex, dataIndex, percent,            center, midAngle, defaultColor,            isEmphasis        ) {            var series = this.series;            var serie = series[seriesIndex];            var data = serie.data[dataIndex];            // 特定状态下是否需要显示文本标签            if (!this._needLabel(serie, data, isEmphasis)) {                return;            }            var status = isEmphasis ? 'emphasis' : 'normal';            // serie里有默认配置,放心大胆的用!            var itemStyle = zrUtil.merge(                    zrUtil.clone(data.itemStyle) || {},                    serie.itemStyle                );            // label配置            var labelControl = itemStyle[status].label;            var textStyle = labelControl.textStyle || {};            var centerX = center[0];                      // 圆心横坐标            var centerY = center[1];                      // 圆心纵坐标            var x;            var y;            var radius = this.parseRadius(this.zr, serie.radius);  // 标签位置半径            var textAlign;            var textBaseline = 'middle';            labelControl.position = labelControl.position                                    || itemStyle.normal.label.position;            if (labelControl.position === 'center') {                // center显示                x = centerX;                y = centerY;                textAlign = 'center';            }            else if (labelControl.position === 'inner' || labelControl.position === 'inside') {                // 内部标签显示, 按外半径比例计算标签位置                radius = (radius[0] + radius[1]) * (labelControl.distance || 0.5);                x = Math.round(centerX + radius * zrMath.cos(midAngle, true));                y = Math.round(centerY - radius * zrMath.sin(midAngle, true));                defaultColor = '#fff';                textAlign = 'center';            }            else {                // 外部显示,默认 labelControl.position === 'outer')                radius = radius[1] - (-itemStyle[status].labelLine.length);                x = Math.round(centerX + radius * zrMath.cos(midAngle, true));                y = Math.round(centerY - radius * zrMath.sin(midAngle, true));                textAlign = (midAngle >= 90 && midAngle <= 270) ? 'right' : 'left';            }            if (labelControl.position != 'center'                && labelControl.position != 'inner'                && labelControl.position != 'inside'            ) {                x += textAlign === 'left' ? 20 : -20;            }            data.__labelX = x - (textAlign === 'left' ? 5 : -5);            data.__labelY = y;            var ts = new TextShape({                zlevel: serie.zlevel,                z: serie.z + 1,                hoverable: false,                style: {                    x: x,                    y: y,                    color: textStyle.color || defaultColor,                    text: this.getLabelText(seriesIndex, dataIndex, percent, status),                    textAlign: textStyle.align || textAlign,                    textBaseline: textStyle.baseline || textBaseline,                    textFont: this.getFont(textStyle)                },                highlightStyle: {                    brushType: 'fill'                }            });            ts._radius = radius;            ts._labelPosition = labelControl.position || 'outer';            ts._rect = ts.getRect(ts.style);            ts._seriesIndex = seriesIndex;            ts._dataIndex = dataIndex;            return ts;        },        /**         * 根据lable.format计算label text         */        getLabelText: function (seriesIndex, dataIndex, percent, status) {            var series = this.series;            var serie = series[seriesIndex];            var data = serie.data[dataIndex];            var formatter = this.deepQuery(                [data, serie],                'itemStyle.' + status + '.label.formatter'            );            if (formatter) {                if (typeof formatter === 'function') {                    return formatter.call(                        this.myChart,                        {                            seriesIndex: seriesIndex,                            seriesName: serie.name || '',                            series: serie,                            dataIndex: dataIndex,                            data: data,                            name: data.name,                            value: data.value,                            percent: percent                        }                    );                }                else if (typeof formatter === 'string') {                    formatter = formatter.replace('{a}','{a0}')                                         .replace('{b}','{b0}')                                         .replace('{c}','{c0}')                                         .replace('{d}','{d0}');                    formatter = formatter.replace('{a0}', serie.name)                                         .replace('{b0}', data.name)                                         .replace('{c0}', data.value)                                         .replace('{d0}', percent);                    return formatter;                }            }            else {                return data.name;            }        },        /**         * 需要显示则会有返回构建好的shape,否则返回undefined         */        getLabelLine: function (            seriesIndex, dataIndex,            center, r0, r1,            midAngle, defaultColor,            isEmphasis        ) {            var series = this.series;            var serie = series[seriesIndex];            var data = serie.data[dataIndex];            // 特定状态下是否需要显示文本标签            if (this._needLabelLine(serie, data, isEmphasis)) {                var status = isEmphasis ? 'emphasis' : 'normal';                // serie里有默认配置,放心大胆的用!                var itemStyle = zrUtil.merge(                        zrUtil.clone(data.itemStyle) || {},                        serie.itemStyle                    );                // labelLine配置                var labelLineControl = itemStyle[status].labelLine;                var lineStyle = labelLineControl.lineStyle || {};                var centerX = center[0];                    // 圆心横坐标                var centerY = center[1];                    // 圆心纵坐标                // 视觉引导线起点半径                var minRadius = r1;                // 视觉引导线终点半径                var maxRadius = this.parseRadius(this.zr, serie.radius)[1]                                - (-labelLineControl.length);                var cosValue = zrMath.cos(midAngle, true);                var sinValue = zrMath.sin(midAngle, true);                return new PolylineShape({                    zlevel: serie.zlevel,                    z: serie.z + 1,                    hoverable: false,                    style: {                        pointList: [                            [                                centerX + minRadius * cosValue,                                centerY - minRadius * sinValue                            ],                            [                                centerX + maxRadius * cosValue,                                centerY - maxRadius * sinValue                            ],                            [                                data.__labelX,                                data.__labelY                            ]                        ],                        //xStart: centerX + minRadius * cosValue,                        //yStart: centerY - minRadius * sinValue,                        //xEnd: centerX + maxRadius * cosValue,                        //yEnd: centerY - maxRadius * sinValue,                        strokeColor: lineStyle.color || defaultColor,                        lineType: lineStyle.type,                        lineWidth: lineStyle.width                    },                    _seriesIndex: seriesIndex,                    _dataIndex: dataIndex                });            }            else {                return;            }        },        /**         * 返回特定状态(normal or emphasis)下是否需要显示label标签文本         * @param {Object} serie         * @param {Object} data         * @param {boolean} isEmphasis true is 'emphasis' and false is 'normal'         */        _needLabel: function (serie, data, isEmphasis) {            return this.deepQuery(                [data, serie],                'itemStyle.'                + (isEmphasis ? 'emphasis' : 'normal')                + '.label.show'            );        },        /**         * 返回特定状态(normal or emphasis)下是否需要显示labelLine标签视觉引导线         * @param {Object} serie         * @param {Object} data         * @param {boolean} isEmphasis true is 'emphasis' and false is 'normal'         */        _needLabelLine: function (serie, data, isEmphasis) {            return this.deepQuery(                [data, serie],                'itemStyle.'                + (isEmphasis ? 'emphasis' : 'normal')                +'.labelLine.show'            );        },        /**         * @param {Array.<Object>} sList 单系列图形集合         */        _autoLabelLayout : function (sList, center, r) {            var leftList = [];            var rightList = [];            for (var i = 0, l = sList.length; i < l; i++) {                if (sList[i]._labelPosition === 'outer' || sList[i]._labelPosition === 'outside') {                    sList[i]._rect._y = sList[i]._rect.y;                    if (sList[i]._rect.x < center[0]) {                        leftList.push(sList[i]);                    }                    else {                        rightList.push(sList[i]);                    }                }            }            this._layoutCalculate(leftList, center, r, -1);            this._layoutCalculate(rightList, center, r, 1);        },        /**         * @param {Array.<Object>} tList 单系列文本图形集合         * @param {number} direction 水平方向参数,left为-1,right为1         */        _layoutCalculate : function(tList, center, r, direction) {            tList.sort(function(a, b){                return a._rect.y - b._rect.y;            });            // 压            function _changeDown(start, end, delta, direction) {                for (var j = start; j < end; j++) {                    tList[j]._rect.y += delta;                    tList[j].style.y += delta;                    if (tList[j]._labelLine) {                        tList[j]._labelLine.style.pointList[1][1] += delta;                        tList[j]._labelLine.style.pointList[2][1] += delta;                    }                    if (j > start                        && j + 1 < end                        && tList[j + 1]._rect.y > tList[j]._rect.y + tList[j]._rect.height                    ) {                        _changeUp(j, delta / 2);                        return;                    }                }                _changeUp(end - 1, delta / 2);            }            // 弹            function _changeUp(end, delta) {                for (var j = end; j >= 0; j--) {                    tList[j]._rect.y -= delta;                    tList[j].style.y -= delta;                    if (tList[j]._labelLine) {                        tList[j]._labelLine.style.pointList[1][1] -= delta;                        tList[j]._labelLine.style.pointList[2][1] -= delta;                    }                    if (j > 0                        && tList[j]._rect.y > tList[j - 1]._rect.y + tList[j - 1]._rect.height                    ) {                        break;                    }                }            }            function _changeX(sList, isDownList, center, r, direction) {                var x = center[0];                var y = center[1];                var deltaX;                var deltaY;                var length;                var lastDeltaX = direction > 0                    ? isDownList                // 右侧                        ? Number.MAX_VALUE      // 下                        : 0                     // 上                    : isDownList                // 左侧                        ? Number.MAX_VALUE      // 下                        : 0;                    // 上                for (var i = 0, l = sList.length; i < l; i++) {                    deltaY = Math.abs(sList[i]._rect.y - y);                    length = sList[i]._radius - r;                    deltaX = (deltaY < r + length)                        ? Math.sqrt(                              (r + length + 20) * (r + length + 20)                              - Math.pow(sList[i]._rect.y - y, 2)                          )                        : Math.abs(                              sList[i]._rect.x + (direction > 0 ? 0 : sList[i]._rect.width) - x                          );                    if (isDownList && deltaX >= lastDeltaX) {                        // 右下,左下                        deltaX = lastDeltaX - 10;                    }                    if (!isDownList && deltaX <= lastDeltaX) {                        // 右上,左上                        deltaX = lastDeltaX + 10;                    }                    sList[i]._rect.x = sList[i].style.x = x + deltaX * direction;                    if (sList[i]._labelLine) {                        sList[i]._labelLine.style.pointList[2][0] = x + (deltaX - 5) * direction;                        sList[i]._labelLine.style.pointList[1][0] = x + (deltaX - 20) *direction;                    }                    lastDeltaX = deltaX;                }            }            var lastY = 0;            var delta;            var len = tList.length;            var upList = [];            var downList = [];            for (var i = 0; i < len; i++) {                delta = tList[i]._rect.y - lastY;                if (delta < 0) {                    _changeDown(i, len, -delta, direction);                }                lastY = tList[i]._rect.y + tList[i]._rect.height;            }            if (this.zr.getHeight() - lastY < 0) {                _changeUp(len - 1, lastY - this.zr.getHeight());            }            for (var i = 0; i < len; i++) {                if (tList[i]._rect.y >= center[1]) {                    downList.push(tList[i]);                }                else {                    upList.push(tList[i]);                }            }            _changeX(downList, true, center, r, direction);            _changeX(upList, false, center, r, direction);        },        /**         * 参数修正&默认值赋值,重载基类方法         * @param {Object} opt 参数         */        reformOption: function (opt) {            // 常用方法快捷方式            var _merge = zrUtil.merge;            opt = _merge(                      _merge(                          opt || {}, zrUtil.clone(this.ecTheme.pie || {})                      ),                      zrUtil.clone(ecConfig.pie)                  );            // 通用字体设置            opt.itemStyle.normal.label.textStyle = this.getTextStyle(                opt.itemStyle.normal.label.textStyle            );            opt.itemStyle.emphasis.label.textStyle = this.getTextStyle(                opt.itemStyle.emphasis.label.textStyle            );            this.z = opt.z;            this.zlevel = opt.zlevel;            return opt;        },        /**         * 刷新         */        refresh: function (newOption) {            if (newOption) {                this.option = newOption;                this.series = newOption.series;            }            this.backupShapeList();            this._buildShape();        },        /**         * 动态数据增加动画         */        addDataAnimation: function (params, done) {            var series = this.series;            var aniMap = {}; // seriesIndex索引参数            for (var i = 0, l = params.length; i < l; i++) {                aniMap[params[i][0]] = params[i];            }            var aniCount = 0;            function animationDone() {                aniCount--;                if (aniCount === 0) {                    done && done();                }            }            // 构建新的饼图匹配差异做动画            var sectorMap = {};            var textMap = {};            var lineMap = {};            var backupShapeList = this.shapeList;            this.shapeList = [];            var seriesIndex;            var isHead;            var dataGrow;            var deltaIdxMap = {};   // 修正新增数据后会对dataIndex产生错位匹配            for (var i = 0, l = params.length; i < l; i++) {                seriesIndex = params[i][0];                isHead = params[i][2];                dataGrow = params[i][3];                if (series[seriesIndex]                    && series[seriesIndex].type === ecConfig.CHART_TYPE_PIE                ) {                    if (isHead) {                        if (!dataGrow) {                            sectorMap[                                seriesIndex                                + '_'                                + series[seriesIndex].data.length                            ] = 'delete';                        }                        deltaIdxMap[seriesIndex] = 1;                    }                    else {                        if (!dataGrow) {                            sectorMap[seriesIndex + '_-1'] = 'delete';                            deltaIdxMap[seriesIndex] = -1;                        }                        else {                            deltaIdxMap[seriesIndex] = 0;                        }                    }                    this._buildSinglePie(seriesIndex);                }            }            var dataIndex;            var key;            for (var i = 0, l = this.shapeList.length; i < l; i++) {                seriesIndex = this.shapeList[i]._seriesIndex;                dataIndex = this.shapeList[i]._dataIndex;                key = seriesIndex + '_' + dataIndex;                // map映射让n*n变n                switch (this.shapeList[i].type) {                    case 'sector' :                        sectorMap[key] = this.shapeList[i];                        break;                    case 'text' :                        textMap[key] = this.shapeList[i];                        break;                    case 'polyline' :                        lineMap[key] = this.shapeList[i];                        break;                }            }            this.shapeList = [];            var targeSector;            for (var i = 0, l = backupShapeList.length; i < l; i++) {                seriesIndex = backupShapeList[i]._seriesIndex;                if (aniMap[seriesIndex]) {                    dataIndex = backupShapeList[i]._dataIndex                                + deltaIdxMap[seriesIndex];                    key = seriesIndex + '_' + dataIndex;                    targeSector = sectorMap[key];                    if (!targeSector) {                        continue;                    }                    if (backupShapeList[i].type === 'sector') {                        if (targeSector != 'delete') {                            aniCount++;                            // 原有扇形                            this.zr.animate(backupShapeList[i].id, 'style')                                .when(                                    400,                                    {                                        startAngle: targeSector.style.startAngle,                                        endAngle: targeSector.style.endAngle                                    }                                )                                .done(animationDone)                                .start();                        }                        else {                            aniCount++;                            // 删除的扇形                            this.zr.animate(backupShapeList[i].id, 'style')                                .when(                                    400,                                    deltaIdxMap[seriesIndex] < 0                                    ? { startAngle: backupShapeList[i].style.startAngle }                                    : { endAngle: backupShapeList[i].style.endAngle }                                )                                .done(animationDone)                                .start();                        }                    }                    else if (backupShapeList[i].type === 'text'                             || backupShapeList[i].type === 'polyline'                    ) {                        if (targeSector === 'delete') {                            // 删除逻辑一样                            this.zr.delShape(backupShapeList[i].id);                        }                        else {                            // 懒得新建变量了,借用一下                            switch (backupShapeList[i].type) {                                case 'text':                                    aniCount++;                                    targeSector = textMap[key];                                    this.zr.animate(backupShapeList[i].id, 'style')                                        .when(                                            400,                                            {                                                x :targeSector.style.x,                                                y :targeSector.style.y                                            }                                        )                                        .done(animationDone)                                        .start();                                    break;                                case 'polyline':                                    aniCount++;                                    targeSector = lineMap[key];                                    this.zr.animate(backupShapeList[i].id, 'style')                                        .when(                                            400,                                            {                                                pointList:targeSector.style.pointList                                            }                                        )                                        .done(animationDone)                                        .start();                                    break;                            }                        }                    }                }            }            this.shapeList = backupShapeList;            // 没有动画            if (!aniCount) {                done && done();            }        },        onclick: function (param) {            var series = this.series;            if (!this.isClick || !param.target) {                // 没有在当前实例上发生点击直接返回                return;            }            this.isClick = false;            var offset;             // 偏移            var target = param.target;            var style = target.style;            var seriesIndex = ecData.get(target, 'seriesIndex');            var dataIndex = ecData.get(target, 'dataIndex');            for (var i = 0, len = this.shapeList.length; i < len; i++) {                if (this.shapeList[i].id === target.id) {                    seriesIndex = ecData.get(target, 'seriesIndex');                    dataIndex = ecData.get(target, 'dataIndex');                    // 当前点击的                    if (!style._hasSelected) {                        var midAngle =                            ((style.startAngle + style.endAngle) / 2)                            .toFixed(2) - 0;                        target.style._hasSelected = true;                        this._selected[seriesIndex][dataIndex] = true;                        target.style._x = target.style.x;                        target.style._y = target.style.y;                        offset = this.query(                            series[seriesIndex],                            'selectedOffset'                        );                        target.style.x += zrMath.cos(midAngle, true)                                          * offset;                        target.style.y -= zrMath.sin(midAngle, true)                                          * offset;                    }                    else {                        // 复位                        target.style.x = target.style._x;                        target.style.y = target.style._y;                        target.style._hasSelected = false;                        this._selected[seriesIndex][dataIndex] = false;                    }                    this.zr.modShape(target.id);                }                else if (this.shapeList[i].style._hasSelected                         && this._selectedMode === 'single'                ) {                    seriesIndex = ecData.get(this.shapeList[i], 'seriesIndex');                    dataIndex = ecData.get(this.shapeList[i], 'dataIndex');                    // 单选模式下需要取消其他已经选中的                    this.shapeList[i].style.x = this.shapeList[i].style._x;                    this.shapeList[i].style.y = this.shapeList[i].style._y;                    this.shapeList[i].style._hasSelected = false;                    this._selected[seriesIndex][dataIndex] = false;                    this.zr.modShape(this.shapeList[i].id);                }            }            this.messageCenter.dispatch(                ecConfig.EVENT.PIE_SELECTED,                param.event,                {                    selected: this._selected,                    target:  ecData.get(target, 'name')                },                this.myChart            );            this.zr.refreshNextFrame();        }    };    zrUtil.inherits(Pie, ChartBase);    // 图表注册    require('../chart').define('pie', Pie);    return Pie;});
 |