OOFILE  1.9
oofGrphs.cpp
Go to the documentation of this file.
1 // COPYRIGHT 1996 A.D. Software, All rights reserved
2 
3 // =================================================================================
4 // oofGrphs.cp
5 // =================================================================================
6 
7 #include "oofpch_g.h" // for precompilation of graph files
8 
9 #ifndef H_OOFRECT
10  #include "oofRect.h"
11 #endif
12 #ifndef H_OOFGRPHS
13  #include "oofGrphs.h"
14 #endif
15 
16 #include <assert.h>
17 #include <math.h>
18 
19 #ifndef H_OOF4
20  #include "oof4.h"
21 #endif
22 #ifndef H_OOFVIEW
23  #include "oofview.h"
24 #endif
25 #ifndef H_OOFGEOS
26  #include "oofGeos.h"
27 #endif
28 #ifndef H_OOFTRMGR
29  #include "oofTrMgr.h"
30 #endif
31 #ifndef H_oofSting
32  #include "oofSting.h"
33 #endif
34 #ifndef H_OOFGRDTA
35  #include "oofGrDta.h"
36 #endif
37 
38 #ifdef OOF_MEM_DEBUG_LAST_INCLUDE
39  #include OOF_MEM_DEBUG_LAST_INCLUDE
40 #endif
41 
42 #ifndef OOF_NO_STDLIB
43  #ifndef std
44  using namespace std;
45  #endif
46 #endif
47 
48 
49 // static variables
51 //oofGraphSettings* oofGraph::sDefaultSettings = 0;
52 
53 // ---------------------------------------------------------------------------------
54 // oofGraph
55 // ---------------------------------------------------------------------------------
56 
58  mIsMono(false), // All graphs start colourful
59  mSettings(adoptedSettings),
60  mDrawStylesWereSet(false),
61  mView(0)
62 {
63  mDrawStyle = new oofDrawStyle; // ALWAYS have a DrawStyle
64  // become the current graph
65  becomeCurrent();
66 }
67 
68 
69 oofGraph::oofGraph(const oofGraph& rhs) : oofColorable(rhs) { assert(0); }
70  // THIS NEEDS TO DUPLICATE ALL THE PLOTBITS!!!!!!!
71 
72 
74 {
75  delete mView;
76  delete mSettings;
77 }
78 
79 
80 void
82 {
83  // do any setup here
84 #ifdef _Macintosh
85  ::TextFace(0); // reset current style as it is global and not currently set by graph objects
86 #endif
87  becomeCurrent();
88  DrawSelf();
89 }
90 
91 
92 void
93 oofGraph::describe(ostream& os) const
94 {
95  // do any setup here
96 #ifdef _Macintosh
97  ::TextFace(0); // reset current style as it is global and not currently set by graph objects
98 #endif
99 // AD - do we need this, breaks const! becomeCurrent();
100  DescribeSelf(os);
101 }
102 
103 
104 void
106 {
107  oofRect rc;
108 
109  rc = inRect;
111 }
112 
113 void
115 {
116  mPlotBits.setPaneRect(inRect);
117 }
118 
119 void
121 {
122  if (!mSeriesSet.isEmpty()) {
123  mSeriesSet.setDrawStyles(inSet);
124  mDrawStylesWereSet = true;
125  }
126 }
127 
128 
129 void
131 {
132  if (!mSeriesSet.isEmpty()) {
133  mSeriesSet.setDrawStyles(inArray);
134  mDrawStylesWereSet = true;
135  }
136 }
137 
138 
139 void
141 {
142  if (inView) {
143  delete mView;
144  mView = new dbView(*inView); // copy lightweight object
145  }
146 }
147 
148 
149 dbView *
151 {
152  return mView; // returns NULL if no view is attached, caller should check
153 }
154 
155 
156 void
157 oofGraph::setTitle(const char* inTitle)
158 {
159  mTitle = inTitle;
160 }
161 
162 
163 const char *
165 {
166  return mTitle;
167 }
168 
169 const char *
171 {
172  return mType;
173 }
174 
175 void
177 {
178  mIsMono = true;
179 }
180 
181 
182 void
184 {
185  mIsMono = false;
186 }
187 
188 
189 oofGraph*
191 {
192  return sCurrentGraph;
193 }
194 
195 const oofGraphSettings*
197 {
198  if (mSettings) // if the graph has its own settings
199  return mSettings;
200  else // use defaults
201  return defaultSettings();
202 }
203 
204 
207 {
209 }
210 
211 
212 void
214 {
215  assert(mView);
216  // blank title is the default and is OK
217 #ifdef _Windows
218  oofCurrentDraw::makeInfoDC();
219 #endif
220  finishConstruction(mView, mTitle, settings()->YAxisHeight()); // default Y-axis height
221 }
222 
223 
226 {
227  if (!mSettings)
228  mSettings = new oofGraphSettings();
229  return mSettings;
230 }
231 
232 
233 void
235 {
236  // DrawSelf must be atomic for this to work
237  if (mIsMono) {
239  mPlotBits.draw();
241  }
242  else
243  mPlotBits.draw();
244 }
245 
246 
247 void
248 oofGraph::DescribeSelf(ostream& os) const
249 {
250  if (mIsMono)
251  os << "mono graph" << endl;
252  else
253  os << "coloured graph" << endl;
254  mPlotBits.describe(os);
255 }
256 
257 
258 void
260 {
261  sCurrentGraph = this;
262 }
263 
264 
265 // ---------------------------------------------------------------------------------
266 // O O F _ m i x O v e r l a y a b l e G r a p h
267 // ---------------------------------------------------------------------------------
269  mNumOverlaid(numOverlaid),
270  mOverlayView(0)
271 {}
272 
273 
275 {
276  delete mOverlayView;
277 }
278 
279 
280 void
281 OOF_mixOverlayableGraph::setOverlaid(unsigned long numOverlaid)
282 {
283  mNumOverlaid = numOverlaid;
284 }
285 
286 
287 void
289 {
290  delete mOverlayView;
291  mOverlayView = new dbView(*clonedView); // copy lightweight object
292 }
293 
294 
295 void
297 {
298  delete mOverlayView;
299  mOverlayView = new dbView(clonedView); // copy lightweight object
300 }
301 
302 
303 // ---------------------------------------------------------------------------------
304 // oofColumnGraph
305 // ---------------------------------------------------------------------------------
306 
307 
309 {
310  setView(inView);
311 }
312 
313 
314 oofGraph*
316 {
317  return new oofColumnGraph(*this);
318 }
319 
320 
321 void
322 oofColumnGraph::finishConstruction(dbView *theView, const char* theTitle, unsigned long yAxisHeight)
323 {
324  OOF_String theFirstFieldStr;
325  OOF_String thePrevStr;
326 
327  long CurLeft=0;
328  unsigned long SeriesWidth=0;
329  const unsigned short YtickLabelLen = settings()->maxYTickLabelLen();
330 
331  mType = "column";
332  oofGraphData Data(theView);
333 
334  // Iterate over the data
335  for (theView->source()->start(); theView->source()->more();theView->source()->next()) {
336  // Get the data out of the View
337  theFirstFieldStr = Data.FirstField()->copyString();
338  if (theFirstFieldStr != thePrevStr) {
339  if(CurLeft) {
340  if(!SeriesWidth)
341  SeriesWidth=CurLeft;
342  mPlotBits.append(new oofGeoXTickLabel(CurLeft-SeriesWidth,SeriesWidth,thePrevStr));
343  CurLeft+=SeriesSpacing;
344  }
345  }
348  thePrevStr.adopt(theFirstFieldStr);
349  CurLeft+=(ColumnWidth+Spacing);
350  }
351  CurLeft-=Spacing;
352  mPlotBits.append(new oofGeoXTickLabel(CurLeft-SeriesWidth, SeriesWidth, thePrevStr));
353  // add the X axis
354  mPlotBits.append(new oofGeoXAxis(CurLeft,SeriesWidth+SeriesSpacing,0));
355  // add the Y axis
356  long theAxisHeight;
357  if(yAxisHeight){ // Quick hack for Andy
358  theAxisHeight=yAxisHeight;
359  } else
360  theAxisHeight=Data.scaleDataValue((long)mPlotBits.getIdealRect().top);
361  oofScaleSizer ScaleSizer(theAxisHeight);
362  theAxisHeight=Data.unScaleDataValue(theAxisHeight);
363  mPlotBits.append(new oofGeoYAxis(Data.unScaleDataValue(ScaleSizer.Max()),
364  Data.unScaleDataValue(ScaleSizer.Div()),ScaleSizer.NumMinorTicks()));
365  // add the Y axis labels
366  for(unsigned p=0;p<ScaleSizer.NumDivs();p++){
367  char labelStr[255];
368  Data.setScaleString(Data.unScaleDataValue(ScaleSizer.Div())*(p+1), labelStr, settings());
370  ((int)Data.unScaleDataValue(ScaleSizer.Div())*(p+1), YtickLabelLen, labelStr));
371  }
372  // add the title
373  mPlotBits.append(new oofGeoTitle(CurLeft,theTitle));
374  // add X label
375  mPlotBits.append(new oofGeoXLabel(CurLeft,Data.FirstField()->fieldName()));
376  // add Y label
378  // add a legend
379  mPlotBits.append(new oofGeoLegend(&mSeriesSet,false /* Use Symbols */));
380 }
381 
382 
383 // ---------------------------------------------------------------------------------
384 // oofPointGraph
385 // ---------------------------------------------------------------------------------
386 
387 
389 {
390  setView(inView);
391 }
392 
393 
394 oofGraph*
396 {
397  return new oofPointGraph(*this);
398 }
399 
400 
401 void
402 oofPointGraph::finishConstruction(dbView *theView, const char* theTitle, unsigned long yAxisHeight)
403 {
404  long CurLeft=-1;
405  unsigned long SeriesWidth=0;
406  const unsigned short YtickLabelLen = settings()->maxYTickLabelLen();
407 
408  OOF_String theFirstFieldStr;
409  OOF_String thePrevStr;
410  mType = "point";
411 
412  oofGraphData Data(theView);
413 
414  // Iterate over the data
415  for (theView->source()->start(); theView->source()->more();theView->source()->next()) {
416  // Get the data out of the View
417  theFirstFieldStr = Data.FirstField()->copyString();
418  if (theFirstFieldStr != thePrevStr) {
419  if(CurLeft==-1)
420  CurLeft=0;
421  else {
422  mPlotBits.append(new oofGeoXTickLabel(CurLeft,PointWidth,thePrevStr));
423  CurLeft+=PointWidth;
424  }
425  }
426  mPlotBits.append(new oofGeoPoint(CurLeft+(PointWidth/2),Data.dataValue(),
427  mSeriesSet.findSeriesByName(*(dbChar*)Data.SeriesField(), true /* symbol */)));
428  thePrevStr.adopt(theFirstFieldStr);
429  }
430  // add the last label
431  mPlotBits.append(new oofGeoXTickLabel(CurLeft, PointWidth, thePrevStr));
432  // and expand the axis to fit it !
433  CurLeft+=PointWidth;
434  // add the X axis
435  mPlotBits.append(new oofGeoXAxis(CurLeft, PointWidth, 0));
436  // add the Y axis
437  long theAxisHeight;
438  if(yAxisHeight){ // Quick hack for Andy
439  theAxisHeight=yAxisHeight;
440  } else
441  theAxisHeight=Data.scaleDataValue((long)mPlotBits.getIdealRect().top);
442  oofScaleSizer ScaleSizer(theAxisHeight);
443  theAxisHeight=Data.unScaleDataValue(theAxisHeight);
444  mPlotBits.append(new oofGeoYAxis(Data.unScaleDataValue(ScaleSizer.Max()),
445  Data.unScaleDataValue(ScaleSizer.Div()),ScaleSizer.NumMinorTicks()));
446  // add the Y axis labels
447  for(unsigned p=0;p<ScaleSizer.NumDivs();p++){
448  char labelStr[255];
449  Data.setScaleString(Data.unScaleDataValue(ScaleSizer.Div())*(p+1), labelStr, settings());
451  ((int)Data.unScaleDataValue(ScaleSizer.Div())*(p+1),YtickLabelLen, labelStr));
452  }
453  // add the title
454  mPlotBits.append(new oofGeoTitle(CurLeft,theTitle));
455  // add X label
456  mPlotBits.append(new oofGeoXLabel(CurLeft,Data.FirstField()->fieldName()));
457  // add Y label
459  // add a legend
460  mPlotBits.append(new oofGeoLegend(&mSeriesSet,true /* Use Symbols */));
461 }
462 
463 
464 // ---------------------------------------------------------------------------------
465 // oofLineGraph
466 // ---------------------------------------------------------------------------------
467 
468 
470 {
471  setView(inView);
472 }
473 
474 
475 oofGraph*
477 {
478  return new oofLineGraph(*this);
479 }
480 
481 
482 void
483 oofLineGraph::finishConstruction(dbView *theView, const char* theTitle, unsigned long yAxisHeight)
484 {
485  long CurLeft=-1;
486  unsigned long SeriesWidth=0;
487  const unsigned short YtickLabelLen = settings()->maxYTickLabelLen();
488 
489  OOF_String theFirstFieldStr;
490  OOF_String thePrevStr;
491  oofGraphData Data(theView);
492  mType = "line";
493 
494 
495  // Iterate over the data
496  for (theView->source()->start(); theView->source()->more();theView->source()->next()) {
497  // Get the data out of the View
498  theFirstFieldStr = Data.FirstField()->copyString();
499  if (theFirstFieldStr != thePrevStr) {
500  if(CurLeft==-1)
501  CurLeft=0;
502  else {
503  mPlotBits.append(new oofGeoXTickLabel(CurLeft,PointWidth,thePrevStr));
504  CurLeft+=PointWidth;
505  }
506  }
507  mPlotBits.append(new oofGeoLine(CurLeft+(PointWidth/2),Data.dataValue(),
508  mSeriesSet.findSeriesByName(*(dbChar*)Data.SeriesField(), true /* symbol */)));
509  thePrevStr.adopt(theFirstFieldStr);
510  }
511  // add the last label
512  mPlotBits.append(new oofGeoXTickLabel(CurLeft, PointWidth, thePrevStr));
513  // and expand the axis to fit it !
514  CurLeft+=PointWidth;
515  // add the X axis
516  mPlotBits.append(new oofGeoXAxis(CurLeft, PointWidth, 0));
517  // add the Y axis
518  long theAxisHeight;
519  if(yAxisHeight){ // Quick hack for Andy
520  theAxisHeight=yAxisHeight;
521  } else
522  theAxisHeight=Data.scaleDataValue((long)mPlotBits.getIdealRect().top);
523  oofScaleSizer ScaleSizer(theAxisHeight);
524  theAxisHeight=Data.unScaleDataValue(theAxisHeight);
525  mPlotBits.append(new oofGeoYAxis(Data.unScaleDataValue(ScaleSizer.Max()),
526  Data.unScaleDataValue(ScaleSizer.Div()),ScaleSizer.NumMinorTicks()));
527  // add the Y axis labels
528  for(unsigned p=0;p<ScaleSizer.NumDivs();p++){
529  char labelStr[255];
530  Data.setScaleString(Data.unScaleDataValue(ScaleSizer.Div())*(p+1), labelStr, settings());
532  ((int)Data.unScaleDataValue(ScaleSizer.Div())*(p+1),YtickLabelLen, labelStr));
533  }
534  // add the title
535  mPlotBits.append(new oofGeoTitle(CurLeft,theTitle));
536  // add X label
537  mPlotBits.append(new oofGeoXLabel(CurLeft,Data.FirstField()->fieldName()));
538  // add Y label
540  // add a legend
541  mPlotBits.append(new oofGeoLegend(&mSeriesSet,true /* Use Symbols */));
542 }
543 
544 
545 // ---------------------------------------------------------------------------------
546 // oofXYGraph
547 // ---------------------------------------------------------------------------------
548 
549 
551 {
552  setView(inView);
553 }
554 
555 
556 oofGraph*
558 {
559  return new oofXYGraph(*this);
560 }
561 
562 
563 void
564 oofXYGraph::finishConstruction(dbView *theView, const char* theTitle, unsigned long yAxisHeight)
565 {
566  mType = "XY";
567 
568  oofGraphData Data(theView);
569  const unsigned short YtickLabelLen = settings()->maxYTickLabelLen();
570 
571  // Iterate over the data
572  for (theView->source()->start(); theView->source()->more();theView->source()->next()) {
573  // Get the data out of the View
575  mSeriesSet.findSeriesByName(*(dbChar*)Data.FirstField(), true /* symbol */)));
576  }
578  // add the X axis
579  long theAxisHeight=Data.scaleDataValue((long)mPlotBits.getIdealRect().right);
580  oofScaleSizer ScaleSizer(theAxisHeight);
581  theAxisHeight=Data.unScaleDataValue(theAxisHeight);
582  mPlotBits.append(new oofGeoXAxis(Data.unScaleDataValue(ScaleSizer.Max()),
583  Data.unScaleDataValue(ScaleSizer.Div()),ScaleSizer.NumMinorTicks()));
584  // add the X axis labels
585  { // extra scope as MSVC4 doesn't do ANSI for declaration rules
586  for(unsigned p=0;p<ScaleSizer.NumDivs();p++){
587  char labelStr[255];
588  Data.setScaleString(Data.unScaleDataValue(ScaleSizer.Div())*(p+1), labelStr, settings());
589  short round=(int)Data.unScaleDataValue(ScaleSizer.Div())%2;
591  ((int)(Data.unScaleDataValue(ScaleSizer.Div())*(p+1)-Data.unScaleDataValue(ScaleSizer.Div())/2),
592  Data.unScaleDataValue(ScaleSizer.Div())+round, labelStr));
593  }
594  }
595  // add the Y axis
596  long theYAxisHeight;
597  if(yAxisHeight){ // Quick hack for Andy
598  theYAxisHeight=yAxisHeight;
599  } else
600  theYAxisHeight=Data.scaleDataValue((long)mPlotBits.getIdealRect().top);
601  oofScaleSizer YScaleSizer(theYAxisHeight);
602  theAxisHeight=Data.unScaleDataValue(theYAxisHeight);
603  mPlotBits.append(new oofGeoYAxis(Data.unScaleDataValue(YScaleSizer.Max()),
604  Data.unScaleDataValue(YScaleSizer.Div()),YScaleSizer.NumMinorTicks()));
605  // add the Y axis labels
606  for(unsigned p=0;p<YScaleSizer.NumDivs();p++){
607  char labelStr[255];
608  Data.setScaleString(Data.unScaleDataValue(YScaleSizer.Div())*(p+1), labelStr, settings());
610  ((int)Data.unScaleDataValue(YScaleSizer.Div())*(p+1), YtickLabelLen, labelStr));
611  }
612  // add the title
613  mPlotBits.append(new oofGeoTitle(I.right-I.left,theTitle));
614  // add X label
615  mPlotBits.append(new oofGeoXLabel(I.right-I.left,Data.XField()->fieldName()));
616  // add Y label
617  mPlotBits.append(new oofGeoYLabel(Data.YField()->fieldName()));
618  // add a legend
619  mPlotBits.append(new oofGeoLegend(&mSeriesSet,true /* Use Symbols */));
620 }
621 
622 
623 // ---------------------------------------------------------------------------------
624 // oofBarGraph
625 // ---------------------------------------------------------------------------------
626 
627 
629 {
630  setView(inView);
631 }
632 
633 
634 oofGraph*
636 {
637  return new oofBarGraph(*this);
638 }
639 
640 
641 void
642 oofBarGraph::finishConstruction(dbView *theView, const char* theTitle, unsigned long xAxisHeight)
643 {
644  // david debug 990908
645  //#ifdef _Macintosh
646  // short *theSize = &(qd.thePort->txSize);
647  //#endif
648 
649  long CurTop=0;
650  unsigned long SeriesHeight=0;
651  const unsigned short YtickLabelLen = settings()->maxYTickLabelLen();
652  mType = "bar";
653 
654  OOF_String theFirstFieldStr;
655  OOF_String thePrevStr;
656 
657  oofGraphData Data(theView);
658 
659  for (theView->source()->start(); theView->source()->more();theView->source()->next()) {
660  theFirstFieldStr = Data.FirstField()->copyString();
661  if (theFirstFieldStr != thePrevStr) {
662  if(CurTop) {
663  if(!SeriesHeight)
664  SeriesHeight=CurTop;
665  mPlotBits.append(new oofGeoYTickLabel(CurTop-SeriesHeight/2,YtickLabelLen,thePrevStr));
666  CurTop+=SeriesSpacing;
667  }
668  }
669  mPlotBits.append(new oofGeoBar(CurTop,BarWidth,Data.dataValue(),
671  thePrevStr.adopt(theFirstFieldStr);
672  CurTop+=(BarWidth+Spacing);
673  }
674  CurTop-=Spacing;
675  mPlotBits.append(new oofGeoYTickLabel(CurTop-SeriesHeight/2,YtickLabelLen,thePrevStr));
676  // add the X axis
677  long theAxisHeight;
678  if(xAxisHeight)
679  theAxisHeight=xAxisHeight;
680  else
681  theAxisHeight=Data.scaleDataValue((long)mPlotBits.getIdealRect().right);
682  oofScaleSizer ScaleSizer(theAxisHeight);
683  theAxisHeight=Data.unScaleDataValue(theAxisHeight);
684  mPlotBits.append(new oofGeoXAxis(Data.unScaleDataValue(ScaleSizer.Max()),
685  Data.unScaleDataValue(ScaleSizer.Div()),ScaleSizer.NumMinorTicks()));
686  // add the X axis labels
687  for(unsigned p=0;p<ScaleSizer.NumDivs();p++){
688  char labelStr[255];
689  Data.setScaleString(Data.unScaleDataValue(ScaleSizer.Div())*(p+1), labelStr, settings());
690  short round=(int)Data.unScaleDataValue(ScaleSizer.Div())%2;
692  ((int)(Data.unScaleDataValue(ScaleSizer.Div())*(p+1)-Data.unScaleDataValue(ScaleSizer.Div())/2),
693  Data.unScaleDataValue(ScaleSizer.Div())+round, labelStr));
694  }
695 
696  // add the Y axis
697  mPlotBits.append(new oofGeoYAxis(CurTop,SeriesHeight+SeriesSpacing,0));
698  // add the title
699  // add the title
700  mPlotBits.append(new oofGeoTitle(theAxisHeight,theTitle));
701  // add X label
702  mPlotBits.append(new oofGeoXLabel(theAxisHeight,Data.DataField()->fieldName()));
703  // add Y label
705  // add a legend
706  mPlotBits.append(new oofGeoLegend(&mSeriesSet,false /* Use Symbols */));
707 
708  //FinishConstruction();
709 }
710 
711 
712 // ---------------------------------------------------------------------------------
713 // oofStackedBarGraph
714 // ---------------------------------------------------------------------------------
715 
716 
717 oofStackedBarGraph::oofStackedBarGraph(dbView* inView, unsigned long numOverlaid) :
718  OOF_mixOverlayableGraph(numOverlaid)
719 {
720  setView(inView);
721 }
722 
723 
724 oofGraph*
726 {
727  return new oofStackedBarGraph(*this);
728 }
729 
730 void
731 oofStackedBarGraph::finishConstruction(dbView *theView, const char* theTitle, unsigned long xAxisHeight)
732 {
733  // david debug 990906
734  //#ifdef _Macintosh
735  // short *theFont = &(qd.thePort->txFont);
736  // #endif
737  // end david debug
738  long CurTop=-1;
739  long StackPos=0;
740  const unsigned short YtickLabelLen = settings()->maxYTickLabelLen();
741 
742  unsigned long numSeries=0;
743  unsigned long seriesNum;
744  mType = "stacked bar";
745 
746  oofGraphData Data(theView,mOverlayView);
747 
748  // Prescan to see how many series there are and set up the oofSeriesSet according to
749  // how many are overlaid !
750  //
751  // NOTE: We boldly assume that all items have the same number of series
752  // Perhaps oofSeriesSet.findSeriesByName() should have a "non-creative"
753  // version !?
754  theView->source()->start();
755  OOF_String theFirstFieldStr;
756  OOF_String thePrevStr = Data.FirstField()->copyString();
757  for (; theView->source()->more();theView->source()->next()) {
758  theFirstFieldStr = Data.FirstField()->copyString();
759  if (theFirstFieldStr != thePrevStr) {
760  break;
761  }
762  oofSeries *newSeries=new oofSeries(*(dbChar*)Data.SeriesField());
763  mSeriesSet.append(newSeries);
764  thePrevStr.adopt(theFirstFieldStr);
765  numSeries++;
766  }
767 
768  // adjust user specifications against actual data
769  // was previously an assert which caused annoying crashes!
770  if (mNumOverlaid>=numSeries) {
771  if (numSeries>0)
772  mNumOverlaid = numSeries-1;
773  else
774  mNumOverlaid = 0;
775  }
776 
777  for(seriesNum=numSeries-1;seriesNum>(numSeries-mNumOverlaid-1);seriesNum--)
778  mSeriesSet[seriesNum]->makeSymbol();
779 
780  seriesNum=numSeries;
781  for (theView->source()->start(); theView->source()->more();theView->source()->next()) {
782  // Get the data out of the View
783  if (seriesNum==numSeries) {
784  seriesNum=0;
785  if(CurTop==-1)
786  CurTop=0;
787  else
788  CurTop+=(BarWidth+Spacing);
789  mPlotBits.append(new oofGeoYTickLabel(CurTop+BarWidth/2, YtickLabelLen,*(dbChar*)Data.FirstField()));
790  mPlotBits.append(new oofGeoBar(CurTop,BarWidth,Data.dataValue(),
792  StackPos=Data.dataValue();
793  } else {
794  if(seriesNum>=(numSeries-mNumOverlaid)){
795  // Overlaid Plot items !
796  mPlotBits.append(new oofGeoPoint(Data.dataValue(),CurTop+(BarWidth/2),
798  } else {
799  mPlotBits.append(new oofGeoBar(StackPos,CurTop,BarWidth,Data.dataValue(),
801  StackPos+=Data.dataValue();
802  }
803  }
804  seriesNum++;
805  }
806  if(mOverlayView){
807  unsigned long CurOverlayTop=0;
808  oofSeries *newSeries=new oofSeries(Data.OverlayField()->fieldName(), true /* Symbol */);
809  mSeriesSet.append(newSeries);
810  for (mOverlayView->source()->start(); mOverlayView->source()->more();
811  mOverlayView->source()->next()) {
812  mPlotBits.append(new oofGeoPoint(Data.overlayValue(),CurOverlayTop+(BarWidth/2),newSeries));
813  CurOverlayTop+=(BarWidth+Spacing);
814  }
815  }
816  // add the X axis
817  long theAxisHeight;
818  if(xAxisHeight)
819  theAxisHeight=xAxisHeight;
820  else
821  theAxisHeight=Data.scaleDataValue((long)mPlotBits.getIdealRect().right);
822  oofScaleSizer ScaleSizer(theAxisHeight);
823  theAxisHeight=Data.unScaleDataValue(theAxisHeight);
824  mPlotBits.append(new oofGeoXAxis(Data.unScaleDataValue(ScaleSizer.Max()),
825  Data.unScaleDataValue(ScaleSizer.Div()),ScaleSizer.NumMinorTicks()));
826  // add the X axis labels
827  for(unsigned p=0;p<ScaleSizer.NumDivs();p++){
828  char labelStr[255];
829  Data.setScaleString(Data.unScaleDataValue(ScaleSizer.Div())*(p+1), labelStr, settings());
830  short round=(int)Data.unScaleDataValue(ScaleSizer.Div())%2;
832  ((int)(Data.unScaleDataValue(ScaleSizer.Div())*(p+1)-Data.unScaleDataValue(ScaleSizer.Div())/2),
833  Data.unScaleDataValue(ScaleSizer.Div())+round, labelStr));
834  }
835  // add the Y axis
837  // add the title
838  mPlotBits.append(new oofGeoTitle(theAxisHeight,theTitle));
839 
840 // on BRAD's source
841 // mPlotBits.append(new oofGeoTitle(mPlotBits.getIdealRect().width(),theTitle));
842 
843 // add X label
844  mPlotBits.append(new oofGeoXLabel(theAxisHeight,Data.DataField()->fieldName()));
845  // add Y label
847  // add a legend
848  mPlotBits.append(new oofGeoLegend(&mSeriesSet,false /* Use Symbols */));
849 
850  //FinishConstruction();
851 }
852 
853 
854 // ---------------------------------------------------------------------------------
855 // oofOrdinalStackedBarGraph
856 // ---------------------------------------------------------------------------------
858 {
859  setView(inView);
860 }
861 
862 
863 oofGraph*
865 {
866  return new oofOrdinalStackedBarGraph(*this);
867 }
868 
869 
870 
871 void
872 oofOrdinalStackedBarGraph::finishConstruction(dbView *theView, const char* theTitle, unsigned long xAxisHeight)
873 {
874  long CurTop=-1;
875  long StackPos=0;
876  const unsigned short YtickLabelLen = settings()->maxYTickLabelLen();
877 
878  unsigned long numSeries=0;
879  unsigned long seriesNum;
880  OOF_String theFirstFieldStr;
881  OOF_String thePrevStr;
882  OOF_String xLabel;
883  bool doneXLabel=false;
884  mType = "ordinal stacked bar";
885 
886  oofGraphData Data(theView,mOverlayView);
887 
888  dbField *theSeriesField = (dbField *) (*theView)[3]; // Hideously unsafe downcast below..
889  // Make sure the View is the one we expect !
890  assert(theSeriesField->fieldType()==charField);
891 
892  xLabel = Data.DataField()->fieldName();
893 
894  // camerons hack -- get rid of x label cuffoonie
895 
896 
897 // xLabel += "\n";
898 
899  for (theView->source()->start(); theView->source()->more();theView->source()->next()) {
900  // Get the data out of the View
901  theFirstFieldStr = Data.FirstField()->copyString();
902  if (theFirstFieldStr != thePrevStr) {
903  seriesNum=0;
904  if(CurTop==-1) {
905  // xLabel += Data.SeriesField()->copyString();
906  CurTop=0;
907  } else {
908  CurTop+=(BarWidth+Spacing);
909  doneXLabel=true;
910  }
911  mPlotBits.append(new oofGeoYTickLabel(CurTop+BarWidth/2, YtickLabelLen,*(dbChar*)Data.FirstField()));
912  mPlotBits.append(new oofGeoBar(CurTop,BarWidth,Data.dataValue(),
913  mSeriesSet.findSeriesByName(*(dbChar*)theSeriesField)));
914  StackPos=Data.dataValue();
915  } else {
916  mPlotBits.append(new oofGeoBar(StackPos,CurTop,BarWidth,Data.dataValue(),
917  mSeriesSet.findSeriesByName(*(dbChar*)theSeriesField),oofGeo::posNone));
918  StackPos+=Data.dataValue();
919 // if(!doneXLabel){
920 // xLabel += " - ";
921 // xLabel += Data.SeriesField()->copyString();
922 // }
923  }
924  thePrevStr.adopt(theFirstFieldStr);
925  }
926 
927  if(mOverlayView){
928  unsigned long CurOverlayTop=0;
929  oofSeries *newSeries=new oofSeries(Data.OverlayField()->fieldName(), true /* Symbol */);
930  mSeriesSet.append(newSeries);
931  for (mOverlayView->source()->start(); mOverlayView->source()->more();
932  mOverlayView->source()->next()) {
933  mPlotBits.append(new oofGeoPoint(Data.overlayValue(),CurOverlayTop+(BarWidth/2),newSeries));
934  CurOverlayTop+=(BarWidth+Spacing);
935  }
936  }
937  // add the X axis
938  long theAxisHeight;
939  if(xAxisHeight)
940  theAxisHeight=xAxisHeight;
941  else
942  theAxisHeight=Data.scaleDataValue((long)mPlotBits.getIdealRect().right);
943  oofScaleSizer ScaleSizer(theAxisHeight);
944  theAxisHeight=Data.unScaleDataValue(theAxisHeight);
945  mPlotBits.append(new oofGeoXAxis(Data.unScaleDataValue(ScaleSizer.Max()),
946  Data.unScaleDataValue(ScaleSizer.Div()),ScaleSizer.NumMinorTicks()));
947  // add the X axis labels
948  for(unsigned p=0;p<ScaleSizer.NumDivs();p++){
949  char labelStr[255];
950  Data.setScaleString(Data.unScaleDataValue(ScaleSizer.Div())*(p+1), labelStr, settings());
951  short round=(int)Data.unScaleDataValue(ScaleSizer.Div())%2;
953  ((int)(Data.unScaleDataValue(ScaleSizer.Div())*(p+1)-Data.unScaleDataValue(ScaleSizer.Div())/2),
954  Data.unScaleDataValue(ScaleSizer.Div())+round, labelStr));
955  }
956  // add the Y axis
958  // add the title
959  mPlotBits.append(new oofGeoTitle(theAxisHeight,theTitle));
960  // add X label
961  mPlotBits.append(new oofGeoXLabel(theAxisHeight,xLabel));
962  // add Y label
964  // add a legend
965  mPlotBits.append(new oofGeoLegend(&mSeriesSet,false /* Use Symbols */));
966 
967  //FinishConstruction();
968 }
969 
970 
971 // oofScaleSizer
972 
974 {
975  const short kDivs[5]={0,1,2,5,10}; // Must be an order 10 repeating set !
976  // This is used for base ascending values
977 
978  short order=log10(ymax);
979 
980  short mult=ymax/pow(10.0,order);
981 
982  double sub=ymax-mult*pow(10.0,order);
983  short submult=sub/pow(10.0,order-1);
984  double product=(double)submult*pow(10.0,order-1);
985  if(sub!=product)
986  submult++; // Make sure we at least encapsulate the maximum value
987 
988  mMax=mult*pow(10.0,order);
989  unsigned i=0;
990  if((submult<=mult)&&(submult!=0))
991  submult=mult+1;
992  while(submult>kDivs[i])
993  i++;
994  mMax+=kDivs[i]*pow(10.0,order-1);
995 
996  if(kDivs[i]) {
997  mDiv=kDivs[i]*pow(10.0,order-1);
998  mNumMinorTicks=kDivs[i];
999  } else {
1000  if(order==log10(ymax)) // We have an actual factor of ten !
1001  mDiv=pow(10.0,order-1);
1002  else
1003  mDiv=pow(10.0,order);
1004  mNumMinorTicks=2;
1005  }
1006 
1007  while((mMax/mDiv)<kMinDivs)
1008  mDiv=mDiv/2;
1009  while((mMax/mDiv)>kMaxDivs) {
1010  mDiv=mDiv*2;
1011  if((mMax/mDiv)!=(double)(long)(mMax/mDiv)) {
1012  mMax+=mDiv/2;
1013  }
1014  }
1015 
1016  mNumDivs=mMax/mDiv;
1017 }
1018 
1019 // ---------------------------------------------------------------------------------
1020 // oofPieGraph
1021 // ---------------------------------------------------------------------------------
1022 
1023 
1025 {
1026  setView(inView);
1027 }
1028 
1029 
1030 oofGraph*
1032 {
1033  return new oofPieGraph(*this);
1034 }
1035 
1036 
1037 void
1038 oofPieGraph::finishConstruction(dbView *theView, const char* theTitle, unsigned long /* meaningless*/)
1039 {
1040  int WhichSeries=0; // Placeholder for a future setting to allow for choosing which series
1041  // We may also want to offer the ability to choose the series by name.
1042  //
1043  // NOTE: The series number is zero based !
1044 
1045  mType = "pie";
1046 
1047  oofGraphData Data(theView);
1048 
1049  // Scan for the n'th series and find out the cumulative total of its values
1050  //
1051  // NOTE: If the series number specified is larger than the number of actual series
1052  // then we will just get the last series.
1053  theView->source()->start();
1054  OOF_String theFirstFieldStr;
1055  unsigned seriesNum=0;
1056  unsigned long Seriestotal=0;
1057  OOF_String thePrevStr = Data.FirstField()->copyString();
1058  for (; theView->source()->more();theView->source()->next()) {
1059  theFirstFieldStr = Data.FirstField()->copyString();
1060  if (theFirstFieldStr != thePrevStr) {
1061  if(seriesNum==WhichSeries) // Have we processed the series we want ?
1062  break;
1063  Seriestotal=0;
1064  seriesNum++;
1065  thePrevStr = Data.FirstField()->copyString();
1066  }
1067  Seriestotal+=Data.dataValue();
1068  }
1069 
1070  // OK - now we scan forward for the first item to chart, and actually add the items
1071  // thePrevStr still holds the name of the series we want.
1072  //
1073  bool done=false;
1074  double start=0;
1075  long roundedstart=0;
1076  for (theView->source()->start(); theView->source()->more();theView->source()->next()) {
1077  theFirstFieldStr = Data.FirstField()->copyString();
1078  if (theFirstFieldStr != thePrevStr)
1079  if (done)
1080  break;
1081  else
1082  continue;
1083  // We've got to the data - add the sectors
1084  double arc=((double)Data.dataValue()/(double)Seriestotal)*360.0;
1085  mPlotBits.append(new oofGeoSector(0, 0, ChartDiameter, roundedstart, arc+0.5, mSeriesSet.findSeriesByName(*(dbChar*)Data.SeriesField()) , oofGeo::posNone));
1086  start+=arc;
1087  roundedstart=start+0.5;
1088  }
1089 
1090  // add the title - with the series title as well - perhaps this should be a setting.
1091  OOF_String TitleStr(theTitle);
1092  TitleStr+="\n";
1093  TitleStr+=thePrevStr;
1094  mPlotBits.append(new oofGeoTitle(ChartDiameter,TitleStr));
1095  // add a legend
1096  mPlotBits.append(new oofGeoLegend(&mSeriesSet,false /* Use Symbols */));
1097 }
long seriesValue()
Definition: oofGrDta.cpp:86
OOF_String mTitle
Definition: oofGrphs.h:125
long dataValue()
Definition: oofGrDta.cpp:104
dbField * OverlayField()
Definition: oofGrDta.h:50
Base for anything that can be drawn in color.
Definition: oofClrbl.h:15
void setView(dbView *)
Definition: oofGrphs.cpp:140
Cross-platform way to specify rectangle with Mac-style setter.
Definition: oofRect.h:39
oofDrawStyle * mDrawStyle
Definition: oofClrbl.h:30
oofSeries * findSeriesByName(const char *theSeries, const bool makeNewItemSymbol=false)
Definition: oofSrSet.cpp:186
virtual const oofString & fieldName() const
Definition: oof3.h:769
void setStyleToColor()
Definition: oofGrphs.cpp:183
double Div()
Definition: oofGrphs.h:356
oofScaleSizer(double Max)
Perform all calcs in ctor for easy subclassing.
Definition: oofGrphs.cpp:973
oofGraphSettings * mSettings
Definition: oofGrphs.h:122
virtual void DrawSelf()
Definition: oofGrphs.cpp:234
Drawing primitive for horizontal bars on graphs.
Definition: oofGeos.h:179
static oofGraph * sCurrentGraph
Definition: oofGrphs.h:121
Y axis, auto-sized from data series max value or constrained.
Definition: oofGeos.h:406
virtual oofGraph * clone() const
Definition: oofGrphs.cpp:635
dbField * SeriesField()
Definition: oofGrDta.h:48
void describe(std::ostream &os) const
Definition: oofGrphs.cpp:93
dbView * getView()
Definition: oofGrphs.cpp:150
void setPaneRect(Rect inRect)
Definition: oofGrphs.cpp:105
long NumMinorTicks()
Definition: oofGrphs.h:358
Temporarily used to calculate axis divisions based on length.
Definition: oofGrphs.h:347
Macintosh structure for a rectangle.
dbField * YField()
Definition: oofGrDta.h:54
oofGraph(oofGraphSettings *adoptedSettings=0)
Definition: oofGrphs.cpp:57
void start()
Definition: oof1.cpp:2057
Settings object for overriding behaviours of an instance of oofGraph.
Definition: oofSting.h:24
void setScaleString(long, char *, const oofGraphSettings *)
Definition: oofGrDta.cpp:200
virtual oofGraph * clone() const
Definition: oofGrphs.cpp:476
oofPointGraph(dbView *clonedView=0)
Definition: oofGrphs.cpp:388
oofOrdinalStackedBarGraph(dbView *clonedView=0)
Definition: oofGrphs.cpp:857
void append(oofSeries *inItem)
Definition: oofSrSet.cpp:119
virtual void finishConstruction(dbView *, const char *theTitle, unsigned long meaningless=0)
Definition: oofGrphs.cpp:1038
X axis, auto-sized from data series.
Definition: oofGeos.h:382
void describe(std::ostream &os) const
Definition: oofPlBit.cpp:213
void draw()
Definition: oofGrphs.cpp:81
void draw()
Definition: oofPlBit.cpp:205
virtual void finishConstruction(dbView *, const char *theTitle, unsigned long yAxisHeight)
Definition: oofGrphs.cpp:642
const char * getType()
Definition: oofGrphs.cpp:170
const char * getTitle()
Definition: oofGrphs.cpp:164
oofRect & getIdealRect()
Definition: oofPlBit.cpp:235
void setDrawStyles(oofDrawStyleSet &)
Definition: oofGrphs.cpp:120
virtual void finishConstruction(dbView *, const char *theTitle, unsigned long yAxisHeight)
Definition: oofGrphs.cpp:322
long scaleDataValue(long)
Definition: oofGrDta.cpp:144
virtual void finishConstruction(dbView *, const char *theTitle, unsigned long yAxisHeight)
Definition: oofGrphs.cpp:483
virtual void DescribeSelf(std::ostream &os) const
Definition: oofGrphs.cpp:248
double NumDivs()
Definition: oofGrphs.h:357
Graph class subclassed to draw different graph types.
Definition: oofGrphs.h:71
virtual oofGraph * clone() const
Definition: oofGrphs.cpp:395
void setTitle(const char *)
Definition: oofGrphs.cpp:157
bool more() const
When iterating a selection, are there any more records beyond current.
Definition: oof1.h:1896
static oofGraphSettings * defaultSettings()
Definition: oofGrphs.cpp:206
virtual void finishConstruction(dbView *, const char *theTitle, unsigned long yAxisHeight)
Definition: oofGrphs.cpp:872
oofSeriesSet mSeriesSet
Definition: oofGrphs.h:119
long overlayValue()
Definition: oofGrDta.cpp:120
Drawing primitive for data as series of points on graphs.
Definition: oofGeos.h:141
oofGraphSettings * getLocalSettings()
Definition: oofGrphs.cpp:225
Provide an iterable set of fields.
Definition: oofview.h:26
static void setStyleToMono()
Definition: oofDStyl.cpp:256
dbTable * source() const
Definition: oofview.h:123
oofPlotBits mPlotBits
Definition: oofGrphs.h:118
virtual void finishConstructionWithPresets()
Definition: oofGrphs.cpp:213
int isEmpty()
Definition: oofSrSet.cpp:166
double Max()
Definition: oofGrphs.h:355
long unScaleDataValue(long)
Definition: oofGrDta.cpp:168
static oofGraph * currentGraph()
Definition: oofGrphs.cpp:190
virtual ~OOF_mixOverlayableGraph()
Definition: oofGrphs.cpp:274
void setPaneRect(oofRect &inRect)
Definition: oofPlBit.cpp:228
virtual ~oofGraph()
Definition: oofGrphs.cpp:73
dbField * XField()
Definition: oofGrDta.h:53
virtual void finishConstruction(dbView *, const char *theTitle, unsigned long yAxisHeight)=0
virtual void finishConstruction(dbView *, const char *theTitle, unsigned long yAxisHeight)
Definition: oofGrphs.cpp:731
oofXYGraph(dbView *clonedView=0)
Definition: oofGrphs.cpp:550
void append(oofGeo *inItem)
Definition: oofPlBit.cpp:87
Label of tick marks graph X axis, generated from data series.
Definition: oofGeos.h:344
Persistent field used to store a fixed-length string.
Definition: oof3.h:255
dbField * FirstField()
Definition: oofGrDta.h:47
Label of graph X axis, generated from data series first item.
Definition: oofGeos.h:306
unsigned short maxYTickLabelLen() const
Definition: oofSting.cpp:494
oofLineGraph(dbView *clonedView=0)
Definition: oofGrphs.cpp:469
Drawing primitive for lines on line graphs.
Definition: oofGeos.h:161
OOF_String mType
Definition: oofGrphs.h:126
oofPieGraph(dbView *clonedView=0)
Definition: oofGrphs.cpp:1024
Virtual base for generator class returning sequence of oofDrawStyle.
Definition: oofDStyl.h:113
Mixin base for oofGraph's that draw lines as overlays on original bars.
Definition: oofGrphs.h:139
Label of graph Y axis, generated from data series first item.
Definition: oofGeos.h:325
void next()
Next record in the selection becomes current.
Definition: oof1.h:1970
Portable highly capable string class.
Definition: oofstr.h:101
Definition: oof3.h:26
void setDrawStyles(oofDrawStyleSet &)
Definition: oofSrSet.cpp:224
Specify drawing styles used in graphs.
Definition: oofDStyl.h:32
void setOverlayView(dbView *clonedView)
will become adoptedView in future
Definition: oofGrphs.cpp:288
Array of owned oofDrawStyle's adopting them for correct lifetime management.
Definition: oofDStyl.h:86
const oofGraphSettings * settings() const
Definition: oofGrphs.cpp:196
virtual void finishConstruction(dbView *, const char *theTitle, unsigned long yAxisHeight)
Definition: oofGrphs.cpp:402
void setStyleToMono()
Definition: oofGrphs.cpp:176
bool mIsMono
Definition: oofGrphs.h:120
virtual void finishConstruction(dbView *, const char *theTitle, unsigned long yAxisHeight)
Definition: oofGrphs.cpp:564
Label of tick marks graph Y axis, generated from data series.
Definition: oofGeos.h:363
static oofGraphSettings * settings()
Definition: oofSting.h:155
static void setStyleToColor()
Definition: oofDStyl.cpp:263
virtual oofGraph * clone() const
Definition: oofGrphs.cpp:725
oofBarGraph(dbView *clonedView=0)
Definition: oofGrphs.cpp:628
Drawing primitive for segments in pie graphs.
Definition: oofGeos.h:205
virtual oofString copyString() const
Definition: oof3.cpp:472
virtual oofGraph * clone() const
Definition: oofGrphs.cpp:557
virtual OOF_fieldTypes fieldType() const =0
oofColumnGraph(dbView *clonedView=0)
Definition: oofGrphs.cpp:308
void becomeCurrent()
Definition: oofGrphs.cpp:259
bool mDrawStylesWereSet
Definition: oofGrphs.h:123
oofStackedBarGraph(dbView *clonedView=0, unsigned long numOverlaid=0)
Definition: oofGrphs.cpp:717
virtual oofGraph * clone() const
Definition: oofGrphs.cpp:1031
void adopt(char *)
Take ownership of incoming buffer, replacing current contents.
Definition: oofstr.cpp:2299
Drawing primitive for vertical bars on graphs.
Definition: oofGeos.h:114
dbView * mOverlayView
OWNED Allow for adding another view (long) with an overlay in it.
Definition: oofGrphs.h:155
virtual oofGraph * clone() const
Definition: oofGrphs.cpp:864
Contains series of data in a graph, eg: a single line of a graph.
Definition: oofSrSet.h:19
OOF_mixOverlayableGraph(unsigned long numOverlaid=0)
Definition: oofGrphs.cpp:268
unsigned long mNumOverlaid
Allow for items in the main view to be overlaid.
Definition: oofGrphs.h:154
Graph legend generated from data series names.
Definition: oofGeos.h:430
Title at top of a graph.
Definition: oofGeos.h:286
Base class for persistent fields in dbTable's.
Definition: oof3.h:63
dbField * DataField()
Definition: oofGrDta.h:49
void setOverlaid(unsigned long numOverlaid)
Definition: oofGrphs.cpp:281
virtual oofGraph * clone() const
Definition: oofGrphs.cpp:315
Temporarily accumulate graph data to be able to scale based on range of all data. ...
Definition: oofGrDta.h:17
dbView * mView
Definition: oofGrphs.h:124