TeeChart .NET For Blazor NullReferenceException

TeeChart for Microsoft Visual Studio .NET, Xamarin Studio (Android, iOS & Forms) & Monodevelop.
Post Reply
dynamicrisk
Newbie
Newbie
Posts: 26
Joined: Thu Apr 06, 2023 12:00 am

TeeChart .NET For Blazor NullReferenceException

Post by dynamicrisk » Thu Jul 25, 2024 6:57 pm

Hi,

I am attempting to draw rectangles on the point chart in the .NET 8 blazor example program and getting a null reference exception when trying to call Graphics3DImageSharp.Rectangle(Rectangle rectangle).

Here is a copy of the stack trace.

at SixLabors.ImageSharp.GraphicOptionsDefaultsExtensions.GetGraphicsOptions(IImageProcessingContext context)
at SixLabors.ImageSharp.Drawing.Processing.DrawingOptionsDefaultsExtensions.GetDrawingOptions(IImageProcessingContext context)
at SixLabors.ImageSharp.Drawing.Processing.FillPathExtensions.Fill(IImageProcessingContext source, IBrush brush, IPath path)
at Steema.TeeChart.Drawing.Graphics3DImageSharp.Rectangle(Rectangle r)
at TeeChartOnBlazor.Pages.GetGeneralChart.DrawRectangle(Graphics3DBase graphics, Rectangle rect, Int32 cornerRadius) in C:\Git\TeeChartOnBlazor\TeeChart-NET-Pro-Samples\Blazor\NET 8\TeeChartOnBlazor\Pages\GetGeneralChart.razor:line 326

Thanks,
Jeff

Edu
Newbie
Newbie
Posts: 40
Joined: Tue Nov 28, 2023 12:00 am

Re: TeeChart .NET For Blazor NullReferenceException

Post by Edu » Fri Jul 26, 2024 2:21 pm

Hello Jeff,

Thank you for reporting this issue to us. To assist you more effectively, could you please provide the specific code you're working with? More specifically, how or where you're calling the function or drawing the rectangle, as we can't seem to replicate the null reference exception you're encountering. This information will help us better understand the situation and provide you with more accurate guidance or troubleshooting steps, or fixing the bug on our end if that's the case.

We appreciate your cooperation and look forward to resolving this issue for you.

Thanks again,
Best regards,
Edu
Edu
Steema Support

dynamicrisk
Newbie
Newbie
Posts: 26
Joined: Thu Apr 06, 2023 12:00 am

Re: TeeChart .NET For Blazor NullReferenceException

Post by dynamicrisk » Tue Jul 30, 2024 2:15 pm

Hello Edu,

Here is a sample of the code.

Code: Select all

protected override async Task OnInitializedAsync()
{
    int chartType = Convert.ToInt32(CType);

    if ((chartType == 31) || (chartType == 32)) //pie, donut
    {
        GetGeneralChart cGen = new GetGeneralChart();
[b]        chartJS = await cGen.GetJSChart(chartType, 1400, 500);[/b]
        chartName = cGen.chartName;
        chartCode = cGen.getFormattedCode();

        title = cGen.title;

        supportUnit = "<script src=\"js/pieplus.js\" type=\"text/javascript\"></script>";
    }
    else if (chartType == 101) //appointments, advanced chart
    {

        //title
        string aTitle = "Appointments";
        //Year labels
        string[] xLabels = new string[] { "2019", "2020", "2021", "2022", "2023" };
        //Series names
        string[] sNames = new string[] { "Ancillaries", "Core staff" };
        //Chart data
        double?[,] apptData = new double?[,] {
                        { /*Ancillaries*/ 10,12,31,34,16 },
                        { /*Core*/ 5,7,12,12,3 }};

        MultiBars stack = MultiBars.Stacked;
        int incr = 5; //left axis increment


        ChartTable cGen = new ChartTable();
        chartJS = await cGen.loadAppointmentsChart(aTitle, sNames, apptData,
                                   stack, xLabels, newLineLabel(xLabels),
                                   incr);

        title = aTitle;

        //Make the sourcecode reference page.
        chartCode = "\n<h3>Setup data</h3>";
        chartCode += getAppointmentsCode();
        chartCode += "\n<h3>Chart generation</h3>";
        chartCode += cGen.getChartCode();
        chartCode += "\n<h3>Javascript Legend code</h3>";
        chartCode += cGen.getJSCode();

        supportUnit = "<script src=\"js/appointment.js\" type=\"text/javascript\"></script>";

    }
    else  //if (chartType < 30) //general charts
    {
        GetGeneralChart cGen = new GetGeneralChart();
        chartJS = await cGen.GetJSChart(chartType, 1400, 500);
        chartName = cGen.chartName;

        chartCode = cGen.getFormattedCode();

        if ((chartType == 34) || (chartType == 33)) //custom gauge
        {
            supportUnit = "<script src=\"js/gauge.js\" type=\"text/javascript\"></script>";
            if (chartType == 34)
                title = "VU Meter - analogue type";
        }
        else
        {
            supportUnit = "<script src=\"js/stdsetup.js\" type=\"text/javascript\"></script>";
            title = cGen.title;
        }
    }

    chartResize = "<script> function resizeChart() { resizeC(" + chartName + "); } </script>";
}

public Task<string> GetJSChart(int chartType, int width, int height)
{
    Steema.TeeChart.TChart mChart = new TChart();

    bool animate = false;

    switch (chartType) {
        case 0: Line line = new Line(mChart.Chart);
            animate=true;
            break;
        case 1: Points points = new Points(mChart.Chart);
            animate=true;
            break;
        case 2: Area area1 = new Area(mChart.Chart);
            Area area2 = new Area(mChart.Chart);
            //countSeries = 2;
            animate = true;
            break;
        case 3: break;
        case 5: Bubble bubble = new Bubble(mChart.Chart); animate = true; break;
        case 6: Candle candle = new Candle(mChart.Chart); break;
        case 7: Gantt gantt = new Gantt(mChart.Chart);
            break;
        case 31: Pie pie = new Pie(mChart.Chart); break;
        case 32: Donut donut = new Donut(mChart.Chart); break;
        case 33:
        case 34: CircularGauge cGauge = new CircularGauge(mChart.Chart); break;
    }

    var series = mChart.Series[0];

    mChart.Header.Text = ""; // series.Description + " series";

    mChart.Axes.Left.Title.Text = "value";

    foreach (Series s in mChart.Series)
    {
        if (series.GetType() == typeof(Bubble))
        {
            ((Bubble)(s)).Pointer.Gradient.Visible = true;
            ((Bubble)(s)).Pointer.Pen.Visible = false;
            s.FillSampleValues(50);
        }
        else if ((series.GetType() == typeof(Gantt)))
            s.FillSampleValues(9);
        else
            s.FillSampleValues();
    }

    if (mChart.Series.Count > 1)
    {
        if (mChart[0].MaxYValue() > mChart[1].MaxYValue())
            mChart.Axes.Left.SetMinMax(0, mChart[0].MaxYValue()+20);
        else
            mChart.Axes.Left.SetMinMax(0, mChart[1].MaxYValue()+20);
    }

    Graphics3DBase graphics = mChart.Graphics3D;
    ChartBrush brush = null;
    ChartPen pen = null;
    graphics.Brush = null;
    graphics.Pen = null;

    Brush = new ChartBrush(mChart.Chart);
    Pen = new ChartPen(mChart.Chart);

    try
    {
        if (Brush != null)
        {
            graphics.Brush = Brush;
            graphics.Brush.Chart = mChart.Chart;
        }

        if (Pen != null)
        {
            graphics.Pen = Pen;
            graphics.Pen.Chart = mChart.Chart;
        }

        var dataSet = series.YValues.Value;
        int counter = 0;

        foreach (int value in dataSet)
        {
            Random rndX = new Random();
            Random rndY = new Random();

            Rectangle rect = new Rectangle(counter, value, rndX.Next(0, 99), rndY.Next(0, 99));
            Rectangle bounds = new Rectangle(0, 0, 900, 300);

            // Draw the point.
            [b]DrawWrappedRectangle(graphics, rect, bounds);[/b]
        }

    }
    finally
    {
        brush?.Dispose();
        pen?.Dispose();
        graphics.Brush = null;
        graphics.Pen = null;
    }

    series.XValues.DateTime = true;
    //mChart.Axes.Bottom.Labels.Angle = 90;
    //mChart.Axes.Bottom.Increment = Steema.TeeChart.Utils.GetDateTimeStep(DateTimeSteps.OneDay);
    //mChart.Axes.Left.Title.Text = "µVal";

    if ((mChart.Series.Count == 1) && (series.GetType() != typeof(Gantt)))
        mChart.Axes.Left.SetMinMax(series.YValues.Minimum - 10, series.YValues.Maximum + 10);

    chartName = "dynoTeeChart";
    mChart.Export.Image.JScript.ChartName = chartName;

    MemoryStream ms = new MemoryStream();
    mChart.Export.Image.JScript.Width = width;
    mChart.Export.Image.JScript.Height = height;
    mChart.Export.Image.JScript.DoFullPage = false; //inline, no page <html> header tags

    if ((series.GetType() == typeof(Pie)) ||
            (series.GetType() == typeof(Donut)))
    {
        series.Marks.Visible = true;
        series.Marks.Arrow.Visible = false;
        series.Marks.Arrow.Color = Color.White;
        series.Marks.Transparent = true;
        series.Marks.Pen.Transparency = 100;
        series.Marks.Pen.Color = Color.White;
        series.Marks.Font.Color = Color.White;

        mChart.Export.Image.JScript.CustomCode = getCustomCodeOp2(mChart);
    }
    else
        mChart.Export.Image.JScript.CustomCode = getCustomCode1(animate, mChart);

    if ((series.GetType() == typeof(Gantt)))
    {
        ((Gantt)series).Brush.Gradient.Visible = false;
        ((Gantt)series).NextTasks[0] = 6;
        mChart.Axes.Left.Title.Text = "task";
    }

    if ((series.GetType() == typeof(CircularGauge)))
    {
        mChart.Axes.Left.Title.Text = "µHz";

        var customCode = new List<string>();

        if (chartType == 34)
        {
            customCode.Add("modGauge(" + chartName + ", " + chartName + ".series.items[0]" + ");");
            customCode.Add("setTimeout(modVal, 500);");
        }
        else
        {
            ((CircularGauge)(mChart[0])).Value = 0;
            customCode.Add(chartName + ".series.items[0]" + ".format.shadow.visible=false;");
            customCode.Add(chartName + ".series.items[0]" + ".back.visible=false;");
            customCode.Add("growVal(" + chartName + ");");
            customCode.Add("setTimeout(growVal, 500);");
        }

        mChart.Export.Image.JScript.CustomCode = customCode.ToArray();

    }

    title = mChart.Series[0].Description;

    mChart.Export.Image.JScript.Save(ms);

    ms.Position = 0;

    StreamReader reader = new StreamReader(ms);
    //setup our chart name, here 'dynoChartName'.
    string result = "<script> var " + chartName + "; " + reader.ReadToEnd() + "</script>";

    return Task.FromResult(result);
}

    /// <summary>
    /// Draws a rectangle that may wrap around the axes.
    /// </summary>
    /// <param name="graphics">The graphics.</param>
    /// <param name="rect">The rectangle.</param>
    /// <param name="bounds">The boundary over which the rectangle may wrap.</param>
    /// <param name="cornerRadius">[Optional] The radius of the rounded corners, in pixels.</param>
    /// <exception cref="ArgumentNullException">Thrown if <paramref name="graphics"/> is <b>null</b>.</exception>
    public static void DrawWrappedRectangle(Graphics3DBase graphics, Rectangle rect, Rectangle bounds, int cornerRadius = 0)
    {
        if (graphics == null)
        {
            throw new ArgumentNullException(nameof(graphics));
        }
        
        [b]DrawRectangle(graphics, rect, cornerRadius);[/b]
    }

/// <summary>
/// Draws a rectangle.
/// </summary>
/// <param name="graphics">The graphics.</param>
/// <param name="rect">The rectangle.</param>
/// <param name="cornerRadius">[Optional] The radius of the rounded corners, in pixels.</param>
public static void DrawRectangle(Graphics3DBase graphics, Rectangle rect, int cornerRadius = 0)
{
    if (cornerRadius == 0)
    {
        try
        {
            [b]graphics.Rectangle(rect);[/b]
        }
        catch (Exception ex)
        {
            String message = ex.Message;
            throw ex;
        }
    }
    else if (cornerRadius > Math.Max(rect.Width, rect.Height) / 2)
    {
        graphics.Ellipse(rect);
    }
    else
    {
        graphics.RoundRectangle(rect, cornerRadius);
    }
}
I bolded each line that is calling the next method. If there is a way I can send you the zipped project please let me know as the forum is saying the file size is too large.

Thanks,
Jeff

Edu
Newbie
Newbie
Posts: 40
Joined: Tue Nov 28, 2023 12:00 am

Re: TeeChart .NET For Blazor NullReferenceException

Post by Edu » Thu Aug 01, 2024 10:44 am

Hello Jeff:
Thank you for providing the code snippet.
We were able to spot the issue you're encountering.

Adding this code after the line ..

Code: Select all

customCode.Add("   drawAppointments(" + chartAppointm.Export.Image.JScript.ChartName + ", " + labelLines + ");");
.. should achieve what you're trying to make (drawing a rectangle)

Code: Select all

customCode.Add($"let myFormat = new Tee.Format({chartAppointm.Export.Image.JScript.ChartName});");
customCode.Add("myFormat.gradient.visible=true;");
customCode.Add("myFormat.gradient.colors=[\"white\",\"lime\"];");
customCode.Add("myFormat.transparency=0.3;");
customCode.Add($"{chartAppointm.Export.Image.JScript.ChartName}.ondraw=function()");
customCode.Add("{");
customCode.Add($"var x1 = {chartAppointm.Export.Image.JScript.ChartName}.axes.bottom.calc(4),");
customCode.Add($"y1 = {chartAppointm.Export.Image.JScript.ChartName}.axes.left.calc(70),");
customCode.Add($"x2 = {chartAppointm.Export.Image.JScript.ChartName}.axes.bottom.calc(7),");
customCode.Add($"y2 = {chartAppointm.Export.Image.JScript.ChartName}.axes.left.calc(40);");
customCode.Add("// X,Y, Width, Height");
customCode.Add("myFormat.rectangle(x1,y1, x2-x1, y2-y1);");
customCode.Add("}");
Here you can see the rectangle with color 'White, Lime' (top right)
aaDrawRectangleExample.png
aaDrawRectangleExample.png (24.54 KiB) Viewed 30636 times

There are complications with drawing a rectangle using the method you were trying to use due to the nature of how Graphics3DImageSharp works (because the chart is not yet drawn ..)
Since there's the conversion to js, custom drawing code should be written on your customCode string list instead.

If there's anything else you may need or any other questions, please let us know

Regards,
Edu
Edu
Steema Support

dynamicrisk
Newbie
Newbie
Posts: 26
Joined: Thu Apr 06, 2023 12:00 am

Re: TeeChart .NET For Blazor NullReferenceException

Post by dynamicrisk » Fri Aug 02, 2024 9:17 pm

Hi Edu,

I got the drawing working on the appointments chart in the sample project. I am trying to draw a box around every data point in the point chart but am getting a blank chart back. Here is the method where I added the custom code.

//general type characteristics
string[] getCustomCode1(bool animate, TChart aChart, double[] dataSet)
{
var customCode = new List<string>();

if (animate)
{
if (aChart[0].GetType() == typeof(Area))
{
customCode.Add(" //animation");
customCode.Add(" animation = new Tee.SeriesAnimation();");
customCode.Add(" animation.duration = 1700;");
customCode.Add(" animation.kind = \"all\";");
customCode.Add(" animation.mode = \"linear\";");
}
else
{
customCode.Add(" //animation");
customCode.Add(" animation = new Tee.SeriesAnimation();");
customCode.Add(" animation.duration = 900;");
customCode.Add(" animation.kind = \"each\";");
customCode.Add(" fadeAnimation = new Tee.FadeAnimation();");
customCode.Add(" fadeAnimation.duration = 500;");
customCode.Add(" fadeAnimation.fade.series = true;");
customCode.Add(" fadeAnimation.fade.marks = true;");
customCode.Add(" animation.mode = \"linear\"; ");
customCode.Add(" fadeAnimation.mode = \"linear\";");
customCode.Add(" animation.items.push(fadeAnimation);");
customCode.Add(" ");
}

customCode.Add(" animation.animate(" + aChart.Export.Image.JScript.ChartName + ");");
}

if (aChart[0].GetType() == typeof(Candle))
{
customCode.Add(aChart.Export.Image.JScript.ChartName + ".axes.bottom.datetime = true;");
customCode.Add(aChart.Export.Image.JScript.ChartName + ".axes.bottom.labels.dateFormat = \"shortDate\";");
customCode.Add(aChart.Export.Image.JScript.ChartName + ".series.items[0].dateFormat = \"shortDate\";");

//cursortool
customCode.Add("var t = new Tee.CursorTool(" + aChart.Export.Image.JScript.ChartName + ");");
customCode.Add("t.direction = \"both\";");
customCode.Add(aChart.Export.Image.JScript.ChartName + ".tools.add(t);");
}

customCode.Add(aChart.Export.Image.JScript.ChartName + ".axes.bottom.labels.format.font.fill = \"rgba(0,0,0,0.6)\";");
customCode.Add(aChart.Export.Image.JScript.ChartName + ".axes.bottom.labels.format.font.setSize(\"10px\");");
customCode.Add(aChart.Export.Image.JScript.ChartName + ".series.items[0].marks.transparent = true;");

//customCode.Add("hostChart = " + aChart.Export.Image.JScript.ChartName + ";");

customCode.Add("chartFeatures(" + chartName + ");"); //call general setup enhancements
customCode.Add("resizeC(" + chartName + ");");

if (aChart[0].GetType() == typeof(Steema.TeeChart.Styles.Points))
{
int counter = 0;

foreach (int value in dataSet)
{
Random rndX = new Random();
Random rndY = new Random();

Rectangle rect = new Rectangle(counter, value, rndX.Next(0, 99), rndY.Next(0, 99));
Rectangle bounds = new Rectangle(0, 0, 900, 300);

customCode.Add($"let myFormat = new Tee.Format({aChart.Export.Image.JScript.ChartName});");
customCode.Add("myFormat.gradient.visible=true;");
customCode.Add("myFormat.gradient.colors=[\"white\",\"lime\"];");
customCode.Add("myFormat.transparency=0.3;");
customCode.Add($"{aChart.Export.Image.JScript.ChartName}.ondraw=function()");
customCode.Add("{");
customCode.Add($"var x1 = {aChart.Export.Image.JScript.ChartName}.axes.bottom.calc(1),");
customCode.Add($"y1 = {aChart.Export.Image.JScript.ChartName}.axes.left.calc(1),");
customCode.Add($"x2 = {aChart.Export.Image.JScript.ChartName}.axes.bottom.calc(100),");
customCode.Add($"y2 = {aChart.Export.Image.JScript.ChartName}.axes.left.calc(100);");
customCode.Add("// X,Y, Width, Height");
customCode.Add("myFormat.rectangle(x1,y1, x2-x1, y2-y1);");
customCode.Add("}");

counter++;
}
}
return customCode.ToArray();
}

Thanks,
Jeff

Edu
Newbie
Newbie
Posts: 40
Joined: Tue Nov 28, 2023 12:00 am

Re: TeeChart .NET For Blazor NullReferenceException

Post by Edu » Mon Aug 05, 2024 2:42 pm

Hello Jeff:

I made some changes to the code you provided to avoid js errors that were happening.

Separating variable declarations and the onDraw from the loop is what I feel is the most important 'change', but I recommend you to take a look at the whole function regardless.
This is just an interpretation of what you said here ...
I am trying to draw a box around every data point in the point chart but am getting a blank chart back.
... so please if you would like the end result to be a bit different, adjust the necessary code to better match your desired result

This is how the result looks like:
Screenshot 2024-08-05 163927.png
Screenshot 2024-08-05 163927.png (47.78 KiB) Viewed 29967 times
and this is how the code looks like:

Code: Select all

string[] getCustomCode1(bool animate, TChart aChart, double[] dataSet)
{
    var customCode = new List<string>();

    if (animate)
    {
        if (aChart[0].GetType() == typeof(Area))
        {
            customCode.Add("   //animation");
            customCode.Add("   animation = new Tee.SeriesAnimation();");
            customCode.Add("   animation.duration = 1700;");
            customCode.Add("   animation.kind = \"all\";");
            customCode.Add("   animation.mode = \"linear\";");
        }
        else
        {
            customCode.Add("   //animation");
            customCode.Add("   animation = new Tee.SeriesAnimation();");
            customCode.Add("   animation.duration = 900;");
            customCode.Add("   animation.kind = \"each\";");
            customCode.Add("   fadeAnimation = new Tee.FadeAnimation();");
            customCode.Add("   fadeAnimation.duration = 500;");
            customCode.Add("   fadeAnimation.fade.series = true;");
            customCode.Add("   fadeAnimation.fade.marks = true;");
            customCode.Add("   animation.mode = \"linear\"; ");
            customCode.Add("   fadeAnimation.mode = \"linear\";");
            customCode.Add("   animation.items.push(fadeAnimation);");
            customCode.Add("   ");
        }

        customCode.Add("   animation.animate(" + aChart.Export.Image.JScript.ChartName + ");");
    }

    if (aChart[0].GetType() == typeof(Candle))
    {
        customCode.Add(aChart.Export.Image.JScript.ChartName + ".axes.bottom.datetime = true;");
        customCode.Add(aChart.Export.Image.JScript.ChartName + ".axes.bottom.labels.dateFormat = \"shortDate\";");
        customCode.Add(aChart.Export.Image.JScript.ChartName + ".series.items[0].dateFormat = \"shortDate\";");

        //cursortool
        customCode.Add("var t = new Tee.CursorTool(" + aChart.Export.Image.JScript.ChartName + ");");
        customCode.Add("t.direction = \"both\";");
        customCode.Add(aChart.Export.Image.JScript.ChartName + ".tools.add(t);");
    }

    customCode.Add(aChart.Export.Image.JScript.ChartName + ".axes.bottom.labels.format.font.fill = \"rgba(0,0,0,0.6)\";");
    customCode.Add(aChart.Export.Image.JScript.ChartName + ".axes.bottom.labels.format.font.setSize(\"10px\");");
    customCode.Add(aChart.Export.Image.JScript.ChartName + ".series.items[0].marks.transparent = true;");

    //customCode.Add("hostChart = " + aChart.Export.Image.JScript.ChartName + ";");

    customCode.Add("chartFeatures(" + chartName + ");"); //call general setup enhancements
    customCode.Add("resizeC(" + chartName + ");");

    if (aChart[0].GetType() == typeof(Steema.TeeChart.Styles.Points))
    {
        int counter = 0;

        Random rndX = new Random();
        Random rndY = new Random();

       customCode.Add($"const myFormat = new Tee.Format({aChart.Export.Image.JScript.ChartName});");
        customCode.Add("myFormat.gradient.visible=true;");
        customCode.Add("myFormat.gradient.colors=[\"white\",\"lime\"];");
        customCode.Add("myFormat.transparency=0.3;");

        customCode.Add("let axisX1, axisY1, axisX2, axisY2;");

        customCode.Add($"{aChart.Export.Image.JScript.ChartName}.ondraw = function()");
        customCode.Add("{");

        foreach (int value in dataSet)
        {
            // Rectangle rect = new Rectangle(counter, value, rndX.Next(0, 99), rndY.Next(0, 99));
            // Rectangle bounds = new Rectangle(0, 0, 900, 300);

            customCode.Add($"axisX1 = {aChart.Export.Image.JScript.ChartName}.axes.bottom.calc({counter});");
            customCode.Add($"axisY1 = {aChart.Export.Image.JScript.ChartName}.axes.left.calc({value});");
            customCode.Add($"axisX2 = {aChart.Export.Image.JScript.ChartName}.axes.bottom.calc({rndX.Next(0, 99)});");
            customCode.Add($"axisY2 = {aChart.Export.Image.JScript.ChartName}.axes.left.calc({rndX.Next(0, 99)});");

            customCode.Add("// X,Y, Width, Height");
            customCode.Add("myFormat.rectangle(axisX1 + 5, axisY1 + 5, 20, 20);");

            counter++;
        }

        customCode.Add("}");
    }

    return customCode.ToArray();
}
If there's anything else we can help with, please let us know.

Regards,
Edu
Edu
Steema Support

Post Reply