In the following, a way is presented to numerically find a thickness for the tactile bars such that all groups fit on the available chart area. To use as much of the given area as possible and to minimize big gaps, the software will try to find the maximum possible thickness within the user defined limits minThickness, maxThickness.
The layout of the bars is as described in the conceptual design:
There are g groups of an arbitrary number of bars b[i] in each group i, resulting in b total bars
The groups are separated by a padding gpad, counted in full cells
The bars inside a group are separated by a padding bpad, also counted in full cells
All bars are of equal tickness
There are enclosing paddings: Between the axis and its closest bar & between the bar furthest from the axis and the end of the cart area, each 1 exactly 1 cell.
The paddings contain the bar borders
A sketch for a layout with horizontal bars:
For a given value of thickness, the full required size of the chart area can be calculated in the following way:
(g-1) * gpad is the sum of paddings between neighboring groups
SUM(0 <= i < g, gSize(i)) is the sum of each groups size
2 constant for the enclosing padding
The size of the group i can be calculated:
gSize(i) = (b[i] - 1) * bpad + b[i] * thickness
(b[i] - 1) * bpad is the sum of paddings between neighboring bars
b[i] * tickness is the sum of the sizes of the actual textured area inside the bars
Now it is possible to insert gSize() into reqSize() and set thickness=0 to calculate a baseSize.
baseSize = reqSize(thickness=0) = (g-1) * gpad + SUM(0 <= i < g, (b[i] - 1) * bpad + b[i] * thickness) + 2= (g-1) * gpad + SUM(0 <= i < g, (b[i] - 1) * bpad + b[i] * 0) + 2= (g-1) * gpad + SUM(0 <= i < g, (b[i] - 1) * bpad) + 2// Now the sum term can be replaced= (g-1) * gpad + SUM(0 <= i < g, (b[i] - 1)) * bpad + 2= (g-1) * gpad + (SUM(0 <= i < g, b[i]) - g) * bpad + 2= (g-1) * gpad + (b - g) * bpad + 2// Simplify term= g * gpad + (b - g) * bpad + 2 - gpad= g * gpad - g * bpad + b * bpad + 2 - gpad= g * (gpad - bpad) + (b * bpad) + 2 - gpad
This baseSize(g, gpad, b, bpad) = g * (gpad - bpad) + (b * bpad) + 2 - gpad which does not depend on the actual arrangement of the groups and bars represents the required size for all paddings. The required size can now be represented much simpler as the sum of the base size and the required bar space:
reqSize(thickness) = baseSize + b * thickness
Of course a limit for the total size is given by the available chart area availableSize. This means:
reqSize(thickness) <= availableSizebaseSize + b * thickness <= availableSize// minus baseSizeb * thickness <= (availableSize - baseSize)// divide by total amount of bars bthickness <= (availableSize - baseSize) / b// The maximum possible thickness is wanted. But it also must be a whole number.thickness = floor((availableSize - baseSize) / b)
So the software will calculate the baseSize for the given g, gpad, b, bpad and then calculate the actual bar thickness complying with the user defined maximum:
In the case of thickness < minThickness an exception will be thrown stating that there is not enough space available.
Floating Dot Area Mode
The floating dot area mode enables embossing by defining dots by their x- and y-coordinate. All plotting algorithms must implement the Plotter interface.
Points are added iteratively to a FloatingPointData with an x- and a y-coordinate. The list with coordinates are passed to the printer starting with an ESC 70 sequence, separated by commas and ending with a semicolon.
Plotting algorithms for diagrams should extend AbstractPlotter or an abstract child class, which provide basic functionalities such as axes drawing and axes scaling. All dimensions adapt dynamically to the size of the paper or to the range of values, respectively.
The user can chose wether a second y-axis should be plotted for scatter and line plots. The user can also chose wether a negative grid should be embossed.
Scatter plots are plotted by adding the points to the diagram and, if desired, plotting a frame around it. Currently three different frames are supported.
Line plots are plotted like scatter plots with additional line plotting between two data points. For this purpose the slope and the y-intercept are calculated. Lines are plotted by taking the x-coordinates between two points and calculating the y-coordinates with y = slope * x + y-intercept.
Currently three different line styles are supported.
The full line style corresponds with the dot frame. The dashed line style corresponds with the cross frame. The dotted line style corresponds with the circle frame. This may be changed in LinePlotter in drawLines (line 161). Variable i corresponds to the different frames.
It is possible for the user to not chose any frame or to chose the dot frame for all data series.
The user can chose wether bar chart data should be plotted as a grouped or a stacked bar chart. Negative values are only supported for grouped bar charts, not for stacked bar charts.
Further documentation can be found in the JavaDoc.
The config values for the user settings can be found in Software Design/Configuration Parsing.
Adding textures, frames and line styles to the floating dot mode
Adding textures to bar charts
To add a new texture to bar charts, first implement a texture function in AbstractBarChartPlotter (e.g. fillFullPattern). Then add a new else-if-statement in plotAndFillRectangle with an incremented value for j and the newly defined function in the body. A comment "new textures are added here" will show you the right spot (line 148).
Adding frames to scatter and line plots
To add a new frame to scatter and line plots, first implement a frame function in AbstractPointPlotter (e.g. drawDot). Then add a new else-if-statement in drawPoint with an incremented value for i and the newly defined function in the body. A comment "new frames are added here" will show you the right spot (line 283).
Adding line styles to line plots.
To add a new line style to line plots, first implement a line function in LinePlotter (e.g. drawFullLine). Then add a new else-if-statement in drawLines with an incremented value for i and the newly defined function in the body. A comment "new line styles are added here" will show you the right spot (line 170).
Notes about the configuration files and parser
first thoughts about possible formats: INI, JSON, XML
readability for normal users?
structure of the files: First section with general properties, following sections with page formats containing format specific properties
windows specific format
good readability, but:
no native support in Java, third party lib necessary
JSON & XML:
not very readable for normal users
syntax can easily be broken unintentionally -> not parsable if broken
Instead: Java Properties?
native support (java.util.Properties)
allows same division into sections
easy list-like syntax similar to INI -> good readability