30 Commits

Author SHA1 Message Date
Martin Preuss
118a8f10cf some markup. 2026-01-10 14:32:12 +01:00
Martin Preuss
fa9656b653 added text. 2026-01-10 14:27:32 +01:00
Martin Preuss
160fea2c0c more text for README.md 2026-01-10 14:26:21 +01:00
Martin Preuss
8b5451c5bd added TODO. 2026-01-05 00:49:06 +01:00
Martin Preuss
1c59e26722 remove unneeded file. 2026-01-05 00:48:09 +01:00
Martin Preuss
c34c5eb51d fixed typos. 2026-01-05 00:43:57 +01:00
Martin Preuss
c06c71b091 added AQDG_Data_DifferenceY() 2026-01-05 00:43:47 +01:00
Martin Preuss
1ac5c428bd another fix for Y ticks. 2026-01-05 00:43:31 +01:00
Martin Preuss
aefbc413a6 another code example 2026-01-04 19:17:49 +01:00
Martin Preuss
9d010c254c added example code. 2026-01-04 19:09:15 +01:00
Martin Preuss
78853bd7be PRepared release 0.1.5. 2026-01-04 15:40:04 +01:00
Martin Preuss
8bafc714c3 another fix for axis ticks. 2026-01-04 15:39:09 +01:00
Martin Preuss
7d139093df fixed axis ticks mainly used for y-axis. 2026-01-04 15:09:10 +01:00
Martin Preuss
a1c610d972 Released 0.1.4 2026-01-03 20:04:08 +01:00
Martin Preuss
28fc5d6445 improved bargraph. 2026-01-03 18:38:10 +01:00
Martin Preuss
a204af508f minor reformatting. 2026-01-03 18:37:49 +01:00
Martin Preuss
93e066d333 added bar graph. 2025-12-31 14:05:50 +01:00
Martin Preuss
a2319c1823 use AQDG_Graph_Axis_AddMargins() 2025-12-31 14:05:33 +01:00
Martin Preuss
aefee5d631 added some functions to Category. 2025-12-31 14:05:16 +01:00
Martin Preuss
ba79f68819 added AQDG_Graph_Axis_AddMargins() 2025-12-31 14:04:56 +01:00
Martin Preuss
545db8bc60 category: remove list1 (tree2 basically has the same features) 2025-12-30 17:45:21 +01:00
Martin Preuss
3b914e5630 added category. 2025-12-30 17:40:42 +01:00
Martin Preuss
36725f170f use smaller margins for X axis. 2025-12-30 14:44:18 +01:00
Martin Preuss
e3eb5cc901 fixed a bug. 2025-12-30 14:43:50 +01:00
Martin Preuss
0325d51c0e share more code. 2025-12-30 12:58:12 +01:00
Martin Preuss
2a641f7a25 add margins also for x axis. 2025-12-30 12:57:49 +01:00
Martin Preuss
42c81e32ce added AQDG_Graph_DataPair_List_GetMinDiffX/Y() 2025-12-30 10:50:57 +01:00
Martin Preuss
87053c5029 clip bars to viewport. 2025-12-30 10:50:09 +01:00
Martin Preuss
fb6af5ef1b implemented vertical bars graph. 2025-12-30 10:44:57 +01:00
Martin Preuss
d6040a6bc9 Updated README. 2025-12-30 01:36:32 +01:00
16 changed files with 1121 additions and 165 deletions

4
0BUILD
View File

@@ -3,8 +3,8 @@
<gwbuild requiredVersion="5.9.0" > <gwbuild requiredVersion="5.9.0" >
<project name="aqdiagram" version="0.1.3-beta" <project name="aqdiagram" version="0.1.5"
so_current="0" so_age="0" so_revision="3" so_current="0" so_age="0" so_revision="5"
write_config_h="TRUE" write_config_h="TRUE"
> >

View File

@@ -19,13 +19,103 @@ mkdir build
cd build cd build
gwbuild -s .. gwbuild -s ..
gwbuild -p gwbuild -p
gwbuild -Btm2builder gwbuild -Btm2builder (not needed with newer versions of gwenbuild)
gwbuild -jNN (with NN number of parallel processes, e.g. 4 for quadcore cpu) gwbuild -jNN (with NN number of parallel processes, e.g. 4 for quadcore cpu)
sudo gwbuild -i sudo gwbuild -i
``` ```
## Structure of AqDiagram
AqDiagram consists of 4 parts:
- __data__:
Library for data manipulation (accumulate, negate, diff, average, floating average, sums for days and months)
- __draw__:
Library for drawing text and simple figures (points, lines, rectangles), current implementation for libcairo).
- __placement__:
Library for placement of objects in a plane.
- __graph__:
Library for drawing graphs using the other libraries.
## Code Examples ## Code Examples
https://gitea.aqbanking.de/martin/aqdiagram/src/branch/master/src/lib/aqdiagram/libtest.c ### Simple Graph with a Single Curve
```
AQDG_GRAPH *g;
AQDG_GRAPH_DATAPAIR_LIST *dpList;
AQDG_DRAW_CONTEXT *dc;
AQDG_OBJECT *graphObject;
g=AQDG_TimeGraph_new("Title", "Subtitle", "Value", "mm", 0);
/* get data to be shown (insert your function here) */
dpList=CREATE_DATA_FOR_GRAPH();
/* add single curve as line graph */
AQDG_TimeGraph_AddCurve(g, "Testdata", AQDG_GRAPH_TYPE_LINE, dpList);
/* setup ticks for X and Y axis (use auto-calculated upper and lower limit) */
AQDG_TimeGraph_SetupTicks(g, 0, 0.0, 0.0);
/* draw graph as PNG file (here with 800x600 pixels) */
dc=AQDG_Draw_ContextCairo_Png_new("/tmp/testgraph.png", 800, 600);
graphObject=AQDG_GraphWidget_new(NULL, AQDG_OBJECT_OPTIONS_STRETCHX | AQDG_OBJECT_OPTIONS_STRETCHY, dc);
AQDG_Object_SetWidth(graphObject, 800);
AQDG_Object_SetHeight(graphObject, 600);
/* use default pens and fonts */
AQDG_GraphWidget_SetupDefaultPens(graphObject);
AQDG_GraphWidget_SetupDefaultFonts(graphObject);
/* finish creating the PNG file */
AQDG_GraphWidget_FinishWithGraph(graphObject, g);
return 0;
```
### Graph with a Bar Graph and a Derived Line Curve
```
AQDG_GRAPH *g;
AQDG_GRAPH_DATAPAIR_LIST *dpList;
AQDG_GRAPH_DATAPAIR_LIST *derivedDpList;
AQDG_DRAW_CONTEXT *dc;
AQDG_OBJECT *graphObject;
g=AQDG_TimeGraph_new("Title", "Subtitle", "Value", "mm", 0);
/* get data to be shown (insert your function here) */
dpList=CREATE_DATA_FOR_GRAPH();
/* add first curve as bar graph */
AQDG_TimeGraph_AddCurve(g, "Testdata", AQDG_GRAPH_TYPE_BARS, dpList);
/* use a data modification function on initial data (here: accumulate) */
derivedDpList=AQDG_Data_Accumulate(dpList);
/* add 2nd curve with accumulated data as line graph */
AQDG_TimeGraph_AddCurve(g, "Accumulated", AQDG_GRAPH_TYPE_LINE, derivedDpList);
/* setup ticks for X and Y axis (use auto-calculated upper and lower limit) */
AQDG_TimeGraph_SetupTicks(g, 0, 0.0, 0.0);
/* draw graph as PNG file (here with 800x600 pixels) */
dc=AQDG_Draw_ContextCairo_Png_new("/tmp/testgraph.png", 800, 600);
graphObject=AQDG_GraphWidget_new(NULL, AQDG_OBJECT_OPTIONS_STRETCHX | AQDG_OBJECT_OPTIONS_STRETCHY, dc);
AQDG_Object_SetWidth(graphObject, 800);
AQDG_Object_SetHeight(graphObject, 600);
/* use default pens and fonts */
AQDG_GraphWidget_SetupDefaultPens(graphObject);
AQDG_GraphWidget_SetupDefaultFonts(graphObject);
/* finish creating the PNG file */
AQDG_GraphWidget_FinishWithGraph(graphObject, g);
return 0;
```

0
TODO Normal file
View File

View File

@@ -32,7 +32,7 @@ AQDG_GRAPH_DATAPAIR_LIST *AQDG_Data_DaySums(const AQDG_GRAPH_DATAPAIR_LIST *dpLi
while(dp) { while(dp) {
double v; double v;
v=AQDG_Graph_DataPair_GetValueX(dp); v=AQDG_Graph_DataPair_GetValueY(dp);
if (lastDate==NULL) { if (lastDate==NULL) {
/* first value */ /* first value */
lastDate=GWEN_Date_fromLocalTime(AQDG_Graph_DataPair_GetValueX(dp)); lastDate=GWEN_Date_fromLocalTime(AQDG_Graph_DataPair_GetValueX(dp));

View File

@@ -84,3 +84,33 @@ double AQDG_Data_GetAbsMinDiffY(const AQDG_GRAPH_DATAPAIR_LIST *dpList)
AQDG_GRAPH_DATAPAIR_LIST *AQDG_Data_DifferenceY(const AQDG_GRAPH_DATAPAIR_LIST *dpList)
{
if (dpList && AQDG_Graph_DataPair_List_GetCount(dpList)) {
AQDG_GRAPH_DATAPAIR_LIST *newList;
const AQDG_GRAPH_DATAPAIR *dp;
newList=AQDG_Graph_DataPair_List_new();
dp=AQDG_Graph_DataPair_List_First(dpList);
if (dp) {
double lastValue;
lastValue=AQDG_Graph_DataPair_GetValueY(dp);
while(dp) {
AQDG_GRAPH_DATAPAIR *newDp;
double v;
v=AQDG_Graph_DataPair_GetValueY(dp);
newDp=AQDG_Graph_DataPair_dup(dp);
AQDG_Graph_DataPair_SetValueY(newDp, v-lastValue);
AQDG_Graph_DataPair_List_Add(newDp, newList);
lastValue=v;
dp=AQDG_Graph_DataPair_List_Next(dp);
}
return newList;
}
}
return NULL;
}

View File

@@ -20,6 +20,9 @@ extern "C" {
AQDG_API double AQDG_Data_GetAbsMinDiffX(const AQDG_GRAPH_DATAPAIR_LIST *dpList); AQDG_API double AQDG_Data_GetAbsMinDiffX(const AQDG_GRAPH_DATAPAIR_LIST *dpList);
AQDG_API double AQDG_Data_GetAbsMinDiffY(const AQDG_GRAPH_DATAPAIR_LIST *dpList);
AQDG_API AQDG_GRAPH_DATAPAIR_LIST *AQDG_Data_DifferenceY(const AQDG_GRAPH_DATAPAIR_LIST *dpList);

View File

@@ -13,6 +13,9 @@
#include "./floatingavg.h" #include "./floatingavg.h"
static double _averageOverArray(const double *lastValues, int num);
AQDG_GRAPH_DATAPAIR_LIST *AQDG_Data_FloatingAverage(const AQDG_GRAPH_DATAPAIR_LIST *dpList, int num) AQDG_GRAPH_DATAPAIR_LIST *AQDG_Data_FloatingAverage(const AQDG_GRAPH_DATAPAIR_LIST *dpList, int num)
{ {
@@ -28,36 +31,19 @@ AQDG_GRAPH_DATAPAIR_LIST *AQDG_Data_FloatingAverage(const AQDG_GRAPH_DATAPAIR_LI
while(dp) { while(dp) {
AQDG_GRAPH_DATAPAIR *newDp; AQDG_GRAPH_DATAPAIR *newDp;
double v; double v;
int i;
v=AQDG_Graph_DataPair_GetValueY(dp); v=AQDG_Graph_DataPair_GetValueY(dp);
if (idx>=num) idx%=num;
idx=0; lastValues[idx++]=v;
lastValues[idx]=v;
idx++;
cnt++; cnt++;
if (cnt<num) { if (cnt<num) {
/* buffer not full, average over the values we already have */ /* buffer not full, average over the values we already have */
if (cnt) { v=_averageOverArray(lastValues, cnt);
double totalSum=0.0;
for (i=0; i<cnt; i++) {
totalSum+=lastValues[i];
}
v=totalSum/((double)cnt);
}
else
v=0.0;
} }
else { else {
double totalSum=0.0;
/* buffer full, average over full buffer */ /* buffer full, average over full buffer */
for (i=0; i<num; i++) { v=_averageOverArray(lastValues, num);
totalSum+=lastValues[i];
}
v=totalSum/((double)num);
} }
newDp=AQDG_Graph_DataPair_dup(dp); newDp=AQDG_Graph_DataPair_dup(dp);
@@ -73,3 +59,23 @@ AQDG_GRAPH_DATAPAIR_LIST *AQDG_Data_FloatingAverage(const AQDG_GRAPH_DATAPAIR_LI
double _averageOverArray(const double *lastValues, int num)
{
double v=0.0;
if (num) {
double totalSum=0.0;
int i;
/* average over full buffer */
for (i=0; i<num; i++) {
totalSum+=lastValues[i];
}
v=totalSum/((double)num);
}
return v;
}

View File

@@ -1 +0,0 @@
Previous af_graphics

View File

@@ -34,6 +34,7 @@
<setVar name="local/typefiles" > <setVar name="local/typefiles" >
datapair.t2d datapair.t2d
category.t2d
subgraph.t2d subgraph.t2d
tick.t2d tick.t2d
axis.t2d axis.t2d
@@ -42,6 +43,7 @@
<setVar name="local/built_sources" > <setVar name="local/built_sources" >
datapair.c datapair.c
category.c
subgraph.c subgraph.c
tick.c tick.c
axis.c axis.c
@@ -50,6 +52,7 @@
<setVar name="local/built_headers_pub"> <setVar name="local/built_headers_pub">
datapair.h datapair.h
category.h
subgraph.h subgraph.h
tick.h tick.h
axis.h axis.h
@@ -59,6 +62,7 @@
<setVar name="local/built_headers_priv" > <setVar name="local/built_headers_priv" >
datapair_p.h datapair_p.h
category_p.h
subgraph_p.h subgraph_p.h
tick_p.h tick_p.h
axis_p.h axis_p.h
@@ -79,6 +83,7 @@
<headers dist="true" install="$(pkgincludedir)/graph"> <headers dist="true" install="$(pkgincludedir)/graph">
graph.h graph.h
timegraph.h timegraph.h
bargraph.h
w_graph.h w_graph.h
w_axis.h w_axis.h
w_xaxis.h w_xaxis.h
@@ -101,6 +106,7 @@
$(local/typefiles) $(local/typefiles)
graph.c graph.c
timegraph.c timegraph.c
bargraph.c
w_graph.c w_graph.c
w_axis.c w_axis.c
w_xaxis.c w_xaxis.c

View File

@@ -52,6 +52,94 @@
</content> </content>
</inline> </inline>
<inline loc="code">
<content>
static int _genLog10TicksUp($(struct_type) *st, \n
double vStart, \n
double vStep, \n
double vBegin, double vEnd, \n
int level, \n
int precision) \n
{ \n
double vRun; \n
GWEN_BUFFER *dbuf; \n
\n
dbuf=GWEN_Buffer_new(0, 256, 0, 1); \n
vRun=vStart; \n
while(vRun&lt;=vEnd) { \n
if (vRun&gt;=vBegin) { \n
if (!$(struct_prefix)_HasTickValue(st, vRun)) { \n
GWEN_Buffer_AppendArgs(dbuf, "%.*f", precision, vRun); \n
$(struct_prefix)_AddNewTick(st, GWEN_Buffer_GetStart(dbuf), vRun, level, 0, vStep); \n
DBG_INFO(NULL, "Adding tick %d: %s", level, GWEN_Buffer_GetStart(dbuf)); \n
GWEN_Buffer_Reset(dbuf); \n
} \n
} \n
vRun+=vStep; \n
} \n
GWEN_Buffer_free(dbuf); \n
return ($(struct_prefix)_HasAtLeastNLevelTicks(st, level, level?2:4))?1:0; \n
} \n
</content>
</inline>
<inline loc="code">
<content>
static int _genLog10TicksDown($(struct_type) *st, \n
double vStart, \n
double vStep, \n
double vBegin, double vEnd, \n
int level, \n
int precision) \n
{ \n
double vRun; \n
GWEN_BUFFER *dbuf; \n
\n
dbuf=GWEN_Buffer_new(0, 256, 0, 1); \n
vRun=vStart; \n
while(vRun&gt;=vEnd) { \n
if (vRun&lt;=vBegin) { \n
if (!$(struct_prefix)_HasTickValue(st, vRun)) { \n
GWEN_Buffer_AppendArgs(dbuf, "%.*f", precision, vRun); \n
$(struct_prefix)_AddNewTick(st, GWEN_Buffer_GetStart(dbuf), vRun, level, 0, vStep); \n
DBG_INFO(NULL, "Adding tick %d: %s", level, GWEN_Buffer_GetStart(dbuf)); \n
GWEN_Buffer_Reset(dbuf); \n
} \n
} \n
vRun-=vStep; \n
} \n
GWEN_Buffer_free(dbuf); \n
return ($(struct_prefix)_HasAtLeastNLevelTicks(st, level, level?2:4))?1:0; \n
} \n
</content>
</inline>
<inline loc="code">
<content>
static int _genLog10Ticks($(struct_type) *st, \n
double vStart, \n
double vStep, \n
double vMin, double vMax, \n
int level, \n
int precision) \n
{ \n
if (vMin&lt;0.0 && vMax&gt;=0.0) { \n
int rv; \n
\n
rv=_genLog10TicksUp(st, 0.0, vStep, 0.0, vMax, level, precision); \n
rv|=_genLog10TicksDown(st, 0.0, vStep, 0.0, vMin, level, precision); \n
return rv; \n
} \n
else if (vMin&lt;0.0 && vMax&lt;=0.0) \n
return _genLog10TicksDown(st, vStart, vStep, vMax, vMin, level, precision); \n
else \n
return _genLog10TicksUp(st, vStart, vStep, vMin, vMax, level, precision); \n
} \n
</content>
</inline>
<inline loc="end" access="public"> <inline loc="end" access="public">
<content> <content>
@@ -65,68 +153,48 @@
{ \n { \n
double absMaxValue; \n double absMaxValue; \n
double v; \n double v; \n
double vRun; \n double vMin; \n
double startValue; \n double vMax; \n
GWEN_BUFFER *dbuf; \n double vStart; \n
int nextLevel=0; \n int nextLevel=0; \n
\n \n
absMaxValue=abs(st-&gt;minValue); \n vMin=st-&gt;minValue; \n
v=abs(st-&gt;maxValue); \n vMax=st-&gt;maxValue; \n
absMaxValue=abs(vMin); \n
v=abs(vMax); \n
absMaxValue=(v&gt;absMaxValue)?v:absMaxValue; \n absMaxValue=(v&gt;absMaxValue)?v:absMaxValue; \n
\n \n
dbuf=GWEN_Buffer_new(0, 64, 0, 1); \n
if (absMaxValue==0.0) \n if (absMaxValue==0.0) \n
absMaxValue=1.0; \n absMaxValue=1.0; \n
v=pow(10, floor(log10(absMaxValue))); \n v=pow(10, floor(log10(absMaxValue))); \n
\n \n
startValue=v; \n vStart=v; \n
if ((st-&gt;minValue)&lt;startValue) \n if (vMin&lt;vStart) \n
startValue=-startValue; \n vStart=-vStart; \n
\n
for(;;) { \n
int rv; \n
\n \n
while(v&gt;=0.0) { \n
DBG_INFO(NULL, "Handling level %d (%.2f)", nextLevel, v); \n DBG_INFO(NULL, "Handling level %d (%.2f)", nextLevel, v); \n
if (nextLevel&gt;=3) \n if (nextLevel&gt;=3) \n
break; \n break; \n
vRun=startValue; \n rv=_genLog10Ticks(st, vStart, v, vMin, vMax, nextLevel, st-&gt;precision); \n
while(vRun&lt;=(st-&gt;maxValue)) { \n if (rv) \n
if (vRun&gt;=(st-&gt;minValue)) { \n nextLevel++; \n
if (!$(struct_prefix)_HasTickValue(st, vRun)) { \n else \n
GWEN_Buffer_AppendArgs(dbuf, "%.*f", st-&gt;precision, vRun); \n $(struct_prefix)_RemoveLevelTicks(st, nextLevel); \n
$(struct_prefix)_AddNewTick(st, GWEN_Buffer_GetStart(dbuf), vRun, nextLevel, 0, v); \n
DBG_INFO(NULL, "Adding tick %d: %s", nextLevel, GWEN_Buffer_GetStart(dbuf)); \n
GWEN_Buffer_Reset(dbuf); \n
} \n
} \n
vRun+=v; \n
} \n
v/=2.0; \n v/=2.0; \n
if ($(struct_prefix)_HasAtLeastNLevelTicks(st, nextLevel, nextLevel?1:4)) \n
nextLevel++; \n
else \n
$(struct_prefix)_RemoveLevelTicks(st, nextLevel); \n
\n \n
DBG_INFO(NULL, "Handling level %d (%.2f)", nextLevel, v); \n
if (nextLevel&gt;=3) \n if (nextLevel&gt;=3) \n
break; \n break; \n
vRun=startValue; \n DBG_INFO(NULL, "Handling level %d (%.2f)", nextLevel, v); \n
while(vRun&lt;=(st-&gt;maxValue)) { \n rv=_genLog10Ticks(st, vStart, v, vMin, vMax, nextLevel, st-&gt;precision); \n
if (vRun&gt;=(st-&gt;minValue)) { \n if (rv) \n
if (!$(struct_prefix)_HasTickValue(st, vRun)) { \n
GWEN_Buffer_AppendArgs(dbuf, "%.*f", st-&gt;precision, vRun); \n
$(struct_prefix)_AddNewTick(st, GWEN_Buffer_GetStart(dbuf), vRun, nextLevel, 0, v); \n
DBG_INFO(NULL, "Adding tick %d: %s", nextLevel, GWEN_Buffer_GetStart(dbuf)); \n
GWEN_Buffer_Reset(dbuf); \n
} \n
} \n
vRun+=v; \n
} \n
v/=5.0; \n
if ($(struct_prefix)_HasAtLeastNLevelTicks(st, nextLevel, nextLevel?1:4)) \n
nextLevel++; \n nextLevel++; \n
else \n else \n
$(struct_prefix)_RemoveLevelTicks(st, nextLevel); \n $(struct_prefix)_RemoveLevelTicks(st, nextLevel); \n
} /* while */ \n v/=5.0; \n
GWEN_Buffer_free(dbuf); \n } /* for */ \n
} \n } \n
</content> </content>
</inline> </inline>
@@ -633,6 +701,42 @@
</content> </content>
</inline> </inline>
<inline loc="end" access="public">
<content>
$(api) void $(struct_prefix)_AddMargins(AQDG_GRAPH_AXIS *axis, double percent);
</content>
</inline>
<inline loc="code">
<content>
void $(struct_prefix)_AddMargins(AQDG_GRAPH_AXIS *axis, double percent)
{
double vMax;
double vMin;
double vDiff;
vMin=axis-&gt;minValue;
vMax=axis-&gt;maxValue;
vDiff=vMax-vMin;
if (vDiff==0.0) {
vDiff=vMax;
if (vDiff==0.0)
vDiff=1.0;
}
if (vDiff>0.0) {
double vDiffForPercent;
vDiffForPercent=vDiff*(percent/100.0);
vMin-=vDiffForPercent;
vMax+=vDiffForPercent;
axis-&gt;minValue=vMin;
axis-&gt;maxValue=vMax;
}
}
</content>
</inline>
</inlines> </inlines>
</lang> </lang>

View File

@@ -0,0 +1,171 @@
/****************************************************************************
* This file is part of the project AqDiagram.
* AqDiagram (c) by 2025 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./bargraph.h"
#include <aqdiagram/data/date.h>
#include <aqdiagram/data/floatingavg.h>
#include <aqdiagram/data/accumulate.h>
#include <aqdiagram/data/negate.h>
#include <gwenhywfar/debug.h>
#include <ctype.h>
/* ------------------------------------------------------------------------------------------------
* definitions
* ------------------------------------------------------------------------------------------------
*/
#define AQDG_BARGRAPH_MARGINSPERCENT_X 1.0
#define AQDG_BARGRAPH_MARGINSPERCENT_Y 10.0
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void _setDataTicks(const AQDG_GRAPH *g, AQDG_GRAPH_AXIS *axis);
static void _setValuesX(AQDG_GRAPH_DATAPAIR_LIST *dpList);
/* ------------------------------------------------------------------------------------------------
* code
* ------------------------------------------------------------------------------------------------
*/
AQDG_GRAPH *AQDG_BarGraph_new(const char *sTitle,
const char *sSubTitle,
const char *sYLabel,
const char *sYUnits,
int yPrecision)
{
AQDG_GRAPH *g;
AQDG_GRAPH_AXIS *xAxis;
AQDG_GRAPH_AXIS *yAxis;
AQDG_GRAPH_SUBGRAPH *subGraph;
g=AQDG_Graph_new();
AQDG_Graph_SetTitle(g, sTitle);
AQDG_Graph_SetSubTitle(g, sSubTitle);
xAxis=AQDG_Graph_Axis_new();
AQDG_Graph_Axis_SetLabel(xAxis, "Category");
AQDG_Graph_Axis_SetPrecision(xAxis, 0);
AQDG_Graph_SetAxis(g, AQDG_GRAPH_AXISPOS_BOTTOM, xAxis);
yAxis=AQDG_Graph_Axis_new();
AQDG_Graph_Axis_SetLabel(yAxis, sYLabel);
AQDG_Graph_Axis_SetPrecision(yAxis, yPrecision);
AQDG_Graph_Axis_SetUnits(yAxis, sYUnits);
AQDG_Graph_SetAxis(g, AQDG_GRAPH_AXISPOS_LEFT, yAxis);
subGraph=AQDG_Graph_SubGraph_new();
AQDG_Graph_SubGraph_SetIndexAxisX(subGraph, AQDG_GRAPH_AXISPOS_BOTTOM);
AQDG_Graph_SubGraph_SetIndexAxisY(subGraph, AQDG_GRAPH_AXISPOS_LEFT);
AQDG_Graph_AddSubGraph(g, subGraph);
return g;
}
void AQDG_BarGraph_AddCurve(AQDG_GRAPH *g, const char *sLabel, int graphType, AQDG_GRAPH_DATAPAIR_LIST *dpList)
{
AQDG_GRAPH_SUBGRAPH *subGraph;
_setValuesX(dpList);
subGraph=AQDG_Graph_GetFirstSubGraph(g);
if (subGraph) {
AQDG_GRAPH_CURVE *curve;
curve=AQDG_Graph_Curve_new();
AQDG_Graph_Curve_SetLabel(curve, sLabel);
AQDG_Graph_Curve_SetGraphType(curve, graphType);
AQDG_Graph_Curve_SetDataPairs(curve, dpList);
AQDG_Graph_SubGraph_AddCurve(subGraph, curve);
}
}
void AQDG_BarGraph_SetupTicks(AQDG_GRAPH *g, uint32_t flags, double minY, double maxY)
{
AQDG_GRAPH_AXIS *axis;
AQDG_Graph_CalcMinMaxValues(g);
/* create ticks for X axis */
axis=AQDG_Graph_GetAxisByIndex(g, AQDG_GRAPH_AXISPOS_BOTTOM);
if (axis) {
AQDG_Graph_Axis_SetMinValue(axis, AQDG_Graph_Axis_GetMinValue(axis)-0.5);
AQDG_Graph_Axis_SetMaxValue(axis, AQDG_Graph_Axis_GetMaxValue(axis)+0.5);
_setDataTicks(g, axis);
}
/* create ticks for Y axis */
axis=AQDG_Graph_GetAxisByIndex(g, AQDG_GRAPH_AXISPOS_LEFT);
if (axis) {
AQDG_Graph_Axis_AddMargins(axis, AQDG_BARGRAPH_MARGINSPERCENT_Y);
if (flags & AQDG_BARGRAPH_SETUPTICKS_FLAGS_MINY)
AQDG_Graph_Axis_SetMinValue(axis, minY);
if (flags & AQDG_BARGRAPH_SETUPTICKS_FLAGS_MAXY)
AQDG_Graph_Axis_SetMaxValue(axis, maxY);
AQDG_Graph_Axis_GenLog10Ticks(axis);
}
}
void _setDataTicks(const AQDG_GRAPH *g, AQDG_GRAPH_AXIS *axis)
{
const AQDG_GRAPH_SUBGRAPH *subGraph;
const AQDG_GRAPH_CURVE_LIST *curveList;
const AQDG_GRAPH_CURVE *curve;
const AQDG_GRAPH_DATAPAIR_LIST *dpList;
const AQDG_GRAPH_DATAPAIR *dp;
subGraph=AQDG_Graph_GetFirstSubGraph(g);
curveList=subGraph?AQDG_Graph_SubGraph_GetCurves(subGraph):NULL;
curve=curveList?AQDG_Graph_Curve_List_First(curveList):NULL;
dpList=curve?AQDG_Graph_Curve_GetDataPairs(curve):NULL;
dp=dpList?AQDG_Graph_DataPair_List_First(dpList):NULL;
while(dp) {
AQDG_Graph_Axis_AddNewTick(axis, AQDG_Graph_DataPair_GetLabel(dp), AQDG_Graph_DataPair_GetValueX(dp), 0, 0, 1);
dp=AQDG_Graph_DataPair_List_Next(dp);
}
}
void _setValuesX(AQDG_GRAPH_DATAPAIR_LIST *dpList)
{
if (dpList) {
AQDG_GRAPH_DATAPAIR *dp;
int idx;
dp=AQDG_Graph_DataPair_List_First(dpList);
while(dp) {
AQDG_Graph_DataPair_SetValueX(dp, (double)(idx++));
dp=AQDG_Graph_DataPair_List_Next(dp);
}
}
}

View File

@@ -0,0 +1,43 @@
/****************************************************************************
* This file is part of the project AqDiagram.
* AqDiagram (c) by 2025 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQDG_GRAPH_BARGRAPH_H
#define AQDG_GRAPH_BARGRAPH_H
#include <aqdiagram/placement/object.h>
#include <aqdiagram/graph/graph.h>
#define AQDG_BARGRAPH_SETUPTICKS_FLAGS_MINY 0x01
#define AQDG_BARGRAPH_SETUPTICKS_FLAGS_MAXY 0x02
#ifdef __cplusplus
extern "C" {
#endif
AQDG_API AQDG_GRAPH *AQDG_BarGraph_new(const char *sTitle,
const char *sSubTitle,
const char *sYLabel,
const char *sYUnits,
int yPrecision);
AQDG_API void AQDG_BarGraph_AddCurve(AQDG_GRAPH *g, const char *sLabel, int graphType, AQDG_GRAPH_DATAPAIR_LIST *dpList);
AQDG_API void AQDG_BarGraph_SetupTicks(AQDG_GRAPH *g, uint32_t flags, double minY, double maxY);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,420 @@
<?xml?>
<tm2>
<type id="AQDG_GRAPH_CATEGORY" type="pointer">
<descr>
This class describes a set of report data for a given category.
</descr>
<lang id="c">
<identifier>AQDG_GRAPH_CATEGORY</identifier>
<prefix>AQDG_Graph_Category</prefix>
<baseFileName>category</baseFileName>
<flags>
with_list2
with_tree2
</flags>
<headers>
<header type="sys" loc="pre">aqdiagram/aqdg_api.h</header>
<header type="sys" loc="pre">aqdiagram/graph/datapair.h</header>
<header type="sys" loc="pre">gwenhywfar/path.h</header>
</headers>
<inlines>
<inline loc="end" access="public">
<content>
$(api) void $(struct_prefix)_AddDataPair($(struct_type) *st, AQDG_GRAPH_DATAPAIR *dp);
</content>
</inline>
<inline loc="code">
<content>
void $(struct_prefix)_AddDataPair($(struct_type) *st, AQDG_GRAPH_DATAPAIR *dp) \n
{ \n
if (st &amp;&amp; dp) { \n
double v; \n
\n
v=AQDG_Graph_DataPair_GetValueY(dp); \n
if (st-&gt;dataPairList==NULL) \n
st-&gt;dataPairList=AQDG_Graph_DataPair_List_new(); \n
AQDG_Graph_DataPair_List_Add(dp, st-&gt;dataPairList); \n
st-&gt;totalAmount+=v; \n
if (v&lt;0.0) \n
st-&gt;negAmount+=v; \n
else \n
st-&gt;posAmount+=v; \n
} \n
} \n
</content>
</inline>
<inline loc="end" access="public">
<content>
$(api) void $(struct_prefix)_AddValue($(struct_type) *st, double v);
</content>
</inline>
<inline loc="code">
<content>
void $(struct_prefix)_AddValue($(struct_type) *st, double v) \n
{ \n
if (st) { \n
st-&gt;totalAmount+=v; \n
if (v&lt;0.0) \n
st-&gt;negAmount+=v; \n
else \n
st-&gt;posAmount+=v; \n
} \n
} \n
</content>
</inline>
<inline loc="end" access="public">
<content>
$(api) int $(struct_prefix)_Tree2_AddDataPair($(struct_type) *st, AQDG_GRAPH_DATAPAIR *dp);
</content>
</inline>
<inline loc="code">
<content>
int $(struct_prefix)_Tree2_AddDataPair($(struct_type) *st, AQDG_GRAPH_DATAPAIR *dp) \n
{ \n
uint32_t categoryId; \n
\n
categoryId=AQDG_Graph_DataPair_GetCategoryId(dp); \n
if (categoryId) { \n
AQDG_GRAPH_CATEGORY *cat; \n
\n
cat=AQDG_Graph_Category_Tree2_GetByCategoryId(st, categoryId); \n
if (cat) { \n
AQDG_Graph_Category_AddDataPair(cat, dp); \n
return 0; \n
} \n
} \n
return GWEN_ERROR_NOT_FOUND; \n
} \n
</content>
</inline>
<inline loc="end" access="public">
<content>
$(api) int $(struct_prefix)_Tree2_AddValue($(struct_type) *st, uint32_t categoryId, double v);
</content>
</inline>
<inline loc="code">
<content>
int $(struct_prefix)_Tree2_AddValue($(struct_type) *st, uint32_t categoryId, double v) \n
{ \n
if (categoryId) { \n
AQDG_GRAPH_CATEGORY *cat; \n
\n
cat=AQDG_Graph_Category_Tree2_GetByCategoryId(st, categoryId); \n
if (cat) { \n
AQDG_Graph_Category_AddValue(cat, v); \n
return 0; \n
} \n
} \n
return GWEN_ERROR_NOT_FOUND; \n
} \n
</content>
</inline>
<inline loc="end" access="public">
<content>
$(api) void $(struct_prefix)_Tree2_SumUpChildren($(struct_type) *st);
</content>
</inline>
<inline loc="code">
<content>
void $(struct_prefix)_Tree2_SumUpChildren($(struct_type) *st) \n
{ \n
if (st) { \n
$(struct_type) *child; \n
\n
child=$(struct_prefix)_Tree2_GetFirstChild(st); \n
while (child) { \n
$(struct_prefix)_Tree2_SumUpChildren(child); \n
st-&gt;totalAmount+=child-&gt;totalAmount; \n
st-&gt;negAmount+=child-&gt;negAmount; \n
st-&gt;posAmount+=child-&gt;posAmount; \n
child=AQDG_Graph_Category_Tree2_GetNext(child); \n
} \n
} \n
} \n
</content>
</inline>
<inline loc="end" access="public">
<content>
$(api) void $(struct_prefix)_Tree2_MarkCategoriesWithDataPairs($(struct_type) *st);
</content>
</inline>
<inline loc="code">
<content>
void $(struct_prefix)_Tree2_MarkCategoriesWithDataPairs($(struct_type) *st) \n
{ \n
while (st) { \n
if (st-&gt;dataPairList &amp;&amp; AQDG_Graph_DataPair_List_GetCount(st-&gt;dataPairList)) \n
st-&gt;flags|=$(struct_type)_FLAGS_SELECTED; \n
st=AQDG_Graph_Category_Tree2_GetBelow(st); \n
} \n
} \n
</content>
</inline>
<inline loc="end" access="public">
<content>
$(api) void $(struct_prefix)_Tree2_SubFlags($(struct_type) *st, uint32_t flags);
</content>
</inline>
<inline loc="code">
<content>
void $(struct_prefix)_Tree2_SubFlags($(struct_type) *st, uint32_t flags) \n
{ \n
while (st) { \n
st-&gt;flags&amp;=~flags; \n
st=AQDG_Graph_Category_Tree2_GetBelow(st); \n
} \n
} \n
</content>
</inline>
<inline loc="end" access="public">
<content>
$(api) void $(struct_prefix)_Tree2_SubFlagsDown($(struct_type) *st, uint32_t flags);
</content>
</inline>
<inline loc="code">
<content>
void $(struct_prefix)_Tree2_SubFlagsDown($(struct_type) *st, uint32_t flags) \n
{ \n
if (st) { \n
st-&gt;flags&amp;=~flags; \n
st=$(struct_prefix)_Tree2_GetFirstChild(st); \n
while (st) { \n
$(struct_prefix)_Tree2_SubFlagsDown(st, flags); \n
st=AQDG_Graph_Category_Tree2_GetNext(st); \n
} \n
} \n
} \n
</content>
</inline>
<inline loc="end" access="public">
<content>
$(api) void $(struct_prefix)_Tree2_AddFlagsDown($(struct_type) *st, uint32_t flags);
</content>
</inline>
<inline loc="code">
<content>
void $(struct_prefix)_Tree2_AddFlagsDown($(struct_type) *st, uint32_t flags) \n
{ \n
if (st) { \n
st-&gt;flags|=flags; \n
st=$(struct_prefix)_Tree2_GetFirstChild(st); \n
while (st) { \n
$(struct_prefix)_Tree2_AddFlagsDown(st, flags); \n
st=AQDG_Graph_Category_Tree2_GetNext(st); \n
} \n
} \n
} \n
</content>
</inline>
<inline loc="end" access="public">
<content>
$(api) void $(struct_prefix)_Tree2_AddFlagsUp($(struct_type) *st, uint32_t flags);
</content>
</inline>
<inline loc="code">
<content>
void $(struct_prefix)_Tree2_AddFlagsUp($(struct_type) *st, uint32_t flags) \n
{ \n
while (st) { \n
st-&gt;flags|=flags; \n
st=AQDG_Graph_Category_Tree2_GetParent(st); \n
} \n
} \n
</content>
</inline>
<inline loc="code">
<content>
static void* _handlePath(const char *aname, void *data, int idx, uint32_t flags) \n
{ \n
$(struct_type) *st; \n
\n
st=($(struct_type)*) data; \n
if (st) { \n
if (flags &amp; GWEN_PATH_FLAGS_ROOT) { \n
while($(struct_prefix)_Tree2_GetParent(st)) \n
st=$(struct_prefix)_Tree2_GetParent(st); \n
return st; \n
} \n
\n
if (strcasecmp(aname, "..")==0) \n
return $(struct_prefix)_Tree2_GetParent(st); \n
else if (strcasecmp(aname, ".")==0) \n
return st; \n
\n
st=$(struct_prefix)_Tree2_GetFirstChild(st); \n
while(st) { \n
const char *s; \n
\n
s=$(struct_prefix)_GetName(st); \n
if (s &amp;&amp; strcasecmp(s, aname)==0) \n
return st; \n
st=$(struct_prefix)_Tree2_GetNext(st); \n
} \n
} \n
return NULL; \n
} \n
</content>
</inline>
<inline loc="end" access="public">
<content>
$(api) $(struct_type)* $(struct_prefix)_Tree2_GetByPath(const $(struct_type) *st, const char *path);
</content>
</inline>
<inline loc="code">
<content>
$(struct_type)* $(struct_prefix)_Tree2_GetByPath(const $(struct_type) *st, const char *path) \n
{ \n
return GWEN_Path_HandleWithIdx(path, (void*) st, GWEN_PATH_FLAGS_NAMEMUSTEXIST, _handlePath); \n
} \n
</content>
</inline>
<inline loc="end" access="public">
<content>
$(api) void $(struct_prefix)_Tree2_CollectChildrenDataPairs($(struct_type) *st);
</content>
</inline>
<inline loc="code">
<content>
void $(struct_prefix)_Tree2_CollectChildrenDataPairs($(struct_type) *st) \n
{ \n
if (st) { \n
$(struct_type) *child; \n
\n
child=$(struct_prefix)_Tree2_GetFirstChild(st); \n
while(child) { \n
$(struct_prefix)_Tree2_CollectChildrenDataPairs(child); \n
if (child-&gt;dataPairList) { \n
AQDG_GRAPH_DATAPAIR *dp; \n
\n
while( (dp=AQDG_Graph_DataPair_List_First(child-&gt;dataPairList)) ){ \n
AQDG_Graph_DataPair_List_Del(dp); \n
$(struct_prefix)_AddDataPair(st, dp); \n
} \n
} \n
child=$(struct_prefix)_Tree2_GetNext(child); \n
} \n
} \n
} \n
</content>
</inline>
</inlines>
</lang>
<defines>
<define id="$(struct_type)_FLAGS" prefix="AQDG_GRAPH_CATEGORY_FLAGS_">
<item name="MODIFIED" value="0x00000001" />
<item name="SELECTED" value="0x00000002" />
</define>
</defines>
<members>
<member name="flags" type="uint32_t" maxlen="8">
<default>0</default>
<preset>0</preset>
<flags>with_flags</flags>
<access>public</access>
</member>
<member name="categoryId" type="uint32_t" maxlen="8">
<default>0</default>
<preset>0</preset>
<flags>none with_getbymember</flags>
<access>public</access>
</member>
<member name="name" type="char_ptr" maxlen="256" >
<access>public</access>
<flags>own with_getbymember</flags>
<setflags>const dup</setflags>
<getflags>const</getflags>
</member>
<member name="label" type="char_ptr" maxlen="256" >
<access>public</access>
<flags>own with_getbymember</flags>
<setflags>const dup</setflags>
<getflags>const</getflags>
</member>
<member name="totalAmount" type="double" maxlen="8" >
<default>0.0</default>
<preset>0.0</preset>
<access>public</access>
<flags>sortbymember</flags>
</member>
<member name="negAmount" type="double" maxlen="8" >
<default>0.0</default>
<preset>0.0</preset>
<access>public</access>
<flags>sortbymember</flags>
</member>
<member name="posAmount" type="double" maxlen="8" >
<default>0.0</default>
<preset>0.0</preset>
<access>public</access>
<flags>sortbymember</flags>
</member>
<member name="dataPairList" type="AQDG_GRAPH_DATAPAIR_LIST" >
<default>NULL</default>
<preset>NULL</preset>
<access>public</access>
<flags>own</flags>
<setflags>nodup</setflags>
<getflags>none</getflags>
</member>
</members>
</type>
</tm2>

View File

@@ -22,6 +22,82 @@
<header type="sys" loc="pre">aqdiagram/aqdg_api.h</header> <header type="sys" loc="pre">aqdiagram/aqdg_api.h</header>
</headers> </headers>
<inlines>
<inline loc="end" access="public">
<content>
$(api) double $(struct_prefix)_List_GetMinDiffX(const $(struct_type)_LIST *st);
</content>
</inline>
<inline loc="code">
<content>
double $(struct_prefix)_List_GetMinDiffX(const $(struct_type)_LIST *stList) \n
{ \n
int idx=0; \n
double diff=0.0; \n
const $(struct_type) *dp; \n
const $(struct_type) *dpPrevious=NULL; \n
\n
dp=$(struct_prefix)_List_First(stList); \n
while(dp) { \n
if (idx==1) \n
diff=dp-&gt;valueX-dpPrevious-&gt;valueX; \n
else if (idx>1) { \n
double newDiff; \n
\n
newDiff=dp-&gt;valueX-dpPrevious-&gt;valueX; \n
if (newDiff&lt;diff) \n
diff=newDiff; \n
} \n
dpPrevious=dp; \n
idx++; \n
\n
dp=$(struct_prefix)_List_Next(dp); \n
} \n
return diff; \n
} \n
</content>
</inline>
<inline loc="end" access="public">
<content>
$(api) double $(struct_prefix)_List_GetMinDiffY(const $(struct_type)_LIST *st);
</content>
</inline>
<inline loc="code">
<content>
double $(struct_prefix)_List_GetMinDiffY(const $(struct_type)_LIST *stList) \n
{ \n
int idx=0; \n
double diff=0.0; \n
const $(struct_type) *dp; \n
const $(struct_type) *dpPrevious=NULL; \n
\n
dp=$(struct_prefix)_List_First(stList); \n
while(dp) { \n
if (idx==1) \n
diff=dp-&gt;valueY-dpPrevious-&gt;valueY; \n
else if (idx>1) { \n
double newDiff; \n
\n
newDiff=dp-&gt;valueY-dpPrevious-&gt;valueY; \n
if (newDiff&lt;diff) \n
diff=newDiff; \n
} \n
dpPrevious=dp; \n
idx++; \n
\n
dp=$(struct_prefix)_List_Next(dp); \n
} \n
return diff; \n
} \n
</content>
</inline>
</inlines>
</lang> </lang>
<members> <members>

View File

@@ -22,14 +22,21 @@
#include <ctype.h> #include <ctype.h>
/* ------------------------------------------------------------------------------------------------
* definitions
* ------------------------------------------------------------------------------------------------
*/
#define AQDG_TIMEGRAPH_MARGINSPERCENT_X 1.0
#define AQDG_TIMEGRAPH_MARGINSPERCENT_Y 10.0
/* ------------------------------------------------------------------------------------------------ /* ------------------------------------------------------------------------------------------------
* forward declarations * forward declarations
* ------------------------------------------------------------------------------------------------ * ------------------------------------------------------------------------------------------------
*/ */
static void _setupTicksForTimeAxis(AQDG_GRAPH_AXIS *axis);
static void _setupTicksForDataAxis(AQDG_GRAPH_AXIS *axis);
static int _readNumFromString(const char **sPtr); static int _readNumFromString(const char **sPtr);
@@ -39,8 +46,6 @@ static int _readNumFromString(const char **sPtr);
* ------------------------------------------------------------------------------------------------ * ------------------------------------------------------------------------------------------------
*/ */
AQDG_GRAPH *AQDG_TimeGraph_new(const char *sTitle, AQDG_GRAPH *AQDG_TimeGraph_new(const char *sTitle,
const char *sSubTitle, const char *sSubTitle,
const char *sYLabel, const char *sYLabel,
@@ -104,92 +109,21 @@ void AQDG_TimeGraph_SetupTicks(AQDG_GRAPH *g, uint32_t flags, double minY, doubl
/* create ticks for X axis */ /* create ticks for X axis */
axis=AQDG_Graph_GetAxisByIndex(g, AQDG_GRAPH_AXISPOS_BOTTOM); axis=AQDG_Graph_GetAxisByIndex(g, AQDG_GRAPH_AXISPOS_BOTTOM);
if (axis) { if (axis) {
_setupTicksForTimeAxis(axis); AQDG_Graph_Axis_AddMargins(axis, AQDG_TIMEGRAPH_MARGINSPERCENT_X);
AQDG_Graph_Axis_GenTimeTicks(axis);
} }
/* create ticks for Y axis */ /* create ticks for Y axis */
axis=AQDG_Graph_GetAxisByIndex(g, AQDG_GRAPH_AXISPOS_LEFT); axis=AQDG_Graph_GetAxisByIndex(g, AQDG_GRAPH_AXISPOS_LEFT);
if (axis) { if (axis) {
double vMax; AQDG_Graph_Axis_AddMargins(axis, AQDG_TIMEGRAPH_MARGINSPERCENT_Y);
double vMin;
double vDiff;
vMin=AQDG_Graph_Axis_GetMinValue(axis);
vMax=AQDG_Graph_Axis_GetMaxValue(axis);
vDiff=vMax-vMin;
DBG_ERROR(NULL, "old vMin=%.2f, vMax=%.2f", vMin, vMax);
if (vDiff==0.0) {
DBG_ERROR(NULL, "min = max = %.2f", vMax);
vDiff=vMax;
if (vDiff==0.0)
vDiff=1.0;
}
if (vDiff>0.0) {
double vDiffBy10;
DBG_ERROR(NULL, "Setting vmin and vmax");
vDiffBy10=vDiff/10.0;
vMin-=vDiffBy10;
vMax+=vDiffBy10;
DBG_ERROR(NULL, "new vMin=%.2f, vMax=%.2f", vMin, vMax);
AQDG_Graph_Axis_SetMinValue(axis, vMin);
AQDG_Graph_Axis_SetMaxValue(axis, vMax);
}
if (flags & AQDG_TIMEGRAPH_SETUPTICKS_FLAGS_MINY) if (flags & AQDG_TIMEGRAPH_SETUPTICKS_FLAGS_MINY)
AQDG_Graph_Axis_SetMinValue(axis, minY); AQDG_Graph_Axis_SetMinValue(axis, minY);
if (flags & AQDG_TIMEGRAPH_SETUPTICKS_FLAGS_MAXY) if (flags & AQDG_TIMEGRAPH_SETUPTICKS_FLAGS_MAXY)
AQDG_Graph_Axis_SetMaxValue(axis, maxY); AQDG_Graph_Axis_SetMaxValue(axis, maxY);
_setupTicksForDataAxis(axis);
}
}
void _setupTicksForTimeAxis(AQDG_GRAPH_AXIS *axis)
{
#if 0
double minValue;
double maxValue;
double diffInDays;
minValue=AQDG_Graph_Axis_GetMinValue(axis);
maxValue=AQDG_Graph_Axis_GetMaxValue(axis);
diffInDays=(maxValue-minValue)/(24*60*60);
DBG_ERROR(AQDG_LOGDOMAIN, "Difference in days: %f.0", diffInDays);
if (diffInDays<3) {
AQDG_Graph_Axis_GenHourTicks(axis, 0, 1);
}
else if (diffInDays<32) {
AQDG_Graph_Axis_GenDayTicks(axis, 0); /* level 0: gen tick for every day */
AQDG_Graph_Axis_GenHourTicks(axis, 1, 8); /* level 1: gen tick for every 8h */
}
else if (diffInDays<90) {
AQDG_Graph_Axis_GenWeekTicks(axis, 0);
AQDG_Graph_Axis_GenDayTicks(axis, 1);
}
else {
AQDG_Graph_Axis_GenMonthTicks(axis, 0);
if (diffInDays<100) {
AQDG_Graph_Axis_GenDayTicks(axis, 1);
}
else if (diffInDays<400) {
AQDG_Graph_Axis_GenWeekTicks(axis, 1);
}
}
#else
AQDG_Graph_Axis_GenTimeTicks(axis);
#endif
}
void _setupTicksForDataAxis(AQDG_GRAPH_AXIS *axis)
{
AQDG_Graph_Axis_GenLog10Ticks(axis); AQDG_Graph_Axis_GenLog10Ticks(axis);
} }
}

View File

@@ -40,6 +40,7 @@ static int _screenDistBetweenLevelTicksX(const AQDG_GRAPH_TICK_LIST *tickList, i
int contentSize, double minValue, double maxValue); int contentSize, double minValue, double maxValue);
static int _screenDistBetweenLevelTicksY(const AQDG_GRAPH_TICK_LIST *tickList, int lvl, static int _screenDistBetweenLevelTicksY(const AQDG_GRAPH_TICK_LIST *tickList, int lvl,
int contentSize, double minValue, double maxValue); int contentSize, double minValue, double maxValue);
static int _distToScreenDist(int contentSize, double minValue, double maxValue, double value);
static void _drawCurveLines(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc, const AQDG_GRAPH_CURVE *curve, static void _drawCurveLines(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc, const AQDG_GRAPH_CURVE *curve,
double minValueX, double maxValueX, double minValueY, double maxValueY, double minValueX, double maxValueX, double minValueY, double maxValueY,
@@ -50,6 +51,9 @@ static void _drawCurvePoints(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc, const AQDG_G
static void _drawCurveStepLines(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc, const AQDG_GRAPH_CURVE *curve, static void _drawCurveStepLines(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc, const AQDG_GRAPH_CURVE *curve,
double minValueX, double maxValueX, double minValueY, double maxValueY, double minValueX, double maxValueX, double minValueY, double maxValueY,
int pen); int pen);
static void _drawCurveVertBars(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc, const AQDG_GRAPH_CURVE *curve,
double minValueX, double maxValueX, double minValueY, double maxValueY,
int pen);
@@ -193,6 +197,8 @@ void _drawCurve(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc, const AQDG_GRAPH_CURVE *c
_drawCurveStepLines(o, dc, curve, minValueX, maxValueX, minValueY, maxValueY, pen); _drawCurveStepLines(o, dc, curve, minValueX, maxValueX, minValueY, maxValueY, pen);
break; break;
case AQDG_GRAPH_TYPE_BARS: case AQDG_GRAPH_TYPE_BARS:
_drawCurveVertBars(o, dc, curve, minValueX, maxValueX, minValueY, maxValueY, pen);
break;
default: default:
break; break;
} }
@@ -327,12 +333,7 @@ void _drawHorizontalGrid(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc)
int _screenDistBetweenLevelTicksX(const AQDG_GRAPH_TICK_LIST *tickList, int lvl, int _screenDistBetweenLevelTicksX(const AQDG_GRAPH_TICK_LIST *tickList, int lvl,
int contentSize, double minValue, double maxValue) int contentSize, double minValue, double maxValue)
{ {
double v; return _distToScreenDist(contentSize, minValue, maxValue, AQDG_Graph_Tick_List_DistanceBetweenTicks(tickList, lvl));
int pts;
v=AQDG_Graph_Tick_List_DistanceBetweenTicks(tickList, lvl);
pts=(v*(contentSize/(maxValue-minValue)));
return pts;
} }
@@ -343,17 +344,20 @@ int _screenDistBetweenLevelTicksY(const AQDG_GRAPH_TICK_LIST *tickList, int lvl,
const AQDG_GRAPH_TICK *firstLevelTick; const AQDG_GRAPH_TICK *firstLevelTick;
firstLevelTick=AQDG_Graph_Tick_List_GetFirstTickForLevel(tickList, lvl); firstLevelTick=AQDG_Graph_Tick_List_GetFirstTickForLevel(tickList, lvl);
if (firstLevelTick) { if (firstLevelTick)
double v; return _distToScreenDist(contentSize, minValue, maxValue, AQDG_Graph_Tick_GetLevelDist(firstLevelTick));
return 0;
}
int _distToScreenDist(int contentSize, double minValue, double maxValue, double value)
{
int pts; int pts;
v=AQDG_Graph_Tick_GetLevelDist(firstLevelTick); pts=(value*(contentSize/(maxValue-minValue)));
pts=(v*(contentSize/(maxValue-minValue)));
DBG_ERROR(NULL, "Level dist %d: %d", lvl, pts);
return pts; return pts;
} }
return 0;
}
@@ -489,6 +493,76 @@ void _drawCurveStepLines(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc, const AQDG_GRAPH
void _drawCurveVertBars(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc, const AQDG_GRAPH_CURVE *curve,
double minValueX, double maxValueX, double minValueY, double maxValueY,
int pen)
{
const AQDG_GRAPH_DATAPAIR_LIST *dpList;
const AQDG_GRAPH_DATAPAIR *dp;
dpList=AQDG_Graph_Curve_GetDataPairs(curve);
dp=dpList?AQDG_Graph_DataPair_List_First(dpList):NULL;
if (dp) {
int width;
int height;
int absX;
int absY;
double valueMinDist;
int barWidth;
double baseLineValueY;
int baseLinePosY;
absX=AQDG_Object_GetAbsoluteX(o);
absY=AQDG_Object_GetAbsoluteY(o);
width=AQDG_Object_GetWidth(o);
height=AQDG_Object_GetHeight(o);
valueMinDist=AQDG_Graph_DataPair_List_GetMinDiffX(dpList);
barWidth=_distToScreenDist(width, minValueX, maxValueX, (valueMinDist*5.0)/6.0);
if (maxValueY<0.0)
baseLineValueY=maxValueY;
else if (minValueY>0.0)
baseLineValueY=minValueY;
else
baseLineValueY=0.0;
baseLinePosY=_calcVerticalPos(baseLineValueY, height, minValueY, maxValueY);
#if 0
DBG_ERROR(NULL,
"valueMinDist=%.2f, barWidth=%d, baseLineValueY=%.2f, baseLinePosY=%d",
valueMinDist, barWidth, baseLineValueY, baseLinePosY);
#endif
while(dp) {
int pos;
int xPos1;
int xPos2;
int yPos;
int h;
double xValue;
double yValue;
xValue=AQDG_Graph_DataPair_GetValueX(dp);
yValue=AQDG_Graph_DataPair_GetValueY(dp);
pos=_calcHorizontalPos(xValue, width, minValueX, maxValueX);
xPos1=pos-barWidth/2;
xPos2=pos+barWidth/2;
xPos1=(xPos1<0)?0:xPos1;
xPos2=(width>xPos2)?xPos2:(width-1);
yPos=_calcVerticalPos(yValue, height, minValueY, maxValueY);
h=baseLinePosY-yPos;
if (h<0) {
yPos+=h;
h=-h;
}
AQDG_Draw_Context_DrawFilledRect(dc, pen, absX+xPos1, absY+yPos, (xPos2-xPos1)+1, h);
dp=AQDG_Graph_DataPair_List_Next(dp);
}
}
}