Xamarin.Forms Microcharts

Xamarin.Forms 使用Microcharts 繪製圖表

吳宗彥(Cliff) 2020/03/17 16:31:58
3336

 

一、前言

Microcharts 是基於SkiaSharp函式庫繪製的圖表。Microcharts可支援Xamrin .NET Standard平台,相較其他圖表元件功能較簡單,但程式容易修改客製化容易。本篇分享MVVM架構的Xamarin.Forms 使用Microcharts 繪製圖表。

 

 

、範例

(一) 加入套件至專案

1.  沒有客製化需求:NuGet 安裝 Microcharts.Forms

2.  有客製化需求:

(1).  Nuget安裝SkiaSharp.Views.Forms

(2). https://github.com/dotnet-ad/Microcharts 下載Source Code,Microcharts.Shared加入專案。

 

(二) 加入自定義的 ChartView

public class ChartView : SKCanvasView
    {
        public ChartView()
        {
            this.BackgroundColor = Color.Transparent;
            this.PaintSurface += OnPaintCanvas;
        }

        public static readonly BindableProperty ChartProperty = BindableProperty.Create(nameof(Chart), typeof(Chart), typeof(ChartView), null, propertyChanged: OnChartChanged);

        public Chart Chart
        {
            get { return (Chart)GetValue(ChartProperty); }
            set { SetValue(ChartProperty, value); }
        }

        private static void OnChartChanged(BindableObject bindable, object oldValue, object newValue)
        {
            ((ChartView)bindable).InvalidateSurface();
        }

        private void OnPaintCanvas(object sender, SKPaintSurfaceEventArgs e)
        {
            if (this.Chart != null)
            {
                this.Chart.Draw(e.Surface.Canvas, e.Info.Width, e.Info.Height);
            }
        }

(三) 在Page內加入ChartView; 自訂高度和邊界,並系結資料圖表資料

<local:ChartView Chart="{Binding Chart}"  HeightRequest="300"  Margin="20,0,20,0" />

 

 (四) 在Viewmodel 中加入系結屬性,取得資料並加資料匯入圖表中

Label 為長條圖中x軸文字,

ValueLabel 為長條圖頂端數值

Color為長條圖顏色

 

public Chart Chart { get; set; }

public BarChartViewModel()
        {
            Title = "BarChart";
            PollValuesAsync();
        }


  private async Task PollValuesAsync()
{
            await Task.Delay(500); 
            // 取得資料
            List<ShopAnalysis> cosumes = cosumeService.GetShopsConsumes();
            // 將資料轉為圖表物件
            IEnumerable<Microcharts.Entry> entries = cosumes.Select((x, i) => new Microcharts.Entry((float)x.ConsumeCount)
            {
                Label = (i + 1).ToString(),
                ValueLabel = x.ConsumeCount.ToString(),
                Color = ConvertColor(i).ToSKColor()
            });

            var _chart = new BarChart();

            //  加入圖表資料
            _chart.Entries = entries;

            // 設定文字大小
            _chart.LabelTextSize = 40;

            // 更新圖表系結屬性
            this.Chart = _chart;
        }


private Color ConvertColor(int idx){
            int colorIndex = idx % 5;
            switch (colorIndex)
            {
                case 0: return Color.Red;
                case 1: return Color.Orange;
                case 2: return Color.Green;
                case 3: return Color.Blue;
                case 4: return Color.Purple;
                default: return Color.Black;
            }
        }

修改c#程式碼,var _chart 切換圖表種類(預設有六種),

var _chart = new DonutChart(); 

var _chart = new LineChart();

var _chart = new PointChart();

var _chart = new RadarChart();  

var _chart = new RadialGaugeChart();

 

三、 客製化範例

(一) 圖表內有顯示中文或特殊字元的需求;

1. 修改Microcharts.Shared 中繪製文字的 C# code

   增加static method 回傳該文字的SKTypeface;範例為省去判斷數字、空白和符號;可再依需求做調整。

   public static SKTypeface ToSKTypeface(this string text)
        {
            for (int i = 0; i <= text.Length - 1; i++)
            {
                if (char.IsWhiteSpace(text[i])) continue;
                if (char.IsNumber(text[i])) continue;
                if (char.IsSymbol(text[i])) continue;
                return SKFontManager.Default.MatchCharacter(text[i]);
            }
            return SKFontManager.Default.MatchCharacter(text[0]);
        }

CanvasExtensions.csPointChart.cs 找到繪製文字的SKPaint,加入Typeface的判斷

new SKPaint(){TextSize = textSize,
              IsAntialias = true,
              Color = labelColor,
              IsStroke = false,
              TextAlign = horizontalAlignment,
              Typeface = label.ToSKTypeface() //加入判斷Typeface
               }

 

2. 加入後圖表就可以正常顯示中文了

 

 

(二) 客製化圖表將各類項目的色塊換成圖片

1. 在Microcharts.Shared Entry.cs中加入 Icon 屬性

		/// <summary>
		/// icon with data
		/// </summary>
		public SKBitmap Icon { get; set; }

2. 在Chart.cs  中 DrawCaptionElements 判斷是否有ICON ,有ICON 則繪製圖片沒有則繪製色塊

  if (entry.Icon == null)
 {
using (var paint = new SKPaint { Style = SKPaintStyle.Fill, Color = entry.Color, })
{var rect = SKRect.Create(captionX, y, this.LabelTextSize, this.LabelTextSize);
 canvas.DrawRect(rect, paint);
 }}else{
SKRect src = SKRect.Create(0, 0, entry.Icon.Width, entry.Icon.Height); 
//setting image width height here
SKRect dest = SKRect.Create(captionX, y - (this.LabelTextSize / 2), this.LabelTextSize, this.LabelTextSize);
 canvas.DrawBitmap(entry.Icon, src, dest, null);
}

 

3.在ViewModel中  ,在new  Microcharts.Entry 中加入 icon

  var entries = cosumes.Select(x => new Microcharts.Entry((float)x.Amount)
                {
                    Label = ChartHelper.ToWord(x.DataType),
                    ValueLabel = x.Amount.ToString(),
                    Color = ChartHelper.GetRandomColor(),  //TODO 隨機顏色或 改成指定顏色
                    Icon = deviceService.GetImgFromFile(x.DataType) //取得圖片
                }

 

4. 加入介面在各自平台取得圖片

    public interface IDeviceService
    {
        /// <summary>
        /// 抓圖片
        /// </summary>
        SKBitmap GetImgFromFile(int shopType);
    }

5. Android 實作取得圖片轉成SKBitmap

using Android.Graphics;
using MicrochartsSample.Droid;
using MicrochartsSample.Services;
using SkiaSharp;
using Xamarin.Forms;

[assembly: Dependency(typeof(DeviceService))]
namespace MicrochartsSample.Droid
{
    public class DeviceService : IDeviceService
    {
        public SKBitmap GetImgFromFile(int shopType)
        {
            switch (shopType)
            {
                case 0:
                    return GetDrawableToBitmap(Resource.Drawable.shoppingcart);
                case 1:
                    return GetDrawableToBitmap(Resource.Drawable.car);
                case 2:
                    return GetDrawableToBitmap(Resource.Drawable.fork);
                case 3:
                    return GetDrawableToBitmap(Resource.Drawable.joystick);
                case 4:
                    return GetDrawableToBitmap(Resource.Drawable.house);
                case 5:
                    return GetDrawableToBitmap(Resource.Drawable.tag);
                default:
                    return GetDrawableToBitmap(Resource.Drawable.tag);
            }
        }

        private SKBitmap GetDrawableToBitmap(int resId)
        {
            Bitmap bitmap = BitmapFactory.DecodeResource(AndroidApp.CurrentContext.Resources, resId);
            return SKBitmap.FromImage(SkiaSharp.Views.Android.AndroidExtensions.ToSKImage(bitmap));
        }

    }
}

 

6. iOS 實作取得圖片轉成SKBitmap

using MicrochartsSample.iOS;
using MicrochartsSample.Services;
using SkiaSharp;
using SkiaSharp.Views.iOS;
using UIKit;
using Xamarin.Forms;

[assembly: Dependency(typeof(DeviceService))]
namespace MicrochartsSample.iOS
{
    public class DeviceService : IDeviceService
    {
        public SKBitmap GetImgFromFile(int shopType)
        {
            switch (shopType)
            {
                case 0:
                    return UIImage.FromBundle("shoppingcart").ToSKBitmap();
                case 1:
                    return UIImage.FromBundle("car").ToSKBitmap();
                case 2:
                    return UIImage.FromBundle("fork").ToSKBitmap();
                case 3:
                    return UIImage.FromBundle("joystick").ToSKBitmap();
                case 4:
                    return UIImage.FromBundle("house").ToSKBitmap();
                case 5:
                    return UIImage.FromBundle("tag").ToSKBitmap();
                default:
                    return UIImage.FromBundle("tag").ToSKBitmap();
            }
        }
    }
}

 

五、更多客製化的需求可以參考github專案內容和 skiasharp的文件,感謝閱讀。

六、 參考

Microcharts Github

https://github.com/dotnet-ad/Microcharts

 

SkiaSharp Graphics in Xamarin.Forms

https://docs.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/graphics/skiasharp/

 

範例網址

https://github.com/WxyCliff/XamarinFormsChart/

 

吳宗彥(Cliff)