tchat point lables (Marks) making my bar charts look weird lazarus / 39-Graphics ---------------------------------------------------------------------- drkppvch · 2013-12-06 02:45 Hello. I am quite new to lazarus, 2 weeks. I have created a charting application for my company database, It works fine with the exception of one chart lables (Marks) seem to be screwing the chart max and min val. Some of the field data that need to be in the lables can be  a bit long, some of my lables are being overlap with other lables and bars making them hard to read. I have change the orientation to be 900 and it works fine for a single series, but when I have 2 series in the same chart (2 separate datasources - one cound go from 0 to 20000 and the other series could go from 0 to -20000) my bar graph goes all weird (it seems brack the range of the chart and it seem to zoom in in the center of the chart.I can't zoom out and can't find a way to format it properly. Is there a way to restrict the lengh of the Marks and do some kind of word wrap? so all my lables show without having to use 900 Orientation? ---------------------------------------------------------------------- wp · 2013-12-06 11:32 Could you upload a screenshot or, better, a short demo that shows the issue? ---------------------------------------------------------------------- drkppvch · 2013-12-06 21:57 Hello WP, Here are some screen soots. When I chart my individual series they show up fine, as in Tab1 and Tab2 Images. When I combine the series I get Tab0 Image. ---------------------------------------------------------------------- wp · 2013-12-06 23:57 Thanks, I understand now. The problem seems to be related to the long series marks, indeed. There are several options: As far as I know, TAChart does not provide automatic wrapping of too- long labels. But inserted line breaks are respected. In the SysUtils unit, there is a function WrapText which introduces linebreaks after at given maximum count of characters. You should loop through your ChartSource and apply this function to the texts of the ChartItems, ie.Code: [Select]var i: Integer; begin   with Chart1BarSeries1 do     for i:=0 to Source.Count-1 do       Source.Item[i]^.Text := WrapText(Source.Item[i]^.Text, 30);        // 30 is the max width before a linebreak ... Charts usually are in "landscape" orientation, therefore, there is more space along the horizontal than the vertical direction. You could rotate the bars by 90°, i.e. draw horizontal bars. You'll still need the WrapText function, but the max width could be a bit longer. To rotate the bar series, interchange the AxisIndexX and AxisIndexY of the series, i.e. AxisIndexX gets the index of the chart's left axis, AxisIndexY correspondingly that of the bottom axis. You could use axis labels instead of marks labels. For this purpose, you assign the source of the series to the source of the chart's bottom axis and set that Style to smsLabel. Unfortunately, I could not find a working solution with the rotated bars for this case.Don't show any series marks labels at all, but use the ChartTools to display them as a MouseOver effect. I have to admit, though, that this solution is not good for printing... Anyway, you could use a TDatapointHintTool with UseDefaultHintText = false and OnHint and OnHintPosition event handlers as follows. You should set the DistanceMode to cdmOnlyX and GrabRadius to something like the bar width in pixels otherwise the hint would appear only if the mouse is in the center of the bar (you could use the BarSeries method GetBarWidth(0) after population of the series, to make sure if bar width changes when resizing the chart).Code: [Select]procedure TForm1.ChartToolset1DataPointHintTool1Hint(ATool: TDataPointHintTool;   const APoint: TPoint; var AHint: String); begin   AHint := TChartSeries(ATool.Series).Source.Item[ATool.PointIndex]^.Text;   // you could also use the WrapText function to introduce line breaks if that string is too long end;  procedure TForm1.ChartToolset1DataPointHintTool1HintPosition(ATool: TDataPointHintTool;   var APoint: TPoint); var   src: TCustomChartSource;   r: TRect;   hintWnd: THintWindow;   s: String;   w, h: Integer; begin   src := TChartSeries(ATool.Series).Source;   { Calculate size of hint window - borrowed from TATools }   s := src.Item[ATool.PointIndex]^.Text;     // if you used WrapText in the OnHint handler, use is here as well.   hintwnd := THintWindow.Create(nil);   try     r := hintwnd.CalcHintRect(Chart1.Width, s, nil);     w := r.Right - r.Left;  // Hint width     h := r.Bottom - r.Top;  // Hint height - not used here   finally     hintwnd.Free;   end;   // Center hint horizontally inside bar   APoint.x := Chart1.XGraphToImage(src.Item[ATool.PointIndex]^.X) - w div 2;   // Show hint 30 pixels below bar top   APoint.y := Chart1.YGraphToImage(src.Item[Atool.PointIndex]^.Y) + 30;   // Hint coordinates are relative to screen   APoint := Chart1.ClientToScreen(APoint); end; ---------------------------------------------------------------------- drkppvch · 2013-12-07 00:50 Hi, Thank you for data. I am not trying to be a pain, I have been working with lazarus for 2 weeks and I dont know much about coding. I have added the code you showed me but is not making any difference to the lables. Can you please let me know if the way I implemented the code is wrong: Code: [Select]procedure TForm1.ButtonChartData2Click(Sender: TObject); var i: Integer;     j: Integer;   begin      begin   SQLQuery9.Close;   SQLQuery10.Close;   Chart2.visible:=False;     SQLQuery9.Params.ParamByName('StartDate').AsDate :=DateEdit9.Date;     SQLQuery9.Params.ParamByName('EndDate').AsDate :=DateEdit10.Date;     SQLQuery9.Params.ParamByName('EnrDate1').AsDate :=DateEdit25.Date;     SQLQuery9.Params.ParamByName('EnrDate2').AsDate :=DateEdit26.Date;     SQLQuery9.Params.ParamByName('CourseType').AsString := Edit2.Text;     SQLQuery10.Params.ParamByName('StartDate1').AsDate :=DateEdit13.Date;     SQLQuery10.Params.ParamByName('EndDate1').AsDate :=DateEdit14.Date;     SQLQuery10.Params.ParamByName('EnrDate3').AsDate :=DateEdit15.Date;     SQLQuery10.Params.ParamByName('EnrDate4').AsDate :=DateEdit16.Date;     SQLQuery10.Params.ParamByName('CourseType1').AsString := Edit2.Text;   end;   IBConnection1.Connected:= True;   SQLTransaction1.Active:= True;   SQLQuery9.Open;   SQLQuery10.Open;   DBChartSource3.FieldY := 'GP';   DBChartSource4.FieldY := 'GP';   Begin      with Chart2BarSeries1 do     for i:=0 to Source.Count-1 do       Source.Item[i]^.Text := WrapText(Source.Item[i]^.Text, 30);       // 30 is the max width before a linebreak    Begin      with Chart2BarSeries2 do     for j:=0 to Source.Count-1 do       Source.Item[j]^.Text := WrapText(Source.Item[j]^.Text, 30);       // 30 is the max width before a linebreak       Chart2.visible:=True;   end; end;   end; Thank you, Your help is very much appreciated. ---------------------------------------------------------------------- wp · 2013-12-07 15:36 You seem to be using a DBChartSource. Did not have so much experience with that so far. But it could be that you cannot modify the items of that source because they come from the Database. There are two options: Every Series has an event OnGetMark which allows you to taylor the text displayed as series label. Just use the WrapText here:Code: [Select]procedure TForm1.Chart1BarSeries1GetMark(out AFormattedMark: String;   AIndex: Integer); begin   AFormattedMark := WrapText(Chart1BarSeries1.Source.Item[AIndex]^.Text; end;Or, if that does not work, add ListChartSources to the form and copy the data from each DBChartSource to them. Then the data are permanent, you can do with them whatever you want. You perform the copy action after the queries are opened, i.e., in your code snippet, before my code. Then, don't forget to assign the series' Source to the corresponding ListChartSource (instead of the DBChartSource). Code: [Select]...   SQLQuery9.Open;   SQLQuery10.Open;   DBChartSource3.FieldY := 'GP';   DBChartSource4.FieldY := 'GP';   // These lines copy the data from DBChartSource3/4 to ListChartSource1/2. Please update   // to your situation...   ListChartSource1.CopyFrom(DBChartSource3);   ListChartSource2.CopyFrom(DBChartSource4); ... ---------------------------------------------------------------------- drkppvch · 2013-12-07 23:08 Thank you, That solved the problem. Quote    Or, if that does not work, add ListChartSources to the form and copy the data from each DBChartSource to them. Then the data are permanent, you can do with them whatever you want. You perform the copy action after the queries are opened, i.e., in your code snippet, before my code. Then, don't forget to assign the series' Source to the corresponding ListChartSource (instead of the DBChartSource). Code: [Select] ...   SQLQuery9.Open;   SQLQuery10.Open;   DBChartSource3.FieldY := 'GP';   DBChartSource4.FieldY := 'GP';   // These lines copy the data from DBChartSource3/4 to ListChartSource1/2. Please update   // to your situation...   ListChartSource1.CopyFrom(DBChartSource3);   ListChartSource2.CopyFrom(DBChartSource4); ...