Add scalable image to gauge chartview (Xamarin Forms)

TeeChart for Microsoft Visual Studio .NET, Xamarin Studio (Android, iOS & Forms) & Monodevelop.
Post Reply
Scobie
Newbie
Newbie
Posts: 10
Joined: Thu Nov 26, 2020 12:00 am

Add scalable image to gauge chartview (Xamarin Forms)

Post by Scobie » Tue Dec 15, 2020 9:51 pm

Using = Steema.TeeChart.NET.Xamarin.Forms v4.2020.10.26
Development platform = Visual Studio 2019 Pro v16.7.7
Target device = Android 6.0 (API 23) to API 10.0 (API 29) smallest res = 480x800

I have a requirement to draw an image on top of a circular gauge at a position relative to the gauge and for the image to scale in size when the ChartView changes size, but to keep it's position relatively within the circular gauge (chart view).

Using information from other posts in the forum, and the TeeChartNetExamples code, I use the Chart_AfterDraw event to draw the image, but my issues are...
1) How to keep the image size scaled relative to the gauge
2) How to position the image, but I would be able to do this if I could define the image size

I have written a test app, showing the same user control in 2 different sizes.
GaugeTestApp.png
GaugeTestApp.png (84.29 KiB) Viewed 18346 times
Code...

public ImageSource ImageSource { get; set; }

private void Chart_AfterDraw(object sender, Steema.TeeChart.Drawing.Graphics3D g)
{
var img = new Image() { Source = ImageSource };
var xpos = g.ChartXCenter - (CircularGauge.XRadius / 2);
var ypos = g.ChartYCenter;

// WORKING
g.Draw(xpos, ypos, img);

// NOT WORKING
//g.Draw(new Rectangle(xpos, ypos, 12, 12), img, Steema.TeeChart.Drawing.ImageMode.Stretch, false);
}

I assume the solution is in one of the g.Draw overloads but I can't find the correct syntax.

The target look is this...
Target.jpg
Target.jpg (5.59 KiB) Viewed 18346 times
All feedback & assistance appreciated

Pep
Site Admin
Site Admin
Posts: 3272
Joined: Fri Nov 14, 2003 5:00 am
Contact:

Re: Add scalable image to gauge chartview (Xamarin Forms)

Post by Pep » Thu Dec 17, 2020 9:11 am

Hello,

just inform to you, that we're looking at it, and doing some tests in order to reproduce the problem , and we'll back to you with an answer as soon as possible.
As a question to you, what does it happens when you use the :
// NOT WORKING
//g.Draw(new Rectangle(xpos, ypos, 12, 12), img, Steema.TeeChart.Drawing.ImageMode.Stretch, false);

Do you have a simple exmaple with which we can reproduce the problem as is ?

Thanks

Pep
Site Admin
Site Admin
Posts: 3272
Joined: Fri Nov 14, 2003 5:00 am
Contact:

Re: Add scalable image to gauge chartview (Xamarin Forms)

Post by Pep » Thu Dec 17, 2020 10:08 am

Hello,

ok, i've been able to reproduce the problem here. It's bug. It has been added on our bug list so it can be addressed into the next maintenance releases.

http://bugs.teechart.net/show_bug.cgi?id=2394

The problem happens once we try to use the Draw method in conjnction with the stretch mode. As a workaround until the problem is fixed, you'd have to use the image mode as "Normal" and resize the image externally, just before to draw over the Chart.

Code: Select all

// first resize the image to desired rectangle size ..
chart.Chart.Graphics3D.Draw(new Rectangle(0, 0, 120, 120), bImage, Steema.TeeChart.Drawing.ImageMode.Normal, false);

Scobie
Newbie
Newbie
Posts: 10
Joined: Thu Nov 26, 2020 12:00 am

Re: Add scalable image to gauge chartview (Xamarin Forms)

Post by Scobie » Wed Jan 06, 2021 11:36 pm

Hello,

Thankyou for your help.

I have now re-written my image overlay code, as suggested, and I now resize the image in separate code before using the following line to draw the image...
g.Draw(new Rectangle(xpos, ypos, imgX, imgY), img, Steema.TeeChart.Drawing.ImageMode.Normal, false);

I can now successfully re-size the image relative to the circular gauge and position it as needed (see image)
GaugeTestAppWithBattery.png
GaugeTestAppWithBattery.png (71.79 KiB) Viewed 18090 times
However, the issue I now have is that the image is not always shown. When the app starts, the Chart_AfterDraw event fires and the code to draw the image is run but the image is not shown. If I click the "DRAW IMAGE" button, which runs the same code, then the image is drawn OK.

Randomly pressing on the gauge, which causes the Chart_AfterDraw event to fire, does sometimes result in the image being drawn but on the next press of the gauge the image disappears.

Obviously, within the main production App, I need the image to draw without having to manually press a button (e.g. when the app is backgrounded & then resumes)

I have attached a zip file with the small sample solution which demonstrates this issue.

Again, all assistance is appreciated as I am very close to a workable solution now.
GaugeTestApp.zip
(296.48 KiB) Downloaded 674 times

Pep
Site Admin
Site Admin
Posts: 3272
Joined: Fri Nov 14, 2003 5:00 am
Contact:

Re: Add scalable image to gauge chartview (Xamarin Forms)

Post by Pep » Thu Jan 07, 2021 7:04 am

Hello,
sure, let me check the example you've attached and back to you asap.
Most likely it can be solved by calling to the draw method at the OnBeforeDrawSeries event, but let me check and see what happens.

Scobie
Newbie
Newbie
Posts: 10
Joined: Thu Nov 26, 2020 12:00 am

Re: Add scalable image to gauge chartview (Xamarin Forms)

Post by Scobie » Tue Jan 12, 2021 7:58 pm

Hello,

Appreciate that you probably have not had chance to look into this yet & reply, but as I am being asked to find a resolution to this issue I've been trying some more possible solutions based on your suggestion.

I've tried all the "Before" events available (i.e. BeforeDraw, BeforeDrawAxes, BeforeDrawSeries) and they throw an exception because my code to calculate the image size & position is based on the size & position of the Circular Gauge (Chart Series) which has not usually been created/drawn at that point.

Code: Select all

double imgX = CircularGauge.YRadius / 2;
double imgY = imgX;

var img = new Image();
byte[] resizedImage = DependencyService.Get<IImageResizer>().ResizeImage(ImageFileName, imgX, imgY);
img.Source = ImageSource.FromStream(() => new MemoryStream(resizedImage));

var xpos = g.ChartXCenter - (imgX / 2);
var ypos = g.ChartYCenter + ((CircularGauge.YRadius / 2) - (imgY / 2));
g.Draw(new Rectangle(xpos, ypos, imgX, imgY), img, Steema.TeeChart.Drawing.ImageMode.Normal, false);
It feels like the AfterDraw event is where I should be sizing the image and using the Graphics3D object to draw in on top of the chart, but as I mentioned before it usually does not appear.

Am I missing something obvious, because I would have thought that drawing images of certain sizes, in certain positions, on top of the chart control is quite a common request & I just can't make it work at the moment.

All help & feedback appreciated

Pep
Site Admin
Site Admin
Posts: 3272
Joined: Fri Nov 14, 2003 5:00 am
Contact:

Re: Add scalable image to gauge chartview (Xamarin Forms)

Post by Pep » Tue Jan 12, 2021 9:45 pm

Hello,
sorry fo delay on this anwer.
Just let you know that we're just looking at it. We hope to send a solution or just to publish a new version that fixes this problem asap.
We're looking for the best solution and will take a while. I hope we can have a this fix before the end of this week.

Thanks and appologies.

Pep
Site Admin
Site Admin
Posts: 3272
Joined: Fri Nov 14, 2003 5:00 am
Contact:

Re: Add scalable image to gauge chartview (Xamarin Forms)

Post by Pep » Wed Jan 20, 2021 1:29 pm

Hello,

We successfully tested a startup, once-only timer that loads the image everytime on startup but we have found in tests, as you noted, that the image can disappear unexpectedly at some screen paints. We think this is down to the environment and are following up on it. In the meantime we offer you this alternative that is based on TeeChart's Canvas methods and is robust under test. It is suitable to plot simple designs.

Code: Select all

private void DoDrawImage(Steema.TeeChart.Drawing.Graphics3D g)
{
    System.Diagnostics.Debug.WriteLine("DoDrawImage");

    double imgX = CircularGauge.YRadius / 2;
    double imgY = imgX;

    var xpos = g.ChartXCenter - (imgX / 2);
    var ypos = g.ChartYCenter + ((CircularGauge.YRadius / 2) - (imgY / 2));

    g.Brush.Visible = false;
    g.Pen.Width = 9; //could scale this according to dimensions

    //relative dimensions
    double left = xpos + (imgX * 0.13);
    double top = ypos + (imgY * 0.27);
    double right = xpos + imgX - (imgX * 0.13);
    double bottom = ypos + imgY - (imgY * 0.24);
    double width = right - left;
    double height = bottom - top;
    double sigBar = width * 3 / 16; //define size for symbols
 
    //top connectors
    g.Pen.Color = Xamarin.Forms.Color.FromRgb(222, 222, 222);
    g.Line(new Point(left + (width / 4) - (sigBar / 3), top - 4), new Point(left + (width / 4) + (sigBar / 3), top - 4));
    g.Line(new Point(right - (width / 4) - (sigBar / 3), top - 4), new Point(right - (width / 4) + (sigBar / 3), top - 4));

    //battery
    g.Pen.Color = Xamarin.Forms.Color.FromRgb(201, 201, 201);
    g.Rectangle(left,top,right,bottom);

     //plus
    g.Pen.Color = Xamarin.Forms.Color.FromRgb(218, 218, 218);
    g.Line(new Point(left+(width/4)-(sigBar/2), top + (height * 3/8)), new Point(left + (width/4) + (sigBar / 2), top + (height * 3/8)));
    g.Line(new Point(left+(width/4), top + (height*3/8) - (sigBar / 2)), new Point(left + (width / 4), top + (height * 3 / 8) + (sigBar / 2)));

    //minus
    g.Line(new Point(right - (width/4) - (sigBar / 2), top + (height * 3 / 8)), new Point(right - (width/4) + (sigBar / 2), top + (height * 3 / 8)));
}
Please, let me know if it helps.

Scobie
Newbie
Newbie
Posts: 10
Joined: Thu Nov 26, 2020 12:00 am

Re: Add scalable image to gauge chartview (Xamarin Forms)

Post by Scobie » Wed Jan 20, 2021 8:30 pm

Hello,

Thank you for your answer. I have tested the proposed work-around solution here and it is working as you have described.

I should be able to use the g.Pen methods, as demonstrated, to create the images required, although it will mean more work than simply resizing an original image file.

The other graphic which I have to show is slightly more involved, so I may ask for the specification to be simplified so I can use the g.Pen methods to draw it easier.
a_tempgauge.png
a_tempgauge.png (1.94 KiB) Viewed 17438 times
Obviously, I would still be interested to know the full answer, if you do find out how to reliably draw the resized original image correctly.

For now, thank you for your efforts with this issue.

Pep
Site Admin
Site Admin
Posts: 3272
Joined: Fri Nov 14, 2003 5:00 am
Contact:

Re: Add scalable image to gauge chartview (Xamarin Forms)

Post by Pep » Thu Jan 21, 2021 1:34 pm

Hello,
Obviously, I would still be interested to know the full answer, if you do find out how to reliably draw the resized original image correctly.
Sure, but for the moment we've not being able to find what is causing this behaviour.
The other graphic which I have to show is slightly more involved, so I may ask for the specification to be simplified so I can use the g.Pen methods to draw it easier.
Please find the code to generate the thermometer. The code was built up as required to plot the various parts of the thermometer. With a little time it can be tidied-up/rationalised a great deal. It will scale according to screen size and all the code to control its relative size, to make it larger or smaller depends on imgX. Changing imgX (eg. from (CircularGauge.YRadius / 4) to (CircularGauge.YRadius / 2)) will resize the whole plot. Growing/shrinking the value of ypos will then move it down or up.

Code: Select all

private void DoDrawImage(Steema.TeeChart.Drawing.Graphics3D g)
{
    DrawThermometer(g);
}

private void DrawThermometer(Steema.TeeChart.Drawing.Graphics3D g)
{
    System.Diagnostics.Debug.WriteLine("DoDrawImage");
 
    double imgX = CircularGauge.YRadius / 4;
    double imgY = imgX;
 
    Xamarin.Forms.Color tColor = Xamarin.Forms.Color.FromRgb(221, 221, 221);
 
    g.Pen.Width = 9; //could scale this according to dimensions
    g.Pen.Color = tColor;
 
    //thermometer
    var xTPos = g.ChartXCenter - (imgX / 4); //horiz offset main bowl
    var ypos = g.ChartYCenter + ((CircularGauge.YRadius / 2) - (imgY / 16)); //vertical offset
 
    double left = xTPos;
    double top = ypos;
    double right = left + (imgX / 2);
    double bottom = top + (imgY / 2);
    double width = right - left;
    double height = bottom - top;
 
    //calc vert line start on arc
    double lineXStart = (imgX / 4) * Math.Cos(50 * Math.PI / 180);
    double lineYStart = (imgX / 4) * Math.Sin(50 * Math.PI / 180);
 
    g.Arc(new Rectangle(left, top, right - left, bottom - top), 310, 280);
    //left side
    g.Line(new Point(g.ChartXCenter - lineXStart, top + (imgY / 4) - lineYStart), new Point(g.ChartXCenter - lineXStart, top + (imgY / 4) - lineYStart - (height*1.5)));

    //right side
    g.Line(new Point(g.ChartXCenter + lineXStart, top + (imgY / 4) - lineYStart), new Point(g.ChartXCenter + lineXStart, top + (imgY / 4) - lineYStart - (height*1.5)));

    g.Arc(new Rectangle(g.ChartXCenter - lineXStart, top + (imgY / 4) - lineYStart - (height * 1.9), lineXStart*2, height * 0.8), 180, 180);
 
    //Mercury
   Steema.TeeChart.Drawing.ChartBrush tmpBrush = g.Brush;
    g.Brush.Color = tColor;
    g.Brush.Visible = true;
    g.Ellipse(new Rectangle(left+(width*3/8), top+(height*3/8), width/4, height /4));
    g.Line(new Point(left + (width/2), top + (height/2)), new Point(left + (width/2), top + (imgY / 4) - lineYStart - height));
    g.Brush = tmpBrush;
 
    //Scale markers
    g.Line(new Point(g.ChartXCenter + lineXStart, top + (imgY / 4) - lineYStart - (height * 1.25)), new Point(g.ChartXCenter + lineXStart + (width/3), top + (imgY / 4) - lineYStart - (height * 1.25)));
    g.Line(new Point(g.ChartXCenter + lineXStart, top + (imgY / 4) - lineYStart - (height * 0.75)), new Point(g.ChartXCenter + lineXStart + (width/4), top + (imgY / 4) - lineYStart - (height * 0.75)));
    g.Line(new Point(g.ChartXCenter + lineXStart, top + (imgY / 4) - lineYStart - (height * 0.25)), new Point(g.ChartXCenter + lineXStart + (width/6), top + (imgY / 4) - lineYStart - (height * 0.25)));
 
    //Symbol
    g.Font.Size = height/3;
    g.Font.Bold = true;
    g.Font.Color = tColor;
    g.TextOut(g.ChartXCenter - lineXStart - (width * 1.2), top + (imgY / 4) - lineYStart - (height * 1.7), "ºC");
}

Scobie
Newbie
Newbie
Posts: 10
Joined: Thu Nov 26, 2020 12:00 am

Re: Add scalable image to gauge chartview (Xamarin Forms)

Post by Scobie » Thu Jan 21, 2021 10:40 pm

Hello,

This new code for the thermometer graphic is excellent & far more than I expected you to provide.

I have now integrated the battery & thermometer graphic drawing code into my main App (see screenshot below) & will be able to move this into production.

Gauge Screenshot (with drawn graphics).png
Gauge Screenshot (with drawn graphics).png (69.82 KiB) Viewed 17387 times

Many thanks for your commitment in helping to resolve this issue :)

Pep
Site Admin
Site Admin
Posts: 3272
Joined: Fri Nov 14, 2003 5:00 am
Contact:

Re: Add scalable image to gauge chartview (Xamarin Forms)

Post by Pep » Fri Jan 22, 2021 7:37 am

Hello,

I'm glad to hear you like it.
Thanks !

Post Reply