ChartConfig Class Reference
[Charts example]

A class that allows configuration of a cartesian chart. More...

#include <ChartConfig.h>

Inherits Wt::WContainerWidget.

List of all members.

Classes

struct  AxisControl
 Struct that holds the controls for one axis. More...
struct  SeriesControl
 Struct that holds the controls for one series. More...

Public Member Functions

 ChartConfig (Wt::Chart::WCartesianChart *chart, Wt::WContainerWidget *parent)
 Constructor.
void setValueFill (Wt::Chart::FillRangeType fill)

Private Member Functions

void connectSignals (Wt::WFormWidget *w)
void update ()

Static Private Member Functions

static bool validate (Wt::WFormWidget *w)

Private Attributes

Wt::Chart::WCartesianChartchart_
Wt::Chart::FillRangeType fill_
std::vector< SeriesControlseriesControls_
 Controls for series.
std::vector< AxisControlaxisControls_
 Controls for axes.
Wt::WLineEdittitleEdit_
Wt::WLineEditchartWidthEdit_
Wt::WLineEditchartHeightEdit_
Wt::WComboBoxchartOrientationEdit_

Detailed Description

A class that allows configuration of a cartesian chart.

This widget provides forms for configuring chart, series, and axis properties and manipulates the chart according to user settings.

This widget is part of the Wt charts example.

Definition at line 37 of file ChartConfig.h.


Constructor & Destructor Documentation

ChartConfig::ChartConfig ( Wt::Chart::WCartesianChart chart,
Wt::WContainerWidget parent 
)

Constructor.

Definition at line 60 of file ChartConfig.C.

00061   : WContainerWidget(parent),
00062     chart_(chart),
00063     fill_(MinimumValueFill)
00064 {
00065   chart->initLayout();
00066 
00067   PanelList *list = new PanelList(this);
00068 
00069   WIntValidator *sizeValidator = new WIntValidator(200, 2000, this);
00070   sizeValidator->setMandatory(true);
00071 
00072   WDoubleValidator *anyNumberValidator = new WDoubleValidator(this);
00073   anyNumberValidator->setMandatory(true);
00074 
00075   WDoubleValidator *angleValidator = new WDoubleValidator(-90, 90, this);
00076   angleValidator->setMandatory(true);
00077 
00078   // ---- Chart properties ----
00079 
00080   WStandardItemModel *orientation = new WStandardItemModel(0, 1, this);
00081   addEntry(orientation, "Vertical");
00082   addEntry(orientation, "Horizontal");
00083 
00084   WTable *chartConfig = new WTable();
00085   chartConfig->setMargin(WLength::Auto, Left | Right);
00086 
00087   int row = 0;
00088   chartConfig->elementAt(row, 0)->addWidget(new WText("Title:"));
00089   titleEdit_ = new WLineEdit(chartConfig->elementAt(row, 1));
00090   connectSignals(titleEdit_);
00091   ++row;
00092 
00093   chartConfig->elementAt(row, 0)->addWidget(new WText("Width:"));
00094   chartWidthEdit_ = new WLineEdit(chartConfig->elementAt(row, 1));
00095   chartWidthEdit_
00096     ->setText(boost::lexical_cast<std::string>(chart_->width().value()));
00097   chartWidthEdit_->setValidator(sizeValidator);
00098   chartWidthEdit_->setMaxLength(4);
00099   connectSignals(chartWidthEdit_);
00100   ++row;
00101 
00102   chartConfig->elementAt(row, 0)->addWidget(new WText("Height:"));
00103   chartHeightEdit_ = new WLineEdit(chartConfig->elementAt(row, 1));
00104   chartHeightEdit_
00105     ->setText(boost::lexical_cast<std::string>(chart_->height().value()));
00106   chartHeightEdit_->setValidator(sizeValidator);
00107   chartHeightEdit_->setMaxLength(4);
00108   connectSignals(chartHeightEdit_);
00109   ++row;
00110 
00111   chartConfig->elementAt(row, 0)->addWidget(new WText("Orientation:"));
00112   chartOrientationEdit_ = new WComboBox(chartConfig->elementAt(row, 1));
00113   chartOrientationEdit_->setModel(orientation);
00114   connectSignals(chartOrientationEdit_);
00115   ++row;
00116 
00117   for (int i = 0; i < chartConfig->rowCount(); ++i) {
00118     chartConfig->elementAt(i, 0)->setStyleClass("tdhead");
00119     chartConfig->elementAt(i, 1)->setStyleClass("tddata");
00120   }
00121 
00122   WPanel *p = list->addWidget("Chart properties", chartConfig);
00123   p->setMargin(WLength::Auto, Left | Right);
00124   p->resize(750, WLength::Auto);
00125   p->setMargin(20, Top | Bottom);
00126 
00127   if (chart_->isLegendEnabled())
00128     chart_->setPlotAreaPadding(200, Right);
00129 
00130   // ---- Series properties ----
00131 
00132   WStandardItemModel *types = new WStandardItemModel(0, 1, this);
00133   addEntry(types, "Points");
00134   addEntry(types, "Line");
00135   addEntry(types, "Curve");
00136   addEntry(types, "Bar");
00137   addEntry(types, "Line Area");
00138   addEntry(types, "Curve Area");
00139   addEntry(types, "Stacked Bar");
00140   addEntry(types, "Stacked Line Area");
00141   addEntry(types, "Stacked Curve Area");
00142 
00143   WStandardItemModel *markers = new WStandardItemModel(0, 1, this);
00144   addEntry(markers, "None");
00145   addEntry(markers, "Square");
00146   addEntry(markers, "Circle");
00147   addEntry(markers, "Cross");
00148   addEntry(markers, "X cross");
00149   addEntry(markers, "Triangle");
00150 
00151   WStandardItemModel *axes = new WStandardItemModel(0, 1, this);
00152   addEntry(axes, "1st Y axis");
00153   addEntry(axes, "2nd Y axis");
00154 
00155   WStandardItemModel *labels = new WStandardItemModel(0, 1, this);
00156   addEntry(labels, "None");
00157   addEntry(labels, "X");
00158   addEntry(labels, "Y");
00159   addEntry(labels, "X: Y");
00160 
00161   WTable *seriesConfig = new WTable();
00162   seriesConfig->setMargin(WLength::Auto, Left | Right);
00163 
00164   ::addHeader(seriesConfig, "Name");
00165   ::addHeader(seriesConfig, "Enabled");
00166   ::addHeader(seriesConfig, "Type");
00167   ::addHeader(seriesConfig, "Marker");
00168   ::addHeader(seriesConfig, "Y axis");
00169   ::addHeader(seriesConfig, "Legend");
00170   ::addHeader(seriesConfig, "Shadow");
00171   ::addHeader(seriesConfig, "Value labels");
00172 
00173   seriesConfig->rowAt(0)->setStyleClass("trhead");
00174 
00175   for (int j = 1; j < chart->model()->columnCount(); ++j) {
00176     SeriesControl sc;
00177 
00178     new WText(asString(chart->model()->headerData(j)),
00179               seriesConfig->elementAt(j, 0));
00180 
00181     sc.enabledEdit = new WCheckBox(seriesConfig->elementAt(j, 1));
00182     connectSignals(sc.enabledEdit);
00183 
00184     sc.typeEdit = new WComboBox(seriesConfig->elementAt(j, 2));
00185     sc.typeEdit->setModel(types);
00186     connectSignals(sc.typeEdit);
00187 
00188     sc.markerEdit = new WComboBox(seriesConfig->elementAt(j, 3));
00189     sc.markerEdit->setModel(markers);
00190     connectSignals(sc.markerEdit);
00191 
00192     sc.axisEdit = new WComboBox(seriesConfig->elementAt(j, 4));
00193     sc.axisEdit->setModel(axes);
00194     connectSignals(sc.axisEdit);
00195 
00196     sc.legendEdit = new WCheckBox(seriesConfig->elementAt(j, 5));
00197     connectSignals(sc.legendEdit);
00198 
00199     sc.shadowEdit = new WCheckBox(seriesConfig->elementAt(j, 6));
00200     connectSignals(sc.shadowEdit);
00201 
00202     sc.labelsEdit = new WComboBox(seriesConfig->elementAt(j, 7));
00203     sc.labelsEdit->setModel(labels);
00204     connectSignals(sc.labelsEdit);
00205 
00206     int si = seriesIndexOf(chart, j);
00207 
00208     if (si != -1) {
00209       sc.enabledEdit->setChecked();
00210       const WDataSeries& s = chart_->series(j);
00211       switch (s.type()) {
00212       case PointSeries:
00213         sc.typeEdit->setCurrentIndex(0); break;
00214       case LineSeries:
00215         sc.typeEdit->setCurrentIndex(s.fillRange() != NoFill ?
00216                                      (s.isStacked() ? 7 : 4) : 1); break;
00217       case CurveSeries:
00218         sc.typeEdit->setCurrentIndex(s.fillRange() != NoFill ?
00219                                      (s.isStacked() ? 8 : 5) : 2); break;
00220       case BarSeries:
00221         sc.typeEdit->setCurrentIndex(s.isStacked() ? 6 : 3);
00222       }
00223 
00224       sc.markerEdit->setCurrentIndex((int)s.marker());
00225       sc.legendEdit->setChecked(s.isLegendEnabled());
00226       sc.shadowEdit->setChecked(s.shadow() != WShadow());
00227     }
00228 
00229     seriesControls_.push_back(sc);
00230 
00231     seriesConfig->rowAt(j)->setStyleClass("trdata");
00232   }
00233 
00234   p = list->addWidget("Series properties", seriesConfig);
00235   p->expand();
00236   p->setMargin(WLength::Auto, Left | Right);
00237   p->resize(750, WLength::Auto);
00238   p->setMargin(20, Top | Bottom);
00239 
00240   // ---- Axis properties ----
00241 
00242   WStandardItemModel *yScales = new WStandardItemModel(0, 1, this);
00243   addEntry(yScales, "Linear scale");
00244   addEntry(yScales, "Log scale");
00245 
00246   WStandardItemModel *xScales = new WStandardItemModel(0, 1, this);
00247   addEntry(xScales, "Categories");
00248   addEntry(xScales, "Linear scale");
00249   addEntry(xScales, "Log scale");
00250   addEntry(xScales, "Date scale");
00251 
00252   WTable *axisConfig = new WTable();
00253   axisConfig->setMargin(WLength::Auto, Left | Right);
00254 
00255   ::addHeader(axisConfig, "Axis");
00256   ::addHeader(axisConfig, "Visible");
00257   ::addHeader(axisConfig, "Scale");
00258   ::addHeader(axisConfig, "Automatic");
00259   ::addHeader(axisConfig, "Minimum");
00260   ::addHeader(axisConfig, "Maximum");
00261   ::addHeader(axisConfig, "Gridlines");
00262   ::addHeader(axisConfig, "Label angle");
00263 
00264   axisConfig->rowAt(0)->setStyleClass("trhead");
00265 
00266   for (int i = 0; i < 3; ++i) {
00267     const char *axisName[] = { "X axis", "1st Y axis", "2nd Y axis" };
00268     int j = i + 1;
00269 
00270     const WAxis& axis = chart_->axis(static_cast<Axis>(i));
00271     AxisControl sc;
00272 
00273     new WText(WString(axisName[i], UTF8), axisConfig->elementAt(j, 0));
00274 
00275     sc.visibleEdit = new WCheckBox(axisConfig->elementAt(j, 1));
00276     sc.visibleEdit->setChecked(axis.isVisible());
00277     connectSignals(sc.visibleEdit);
00278 
00279     sc.scaleEdit = new WComboBox(axisConfig->elementAt(j, 2));
00280     if (axis.scale() == CategoryScale)
00281       sc.scaleEdit->addItem("Category scale");
00282     else {
00283       if (axis.id() == XAxis) {
00284         sc.scaleEdit->setModel(xScales);
00285         sc.scaleEdit->setCurrentIndex(axis.scale());
00286       } else {
00287         sc.scaleEdit->setModel(yScales);
00288         sc.scaleEdit->setCurrentIndex(axis.scale() - 1);
00289       }
00290     }
00291     connectSignals(sc.scaleEdit);
00292 
00293     bool autoValues = axis.autoLimits() == (MinimumValue | MaximumValue);
00294 
00295     sc.minimumEdit = new WLineEdit(axisConfig->elementAt(j, 4));
00296     sc.minimumEdit->setText(boost::lexical_cast<std::string>(axis.minimum()));
00297     sc.minimumEdit->setValidator(anyNumberValidator);
00298     sc.minimumEdit->setEnabled(!autoValues);
00299     connectSignals(sc.minimumEdit);
00300 
00301     sc.maximumEdit = new WLineEdit(axisConfig->elementAt(j, 5));
00302     sc.maximumEdit->setText(boost::lexical_cast<std::string>(axis.maximum()));
00303     sc.maximumEdit->setValidator(anyNumberValidator);
00304     sc.maximumEdit->setEnabled(!autoValues);
00305     connectSignals(sc.maximumEdit);
00306 
00307     sc.autoEdit = new WCheckBox(axisConfig->elementAt(j, 3));
00308     sc.autoEdit->setChecked(autoValues);
00309     connectSignals(sc.autoEdit);
00310     sc.autoEdit->checked().connect(SLOT(sc.maximumEdit, WLineEdit::disable));
00311     sc.autoEdit->unChecked().connect(SLOT(sc.maximumEdit, WLineEdit::enable));
00312     sc.autoEdit->checked().connect(SLOT(sc.minimumEdit, WLineEdit::disable));
00313     sc.autoEdit->unChecked().connect(SLOT(sc.minimumEdit, WLineEdit::enable));
00314 
00315     sc.gridLinesEdit = new WCheckBox(axisConfig->elementAt(j, 6));
00316     connectSignals(sc.gridLinesEdit);
00317 
00318     sc.labelAngleEdit = new WLineEdit(axisConfig->elementAt(j, 7));
00319     sc.labelAngleEdit->setText("0");
00320     sc.labelAngleEdit->setValidator(angleValidator);
00321     connectSignals(sc.labelAngleEdit);
00322 
00323     axisConfig->rowAt(j)->setStyleClass("trdata");
00324 
00325     axisControls_.push_back(sc);
00326   }
00327 
00328   p = list->addWidget("Axis properties", axisConfig);
00329   p->setMargin(WLength::Auto, Left | Right);
00330   p->resize(750, WLength::Auto);
00331   p->setMargin(20, Top | Bottom);
00332 
00333   /*
00334    * If we do not have JavaScript, then add a button to reflect changes to
00335    * the chart.
00336    */
00337   if (!WApplication::instance()->environment().javaScript()) {
00338     WPushButton *b = new WPushButton(this);
00339     b->setText("Update chart");
00340     b->setInline(false); // so we can add margin to center horizontally
00341     b->setMargin(WLength::Auto, Left | Right);
00342     b->clicked().connect(SLOT(this, ChartConfig::update));
00343   }
00344 }


Member Function Documentation

void ChartConfig::connectSignals ( Wt::WFormWidget w  )  [private]

Definition at line 521 of file ChartConfig.C.

00522 {
00523   w->changed().connect(SLOT(this, ChartConfig::update));
00524   if (dynamic_cast<WLineEdit *>(w))
00525     w->enterPressed().connect(SLOT(this, ChartConfig::update));
00526 }

void ChartConfig::setValueFill ( Wt::Chart::FillRangeType  fill  ) 

Definition at line 346 of file ChartConfig.C.

00347 {
00348   fill_ = fill;
00349 }

void ChartConfig::update (  )  [private]

Definition at line 351 of file ChartConfig.C.

00352 {
00353   bool haveLegend = false;
00354   std::vector<WDataSeries> series;
00355 
00356   for (int i = 1; i < chart_->model()->columnCount(); ++i) {
00357     SeriesControl& sc = seriesControls_[i-1];
00358 
00359     if (sc.enabledEdit->isChecked()) {
00360       WDataSeries s(i);
00361 
00362       switch (sc.typeEdit->currentIndex()) {
00363       case 0:
00364         s.setType(PointSeries);
00365         if (sc.markerEdit->currentIndex() == 0)
00366           sc.markerEdit->setCurrentIndex(1);
00367         break;
00368       case 1:
00369         s.setType(LineSeries);
00370         break;
00371       case 2:
00372         s.setType(CurveSeries);
00373         break;
00374       case 3:
00375         s.setType(BarSeries);
00376         break;
00377       case 4:
00378         s.setType(LineSeries);
00379         s.setFillRange(fill_);
00380         break;
00381       case 5:
00382         s.setType(CurveSeries);
00383         s.setFillRange(fill_);
00384         break;
00385       case 6:
00386         s.setType(BarSeries);
00387         s.setStacked(true);
00388         break;
00389       case 7:
00390         s.setType(LineSeries);
00391         s.setFillRange(fill_);
00392         s.setStacked(true);
00393         break;
00394       case 8:
00395         s.setType(CurveSeries);
00396         s.setFillRange(fill_);
00397         s.setStacked(true);     
00398       }
00399 
00400       s.setMarker(static_cast<MarkerType>(sc.markerEdit->currentIndex()));
00401 
00402       if (sc.axisEdit->currentIndex() == 1) {
00403         s.bindToAxis(Y2Axis);
00404       }
00405 
00406       if (sc.legendEdit->isChecked()) {
00407         s.setLegendEnabled(true);
00408         haveLegend = true;
00409       } else
00410         s.setLegendEnabled(false);
00411 
00412       if (sc.shadowEdit->isChecked()) {
00413         s.setShadow(WShadow(3, 3, WColor(0, 0, 0, 127), 3));
00414       } else
00415         s.setShadow(WShadow());
00416 
00417       switch (sc.labelsEdit->currentIndex()) {
00418       case 1:
00419         s.setLabelsEnabled(XAxis);
00420         break;
00421       case 2:
00422         s.setLabelsEnabled(YAxis);
00423         break;
00424       case 3:
00425         s.setLabelsEnabled(XAxis);      
00426         s.setLabelsEnabled(YAxis);
00427         break;
00428       }
00429 
00430       series.push_back(s);
00431     }
00432   }
00433 
00434   chart_->setSeries(series);
00435 
00436   for (int i = 0; i < 3; ++i) {
00437     AxisControl& sc = axisControls_[i];
00438     WAxis& axis = chart_->axis(static_cast<Axis>(i));
00439 
00440     axis.setVisible(sc.visibleEdit->isChecked());
00441 
00442     if (sc.scaleEdit->count() != 1) {
00443       int k = sc.scaleEdit->currentIndex();
00444       if (axis.id() != XAxis)
00445         k += 1;
00446       else {
00447         if (k == 0)
00448           chart_->setType(CategoryChart);
00449         else
00450           chart_->setType(ScatterPlot);
00451       }
00452 
00453       switch (k) {
00454       case 1:
00455         axis.setScale(LinearScale); break;
00456       case 2:
00457         axis.setScale(LogScale); break;
00458       case 3:
00459         axis.setScale(DateScale); break;
00460       }
00461     }
00462 
00463     if (sc.autoEdit->isChecked())
00464       axis.setAutoLimits(MinimumValue | MaximumValue);
00465     else {
00466       if (validate(sc.minimumEdit) && validate(sc.maximumEdit)) {
00467         double min, max;
00468         getDouble(sc.minimumEdit, min);
00469         getDouble(sc.maximumEdit, max);
00470 
00471         if (axis.scale() == LogScale)
00472           if (min <= 0)
00473             min = 0.0001;
00474 
00475         axis.setRange(min, max);
00476       }
00477 
00478     }
00479 
00480     if (validate(sc.labelAngleEdit)) {
00481       double angle;
00482       getDouble(sc.labelAngleEdit, angle);
00483       axis.setLabelAngle(angle);
00484     }
00485 
00486     axis.setGridLinesEnabled(sc.gridLinesEdit->isChecked());
00487   }
00488 
00489   chart_->setTitle(titleEdit_->text());
00490 
00491   if (validate(chartWidthEdit_) && validate(chartHeightEdit_)) {
00492     double width, height;
00493     getDouble(chartWidthEdit_, width);
00494     getDouble(chartHeightEdit_, height);
00495     chart_->resize(width, height);
00496   }
00497 
00498   switch (chartOrientationEdit_->currentIndex()) {
00499   case 0:
00500     chart_->setOrientation(Vertical); break;
00501   case 1:
00502     chart_->setOrientation(Horizontal); break;
00503   }
00504 
00505   chart_->setLegendEnabled(haveLegend);
00506   chart_->setPlotAreaPadding(haveLegend ? 200 : 40, Right);
00507 }

bool ChartConfig::validate ( Wt::WFormWidget w  )  [static, private]

Definition at line 509 of file ChartConfig.C.

00510 {
00511   bool valid = w->validate() == WValidator::Valid;
00512 
00513   if (!WApplication::instance()->environment().javaScript()) {
00514     w->setStyleClass(valid ? "" : "Wt-invalid");
00515     w->setToolTip(valid ? "" : "Invalid value");
00516   }
00517 
00518   return valid;
00519 }


Member Data Documentation

std::vector<AxisControl> ChartConfig::axisControls_ [private]

Controls for axes.

Definition at line 76 of file ChartConfig.h.

Definition at line 47 of file ChartConfig.h.

Definition at line 80 of file ChartConfig.h.

Definition at line 81 of file ChartConfig.h.

Definition at line 79 of file ChartConfig.h.

Definition at line 48 of file ChartConfig.h.

Controls for series.

Definition at line 62 of file ChartConfig.h.

Definition at line 78 of file ChartConfig.h.


The documentation for this class was generated from the following files:

Generated on Thu May 13 05:16:01 2010 for Wt by doxygen 1.6.3