Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
Showing results for 
Search instead for 
Did you mean: 
Active Contributor

There is sometimes a case to not use the default charting engine in Crystal Reports. You may need a simple horizontal indicator for example, or you may wish to have more control over the conditional colour of a bar, or you may have a report with whileprintingrecords values and you wish to show those in a chart. Another case would be that you've got lots of charts that are causing delays when viewing over the web due to the processing time involved.

This blog post will show you how to make a couple different types of custom (or fake) charts. Please note that this solution will not cover most of the chart types as it is applicable to horizontal chart styles only.

In the above screenshot, taken from a dynamic multicolumn report (which is also attached to this blog post) the simple charts in the green oval are the types you can make easily using text objects, formulae, and the object Size & Position conditional X or Width properties. These conditional properties for X & Width are in later versions such as CR 2008, 2011, 2013. If you do decide to download the sample, change the extracted content's file extension from .txt to .rpt. After opening up the report, note that the custom chart objects are in the Group Header 3 (GH3) section.

Looking at the first example from the picture above, Total Aces, the placement of a text object (the green circle) and its label, are conditional based on the range of the minimum value to the maximum value for Total Aces. The formula for the placement of the green circle (found by right clicking on the object and choosing Size and Position > X dialogue) as an example is:

numbervar tval:= {@TotalAces};
numbervar tmin:= minimum({@TotalAces});
numbervar tmax:= maximum({@TotalAces});

numbervar twid:= 850;
numbervar scaler:= twid/(tmax - tmin);

DefaultAttribute + int((tval  - tmin)* scaler)

It is important to note that the Width and X position measurement is in twips where there are 1440 twips per inch. Each of the lines that you see in the fake chart section containing the circles is .703 inches and I want to make sure that the circle's edges don't cross over the edge of the lines...that's why I chose the value of 850 (in twips) for the range of travel of the circle. Based on the formula above, if a player has the lowest number of aces, then the circle will not move and the circle will move 850 twips for the player(s) with the most number of aces.

You can take the formula above and use it for your own scenario keeping the definition below in mind:

numbervar tval:= {the measure or value that you want the position to represent}; // similar to the Show Value in a chart

numbervar tmin:= {the minimum value that represents the start of the X scale}; // you can set this to 0 if you want
numbervar tmax:= {the maximum value that represents the end of the X scale};

numbervar twid:= {the maximum distance in twips do you want the object to move};

numbervar scaler:= twid/(tmax - tmin); // you don't have to change this

DefaultAttribute + int((tval  - tmin)* scaler) // you don't have to change this

As setting the scale dynamically in a regular chart or having a scale that is consistent across chart objects requires some work and is sometimes not possible, this method may help you as the scale can be easily set based on any value you want and remains across groups.

Creating the horizontal bar charts is based on using the object Size and Position > Width conditional property. In the sample report the formula looks like this:

numbervar tval:= {@1stServePct};

numbervar tmin:= 1;
numbervar tmax:= 100;// 100% is the maximum;

numbervar twid:= 850;
numbervar scaler:= twid/(tmax - tmin);

DefaultAttribute + int((tval  - tmin)* scaler)

In the sample I've set the minimum (tmin) to 1 and the maximum to 100 as this is a percentage based measure. I wanted to show a 0 to 100 representation of the measure on the scale versus a having scale that starts at the minimum and only goes to the maximum 1st serve percentage.

Another advantage of this method over the regular charting engine is that you have much greater control over the colour of the object. In the picture above as an example, if a player has a maximum or a minimum versus all players on a certain measure, e.g. 1st Serve %, then the horizontal bar colour can be controlled to reflect that. In fact you can put in as many colours or conditions as you want or base the colour on another measure.

numbervar tval:= {@1stServePct};

if tval = minimum({@1stServePct}) then crred else

if tval = maximum({@1stServePct}) then crgreen else


One feature of this is that you can quickly bind any charts based on a Summary measure to a Sort Control. In the attached sample report, each of the Summary measures is bound to a sort control. And since the fake chart objects are also based on these Sort Controls, the end user can quickly sort a report and the fake chart objects based on the control. And since these objects are formulae or text objects there is no big performance hit versus having a lot of charts. You don't need a multicolumn report to do this though as you can use one of these custom chart objects on the details section of your report as well which is another advantage.

And one more big advantage is that it takes a bit of effort to create a simple chart in the regular charting engine that is just an indicator on a's possible to do but it does require some patience and trial and error. Once you've created one of these custom / fake charts you can easily copy and paste them to another report and quickly change up the values used in the scales, positions, widths, colours, etc.  The screenshot below is a mix of two vertical charts and several fake charts using this method. Again, this is only for horizontal charts or indicators as there are no conditional Y or Height properties for an object's Size and Position at this time.