From ce0fffabf49089f750f1df552c2d39e2e627d7a2 Mon Sep 17 00:00:00 2001
From: yufeng04 <yufeng04@baidu.com>
Date: Sat, 21 Sep 2019 01:06:48 +0800
Subject: [PATCH] fix bug #7340

---
 src/component/legend/LegendModel.js |   8 +
 src/component/legend/LegendView.js  |  49 +++-
 src/model/Series.js                 |   5 +
 src/model/mixin/dataFormat.js       |   2 +
 src/visual/dataColor.js             |  28 +-
 src/visual/seriesColor.js           |  21 ++
 test/lengend-borderColor.html       | 402 ++++++++++++++++++++++++++++
 7 files changed, 504 insertions(+), 11 deletions(-)
 create mode 100644 test/lengend-borderColor.html

diff --git a/src/component/legend/LegendModel.js b/src/component/legend/LegendModel.js
index 70bf54040e..5442c302f3 100644
--- a/src/component/legend/LegendModel.js
+++ b/src/component/legend/LegendModel.js
@@ -283,6 +283,14 @@ var LegendModel = echarts.extendComponentModel({
         // 图例关闭时候的颜色
         inactiveColor: '#ccc',
 
+        // 图例关闭时候的颜色
+        inactiveBorderColor: '#ccc',
+
+        itemStyle: {
+            // 图例默认无边框
+            borderWidth: 0
+        },
+
         textStyle: {
             // 图例文字颜色
             color: '#333'
diff --git a/src/component/legend/LegendView.js b/src/component/legend/LegendView.js
index fc0d15660e..f12f5336ba 100644
--- a/src/component/legend/LegendView.js
+++ b/src/component/legend/LegendView.js
@@ -179,6 +179,7 @@ export default echarts.extendComponentView({
             if (seriesModel) {
                 var data = seriesModel.getData();
                 var color = data.getVisual('color');
+                var borderColor = data.getVisual('borderColor');
 
                 // If color is a callback function
                 if (typeof color === 'function') {
@@ -186,6 +187,12 @@ export default echarts.extendComponentView({
                     color = color(seriesModel.getDataParams(0));
                 }
 
+                 // If borderColor is a callback function
+                if (typeof borderColor === 'function') {
+                    // Use the first data
+                    borderColor = borderColor(seriesModel.getDataParams(0));
+                }
+
                 // Using rect symbol defaultly
                 var legendSymbolType = data.getVisual('legendSymbol') || 'roundRect';
                 var symbolType = data.getVisual('symbol');
@@ -193,7 +200,7 @@ export default echarts.extendComponentView({
                 var itemGroup = this._createItem(
                     name, dataIndex, itemModel, legendModel,
                     legendSymbolType, symbolType,
-                    itemAlign, color,
+                    itemAlign, color, borderColor,
                     selectMode
                 );
 
@@ -219,13 +226,14 @@ export default echarts.extendComponentView({
                         }
 
                         var color = data.getItemVisual(idx, 'color');
+                        var borderColor = data.getItemVisual(idx, 'borderColor');
 
                         var legendSymbolType = 'roundRect';
 
                         var itemGroup = this._createItem(
                             name, dataIndex, itemModel, legendModel,
                             legendSymbolType, null,
-                            itemAlign, color,
+                            itemAlign, color, borderColor,
                             selectMode
                         );
 
@@ -299,12 +307,14 @@ export default echarts.extendComponentView({
     _createItem: function (
         name, dataIndex, itemModel, legendModel,
         legendSymbolType, symbolType,
-        itemAlign, color, selectMode
+        itemAlign, color, borderColor, selectMode
     ) {
         var itemWidth = legendModel.get('itemWidth');
         var itemHeight = legendModel.get('itemHeight');
         var inactiveColor = legendModel.get('inactiveColor');
+        var inactiveBorderColor = legendModel.get('inactiveBorderColor');
         var symbolKeepAspect = legendModel.get('symbolKeepAspect');
+        var itemStyle = legendModel.getModel('itemStyle').getItemStyle();
 
         var isSelected = legendModel.isSelected(name);
         var itemGroup = new Group();
@@ -318,7 +328,7 @@ export default echarts.extendComponentView({
 
         // Use user given icon first
         legendSymbolType = itemIcon || legendSymbolType;
-        itemGroup.add(createSymbol(
+        var legendSymbol = createSymbol(
             legendSymbolType,
             0,
             0,
@@ -327,7 +337,13 @@ export default echarts.extendComponentView({
             isSelected ? color : inactiveColor,
             // symbolKeepAspect default true for legend
             symbolKeepAspect == null ? true : symbolKeepAspect
-        ));
+        );
+        itemGroup.add(
+            setSympleStyle(
+                legendSymbol, legendSymbolType, itemStyle,
+                borderColor, inactiveBorderColor, isSelected
+            )
+        );
 
         // Compose symbols
         // PENDING
@@ -339,8 +355,7 @@ export default echarts.extendComponentView({
             if (symbolType === 'none') {
                 symbolType = 'circle';
             }
-            // Put symbol in the center
-            itemGroup.add(createSymbol(
+            var legendSymbolCenter = createSymbol(
                 symbolType,
                 (itemWidth - size) / 2,
                 (itemHeight - size) / 2,
@@ -349,7 +364,14 @@ export default echarts.extendComponentView({
                 isSelected ? color : inactiveColor,
                 // symbolKeepAspect default true for legend
                 symbolKeepAspect == null ? true : symbolKeepAspect
-            ));
+            );
+            // Put symbol in the center
+            itemGroup.add(
+                setSympleStyle(
+                    legendSymbolCenter, symbolType, itemStyle,
+                    borderColor, inactiveBorderColor, isSelected
+                )
+            );
         }
 
         var textX = itemAlign === 'left' ? itemWidth + 5 : -5;
@@ -481,6 +503,17 @@ export default echarts.extendComponentView({
 
 });
 
+function setSympleStyle(symbol, symbolType, itemStyle, borderColor, inactiveBorderColor, isSelected) {
+    if (symbolType !== 'line' && symbolType.indexOf('empty') < 0) {
+        symbol.style.stroke = borderColor;
+        if (!isSelected) {
+            itemStyle.stroke = inactiveBorderColor;
+        }
+        symbol.setStyle(itemStyle);
+    }
+    return symbol;
+}
+
 function dispatchSelectAction(name, api) {
     api.dispatchAction({
         type: 'legendToggleSelect',
diff --git a/src/model/Series.js b/src/model/Series.js
index 395a096560..8b090e6b93 100644
--- a/src/model/Series.js
+++ b/src/model/Series.js
@@ -73,6 +73,11 @@ var SeriesModel = ComponentModel.extend({
      */
     visualColorAccessPath: 'itemStyle.color',
 
+    /**
+     * Access path of borderColor for visual
+     */
+    visualBorderColorAccessPath: 'itemStyle.borderColor',
+
     /**
      * Support merge layout params.
      * Only support 'box' now (left/right/top/bottom/width/height).
diff --git a/src/model/mixin/dataFormat.js b/src/model/mixin/dataFormat.js
index 1d10e6e55d..64d4643092 100644
--- a/src/model/mixin/dataFormat.js
+++ b/src/model/mixin/dataFormat.js
@@ -38,6 +38,7 @@ export default {
         var name = data.getName(dataIndex);
         var itemOpt = data.getRawDataItem(dataIndex);
         var color = data.getItemVisual(dataIndex, 'color');
+        var borderColor = data.getItemVisual(dataIndex, 'borderColor');
         var tooltipModel = this.ecModel.getComponent('tooltip');
         var renderModeOption = tooltipModel && tooltipModel.get('renderMode');
         var renderMode = getTooltipRenderMode(renderModeOption);
@@ -59,6 +60,7 @@ export default {
             dataType: dataType,
             value: rawValue,
             color: color,
+            borderColor: borderColor,
             dimensionNames: userOutput ? userOutput.dimensionNames : null,
             encode: userOutput ? userOutput.encode : null,
             marker: getTooltipMarker({
diff --git a/src/visual/dataColor.js b/src/visual/dataColor.js
index 8fbd9ebfd4..5d5f1523fe 100644
--- a/src/visual/dataColor.js
+++ b/src/visual/dataColor.js
@@ -53,10 +53,13 @@ export default function (seriesType) {
                 var singleDataColor = filteredIdx != null
                     && data.getItemVisual(filteredIdx, 'color', true);
 
-                if (!singleDataColor) {
-                    // FIXME Performance
-                    var itemModel = dataAll.getItemModel(rawIdx);
+                var singleDataBorderColor = filteredIdx != null
+                    && data.getItemVisual(filteredIdx, 'borderColor', true);
+
+                // FIXME Performance
+                var itemModel = dataAll.getItemModel(rawIdx);
 
+                if (!singleDataColor) {
                     var color = itemModel.get('itemStyle.color')
                         || seriesModel.getColorFromPalette(
                             dataAll.getName(rawIdx) || (rawIdx + ''), seriesModel.__paletteScope,
@@ -74,6 +77,25 @@ export default function (seriesType) {
                     // Set data all color for legend
                     dataAll.setItemVisual(rawIdx, 'color', singleDataColor);
                 }
+
+                if (!singleDataBorderColor) {
+                    var borderColor = itemModel.get('itemStyle.borderColor')
+                    || seriesModel.getColorFromPalette(
+                        dataAll.getName(rawIdx) || (rawIdx + ''), seriesModel.__paletteScope,
+                        dataAll.count()
+                    );
+                    // Legend may use the visual info in data before processed
+                    dataAll.setItemVisual(rawIdx, 'borderColor', borderColor);
+
+                    // Data is not filtered
+                    if (filteredIdx != null) {
+                        data.setItemVisual(filteredIdx, 'borderColor', borderColor);
+                    }
+                }
+                else {
+                    // Set data all borderColor for legend
+                    dataAll.setItemVisual(rawIdx, 'borderColor', singleDataBorderColor);
+                }
             });
         }
     };
diff --git a/src/visual/seriesColor.js b/src/visual/seriesColor.js
index b253fff6ea..0cd240ab1c 100644
--- a/src/visual/seriesColor.js
+++ b/src/visual/seriesColor.js
@@ -33,6 +33,15 @@ export default {
 
         // FIXME Set color function or use the platte color
         data.setVisual('color', color);
+        
+        var borderColorAccessPath = (seriesModel.visualBorderColorAccessPath || 'itemStyle.borderColor').split('.');
+        var borderColor = seriesModel.get(borderColorAccessPath) // Set in itemStyle
+            || seriesModel.getColorFromPalette(
+                // TODO series count changed.
+                seriesModel.name, null, ecModel.getSeriesCount()
+            );  // Default borderColor
+        // FIXME Set borderColor function or use the platte borderColor
+        data.setVisual('borderColor', borderColor);
 
         // Only visible series has each data be visual encoded
         if (!ecModel.isSeriesFiltered(seriesModel)) {
@@ -44,13 +53,25 @@ export default {
                 });
             }
 
+            if (typeof borderColor === 'function' && !(borderColor instanceof Gradient)) {
+                data.each(function (idx) {
+                    data.setItemVisual(
+                        idx, 'borderColor', borderColor(seriesModel.getDataParams(idx))
+                    );
+                });
+            }
+
             // itemStyle in each data item
             var dataEach = function (data, idx) {
                 var itemModel = data.getItemModel(idx);
                 var color = itemModel.get(colorAccessPath, true);
+                var borderColor = itemModel.get(borderColorAccessPath, true);
                 if (color != null) {
                     data.setItemVisual(idx, 'color', color);
                 }
+                if (borderColor != null) {
+                    data.setItemVisual(idx, 'borderColor', borderColor);
+                }
             };
 
             return { dataEach: data.hasItemOption ? dataEach : null };
diff --git a/test/lengend-borderColor.html b/test/lengend-borderColor.html
new file mode 100644
index 0000000000..d7515332d7
--- /dev/null
+++ b/test/lengend-borderColor.html
@@ -0,0 +1,402 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<html>
+
+<head>
+    <meta charset="utf-8">
+    <script src="lib/esl.js"></script>
+    <script src="lib/config.js"></script>
+    <meta name="viewport" content="width=device-width, initial-scale=1" />
+</head>
+
+<body>
+    <style>
+        h1 {
+            line-height: 60px;
+            height: 60px;
+            background: #146402;
+            text-align: center;
+            font-weight: bold;
+            color: #eee;
+            font-size: 14px;
+        }
+        .chart {
+            height: 300px;
+        }
+    </style>
+
+    <h1>The line in legend symble should be default value and the borderWidth of legend symble should be legend.itemSyle.borderWidth</h1>
+    <div class="chart" id="plain"></div>
+    <h1>The style with legend symble should be series[i].itemStyle</h1>
+    <div class="chart" id="plain1"></div>
+    <h1>The style with legend symble should be legend.itemStyle</h1>
+    <div class="chart" id="plain2"></div>
+    <script>
+        require([
+            'echarts'
+            // 'echarts/util/graphic',
+            // 'echarts/chart/line',
+            // 'echarts/component/legend',
+            // 'echarts/component/grid',
+            // 'echarts/component/tooltip'
+        ], function (echarts) {
+            var graphic = echarts.graphic;
+
+                var chart = echarts.init(document.getElementById('plain'), null, {
+
+                });
+
+                var option = {
+                    tooltip: {
+                        trigger: 'axis',
+                        axisPointer: {
+                            type: 'cross',
+                            label: {
+                                backgroundColor: '#6a7985'
+                            }
+                        }
+                    },
+                    legend: {
+                        data: ['邮件营销', '联盟广告', '视频广告', '直接访问', '搜索引擎'],
+                        itemStyle: {
+                            // borderColor: '#f00',
+                            borderWidth: 3
+                        }
+                    },
+                    toolbox: {
+                        feature: {
+                            saveAsImage: {}
+                        }
+                    },
+                    grid: {
+                        left: '3%',
+                        right: '4%',
+                        bottom: '3%',
+                        containLabel: true
+                    },
+                    xAxis: [
+                        {
+                            type: 'category',
+                            boundaryGap: false,
+                            data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
+                        }
+                    ],
+                    yAxis: [
+                        {
+                            type: 'value'
+                        }
+                    ],
+                    series: [
+                        {
+                            name: '邮件营销',
+                            type: 'line',
+                            stack: '总量',
+                            areaStyle: {},
+                            // default emptyCircle
+                            // symbol: 'circle',
+                            itemStyle: {
+                                borderColor: '#096',
+                                borderWidth: 1
+                            },
+                            data: [120, 132, 101, 134, 90, 230, 210]
+                        },
+                        {
+                            name: '联盟广告',
+                            type: 'line',
+                            stack: '总量',
+                            areaStyle: {},
+                            symbol: 'circle',
+                            itemStyle: {
+                                borderColor: '#ffde33',
+                                borderWidth: 1
+                            },
+                            data: [220, 182, 191, 234, 290, 330, 310]
+                        },
+                        {
+                            name: '视频广告',
+                            type: 'line',
+                            stack: '总量',
+                            areaStyle: {},
+                            symbol: 'rect',
+                            itemStyle: {
+                                borderColor: '#ff9933',
+                                borderWidth: 2
+                            },
+                            data: [150, 232, 201, 154, 190, 330, 410]
+                        },
+                        {
+                            name: '直接访问',
+                            type: 'line',
+                            stack: '总量',
+                            areaStyle: { normal: {} },
+                            symbol: 'roundRect',
+                            itemStyle: {
+                                borderColor: '#cc0033',
+                                borderWidth: 3
+                            },
+                            data: [320, 332, 301, 334, 390, 330, 320]
+                        },
+                        {
+                            name: '搜索引擎',
+                            type: 'line',
+                            stack: '总量',
+                            label: {
+                                normal: {
+                                    show: true,
+                                    position: 'top'
+                                }
+                            },
+                            areaStyle: { normal: {} },
+                            symbol: 'triangle',
+                            itemStyle: {
+                                borderColor: '#660099',
+                                borderWidth: 4
+                            },
+                            data: [820, 932, 901, 934, 1290, 1330, 1320]
+                        }
+                    ]
+                };
+            chart.setOption(option);
+
+            var chart1 = echarts.init(document.getElementById('plain1'), null, {});
+
+            var option1 = {
+                tooltip: {
+                    trigger: 'axis',
+                    axisPointer: {            // 坐标轴指示器,坐标轴触发有效
+                        type: 'shadow'        // 默认为直线,可选为:'line' | 'shadow'
+                    }
+                },
+                legend: {
+                    data: ['直接访问', '邮件营销', '联盟广告', '视频广告', '搜索引擎', '百度', '谷歌', '必应', '其他'],
+                    itemStyle: {
+                        borderWidth: 3
+                    }
+                },
+                grid: {
+                    left: '3%',
+                    right: '4%',
+                    bottom: '3%',
+                    containLabel: true
+                },
+                xAxis: [
+                    {
+                        type: 'category',
+                        data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
+                    }
+                ],
+                yAxis: [
+                    {
+                        type: 'value'
+                    }
+                ],
+                series: [
+                    {
+                        name: '直接访问',
+                        type: 'bar',
+                        data: [320, 332, 301, 334, 390, 330, 320],
+                        itemStyle: {
+                            borderColor: '#000',
+                            borderWidth: 3
+                        }
+                    },
+                    {
+                        name: '邮件营销',
+                        type: 'bar',
+                        stack: '广告',
+                        data: [120, 132, 101, 134, 90, 230, 210],
+                        itemStyle: {
+                            borderColor: '#f00',
+                            borderWidth: 0
+                        }
+                    },
+                    {
+                        name: '联盟广告',
+                        type: 'bar',
+                        stack: '广告',
+                        data: [220, 182, 191, 234, 290, 330, 310]
+                    },
+                    {
+                        name: '视频广告',
+                        type: 'bar',
+                        stack: '广告',
+                        data: [150, 232, 201, 154, 190, 330, 410]
+                    },
+                    {
+                        name: '搜索引擎',
+                        type: 'bar',
+                        data: [862, 1018, 964, 1026, 1679, 1600, 1570],
+                        markLine: {
+                            lineStyle: {
+                                normal: {
+                                    type: 'dashed'
+                                }
+                            },
+                            data: [
+                                [{ type: 'min' }, { type: 'max' }]
+                            ]
+                        }
+                    },
+                    {
+                        name: '百度',
+                        type: 'bar',
+                        barWidth: 5,
+                        stack: '搜索引擎',
+                        data: [620, 732, 701, 734, 1090, 1130, 1120]
+                    },
+                    {
+                        name: '谷歌',
+                        type: 'bar',
+                        stack: '搜索引擎',
+                        data: [120, 132, 101, 134, 290, 230, 220]
+                    },
+                    {
+                        name: '必应',
+                        type: 'bar',
+                        stack: '搜索引擎',
+                        data: [60, 72, 71, 74, 190, 130, 110]
+                    },
+                    {
+                        name: '其他',
+                        type: 'bar',
+                        stack: '搜索引擎',
+                        data: [62, 82, 91, 84, 109, 110, 120]
+                    }
+                ]
+            };
+            chart1.setOption(option1);
+
+
+            var chart2 = echarts.init(document.getElementById('plain2'), null, {});
+
+            var option2 = {
+                    tooltip: {
+                        trigger: 'item',
+                        formatter: "{a} <br/>{b}: {c} ({d}%)"
+                    },
+                    legend: {
+                        orient: 'vertical',
+                        x: 'left',
+                        data: ['直达', '营销广告', '搜索引擎', '邮件营销', '联盟广告', '视频广告', '百度', '谷歌', '必应', '其他'],
+                        itemStyle: {
+                            borderWidth: 3,
+                            borderColor: '#f00'
+                        }
+                    },
+                    series: [
+                        {
+                            name: '访问来源',
+                            type: 'pie',
+                            selectedMode: 'single',
+                            radius: [0, '30%'],
+
+                            label: {
+                                normal: {
+                                    position: 'inner'
+                                }
+                            },
+                            itemStyle: {
+                                borderColor: '#ff9933',
+                                borderWidth: 2
+                            },
+                            labelLine: {
+                                normal: {
+                                    show: false
+                                }
+                            },
+                            data: [
+                                { value: 335, name: '直达', selected: true },
+                                { value: 679, name: '营销广告' },
+                                { value: 1548, name: '搜索引擎' }
+                            ]
+                        },
+                        {
+                            name: '访问来源',
+                            type: 'pie',
+                            radius: ['40%', '55%'],
+                            label: {
+                                normal: {
+                                    formatter: '{a|{a}}{abg|}\n{hr|}\n  {b|{b}:}{c}  {per|{d}%}  ',
+                                    backgroundColor: '#eee',
+                                    borderColor: '#aaa',
+                                    borderWidth: 1,
+                                    borderRadius: 4,
+                                    // shadowBlur:3,
+                                    // shadowOffsetX: 2,
+                                    // shadowOffsetY: 2,
+                                    // shadowColor: '#999',
+                                    // padding: [0, 7],
+                                    rich: {
+                                        a: {
+                                            color: '#999',
+                                            lineHeight: 22,
+                                            align: 'center'
+                                        },
+                                        // abg: {
+                                        //     backgroundColor: '#333',
+                                        //     width: '100%',
+                                        //     align: 'right',
+                                        //     height: 22,
+                                        //     borderRadius: [4, 4, 0, 0]
+                                        // },
+                                        hr: {
+                                            borderColor: '#aaa',
+                                            width: '100%',
+                                            borderWidth: 0.5,
+                                            height: 0
+                                        },
+                                        b: {
+                                            fontSize: 16,
+                                            lineHeight: 33
+                                        },
+                                        per: {
+                                            color: '#eee',
+                                            backgroundColor: '#334455',
+                                            padding: [2, 4],
+                                            borderRadius: 2
+                                        }
+                                    }
+                                }
+                            },
+                            itemStyle: {
+                                borderColor: '#660099',
+                                borderWidth: 4
+                            },
+                            data: [
+                                { value: 335, name: '直达' },
+                                { value: 310, name: '邮件营销' },
+                                { value: 234, name: '联盟广告' },
+                                { value: 135, name: '视频广告' },
+                                { value: 1048, name: '百度' },
+                                { value: 251, name: '谷歌' },
+                                { value: 147, name: '必应' },
+                                { value: 102, name: '其他' }
+                            ]
+                        }
+                    ]
+                };
+                chart2.setOption(option2);
+
+        });
+
+    </script>
+</body>
+
+</html>
\ No newline at end of file