Richard.Ma 发表于 2024-1-22 11:47:25

GCExcel复制Chart中一个系列的配置到另一个系列

本帖最后由 Richard.Ma 于 2024-1-22 12:10 编辑

在通过GCExcel代码自动化构建可视化图表的过程中,一些用户需要复制图表系列的配置,包括样式。以及系列中包含的元素及样式,如:数据标签,趋势线,误差线 等等。

本教程提供了代码复制同一个Chart的一个系列的样式及元素到另一个系列,以提供相同的展示效果。同时,大家也通过代码可以更好的理解系列中的样式和元素的结构。

首先,需要明确以下的前提条件

1.不是所有的内容都是可以复制的,不同系列一些属性肯定是不同的,否则图表会出错或者不同系列本身也就没有意义了。例如:系列名称,系列的引用数据区域等等

2.不是所有的Chart类型都有多个系列的,例如饼图,散点图,股票图,瀑布图等图表类型,都是用来展示单个系列的。

3.一个图表内的多个系列如果是不同的Chart类型,例如一个是柱形图,一个是点线图。那么相关的样式选项是不同的。因此复制时,应该先同步系列的类型。

4.对于填充,边框等等的样式,除了给series本身设置外,还需要注意给系列中的每个数据点设置。


具体的代码可以参考文末,提供了一个CloneSeries的静态方法。可以复制系列
需要调用的时候,可以通过这句代码
ChartHelper.CloneSeries(chart.SeriesCollection, chart.SeriesCollection);
具体效果:

复制配置前


复制配置后



以下代码为C#代码,适用于GCExcel.NET组件,GCExcel Java版本和.NET版本的接口命名规则很类似。如有需要可以参考编写对应代码。

CloneSeries方法↓↓↓↓↓
public static class ChartHelper
{
    public static void CloneSeries(ISeries newSer, ISeries oldSer)
    {
      newSer.ChartType = oldSer.ChartType;

      //判断图表类型,当前仅测试了柱状图,折线图,面积图,条形图
      if (newSer.ChartType != ChartType.ColumnClustered &&
            newSer.ChartType != ChartType.Line &&
            newSer.ChartType != ChartType.LineMarkers &&
            newSer.ChartType != ChartType.Area &&
            newSer.ChartType != ChartType.BarClustered
            )
      {
            Exception ex = new Exception("Clone Series operation is not supported for this chart type");
            throw ex;
      }
      

      newSer.AxisGroup = oldSer.AxisGroup;
      newSer.PictureType = oldSer.PictureType;
      newSer.Smooth = oldSer.Smooth;


      //Format
      CloneFill(newSer.Format.Fill, oldSer.Format.Fill);
      CloneLine(newSer.Format.Line, oldSer.Format.Line);
      Clone3D(newSer.Format.ThreeD, oldSer.Format.ThreeD);//阴影/发光/柔化/3D等可以自己再设置
      newSer.InvertIfNegative = oldSer.InvertIfNegative;
      if (newSer.InvertIfNegative)
      {
            CloneColor(newSer.InvertColor, oldSer.InvertColor);
      }
            

      //Points Format
      for (int i = 0; i < Math.Min(newSer.Points.Count, oldSer.Points.Count); i++)
      {
            CloneFill(newSer.Points.Format.Fill, oldSer.Points.Format.Fill);
            CloneLine(newSer.Points.Format.Line, oldSer.Points.Format.Line);
      }

      //MarkerFormat for LineMarkers
      if (newSer.ChartType == ChartType.LineMarkers)
      {
            newSer.ShowMeanMarkers = oldSer.ShowMeanMarkers;
            newSer.MarkerSize = oldSer.MarkerSize;
            newSer.MarkerStyle = oldSer.MarkerStyle;
            CloneFill(newSer.MarkerFormat.Fill, oldSer.MarkerFormat.Fill);
            CloneLine(newSer.MarkerFormat.Line, oldSer.MarkerFormat.Line);
            for (int i = 0; i < Math.Min(newSer.Points.Count, oldSer.Points.Count); i++)
            {
                CloneFill(newSer.Points.MarkerFormat.Fill, oldSer.Points.MarkerFormat.Fill);
                CloneLine(newSer.Points.MarkerFormat.Line, oldSer.Points.MarkerFormat.Line);
            }
      }


      //Series DataLabels
      newSer.HasDataLabels = oldSer.HasDataLabels;
      if (newSer.HasDataLabels)
      {
            CloneFill(newSer.DataLabels.Format.Fill, oldSer.DataLabels.Format.Fill);
            CloneLine(newSer.DataLabels.Format.Line, oldSer.DataLabels.Format.Line);
            CloneFont(newSer.DataLabels.Font, oldSer.DataLabels.Font);
            CloneLabelOptions(newSer.DataLabels, oldSer.DataLabels, newSer.ChartType);

            //Point DataLabels
            for (int i = 0; i < Math.Min(newSer.DataLabels.Count, oldSer.DataLabels.Count); i++)
            {
                CloneFill(newSer.DataLabels.Format.Fill, oldSer.DataLabels.Format.Fill);
                CloneLine(newSer.DataLabels.Format.Line, oldSer.DataLabels.Format.Line);
                CloneFont(newSer.DataLabels.Font, oldSer.DataLabels.Font);
            }
      }
      //Trendlines
      newSer.Trendlines.All((tl) => { tl.Delete(); return true; });
      oldSer.Trendlines.All((tl) => { newSer.Trendlines.Add(); return true; });
      for (int i = 0; i < Math.Min(newSer.Trendlines.Count, oldSer.Trendlines.Count); i++)
      {
            CloneLine(newSer.Trendlines.Format.Line, oldSer.Trendlines.Format.Line);
            newSer.Trendlines.Type = oldSer.Trendlines.Type;
            if (newSer.Trendlines.Type == TrendlineType.MovingAvg)
                newSer.Trendlines.Period = oldSer.Trendlines.Period;
            if (newSer.Trendlines.Type == TrendlineType.Polynomial)
                newSer.Trendlines.Order = oldSer.Trendlines.Order;
            newSer.Trendlines.Backward = oldSer.Trendlines.Backward;
            newSer.Trendlines.Forward = oldSer.Trendlines.Forward;
            newSer.Trendlines.Intercept = oldSer.Trendlines.Intercept;
            newSer.Trendlines.DisplayEquation = oldSer.Trendlines.DisplayEquation;
            newSer.Trendlines.DisplayRSquared = oldSer.Trendlines.DisplayRSquared;
      }

      //ErrorBar
      if (oldSer.HasErrorBars)
      {
            newSer.HasErrorBars = oldSer.HasErrorBars;
            CloneErrorBar(newSer.YErrorBar, oldSer.YErrorBar);
      }
    }

    private static void CloneFill(IFillFormat newFill, IFillFormat oldFill)
    {

      switch (oldFill.Type)
      {
            case FillType.Solid:

                newFill.Color.ColorType = oldFill.Color.ColorType;
                switch (newFill.Color.ColorType)
                {
                  case SolidColorType.RGB:
                        newFill.Color.RGB = oldFill.Color.RGB;
                        break;
                  case SolidColorType.Theme:
                        newFill.Color.ObjectThemeColor = oldFill.Color.ObjectThemeColor;
                        newFill.Color.TintAndShade = oldFill.Color.TintAndShade;
                        break;
                }
                newFill.Color.Brightness = oldFill.Color.Brightness;
                newFill.Transparency = oldFill.Transparency;
                newFill.Solid();
                break;
            case FillType.Gradient:
                newFill.PresetGradient(oldFill.GradientStyle, oldFill.GradientVariant, oldFill.PresetGradientType);
                foreach (IGradientStop item in oldFill.GradientStops)
                {
                  newFill.GradientStops.Insert(item.Color.RGB.ToArgb(), item.Position, item.Transparency);
                }
                newFill.GradientPathType = oldFill.GradientPathType;
                newFill.GradientAngle = oldFill.GradientAngle;
                break;
            case FillType.Picture:
                //newFill.UserPicture("");   //不提供获取接口

                newFill.PatternColor.RGB = oldFill.PatternColor.RGB;
                newFill.PatternColor.ObjectThemeColor = oldFill.PatternColor.ObjectThemeColor;
                newFill.PatternColor.ColorType = oldFill.PatternColor.ColorType;
                newFill.PatternColor.TintAndShade = oldFill.PatternColor.TintAndShade;
                newFill.PatternColor.Brightness = oldFill.PatternColor.Brightness;
                newFill.Transparency = oldFill.Transparency;
                break;
            case FillType.Textured:
                newFill.PresetTextured(oldFill.PresetTexture);
                newFill.TextureAlignment = oldFill.TextureAlignment;
                newFill.TextureOffsetX = oldFill.TextureOffsetX;
                newFill.TextureOffsetY = oldFill.TextureOffsetY;
                break;
            case FillType.Patterned:
                newFill.Patterned(oldFill.Pattern);
                newFill.PatternColor.ColorType = oldFill.PatternColor.ColorType;
                switch (newFill.PatternColor.ColorType)
                {
                  case SolidColorType.RGB:
                        newFill.Color.RGB = oldFill.Color.RGB;
                        newFill.PatternColor.RGB = oldFill.PatternColor.RGB;
                        break;
                  case SolidColorType.Theme:
                        newFill.Color.ObjectThemeColor = oldFill.Color.ObjectThemeColor;
                        newFill.Color.TintAndShade = oldFill.Color.TintAndShade;
                        newFill.PatternColor.ObjectThemeColor = oldFill.PatternColor.ObjectThemeColor;
                        newFill.PatternColor.TintAndShade = oldFill.PatternColor.TintAndShade;
                        break;
                }
                newFill.PatternColor.Brightness = oldFill.PatternColor.Brightness;
                newFill.Transparency = oldFill.Transparency;
                break;
      }
      newFill.Visible = oldFill.Visible;
    }
    private static void CloneLine(ILineFormat newLine, ILineFormat oldLine)
    {
      newLine.Style = oldLine.Style;
      newLine.Weight = oldLine.Weight;
      newLine.DashStyle = oldLine.DashStyle;
      newLine.Transparency = oldLine.Transparency;
      switch (oldLine.Type)
      {
            case FillType.Solid:
                newLine.Solid();
                CloneColor(newLine.Color, oldLine.Color);
                break;
            case FillType.Gradient:


                newLine.PresetGradient(oldLine.GradientStyle, oldLine.GradientVariant, PresetGradientType.Ocean);
                foreach (IGradientStop item in oldLine.GradientStops)
                  newLine.GradientStops.Insert(item.Color.RGB.ToArgb(), item.Position, item.Transparency);
                newLine.GradientAngle = oldLine.GradientAngle;
                break;


      }
      newLine.Visible = oldLine.Visible;
    }
    private static void CloneColor(IColorFormat newColor, IColorFormat oldColor)
    {
      newColor.ColorType = oldColor.ColorType;
      switch (newColor.ColorType)
      {
            case SolidColorType.RGB:
                newColor.RGB = oldColor.RGB;
                break;
            case SolidColorType.Theme:
                newColor.ObjectThemeColor = oldColor.ObjectThemeColor;
                newColor.TintAndShade = oldColor.TintAndShade;
                break;
      }
      newColor.Brightness = oldColor.Brightness;
    }
    private static void CloneFont(IFontFormat newFont, IFontFormat oldFont)
    {
      newFont.Color.ColorType = oldFont.Color.ColorType;
      switch (newFont.Color.ColorType)
      {
            case SolidColorType.RGB:
                newFont.Color.RGB = oldFont.Color.RGB;
                break;
            case SolidColorType.Theme:
                newFont.Color.ObjectThemeColor = oldFont.Color.ObjectThemeColor;
                newFont.Color.TintAndShade = oldFont.Color.TintAndShade;
                break;
      }
      newFont.Bold = oldFont.Bold;
      newFont.Italic = oldFont.Italic;
      newFont.Color.Brightness = oldFont.Color.Brightness;
      newFont.Size = oldFont.Size;
      newFont.Name = oldFont.Name;
      newFont.Underline = oldFont.Underline;
      newFont.Strikethrough = oldFont.Strikethrough;
      newFont.Superscript = oldFont.Superscript;
      newFont.Subscript = oldFont.Subscript;
      newFont.Italic = oldFont.Italic;

    }
    private static void CloneLabelOptions(IDataLabels newLabels, IDataLabels oldLabels, ChartType chartType)
    {
      newLabels.ShowValue = oldLabels.ShowValue;
      newLabels.ShowCategoryName = oldLabels.ShowCategoryName;
      newLabels.ShowSeriesName = oldLabels.ShowSeriesName;
      newLabels.ShowLegendKey = oldLabels.ShowLegendKey;
      newLabels.ShowLeaderLines = oldLabels.ShowLeaderLines;
      newLabels.Separator = oldLabels.Separator;
      newLabels.Position = oldLabels.Position;
      newLabels.NumberFormat = oldLabels.NumberFormat;
      if (chartType == ChartType.Pie || chartType == ChartType.Doughnut)
            newLabels.ShowPercentage = oldLabels.ShowPercentage;
      if (chartType == ChartType.Bubble)
            newLabels.ShowBubbleSize = oldLabels.ShowBubbleSize;

      for (int i = 0; i < Math.Min(newLabels.Count, oldLabels.Count); i++)
      {
            newLabels.Position = oldLabels.Position;
            newLabels.ShowValue = oldLabels.ShowValue;
            newLabels.ShowCategoryName = oldLabels.ShowCategoryName;
            newLabels.ShowSeriesName = oldLabels.ShowSeriesName;
            newLabels.ShowLegendKey = oldLabels.ShowLegendKey;
            newLabels.Separator = oldLabels.Separator;
            newLabels.Position = oldLabels.Position;
            newLabels.Text = oldLabels.Text;
            newLabels.NumberFormat = oldLabels.NumberFormat;
            if (chartType == ChartType.Pie || chartType == ChartType.Doughnut)
                newLabels.ShowPercentage = oldLabels.ShowPercentage;
            if (chartType == ChartType.Bubble)
                newLabels.ShowBubbleSize = oldLabels.ShowBubbleSize;
      }
    }
    private static void CloneErrorBar(IErrorBar newErr, IErrorBar oldErr)
    {
      newErr.Type = oldErr.Type;
      newErr.Amount = oldErr.Amount;
      newErr.EndStyle = oldErr.EndStyle;
      newErr.ValueType = oldErr.ValueType;
      switch (newErr.ValueType)
      {
            case ErrorBarType.Custom:
                newErr.Minus = oldErr.Minus;
                newErr.Plus = oldErr.Plus;
                break;
      }
      CloneLine(newErr.Format.Line, oldErr.Format.Line);
    }
    private static void Clone3D(IThreeDFormat newo3d, IThreeDFormat old3d)
    {

    }

}




页: [1]
查看完整版本: GCExcel复制Chart中一个系列的配置到另一个系列