A class that allows configuration of a cartesian chart. More...
#include <ChartConfig.h>
Inherits Wt::WContainerWidget.
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::WCartesianChart * | chart_ |
Wt::Chart::FillRangeType | fill_ |
std::vector< SeriesControl > | seriesControls_ |
Controls for series. | |
std::vector< AxisControl > | axisControls_ |
Controls for axes. | |
Wt::WLineEdit * | titleEdit_ |
Wt::WLineEdit * | chartWidthEdit_ |
Wt::WLineEdit * | chartHeightEdit_ |
Wt::WComboBox * | chartOrientationEdit_ |
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.
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 }
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 }
std::vector<AxisControl> ChartConfig::axisControls_ [private] |
Controls for axes.
Definition at line 76 of file ChartConfig.h.
Wt::Chart::WCartesianChart* ChartConfig::chart_ [private] |
Definition at line 47 of file ChartConfig.h.
Wt::WLineEdit* ChartConfig::chartHeightEdit_ [private] |
Definition at line 80 of file ChartConfig.h.
Wt::WComboBox* ChartConfig::chartOrientationEdit_ [private] |
Definition at line 81 of file ChartConfig.h.
Wt::WLineEdit* ChartConfig::chartWidthEdit_ [private] |
Definition at line 79 of file ChartConfig.h.
Wt::Chart::FillRangeType ChartConfig::fill_ [private] |
Definition at line 48 of file ChartConfig.h.
std::vector<SeriesControl> ChartConfig::seriesControls_ [private] |
Controls for series.
Definition at line 62 of file ChartConfig.h.
Wt::WLineEdit* ChartConfig::titleEdit_ [private] |
Definition at line 78 of file ChartConfig.h.