Wt examples  4.10.4
ChartConfig.C
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2008 Emweb bv, Herent, Belgium.
3  *
4  * See the LICENSE file for terms of use.
5  */
6 
7 #include "ChartConfig.h"
8 #include "PanelList.h"
9 
10 #include <iostream>
11 
12 #include <Wt/WAbstractItemModel.h>
13 #include <Wt/WApplication.h>
14 #include <Wt/WCheckBox.h>
15 #include <Wt/WComboBox.h>
16 #include <Wt/WDoubleValidator.h>
17 #include <Wt/WDate.h>
18 #include <Wt/WEnvironment.h>
19 #include <Wt/WIntValidator.h>
20 #include <Wt/WLineEdit.h>
21 #include <Wt/WLocale.h>
22 #include <Wt/WPanel.h>
23 #include <Wt/WPushButton.h>
24 #include <Wt/WStandardItemModel.h>
25 #include <Wt/WTable.h>
26 #include <Wt/WText.h>
27 #include <Wt/WPainterPath.h>
28 
29 #include <Wt/Chart/WCartesianChart.h>
30 
31 using namespace Wt;
32 using namespace Wt::Chart;
33 
34 namespace {
35  void addHeader(WTable *t, const char *value) {
36  t->elementAt(0, t->columnCount())->addWidget(std::make_unique<WText>(value));
37  }
38 
39  void addEntry(const std::shared_ptr<WAbstractItemModel>& model, const char *value) {
40  model->insertRows(model->rowCount(), 1);
41  model->setData(model->rowCount()-1, 0, cpp17::any(std::string(value)));
42  }
43 
44  void addEntry(const std::shared_ptr<WAbstractItemModel>& model, const WString &value) {
45  model->insertRows(model->rowCount(), 1);
46  model->setData(model->rowCount()-1, 0, cpp17::any(value));
47  }
48 
49  bool getDouble(WLineEdit *edit, double& value) {
50  try {
51  value = WLocale::currentLocale().toDouble(edit->text());
52  return true;
53  } catch (...) {
54  return false;
55  }
56  }
57 
58  int seriesIndexOf(WCartesianChart* chart, int modelColumn) {
59  for (unsigned i = 0; i < chart->series().size(); ++i)
60  if (chart->series()[i]->modelColumn() == modelColumn)
61  return i;
62 
63  return -1;
64  }
65 
66  WString axisName(Axis axis, int axisId)
67  {
68  if (axis == Axis::X) {
69  return Wt::utf8("X Axis {1}").arg(axisId + 1);
70  } else {
71  return Wt::utf8("Y axis {1}").arg(axisId + 1);
72  }
73  }
74 }
75 
77  : WContainerWidget(),
78  chart_(chart),
80 {
82  WBrush(WColor(0xFF, 0xFA, 0xE5)));
83 
84  PanelList *list = this->addWidget(std::make_unique<PanelList>());
85 
86  std::shared_ptr<WIntValidator> sizeValidator
87  = std::make_shared<WIntValidator>(200,2000);
88  sizeValidator->setMandatory(true);
89 
90  anyNumberValidator_ = std::make_shared<WDoubleValidator>();
91  anyNumberValidator_->setMandatory(true);
92 
93  angleValidator_ = std::make_shared<WDoubleValidator>(-90, 90);
94  angleValidator_->setMandatory(true);
95 
96  // ---- Chart properties ----
97 
98  std::shared_ptr<WStandardItemModel> orientation
99  = std::make_shared<WStandardItemModel>(0,1);
100  addEntry(orientation, "Vertical");
101  addEntry(orientation, "Horizontal");
102 
103  std::shared_ptr<WStandardItemModel> legendLocation
104  = std::make_shared<WStandardItemModel>(0,1);
105  addEntry(legendLocation, "Outside");
106  addEntry(legendLocation, "Inside");
107 
108  std::shared_ptr<WStandardItemModel> legendSide
109  = std::make_shared<WStandardItemModel>(0,1);
110  addEntry(legendSide, "Top");
111  addEntry(legendSide, "Right");
112  addEntry(legendSide, "Bottom");
113  addEntry(legendSide, "Left");
114 
115  std::shared_ptr<WStandardItemModel> legendAlignment
116  = std::make_shared<WStandardItemModel>(0,1);
117  addEntry(legendAlignment, "AlignLeft");
118  addEntry(legendAlignment, "AlignCenter");
119  addEntry(legendAlignment, "AlignRight");
120  addEntry(legendAlignment, "AlignTop");
121  addEntry(legendAlignment, "AlignMiddle");
122  addEntry(legendAlignment, "AlignBottom");
123 
124  std::unique_ptr<WTable> chartConfig
125  = std::make_unique<WTable>();
126  chartConfig->setMargin(WLength::Auto, Side::Left | Side::Right);
127 
128  int row = 0;
129  chartConfig->elementAt(row, 0)->addWidget(std::make_unique<WText>("Title:"));
130  titleEdit_ = chartConfig->elementAt(row,1)->addWidget(std::make_unique<WLineEdit>());
132  ++row;
133 
134  chartConfig->elementAt(row, 0)->addWidget(std::make_unique<WText>("Width:"));
135  chartWidthEdit_ = chartConfig->elementAt(row,1)->addWidget(std::make_unique<WLineEdit>());
137  ->setText(WLocale::currentLocale().toString(chart_->width().value()));
138  chartWidthEdit_->setValidator(sizeValidator);
141  ++row;
142 
143  chartConfig->elementAt(row, 0)->addWidget(std::make_unique<WText>("Height:"));
144  chartHeightEdit_ = chartConfig->elementAt(row,1)->addWidget(std::make_unique<WLineEdit>());
146  ->setText(WLocale::currentLocale().toString(chart_->height().value()));
147  chartHeightEdit_->setValidator(sizeValidator);
150  ++row;
151 
152  chartConfig->elementAt(row, 0)->addWidget(std::make_unique<WText>("Orientation:"));
153  chartOrientationEdit_ = chartConfig->elementAt(row,1)->addWidget(std::make_unique<WComboBox>());
154  chartOrientationEdit_->setModel(orientation);
157  ++row;
158 
159  chartConfig->elementAt(row, 0)->addWidget(std::make_unique<WText>("Legend location:"));
160  legendLocationEdit_ = chartConfig->elementAt(row,1)->addWidget(std::make_unique<WComboBox>());
161  legendLocationEdit_->setModel(legendLocation);
164  ++row;
165 
166  chartConfig->elementAt(row, 0)->addWidget(std::make_unique<WText>("Legend side:"));
167  legendSideEdit_ = chartConfig->elementAt(row,1)->addWidget(std::make_unique<WComboBox>());
168  legendSideEdit_->setModel(legendSide);
171  ++row;
172 
173  chartConfig->elementAt(row, 0)->addWidget(std::make_unique<WText>("Legend alignment:"));
174  legendAlignmentEdit_ = chartConfig->elementAt(row,1)->addWidget(std::make_unique<WComboBox>());
175  legendAlignmentEdit_->setModel(legendAlignment);
178  ++row;
179 
180  chartConfig->elementAt(row, 0)->addWidget(std::make_unique<WText>("Border:"));
181  borderEdit_ = chartConfig->elementAt(row,1)->addWidget(std::make_unique<WCheckBox>());
182  borderEdit_->setChecked(false);
184  ++row;
185 
186  for (int i = 0; i < chartConfig->rowCount(); ++i) {
187  chartConfig->elementAt(i, 0)->setStyleClass("tdhead");
188  chartConfig->elementAt(i, 1)->setStyleClass("tddata");
189  }
190 
191  WPanel *p = list->addWidget("Chart properties", std::move(chartConfig));
192  p->setMargin(WLength::Auto, Side::Left | Side::Right);
193  p->resize(1160, WLength::Auto);
194  p->setMargin(20, Side::Top | Side::Bottom);
195 
196  // ---- Series properties ----
197 
198  std::shared_ptr<WStandardItemModel> types
199  = std::make_shared<WStandardItemModel>(0,1);
200  addEntry(types, "Points");
201  addEntry(types, "Line");
202  addEntry(types, "Curve");
203  addEntry(types, "Bar");
204  addEntry(types, "Line Area");
205  addEntry(types, "Curve Area");
206  addEntry(types, "Stacked Bar");
207  addEntry(types, "Stacked Line Area");
208  addEntry(types, "Stacked Curve Area");
209 
210  std::shared_ptr<WStandardItemModel> markers
211  = std::make_shared<WStandardItemModel>(0,1);
212  addEntry(markers, "None");
213  addEntry(markers, "Square");
214  addEntry(markers, "Circle");
215  addEntry(markers, "Cross");
216  addEntry(markers, "X cross");
217  addEntry(markers, "Triangle");
218  addEntry(markers, "Pipe");
219  addEntry(markers, "Star");
220  addEntry(markers, "Inverted triangle");
221  addEntry(markers, "Asterisk");
222  addEntry(markers, "Diamond");
223 
224  xAxesModel_ = std::make_shared<WStandardItemModel>(0, 1);
225  addEntry(xAxesModel_, axisName(Axis::X, 0));
226 
227  yAxesModel_ = std::make_shared<WStandardItemModel>(0, 1);
228  addEntry(yAxesModel_, axisName(Axis::Y, 0));
229  addEntry(yAxesModel_, axisName(Axis::Y, 1));
230 
231  std::shared_ptr<WStandardItemModel> labels
232  = std::make_shared<WStandardItemModel>(0,1);
233  addEntry(labels, "None");
234  addEntry(labels, "X");
235  addEntry(labels, "Y");
236  addEntry(labels, "X: Y");
237 
238  std::unique_ptr<WTable> seriesConfig
239  = std::make_unique<WTable>();
240  WTable *seriesConfigPtr = seriesConfig.get();
241  seriesConfig->setMargin(WLength::Auto, Side::Left | Side::Right);
242  ::addHeader(seriesConfigPtr, "Name");
243  ::addHeader(seriesConfigPtr, "Enabled");
244  ::addHeader(seriesConfigPtr, "Type");
245  ::addHeader(seriesConfigPtr, "Marker");
246  ::addHeader(seriesConfigPtr, "X axis");
247  ::addHeader(seriesConfigPtr, "Y axis");
248  ::addHeader(seriesConfigPtr, "Legend");
249  ::addHeader(seriesConfigPtr, "Shadow");
250  ::addHeader(seriesConfigPtr, "Value labels");
251 
252  seriesConfig->rowAt(0)->setStyleClass("trhead");
253 
254  for (int j = 1; j < chart->model()->columnCount(); ++j) {
255  SeriesControl sc;
256 
257  seriesConfig->elementAt(j,0)->addWidget(std::make_unique<WText>(chart->model()->headerData(j)));
258 
259  sc.enabledEdit = seriesConfig->elementAt(j,1)->addWidget(std::make_unique<WCheckBox>());
261 
262  sc.typeEdit = seriesConfig->elementAt(j,2)->addWidget(std::make_unique<WComboBox>());
263  sc.typeEdit->setModel(types);
264  sc.typeEdit->setCurrentIndex(0);
266 
267  sc.markerEdit = seriesConfig->elementAt(j,3)->addWidget(std::make_unique<WComboBox>());
268  sc.markerEdit->setModel(markers);
271 
272  sc.xAxisEdit = seriesConfig->elementAt(j, 4)->addNew<WComboBox>();
274  sc.xAxisEdit->setCurrentIndex(0);
276 
277  sc.yAxisEdit = seriesConfig->elementAt(j, 5)->addNew<WComboBox>();
279  sc.yAxisEdit->setCurrentIndex(0);
281 
282  sc.legendEdit = seriesConfig->elementAt(j, 6)->addWidget(std::make_unique<WCheckBox>());
284 
285  sc.shadowEdit = seriesConfig->elementAt(j, 7)->addWidget(std::make_unique<WCheckBox>());
287 
288  sc.labelsEdit = seriesConfig->elementAt(j, 8)->addWidget(std::make_unique<WComboBox>());
289  sc.labelsEdit->setModel(labels);
292 
293  int si = seriesIndexOf(chart, j);
294 
295  if (si != -1) {
296  sc.enabledEdit->setChecked();
297  const WDataSeries& s = chart_->series(j);
298  switch (s.type()) {
299  case SeriesType::Point:
300  sc.typeEdit->setCurrentIndex(0); break;
301  case SeriesType::Line:
303  (s.isStacked() ? 7 : 4) : 1); break;
304  case SeriesType::Curve:
306  (s.isStacked() ? 8 : 5) : 2); break;
307  case SeriesType::Bar:
308  sc.typeEdit->setCurrentIndex(s.isStacked() ? 6 : 3);
309  }
310 
311  sc.markerEdit->setCurrentIndex((int)s.marker());
313  sc.shadowEdit->setChecked(s.shadow() != WShadow());
314  }
315 
316  seriesControls_.push_back(sc);
317 
318  seriesConfig->rowAt(j)->setStyleClass("trdata");
319  }
320 
321  p = list->addWidget("Series properties", std::move(seriesConfig));
322  p->expand();
323  p->setMargin(WLength::Auto, Side::Left | Side::Right);
324  p->resize(1160, WLength::Auto);
325  p->setMargin(20, Side::Top | Side::Bottom);
326 
327  // ---- Axis properties ----
328 
329  yScales_ = std::make_shared<WStandardItemModel>(0, 1);
330  addEntry(yScales_, "Linear scale");
331  addEntry(yScales_, "Log scale");
332 
333  xScales_ = std::make_shared<WStandardItemModel>(0, 1);
334  addEntry(xScales_, "Categories");
335  addEntry(xScales_, "Linear scale");
336  addEntry(xScales_, "Log scale");
337  addEntry(xScales_, "Date scale");
338 
339  auto axisConfig = std::make_unique<WContainerWidget>();
340  axisConfig_ = axisConfig->addNew<WTable>();
341  axisConfig_->setMargin(WLength::Auto, Side::Left | Side::Right);
342 
343  ::addHeader(axisConfig_, "Axis");
344  ::addHeader(axisConfig_, "Visible");
345  ::addHeader(axisConfig_, "Scale");
346  ::addHeader(axisConfig_, "Automatic");
347  ::addHeader(axisConfig_, "Minimum");
348  ::addHeader(axisConfig_, "Maximum");
349  ::addHeader(axisConfig_, "Gridlines");
350  ::addHeader(axisConfig_, "Label angle");
351  ::addHeader(axisConfig_, "Title");
352  ::addHeader(axisConfig_, "Title orientation");
353  ::addHeader(axisConfig_, "Tick direction");
354  ::addHeader(axisConfig_, "Location");
355 
356  axisConfig_->rowAt(0)->setStyleClass("trhead");
357 
358  addAxis(Axis::X, 0);
359  addAxis(Axis::Y, 0);
360  addAxis(Axis::Y, 1);
361 
362  WPushButton *addXAxisBtn =
363  axisConfig->addNew<WPushButton>(Wt::utf8("Add X axis"));
364  addXAxisBtn->clicked().connect(this, &ChartConfig::addXAxis);
365  WPushButton *clearXAxesBtn =
366  axisConfig->addNew<WPushButton>(Wt::utf8("Clear X axes"));
367  clearXAxesBtn->clicked().connect(this, &ChartConfig::clearXAxes);
368  WPushButton *addYAxisBtn =
369  axisConfig->addNew<WPushButton>(utf8("Add Y axis"));
370  addYAxisBtn->clicked().connect(this, &ChartConfig::addYAxis);
371  WPushButton *clearYAxesBtn =
372  axisConfig->addNew<WPushButton>(utf8("Clear Y axes"));
373  clearYAxesBtn->clicked().connect(this, &ChartConfig::clearYAxes);
374 
375  p = list->addWidget("Axis properties", std::move(axisConfig));
376  p->setMargin(WLength::Auto, Side::Left | Side::Right);
377  p->resize(1160, WLength::Auto);
378  p->setMargin(20, Side::Top | Side::Bottom);
379 
380  /*
381  * If we do not have JavaScript, then add a button to reflect changes to
382  * the chart.
383  */
384  if (!WApplication::instance()->environment().javaScript()) {
385  auto *b = this->addWidget(std::make_unique<WPushButton>());
386  b->setText("Update chart");
387  b->setInline(false); // so we can add margin to center horizontally
388  b->setMargin(WLength::Auto, Side::Left | Side::Right);
389  b->clicked().connect(this, &ChartConfig::update);
390  }
391 }
392 
394 {
395  fill_ = fill;
396 }
397 
399 {
400  bool haveLegend = false;
401  std::vector<std::unique_ptr<WDataSeries>> series;
402 
403  for (int i = 1; i < chart_->model()->columnCount(); ++i) {
404  SeriesControl& sc = seriesControls_[i-1];
405 
406  if (sc.enabledEdit->isChecked()) {
407  std::unique_ptr<WDataSeries> s
408  = std::make_unique<WDataSeries>(i);
409 
410  switch (sc.typeEdit->currentIndex()) {
411  case 0:
412  s->setType(SeriesType::Point);
413  if (sc.markerEdit->currentIndex() == 0)
415  break;
416  case 1:
417  s->setType(SeriesType::Line);
418  break;
419  case 2:
420  s->setType(SeriesType::Curve);
421  break;
422  case 3:
423  s->setType(SeriesType::Bar);
424  break;
425  case 4:
426  s->setType(SeriesType::Line);
427  s->setFillRange(fill_);
428  break;
429  case 5:
430  s->setType(SeriesType::Curve);
431  s->setFillRange(fill_);
432  break;
433  case 6:
434  s->setType(SeriesType::Bar);
435  s->setStacked(true);
436  break;
437  case 7:
438  s->setType(SeriesType::Line);
439  s->setFillRange(fill_);
440  s->setStacked(true);
441  break;
442  case 8:
443  s->setType(SeriesType::Curve);
444  s->setFillRange(fill_);
445  s->setStacked(true);
446  }
447 
448  //set WPainterPath to draw a pipe
449  if(sc.markerEdit->currentIndex() == static_cast<int>(MarkerType::Custom)){ //was customMarker before
450  WPainterPath pp = WPainterPath();
451  pp.moveTo(0, -6);
452  pp.lineTo(0, 6);
453  s->setCustomMarker(pp);
454  }
455 
456  s->setMarker(static_cast<MarkerType>(sc.markerEdit->currentIndex()));
457 
458  s->bindToXAxis(sc.xAxisEdit->currentIndex());
459  s->bindToYAxis(sc.yAxisEdit->currentIndex());
460 
461  if (sc.legendEdit->isChecked()) {
462  s->setLegendEnabled(true);
463  haveLegend = true;
464  } else
465  s->setLegendEnabled(false);
466 
467  if (sc.shadowEdit->isChecked()) {
468  s->setShadow(WShadow(3, 3, WColor(0, 0, 0, 127), 3));
469  } else
470  s->setShadow(WShadow());
471 
472  switch (sc.labelsEdit->currentIndex()) {
473  case 1:
474  s->setLabelsEnabled(Axis::X);
475  break;
476  case 2:
477  s->setLabelsEnabled(Axis::Y);
478  break;
479  case 3:
480  s->setLabelsEnabled(Axis::X);
481  s->setLabelsEnabled(Axis::Y);
482  break;
483  }
484 
485  series.push_back(std::move(s));
486  }
487  }
488 
489  chart_->setSeries(std::move(series));
490 
491  for (std::size_t i = 0; i < axisControls_.size(); ++i) {
492  AxisControl& sc = axisControls_[i];
493  WAxis& axis = static_cast<int>(i) < chart_->xAxisCount() ? chart_->xAxis(i) : chart_->yAxis(i - chart_->xAxisCount());
494 
495  axis.setVisible(sc.visibleEdit->isChecked());
496 
497  if (sc.scaleEdit->count() != 1) {
498  int k = sc.scaleEdit->currentIndex();
499  if (axis.id() != Axis::X)
500  k += 1;
501  else {
502  if (k == 0)
504  else
506  }
507 
508  switch (k) {
509  case 1:
510  axis.setScale(AxisScale::Linear); break;
511  case 2:
512  axis.setScale(AxisScale::Log); break;
513  case 3:
514  axis.setScale(AxisScale::Date); break;
515  }
516  }
517 
518  if (sc.autoEdit->isChecked())
520  else {
521  if (!(axis.autoLimits() & (AxisValue::Minimum | AxisValue::Maximum)).empty()) {
522  sc.minimumEdit->setText(WLocale::currentLocale()
523  .toString(axis.minimum()));
524  sc.maximumEdit->setText(WLocale::currentLocale()
525  .toString(axis.maximum()));
526  }
527  if (validate(sc.minimumEdit) && validate(sc.maximumEdit)) {
528  double min, max;
529  getDouble(sc.minimumEdit, min);
530  getDouble(sc.maximumEdit, max);
531 
532  if (axis.scale() == AxisScale::Log)
533  if (min <= 0)
534  min = 0.0001;
535 
536  if (axis.scale() == AxisScale::Date){
537  //the number of julian days until year 1986
538  WDate dMin = WDate(1900,1,1);
539  double gregDaysMin = (double)dMin.toJulianDay();
540  //the number of julian days until year 1988
541  WDate dMax = WDate(3000,1,1);
542  double gregDaysMax = (double)dMax.toJulianDay();
543 
544  bool greg_year_validation =
545  (min > gregDaysMin &&
546  min < gregDaysMax &&
547  max > gregDaysMin &&
548  max < gregDaysMax);
549 
550  if(!greg_year_validation){
551  min = gregDaysMin;
552  max = gregDaysMax;
553  }
554  }
555 
556  axis.setRange(min, max);
557  }
558 
559  }
560 
561  if (validate(sc.labelAngleEdit)) {
562  double angle;
563  getDouble(sc.labelAngleEdit, angle);
564  axis.setLabelAngle(angle);
565  }
566 
568 
569  axis.setTitle(sc.titleEdit->text());
570 
571  axis.setTitleOrientation(sc.titleOrientationEdit->currentIndex() == 0 ? Orientation::Horizontal : Orientation::Vertical);
572 
573  axis.setTickDirection(sc.tickDirectionEdit->currentIndex() == 0 ? TickDirection::Outwards : TickDirection::Inwards);
574 
575  switch (sc.locationEdit->currentIndex()) {
576  case 0:
578  break;
579  case 1:
581  break;
582  case 2:
584  break;
585  case 3:
587  break;
588  }
589  }
590 
592 
594  double width, height;
595  getDouble(chartWidthEdit_, width);
596  getDouble(chartHeightEdit_, height);
598  }
599 
600  switch (chartOrientationEdit_->currentIndex()) {
601  case 0:
602  chart_->setOrientation(Orientation::Vertical); break;
603  case 1:
604  chart_->setOrientation(Orientation::Horizontal); break;
605  }
606 
607  chart_->setLegendEnabled(haveLegend);
608 
609  if (haveLegend) {
611  Side side = Side::Right;
612  AlignmentFlag alignment = AlignmentFlag::Middle;
613  switch (legendLocationEdit_->currentIndex()) {
614  case 0: location = LegendLocation::Outside; break;
615  case 1: location = LegendLocation::Inside; break;
616  }
617 
618  switch (legendSideEdit_->currentIndex()) {
619  case 0: side = Side::Top; break;
620  case 1: side = Side::Right; break;
621  case 2: side = Side::Bottom; break;
622  case 3: side = Side::Left; break;
623  }
624 
625  if (side == Side::Left || side == Side::Right) {
628  } else {
631  }
632 
633  switch (legendAlignmentEdit_->currentIndex()) {
634  case 0: alignment = AlignmentFlag::Left; break;
635  case 1: alignment = AlignmentFlag::Center; break;
636  case 2: alignment = AlignmentFlag::Right; break;
637  case 3: alignment = AlignmentFlag::Top; break;
638  case 4: alignment = AlignmentFlag::Middle; break;
639  case 5: alignment = AlignmentFlag::Bottom; break;
640  }
641 
642  chart_->setLegendLocation(location, side, alignment);
643 
644  chart_->setLegendColumns((side == Side::Top || side == Side::Bottom ) ? 2 : 1,
645  WLength(100));
646  }
647 
648  if (borderEdit_->isChecked()) {
650  } else {
652  }
653 }
654 
656 {
657  bool valid = w->validate() == ValidationState::Valid;
658 
659  if (!WApplication::instance()->environment().javaScript()) {
660  w->setStyleClass(valid ? "" : "Wt-invalid");
661  w->setToolTip(valid ? "" : "Invalid value");
662  }
663 
664  return valid;
665 }
666 
668 {
669  w->changed().connect(this, &ChartConfig::update);
670  if (dynamic_cast<WLineEdit *>(w))
672 }
673 
675 {
676  int xAxis = chart_->addXAxis(std::make_unique<WAxis>());
677  addAxis(Axis::X, xAxis);
678  addEntry(xAxesModel_, axisName(Axis::X, xAxis));
679  if (xAxis == 0)
680  update();
681 }
682 
684 {
685  int yAxis = chart_->addYAxis(std::make_unique<WAxis>());
686  addAxis(Axis::Y, yAxis);
687  addEntry(yAxesModel_, axisName(Axis::Y, yAxis));
688  if (yAxis == 0)
689  update();
690 }
691 
692 void ChartConfig::addAxis(Axis ax, int axisId)
693 {
694  int j = ax == Axis::X ? 1 + axisId : 1 + chart_->xAxisCount() + axisId;
695 
696  const WAxis& axis = ax == Axis::X ? chart_->xAxis(axisId) : chart_->yAxis(axisId);
697  AxisControl sc;
698 
700  axisConfig_->elementAt(j, 0)->addNew<WText>(axisName(axis.id(), axis.yAxisId()));
701 
703  sc.visibleEdit->setChecked(axis.isVisible());
705 
707  if (axis.scale() == AxisScale::Discrete)
708  sc.scaleEdit->addItem("Discrete scale");
709  else {
710  if (axis.id() == Axis::X) {
712  sc.scaleEdit->setCurrentIndex(static_cast<int>(axis.scale()));
713  } else {
715  sc.scaleEdit->setCurrentIndex(static_cast<int>(axis.scale()) - 1);
716  }
717  }
719 
720  bool autoValues = axis.autoLimits() == (AxisValue::Minimum | AxisValue::Maximum);
721 
723  sc.minimumEdit->setText(WLocale::currentLocale()
724  .toString(axis.minimum()));
726  sc.minimumEdit->setEnabled(!autoValues);
728 
730  sc.maximumEdit->setText(WLocale::currentLocale()
731  .toString(axis.maximum()));
733  sc.maximumEdit->setEnabled(!autoValues);
735 
737  sc.autoEdit->setChecked(autoValues);
739  sc.autoEdit->checked().connect(sc.maximumEdit, &WLineEdit::disable);
740  sc.autoEdit->unChecked().connect(sc.maximumEdit, &WLineEdit::enable);
741  sc.autoEdit->checked().connect(sc.minimumEdit, &WLineEdit::disable);
742  sc.autoEdit->unChecked().connect(sc.minimumEdit, &WLineEdit::enable);
743 
746 
748  sc.labelAngleEdit->setText("0");
751 
753  sc.titleEdit->setText("");
755 
757  sc.titleOrientationEdit->addItem("Horizontal");
758  sc.titleOrientationEdit->addItem("Vertical");
761 
763  sc.tickDirectionEdit->addItem("Outwards");
764  sc.tickDirectionEdit->addItem("Inwards");
767 
769  sc.locationEdit->addItem("Minimum value");
770  sc.locationEdit->addItem("Maximum value");
771  sc.locationEdit->addItem("Zero value");
772  sc.locationEdit->addItem("Both sides");
774  if (axis.location() == AxisValue::Maximum) {
776  } else if (axis.location() == AxisValue::Zero) {
778  }
780 
781  WPushButton *removeAxisButton =
782  axisConfig_->elementAt(j, 12)->addNew<WPushButton>(utf8("x"));
783  if (ax == Axis::X) {
784  removeAxisButton->clicked().connect(std::bind(&ChartConfig::removeXAxis, this, &axis));
785  } else {
786  removeAxisButton->clicked().connect(std::bind(&ChartConfig::removeYAxis, this, &axis));
787  }
788 
789  axisConfig_->rowAt(j)->setStyleClass("trdata");
790 
791  axisControls_.insert(axisControls_.begin() + j - 1, sc);
792 }
793 
795 {
796  int xAxis = axis->xAxisId();
797  for (std::size_t i = 0; i < chart_->series().size(); ++i) {
798  if (chart_->series()[i]->xAxis() == xAxis)
799  chart_->series()[i]->bindToXAxis(-1);
800  }
801  chart_->removeXAxis(xAxis);
802  axisConfig_->removeRow(1 + xAxis);
803  xAxesModel_->removeRow(xAxis);
804  axisControls_.erase(axisControls_.begin() + xAxis);
805  update();
806 }
807 
809 {
810  int yAxis = axis->yAxisId();
811  for (std::size_t i = 0; i < chart_->series().size(); ++i) {
812  if (chart_->series()[i]->yAxis() == yAxis)
813  chart_->series()[i]->bindToYAxis(-1);
814  }
815  chart_->removeYAxis(yAxis);
816  axisConfig_->removeRow(1 + chart_->xAxisCount() + yAxis);
817  yAxesModel_->removeRow(yAxis);
818  axisControls_.erase(axisControls_.begin() + chart_->xAxisCount() + yAxis);
819  update();
820 }
821 
823 {
824  if (chart_->xAxisCount() == 0)
825  return;
826 
827  for (std::size_t i = 0; i < chart_->series().size(); ++i) {
828  chart_->series()[i]->bindToXAxis(-1);
829  }
830  const int xAxisCount = chart_->xAxisCount();
831  chart_->clearXAxes();
832  for (int i = 0; i < xAxisCount; ++i) {
834  }
835  xAxesModel_->clear();
836  axisControls_.erase(axisControls_.begin(), axisControls_.begin() + xAxisCount);
837 }
838 
840 {
841  if (chart_->yAxisCount() == 0)
842  return;
843 
844  for (std::size_t i = 0; i < chart_->series().size(); ++i) {
845  chart_->series()[i]->bindToYAxis(-1);
846  }
847  const int yAxisCount = chart_->yAxisCount();
848  chart_->clearYAxes();
849  for (int i = 0; i < yAxisCount; ++i) {
851  }
852  yAxesModel_->clear();
853  axisControls_.resize(chart_->xAxisCount());
854 }
std::vector< SeriesControl > seriesControls_
Controls for series.
Definition: ChartConfig.h:66
void addAxis(Wt::Chart::Axis axis, int axisId)
Definition: ChartConfig.C:692
Wt::WComboBox * legendAlignmentEdit_
Definition: ChartConfig.h:92
Wt::WComboBox * legendLocationEdit_
Definition: ChartConfig.h:90
std::shared_ptr< Wt::WValidator > angleValidator_
Definition: ChartConfig.h:97
Wt::WTable * axisConfig_
Definition: ChartConfig.h:96
Wt::WComboBox * legendSideEdit_
Definition: ChartConfig.h:91
void removeXAxis(const Wt::Chart::WAxis *axis)
Definition: ChartConfig.C:794
std::shared_ptr< Wt::WValidator > anyNumberValidator_
Definition: ChartConfig.h:97
void setValueFill(Wt::Chart::FillRangeType fill)
Definition: ChartConfig.C:393
Wt::WLineEdit * chartWidthEdit_
Definition: ChartConfig.h:87
Wt::WLineEdit * titleEdit_
Definition: ChartConfig.h:86
void removeYAxis(const Wt::Chart::WAxis *axis)
Definition: ChartConfig.C:808
void addYAxis()
Definition: ChartConfig.C:683
std::shared_ptr< Wt::WStandardItemModel > xAxesModel_
Definition: ChartConfig.h:95
static bool validate(Wt::WFormWidget *w)
Definition: ChartConfig.C:655
void connectSignals(Wt::WFormWidget *w)
Definition: ChartConfig.C:667
Wt::Chart::WCartesianChart * chart_
Definition: ChartConfig.h:50
std::vector< AxisControl > axisControls_
Controls for axes.
Definition: ChartConfig.h:84
void clearYAxes()
Definition: ChartConfig.C:839
ChartConfig(Wt::Chart::WCartesianChart *chart)
Constructor.
Definition: ChartConfig.C:76
std::shared_ptr< Wt::WStandardItemModel > xScales_
Definition: ChartConfig.h:95
void clearXAxes()
Definition: ChartConfig.C:822
Wt::Chart::FillRangeType fill_
Definition: ChartConfig.h:51
void addXAxis()
Definition: ChartConfig.C:674
void update()
Definition: ChartConfig.C:398
Wt::WCheckBox * borderEdit_
Definition: ChartConfig.h:93
Wt::WLineEdit * chartHeightEdit_
Definition: ChartConfig.h:88
std::shared_ptr< Wt::WStandardItemModel > yAxesModel_
Definition: ChartConfig.h:95
Wt::WComboBox * chartOrientationEdit_
Definition: ChartConfig.h:89
std::shared_ptr< Wt::WStandardItemModel > yScales_
Definition: ChartConfig.h:95
Wt::WPanel * addWidget(const Wt::WString &text, std::unique_ptr< Wt::WWidget > w)
Definition: PanelList.C:17
std::shared_ptr< WAbstractChartModel > model() const
void setTitle(const WString &title)
double maximum() const
int yAxisId() const
WFlags< AxisValue > autoLimits() const
void setAutoLimits(WFlags< AxisValue > locations)
Axis id() const
void setVisible(bool visible)
void setLocation(AxisValue value)
void setGridLinesEnabled(bool enabled)
bool isVisible() const
AxisScale scale() const
void setRange(double minimum, double maximum)
void setScale(AxisScale scale)
void setTickDirection(TickDirection direction)
int xAxisId() const
double minimum() const
AxisValue location() const
void setTitleOrientation(const Orientation &orientation)
void setTitle(const WString &title)
void setLabelAngle(double angle)
void setType(ChartType type)
int addYAxis(std::unique_ptr< WAxis > waxis)
void setLegendEnabled(bool enabled)
int addXAxis(std::unique_ptr< WAxis > waxis)
std::unique_ptr< WAxis > removeXAxis(int xAxisId)
std::unique_ptr< WAxis > removeYAxis(int yAxisId)
void setLegendStyle(const WFont &font, const WPen &border, const WBrush &background)
WDataSeries & series(int modelColumn)
void setLegendColumns(int columns, const WLength &width)
void setOrientation(Orientation orientation)
void setBorderPen(const WPen &pen)
void setSeries(std::vector< std::unique_ptr< WDataSeries > > series)
void setLegendLocation(LegendLocation location, Side side, AlignmentFlag alignment)
MarkerType marker() const
const WShadow & shadow() const
void bindToXAxis(int xAxis)
bool isStacked() const
FillRangeType fillRange() const
SeriesType type() const
void bindToYAxis(int yAxis)
bool isLegendEnabled() const
Wt::Signals::connection connect(F function)
void setChecked(bool checked)
EventSignal & unChecked()
EventSignal & checked()
int currentIndex() const
void setCurrentIndex(int index)
void addItem(const WString &text)
int count() const
void setModel(const std::shared_ptr< WAbstractItemModel > model)
virtual void resize(const WLength &width, const WLength &height) override
virtual void setMargin(const WLength &margin, WFlags< Side > sides=AllSides) override
Widget * addNew(Args &&...args)
virtual void addWidget(std::unique_ptr< WWidget > widget)
int toJulianDay() const
virtual ValidationState validate()
EventSignal & changed()
void setValidator(const std::shared_ptr< WValidator > &validator)
void setEnabled(bool enabled)
virtual void setToolTip(const WString &text, TextFormat textFormat=TextFormat::Plain) override
EventSignal & enterPressed()
EventSignal< WMouseEvent > & clicked()
double value() const
const WString & text() const
void setMaxLength(int length)
virtual void setText(const WString &text)
double toDouble(const WString &value) const
static const WLocale & currentLocale()
virtual void resize(const WLength &width, const WLength &height) override
void moveTo(const WPointF &point)
void lineTo(const WPointF &point)
void expand()
WString & arg(const std::wstring &value)
void setStyleClass(const WString &style)
int rowCount() const
int columnCount() const
virtual WTableRow * insertRow(int row, std::unique_ptr< WTableRow > tableRow=nullptr)
virtual std::unique_ptr< WTableRow > removeRow(int row)
WTableCell * elementAt(int row, int column)
WTableRow * rowAt(int row)
virtual WLength width() const override
virtual void setMargin(const WLength &margin, WFlags< Side > sides=AllSides) override
virtual void setStyleClass(const WString &styleClass) override
virtual WLength height() const override
AlignmentFlag
Struct that holds the controls for one axis.
Definition: ChartConfig.h:69
Wt::WLineEdit * maximumEdit
Definition: ChartConfig.h:74
Wt::WComboBox * tickDirectionEdit
Definition: ChartConfig.h:79
Wt::WLineEdit * titleEdit
Definition: ChartConfig.h:77
Wt::WLineEdit * labelAngleEdit
Definition: ChartConfig.h:76
Wt::WComboBox * titleOrientationEdit
Definition: ChartConfig.h:78
Wt::WCheckBox * gridLinesEdit
Definition: ChartConfig.h:75
Wt::WLineEdit * minimumEdit
Definition: ChartConfig.h:73
Wt::WComboBox * locationEdit
Definition: ChartConfig.h:80
Wt::WComboBox * scaleEdit
Definition: ChartConfig.h:71
Wt::WCheckBox * visibleEdit
Definition: ChartConfig.h:70
Wt::WCheckBox * autoEdit
Definition: ChartConfig.h:72
Struct that holds the controls for one series.
Definition: ChartConfig.h:54
Wt::WComboBox * markerEdit
Definition: ChartConfig.h:57
Wt::WComboBox * labelsEdit
Definition: ChartConfig.h:62
Wt::WCheckBox * enabledEdit
Definition: ChartConfig.h:55
Wt::WCheckBox * legendEdit
Definition: ChartConfig.h:60
Wt::WCheckBox * shadowEdit
Definition: ChartConfig.h:61
Wt::WComboBox * typeEdit
Definition: ChartConfig.h:56
Wt::WComboBox * xAxisEdit
Definition: ChartConfig.h:58
Wt::WComboBox * yAxisEdit
Definition: ChartConfig.h:59