Wt examples  4.5.0
Classes | Public Member Functions | Private Member Functions | Static Private Member Functions | Private Attributes | List of all members
ChartConfig Class Reference

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

#include <ChartConfig.h>

Inheritance diagram for ChartConfig:
Inheritance graph
[legend]

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)
 Constructor. More...
 
void setValueFill (Wt::Chart::FillRangeType fill)
 

Private Member Functions

void connectSignals (Wt::WFormWidget *w)
 
void update ()
 
void addXAxis ()
 
void addYAxis ()
 
void addAxis (Wt::Chart::Axis axis, int axisId)
 
void removeXAxis (const Wt::Chart::WAxis *axis)
 
void removeYAxis (const Wt::Chart::WAxis *axis)
 
void clearXAxes ()
 
void clearYAxes ()
 

Static Private Member Functions

static bool validate (Wt::WFormWidget *w)
 

Private Attributes

Wt::Chart::WCartesianChart * chart_
 
Wt::Chart::FillRangeType fill_
 
std::vector< SeriesControlseriesControls_
 Controls for series. More...
 
std::vector< AxisControlaxisControls_
 Controls for axes. More...
 
Wt::WLineEdit * titleEdit_
 
Wt::WLineEdit * chartWidthEdit_
 
Wt::WLineEdit * chartHeightEdit_
 
Wt::WComboBox * chartOrientationEdit_
 
Wt::WComboBox * legendLocationEdit_
 
Wt::WComboBox * legendSideEdit_
 
Wt::WComboBox * legendAlignmentEdit_
 
Wt::WCheckBox * borderEdit_
 
std::shared_ptr< Wt::WStandardItemModel > xAxesModel_
 
std::shared_ptr< Wt::WStandardItemModel > yAxesModel_
 
std::shared_ptr< Wt::WStandardItemModel > xScales_
 
std::shared_ptr< Wt::WStandardItemModel > yScales_
 
Wt::WTable * axisConfig_
 
std::shared_ptr< Wt::WValidator > anyNumberValidator_
 
std::shared_ptr< Wt::WValidator > angleValidator_
 

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 40 of file ChartConfig.h.

Constructor & Destructor Documentation

◆ ChartConfig()

ChartConfig::ChartConfig ( Wt::Chart::WCartesianChart *  chart)

Constructor.

Definition at line 76 of file ChartConfig.C.

77  : WContainerWidget(),
78  chart_(chart),
79  fill_(FillRangeType::MinimumValue)
80 {
81  chart_->setLegendStyle(chart_->legendFont(), WPen(WColor("black")),
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);
139  chartWidthEdit_->setMaxLength(4);
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);
148  chartHeightEdit_->setMaxLength(4);
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);
155  chartOrientationEdit_->setCurrentIndex(0);
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);
162  legendLocationEdit_->setCurrentIndex(0);
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);
169  legendSideEdit_->setCurrentIndex(1);
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);
176  legendAlignmentEdit_->setCurrentIndex(4);
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>());
260  connectSignals(sc.enabledEdit);
261 
262  sc.typeEdit = seriesConfig->elementAt(j,2)->addWidget(std::make_unique<WComboBox>());
263  sc.typeEdit->setModel(types);
264  sc.typeEdit->setCurrentIndex(0);
265  connectSignals(sc.typeEdit);
266 
267  sc.markerEdit = seriesConfig->elementAt(j,3)->addWidget(std::make_unique<WComboBox>());
268  sc.markerEdit->setModel(markers);
269  sc.markerEdit->setCurrentIndex(0);
270  connectSignals(sc.markerEdit);
271 
272  sc.xAxisEdit = seriesConfig->elementAt(j, 4)->addNew<WComboBox>();
273  sc.xAxisEdit->setModel(xAxesModel_);
274  sc.xAxisEdit->setCurrentIndex(0);
275  connectSignals(sc.xAxisEdit);
276 
277  sc.yAxisEdit = seriesConfig->elementAt(j, 5)->addNew<WComboBox>();
278  sc.yAxisEdit->setModel(yAxesModel_);
279  sc.yAxisEdit->setCurrentIndex(0);
280  connectSignals(sc.yAxisEdit);
281 
282  sc.legendEdit = seriesConfig->elementAt(j, 6)->addWidget(std::make_unique<WCheckBox>());
283  connectSignals(sc.legendEdit);
284 
285  sc.shadowEdit = seriesConfig->elementAt(j, 7)->addWidget(std::make_unique<WCheckBox>());
286  connectSignals(sc.shadowEdit);
287 
288  sc.labelsEdit = seriesConfig->elementAt(j, 8)->addWidget(std::make_unique<WComboBox>());
289  sc.labelsEdit->setModel(labels);
290  sc.labelsEdit->setCurrentIndex(0);
291  connectSignals(sc.labelsEdit);
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:
302  sc.typeEdit->setCurrentIndex(s.fillRange() != FillRangeType::None ?
303  (s.isStacked() ? 7 : 4) : 1); break;
304  case SeriesType::Curve:
305  sc.typeEdit->setCurrentIndex(s.fillRange() != FillRangeType::None ?
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());
312  sc.legendEdit->setChecked(s.isLegendEnabled());
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 }
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
std::shared_ptr< Wt::WValidator > anyNumberValidator_
Definition: ChartConfig.h:97
Wt::WLineEdit * chartWidthEdit_
Definition: ChartConfig.h:87
Wt::WLineEdit * titleEdit_
Definition: ChartConfig.h:86
void addYAxis()
Definition: ChartConfig.C:683
std::shared_ptr< Wt::WStandardItemModel > xAxesModel_
Definition: ChartConfig.h:95
void connectSignals(Wt::WFormWidget *w)
Definition: ChartConfig.C:667
Wt::Chart::WCartesianChart * chart_
Definition: ChartConfig.h:50
void clearYAxes()
Definition: ChartConfig.C:839
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

Member Function Documentation

◆ addAxis()

void ChartConfig::addAxis ( Wt::Chart::Axis  axis,
int  axisId 
)
private

Definition at line 692 of file ChartConfig.C.

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 
699  axisConfig_->insertRow(j);
700  axisConfig_->elementAt(j, 0)->addNew<WText>(axisName(axis.id(), axis.yAxisId()));
701 
702  sc.visibleEdit = axisConfig_->elementAt(j, 1)->addNew<WCheckBox>();
703  sc.visibleEdit->setChecked(axis.isVisible());
704  connectSignals(sc.visibleEdit);
705 
706  sc.scaleEdit = axisConfig_->elementAt(j, 2)->addNew<WComboBox>();
707  if (axis.scale() == AxisScale::Discrete)
708  sc.scaleEdit->addItem("Discrete scale");
709  else {
710  if (axis.id() == Axis::X) {
711  sc.scaleEdit->setModel(xScales_);
712  sc.scaleEdit->setCurrentIndex(static_cast<int>(axis.scale()));
713  } else {
714  sc.scaleEdit->setModel(yScales_);
715  sc.scaleEdit->setCurrentIndex(static_cast<int>(axis.scale()) - 1);
716  }
717  }
718  connectSignals(sc.scaleEdit);
719 
720  bool autoValues = axis.autoLimits() == (AxisValue::Minimum | AxisValue::Maximum);
721 
722  sc.minimumEdit = axisConfig_->elementAt(j, 4)->addNew<WLineEdit>();
723  sc.minimumEdit->setText(WLocale::currentLocale()
724  .toString(axis.minimum()));
725  sc.minimumEdit->setValidator(anyNumberValidator_);
726  sc.minimumEdit->setEnabled(!autoValues);
727  connectSignals(sc.minimumEdit);
728 
729  sc.maximumEdit = axisConfig_->elementAt(j, 5)->addNew<WLineEdit>();
730  sc.maximumEdit->setText(WLocale::currentLocale()
731  .toString(axis.maximum()));
732  sc.maximumEdit->setValidator(anyNumberValidator_);
733  sc.maximumEdit->setEnabled(!autoValues);
734  connectSignals(sc.maximumEdit);
735 
736  sc.autoEdit = axisConfig_->elementAt(j, 3)->addNew<WCheckBox>();
737  sc.autoEdit->setChecked(autoValues);
738  connectSignals(sc.autoEdit);
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 
744  sc.gridLinesEdit = axisConfig_->elementAt(j, 6)->addNew<WCheckBox>();
745  connectSignals(sc.gridLinesEdit);
746 
747  sc.labelAngleEdit = axisConfig_->elementAt(j, 7)->addNew<WLineEdit>();
748  sc.labelAngleEdit->setText("0");
749  sc.labelAngleEdit->setValidator(angleValidator_);
750  connectSignals(sc.labelAngleEdit);
751 
752  sc.titleEdit = axisConfig_->elementAt(j, 8)->addNew<WLineEdit>();
753  sc.titleEdit->setText("");
754  connectSignals(sc.titleEdit);
755 
756  sc.titleOrientationEdit = axisConfig_->elementAt(j, 9)->addNew<WComboBox>();
757  sc.titleOrientationEdit->addItem("Horizontal");
758  sc.titleOrientationEdit->addItem("Vertical");
759  sc.titleOrientationEdit->setCurrentIndex(0);
760  connectSignals(sc.titleOrientationEdit);
761 
762  sc.tickDirectionEdit = axisConfig_->elementAt(j, 10)->addNew<WComboBox>();
763  sc.tickDirectionEdit->addItem("Outwards");
764  sc.tickDirectionEdit->addItem("Inwards");
765  sc.tickDirectionEdit->setCurrentIndex(0);
766  connectSignals(sc.tickDirectionEdit);
767 
768  sc.locationEdit = axisConfig_->elementAt(j, 11)->addNew<WComboBox>();
769  sc.locationEdit->addItem("Minimum value");
770  sc.locationEdit->addItem("Maximum value");
771  sc.locationEdit->addItem("Zero value");
772  sc.locationEdit->addItem("Both sides");
773  sc.locationEdit->setCurrentIndex(0);
774  if (axis.location() == AxisValue::Maximum) {
775  sc.locationEdit->setCurrentIndex(1);
776  } else if (axis.location() == AxisValue::Zero) {
777  sc.locationEdit->setCurrentIndex(2);
778  }
779  connectSignals(sc.locationEdit);
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 }
void removeXAxis(const Wt::Chart::WAxis *axis)
Definition: ChartConfig.C:794
void removeYAxis(const Wt::Chart::WAxis *axis)
Definition: ChartConfig.C:808
std::vector< AxisControl > axisControls_
Controls for axes.
Definition: ChartConfig.h:84

◆ addXAxis()

void ChartConfig::addXAxis ( )
private

Definition at line 674 of file ChartConfig.C.

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 }

◆ addYAxis()

void ChartConfig::addYAxis ( )
private

Definition at line 683 of file ChartConfig.C.

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 }

◆ clearXAxes()

void ChartConfig::clearXAxes ( )
private

Definition at line 822 of file ChartConfig.C.

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) {
833  axisConfig_->removeRow(1);
834  }
835  xAxesModel_->clear();
836  axisControls_.erase(axisControls_.begin(), axisControls_.begin() + xAxisCount);
837 }

◆ clearYAxes()

void ChartConfig::clearYAxes ( )
private

Definition at line 839 of file ChartConfig.C.

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) {
850  axisConfig_->removeRow(axisConfig_->rowCount() - 1);
851  }
852  yAxesModel_->clear();
853  axisControls_.resize(chart_->xAxisCount());
854 }

◆ connectSignals()

void ChartConfig::connectSignals ( Wt::WFormWidget *  w)
private

Definition at line 667 of file ChartConfig.C.

668 {
669  w->changed().connect(this, &ChartConfig::update);
670  if (dynamic_cast<WLineEdit *>(w))
671  w->enterPressed().connect(this, &ChartConfig::update);
672 }

◆ removeXAxis()

void ChartConfig::removeXAxis ( const Wt::Chart::WAxis *  axis)
private

Definition at line 794 of file ChartConfig.C.

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 }

◆ removeYAxis()

void ChartConfig::removeYAxis ( const Wt::Chart::WAxis *  axis)
private

Definition at line 808 of file ChartConfig.C.

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 }

◆ setValueFill()

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

Definition at line 393 of file ChartConfig.C.

394 {
395  fill_ = fill;
396 }

◆ update()

void ChartConfig::update ( )
private

Definition at line 398 of file ChartConfig.C.

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)
414  sc.markerEdit->setCurrentIndex(1);
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)
503  chart_->setType(ChartType::Category);
504  else
505  chart_->setType(ChartType::Scatter);
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())
519  axis.setAutoLimits(AxisValue::Minimum | AxisValue::Maximum);
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 
567  axis.setGridLinesEnabled(sc.gridLinesEdit->isChecked());
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:
577  axis.setLocation(AxisValue::Minimum);
578  break;
579  case 1:
580  axis.setLocation(AxisValue::Maximum);
581  break;
582  case 2:
583  axis.setLocation(AxisValue::Zero);
584  break;
585  case 3:
586  axis.setLocation(AxisValue::Both);
587  break;
588  }
589  }
590 
591  chart_->setTitle(titleEdit_->text());
592 
594  double width, height;
595  getDouble(chartWidthEdit_, width);
596  getDouble(chartHeightEdit_, height);
597  chart_->resize(width, 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) {
610  LegendLocation location = LegendLocation::Outside;
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) {
626  if (legendAlignmentEdit_->currentIndex() < 3)
627  legendAlignmentEdit_->setCurrentIndex(4);
628  } else {
629  if (legendAlignmentEdit_->currentIndex() >= 3)
630  legendAlignmentEdit_->setCurrentIndex(2);
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()) {
649  chart_->setBorderPen(WPen());
650  } else {
651  chart_->setBorderPen(PenStyle::None);
652  }
653 }
static bool validate(Wt::WFormWidget *w)
Definition: ChartConfig.C:655

◆ validate()

bool ChartConfig::validate ( Wt::WFormWidget *  w)
staticprivate

Definition at line 655 of file ChartConfig.C.

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 }

Member Data Documentation

◆ angleValidator_

std::shared_ptr<Wt::WValidator> ChartConfig::angleValidator_
private

Definition at line 97 of file ChartConfig.h.

◆ anyNumberValidator_

std::shared_ptr<Wt::WValidator> ChartConfig::anyNumberValidator_
private

Definition at line 97 of file ChartConfig.h.

◆ axisConfig_

Wt::WTable* ChartConfig::axisConfig_
private

Definition at line 96 of file ChartConfig.h.

◆ axisControls_

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

Controls for axes.

Definition at line 84 of file ChartConfig.h.

◆ borderEdit_

Wt::WCheckBox* ChartConfig::borderEdit_
private

Definition at line 93 of file ChartConfig.h.

◆ chart_

Wt::Chart::WCartesianChart* ChartConfig::chart_
private

Definition at line 50 of file ChartConfig.h.

◆ chartHeightEdit_

Wt::WLineEdit* ChartConfig::chartHeightEdit_
private

Definition at line 88 of file ChartConfig.h.

◆ chartOrientationEdit_

Wt::WComboBox* ChartConfig::chartOrientationEdit_
private

Definition at line 89 of file ChartConfig.h.

◆ chartWidthEdit_

Wt::WLineEdit* ChartConfig::chartWidthEdit_
private

Definition at line 87 of file ChartConfig.h.

◆ fill_

Wt::Chart::FillRangeType ChartConfig::fill_
private

Definition at line 51 of file ChartConfig.h.

◆ legendAlignmentEdit_

Wt::WComboBox* ChartConfig::legendAlignmentEdit_
private

Definition at line 92 of file ChartConfig.h.

◆ legendLocationEdit_

Wt::WComboBox* ChartConfig::legendLocationEdit_
private

Definition at line 90 of file ChartConfig.h.

◆ legendSideEdit_

Wt::WComboBox* ChartConfig::legendSideEdit_
private

Definition at line 91 of file ChartConfig.h.

◆ seriesControls_

std::vector<SeriesControl> ChartConfig::seriesControls_
private

Controls for series.

Definition at line 66 of file ChartConfig.h.

◆ titleEdit_

Wt::WLineEdit* ChartConfig::titleEdit_
private

Definition at line 86 of file ChartConfig.h.

◆ xAxesModel_

std::shared_ptr<Wt::WStandardItemModel> ChartConfig::xAxesModel_
private

Definition at line 95 of file ChartConfig.h.

◆ xScales_

std::shared_ptr<Wt::WStandardItemModel> ChartConfig::xScales_
private

Definition at line 95 of file ChartConfig.h.

◆ yAxesModel_

std::shared_ptr<Wt::WStandardItemModel> ChartConfig::yAxesModel_
private

Definition at line 95 of file ChartConfig.h.

◆ yScales_

std::shared_ptr<Wt::WStandardItemModel> ChartConfig::yScales_
private

Definition at line 95 of file ChartConfig.h.


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

Generated on Sat Aug 14 2021 for the C++ Web Toolkit (Wt) by doxygen 1.9.1