Reputation: 191
Delphi 10.1, VCL, with embedded Teechart.
I've an Area Series with a Mark moved by code to a custom position. When the Mark title content is changed, the Yellow background is not adjusted (Auto Sized) to the new Mark content. I've a work around for that, but it has flickers and it is not elegant. I'm looking for an idea how to do it better.
In details: I put three buttons on the chart, one to move the Mark location, the 2nd button to add a second content line to Mark title. The 3rd button is my work around to get a proper size. The Series Creation:
procedure TForm2.FormCreate(Sender: TObject);
begin
Chart1.View3D := false;
Chart1.Axes.Bottom.SetMinMax(0,5);
with Chart1.AddSeries(tAreaSeries) as tAreaSeries do
begin
AddXY(1, 10); // Two points AreaSeries
AddXY(4, 10);
Marks[1].Visible := false; // Hide the other Mark, the default is true
Marks.Visible := true; // Global Visibility for all Markers
Chart1[0].Marks[0].Text.Text := 'First-line';
end;
end;
Pressing Move Mark button code:
procedure TForm2.btnMoveMarkClick(Sender: TObject);
begin
Chart1[0].Marks.Positions[0].Custom := true;
Chart1[0].Marks.Positions[0].Offset(point(50,70));
// Chart1[0].Marks.Positions[0].LeftTop := point(150,200); // It is moving the Mark but not drawing the line to Series point
Chart1.Repaint; // It doesn't work without this Repaint
end;
Will generate the following screen:
Now, pressing the 2nd button to change Mark Title content as follow:
procedure TForm2.btnChangeMarkContentClick(Sender: TObject);
begin
Chart1[0].Marks[0].Text.Text := 'First-line'+#13+'Second-line';
end;
As you can see, the Yellow background size was not changed:
My brut-force work around is to delete the custom position, this will resize the Mark, then reposition the Mark again as follow:
procedure TForm2.btnResizeMarkClick(Sender: TObject);
var
LastPoint: tpoint;
begin
LastPoint := Chart1[0].Marks.Positions[0].LeftTop;
Chart1[0].Marks.Positions.Automatic(0);
Chart1.Repaint;
Chart1[0].Marks.Positions[0].Custom := true;
Chart1.Repaint;
// Chart1[0].Marks[0].MoveTo(LastPoint); // It doesn't work - Why?
Chart1[0].Marks.Positions[0].LeftTop := LastPoint; // Better to use Offset
Chart1.Repaint;
end;
It is doing the job, but with flicker due to Mark movement, as follow:
Thanks for any hint how to resize the Mark without delete its custom position which cause the flicker. Reron
Upvotes: 0
Views: 527
Reputation: 191
Yeray solved the main problem. In addition, the Arrows should be adjusted too as follow:
type
tCustomTextShapeAccess = class(tCustomTextShape); // Yeray: tCustomTextShapeAccess class to get access to the protected CalcBounds method
const
tcaTopLeft = 0;
tcaArrowTo = 1;
procedure TeeChart_ResizeCustomMark(aChart: tChart; aSeriesInx, aMarkInx, aAnchor: integer);
// Resize Custom Mark area shape. It is required after Title text modification
// aAnchor: tcaTopLeft(0), tcaArrowTo(1); Choose which point to keep
var
aSeries: tChartSeries;
aMark : tMarksItem;
aMarkPosision: tSeriesMarkPosition;
begin
// Assignments for more readable code
aSeries := aChart[aSeriesInx];
aMark := aChart[aSeriesInx].Marks[aMarkInx];
aMarkPosision := aSeries.Marks.Positions[aMarkInx];
// Bounds Calculation of the new Mark. Yeray solution.
tCustomTextShapeAccess(aMark).CalcBounds(aChart); // Yeray: tCustomTextShapeAccess class to get access to the protected CalcBounds method
aMarkPosision.Height := aMark.Height;
aMarkPosision.Width := aMark.Width;
// Set Mark position based on aAnchor
case aAnchor of
tcaTopLeft: // Keep LeftTop point. Set new ArrowTo point.
begin
aMarkPosision.ArrowTo.X := aMarkPosision.LeftTop.X + (aMarkPosision.Width div 2);
if aSeries.CalcYPos(aMarkInx) > aMarkPosision.ArrowTo.Y then // Mark above Series point
aMarkPosision.ArrowTo.Y := aMarkPosision.LeftTop.Y + aMarkPosision.Height
else
aMarkPosision.ArrowTo.Y := aMarkPosision.LeftTop.Y;
end;
else // Set ArrowTo point. Set a New LeftTop point.
begin
aMarkPosision.LeftTop.X := aMarkPosision.ArrowTo.X - (aMarkPosision.Width div 2);
if aSeries.CalcYPos(aMarkInx) > aMarkPosision.ArrowTo.Y then // Mark above Series point
aMarkPosision.LeftTop.Y := aMarkPosision.ArrowTo.Y - (aMarkPosision.Height -1)
else // Mark below Series point
aMarkPosision.ArrowTo.Y := aMarkPosision.LeftTop.Y;
end;
end; // case
aChart.Repaint;
end;
Upvotes: 0
Reputation: 5039
You could recalculate the Mark bounds and assign the Width
and Height
to the corresponding Position:
TCustomTextShapeAccess(Chart1[0].Marks[0]).CalcBounds(Chart1);
Chart1[0].Marks.Positions[0].Height:=Chart1[0].Marks[0].Height;
Chart1[0].Marks.Positions[0].Width:=Chart1[0].Marks[0].Width;
Chart1.Repaint;
Note you have to declare the TCustomTextShapeAccess
class to get access to the protected CalcBounds
method:
type TCustomTextShapeAccess=class(TCustomTextShape);
Upvotes: 1