I have tried to draw a picture similar to the screenshot using TAdvChartView, but have had no luck. I am able to calculate everything needed for the shapes and lines, but I do not know how to then draw these on the chart.
I need to draw the following on the same chart:
-An ellipse
-A cross within the ellipse
-Markers/points
-Arrows from the points to the ellipse
Is there an easy way to draw these shapes?
Hi,
You could use the OnAfterDrawSeries event and copy the DrawArrow procedure from the AdvChart unit. We will expose it in the next version.
procedure DrawArrow(Canvas : TCanvas; ArrowColor: TColor; ArrowSize: integer; origin, target : TPoint; ScaleX, ScaleY: Double);
var
quarter: byte;
fx, px: Integer;
fy, py: Integer;
x, y: integer;
arrowpts: array[0..3] of Tpoint;
p: tpoint;
ar: TPoint;
h: Integer;
arx, ary: integer;
begin
arx := Round(ArrowSize * ScaleX);
ary := Round(ArrowSize * ScaleY);
arrowpts[0] := target;
x := target.x - origin.x;
y := target.y - origin.y;
h := round(sqrt(sqr(x) + sqr(y)));
if h = 0 then
h := 1;
// quarter?
if origin.x < target.x then
begin
if origin.y < target.y then
quarter := 1
else
quarter := 3;
end
else
begin
if origin.y < target.y then
quarter := 2
else
quarter := 4;
end;
// calculate the actual P position using the adjustments px and py.
px := x * arx div h;
py := y * ary div h;
case quarter of
1 :
begin
p.x := target.x - px;
p.y := target.y - py;
ar.x := target.x - (x * arx div h);
ar.y := target.y - (y * ary div h);
end;
2 :
begin
p.x := target.x - px;
p.y := target.y - py;
ar.x := target.x - (x * arx div h);
ar.y := target.y - (y * ary div h);
end;
3 :
begin
p.x := target.x - px;
p.y := target.y - py;
ar.x := target.x - (x * arx div h);
ar.y := target.y - (y * ary div h);
end;
4 :
begin
p.x := Target.x - px;
p.y := Target.y - py;
ar.x := target.x - (x * arx div h);
ar.y := target.y - (y * ary div h);
end;
end;
//calculate pts[1] and pts[2] from the P position to give us the back of the arrow.
fx := y * (arx div 2) div h;
fy := x * (ary div 2) div h;
case quarter of
1 :
begin
arrowpts[1].x := p.x - fx;
arrowpts[1].y := p.y + fy;
arrowpts[3].x := p.x + fx;
arrowpts[3].y := p.y - fy;
end;
2 :
begin
arrowpts[1].x := p.x + fx;
arrowpts[1].y := p.y - fy;
arrowpts[3].x := p.x - fx;
arrowpts[3].y := p.y + fy;
end;
3 :
begin
arrowpts[1].x := p.x + fx;
arrowpts[1].y := p.y - fy;
arrowpts[3].x := p.x - fx;
arrowpts[3].y := p.y + fy;
end;
4 :
begin
arrowpts[1].x := p.x + fx;
arrowpts[1].y := p.y - fy;
arrowpts[3].x := p.x - fx;
arrowpts[3].y := p.y + fy;
end;
end;
arrowpts[2] := ar;
if ArrowColor <> clNone then
canvas.Brush.color := ArrowColor
else
canvas.Brush.Style := bsClear;
Canvas.polygon(arrowpts);
end;
For the markers, ellipsis and cross you can use the default canvas functionality and for calculation from pixel to value you can use YToValue and ValueToY or the XToValue and ValueToX equivalent on series level, with the series rectangle. The code below for example will convert a value of 100 to Y pixel values based on the Y-Scale of the first series.
procedure TForm1.AdvGDIPChartView1AfterDrawSeries(Sender: TObject;
ARect: TRect; ACanvas: TCanvas; APaneIndex: Integer);
var
s: TChartSerie;
begin
s := AdvGDIPChartView1.Panes[APaneIndex].Series[0];
s.ValueToY(100, s.Chart.Series.SeriesRectangle);
end;
Kind Regards,
Pieter
Pieter Scheldeman2015-09-16 08:41:11
What do you use to draw the ellipse. I am still struggling with that aspect of the task.
You have the VCL TCanvas at your disposition to do any drawing you want, including drawing an ellipse.