Page 1 of 1

Efficient calculation of custom axis position

Posted: Fri Dec 09, 2016 10:13 am
by 16578912
Hello

I have function "PlaceChartObjects" that automatically calculate the position of custom axis, legend and resize chart margins to prepare place for this elements.
The problem is that I have to call this function and pTChart->Draw() a few times to get proper results because some objects size have wrong width or height after first pass.
This is very inefficient because it is called from ChartAfterDraw event to reflect changes from Chart Editor immediately.

Code: Select all

void __fastcall CBasicChartManager::ChartAfterDraw(TObject *Sender)
{
	if(pTChart)
	{
		ResetAxisPositions();
		ChartTools->PrepareAxisVisibility(pTChart);
		CheckToolsVisibility();
		ChartTools->PlaceChartObjects(pTChart, this);

		TNotifyEvent OnAfterDraw = pTChart->OnAfterDraw;
		try
		{
			pTChart->OnAfterDraw = NULL;
			pTChart->Draw();
			ChartTools->PlaceChartObjects(pTChart, this);
			SetAxisGridVisibility();
			pTChart->Draw();
		}
		__finally
		{
			pTChart->OnAfterDraw = OnAfterDraw;
		}
	}
}
Is there any better way to do this?

Best Regards,
Grzegorz

Re: Efficient calculation of custom axis position

Posted: Mon Dec 12, 2016 10:06 am
by yeray
Hello Grzegorz,

You could try other events such as OnBeforeDrawChart or OnBeforeDrawSeries to see if they are fired late enough for the elements your calculations depend on to have the appropriate values, and soon enough to avoid needing to repaint it again.

Re: Efficient calculation of custom axis position

Posted: Thu Jan 05, 2017 9:43 am
by 16578912
Hello

I have also problem when calculation position of titles and legend (CustomPosition = true);
To center eg. title I use Chart->Width to calculate position (center) and i works ok.
But when I try to create metafile to put it on the report like this

Code: Select all

   foMeta->Image1->Picture->Assign(Chart1->TeeCreateMetafile(false, Rect(0, 0, foMeta->Image1->Width, foMeta->Image1->Height)));
the title is not properly center because I need the width of the current draw rect.
How can I read this width from chart?

Best Regards,
Grzegorz

Re: Efficient calculation of custom axis position

Posted: Mon Jan 09, 2017 11:22 am
by yeray
Hello Grzegorz,

You can read the ChartBounds property. Ie, the width:

Code: Select all

Chart1.ChartBounds.Right-Chart1.ChartBounds.Left

Re: Efficient calculation of custom axis position

Posted: Mon Jan 09, 2017 12:32 pm
by 16578912
Hello

Thank You for the answer.

I'm still fighting with proper chart objects placement (custom axis axis, title and legend).
I'm calculating position and prepare place for this objects by setting chart margins.

Code: Select all

	
if(Chart->MarginTop != MargTop)
	{
		Chart->MarginTop = MargTop;
	}
	if(Chart->MarginBottom != MargBottom)
	{
		Chart->MarginBottom = MargBottom;
	}
	if(Chart->MarginLeft != MargLeft)
	{
		Chart->MarginLeft = MargLeft;
	}
	if(Chart->MarginRight != MargRight)
	{
		Chart->MarginRight = MargRight;
	}
I don't understand why I have to call a few times chart->Draw() to get right results. I looks like the property I use to calculate position are not properly initialize if I don't call Draw() method.
When I'm changing margin properties eg. MarginBottom do I have to call something to recalculate ChartRect, ChartHeight, ChartWidth etc?


Best Regards,
Grzegorz

Re: Efficient calculation of custom axis position

Posted: Tue Jan 10, 2017 9:27 am
by yeray
Hello Gregorz,

Some internal properties are calculated at late stages of the drawing process. Ie, the ChartRect (the rectangle defined by the axes) is resized when the legend is drawn, depending on the legend alignment. And some of these internal properties need to have their final values if you want to call functions such as CalcPosPoint/CalcPosValue/CalcSizeValue/... or properties like ChartRect.
That's why we use to recommend forcing a chart repaint before using some properties/methods.

When the only way to achieve something is to play with events manipulating these properties, it may indicate there's something that could be done better by the component or in the customer's code.
To know if there's something the component could do better, we should study the case globally, so a simple example project would probably help here. This is, a project as simple as possible without extra code not needed to demonstrate the situation, but complete enough to be run as-is and to explain the hole problematic.

Re: Efficient calculation of custom axis position

Posted: Wed Jan 11, 2017 9:32 am
by 16578912
Hello,

I've prepared small project to explain the hole problematic.

When You run application click button "AddBottomSeries"

As You will see You have to click "refresh" button 2x to calculate position of footer sub-footer and bottom legend.

The same problem is to create proper metafile via TeeCreateMetafile You have to create it tree times (3x "Meta" buttons clicks)

I try to call extra draw methods form OnAfterDraw event but the effect is even worse (check cbAutoDraw2x to see the effects).

Chart->ChartHeight which I use to calculate position is still changing values between call Draw().

I use CustomPosition to all my objects (custom axis, legend, title, footer etc.) on the chart to have full control over them but it sill not work as I expect.

Do You have any tips how to properly calculate my objects size to prepare empty place for them and put it on the right position?

Best Regards,
Grzegorz

Re: Efficient calculation of custom axis position

Posted: Fri Jan 13, 2017 2:18 pm
by yeray
Hello Grzegorz,

I see the elements moving as you describe, but your project contains more than 1700 lines of code so it isn't easy to debug for us.
Please read StackOverflow's How to create a Minimal, Complete, and Verifiable example as reference.