Wt examples  4.12.2
Loading...
Searching...
No Matches
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
31using namespace Wt;
32using namespace Wt::Chart;
33
34namespace {
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
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>());
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);
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>();
276
277 sc.yAxisEdit = seriesConfig->elementAt(j, 5)->addNew<WComboBox>();
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) {
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());
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) {
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
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()) {
523 .toString(axis.minimum()));
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:
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
592
594 double width, height;
595 getDouble(chartWidthEdit_, width);
596 getDouble(chartHeightEdit_, height);
598 }
599
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;
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
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 {
651 chart_->setBorderPen(PenStyle::None);
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{
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
692void 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
724 .toString(axis.minimum()));
726 sc.minimumEdit->setEnabled(!autoValues);
728
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();
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();
849 for (int i = 0; i < yAxisCount; ++i) {
851 }
852 yAxesModel_->clear();
854}
std::vector< SeriesControl > seriesControls_
Controls for series.
Definition ChartConfig.h:66
void addAxis(Wt::Chart::Axis axis, int axisId)
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)
std::shared_ptr< Wt::WValidator > anyNumberValidator_
Definition ChartConfig.h:97
void setValueFill(Wt::Chart::FillRangeType fill)
Wt::WLineEdit * chartWidthEdit_
Definition ChartConfig.h:87
Wt::WLineEdit * titleEdit_
Definition ChartConfig.h:86
void removeYAxis(const Wt::Chart::WAxis *axis)
void addYAxis()
std::shared_ptr< Wt::WStandardItemModel > xAxesModel_
Definition ChartConfig.h:95
static bool validate(Wt::WFormWidget *w)
void connectSignals(Wt::WFormWidget *w)
Wt::Chart::WCartesianChart * chart_
Definition ChartConfig.h:50
std::vector< AxisControl > axisControls_
Controls for axes.
Definition ChartConfig.h:84
void clearYAxes()
ChartConfig(Wt::Chart::WCartesianChart *chart)
Constructor.
Definition ChartConfig.C:76
std::shared_ptr< Wt::WStandardItemModel > xScales_
Definition ChartConfig.h:95
void clearXAxes()
Wt::Chart::FillRangeType fill_
Definition ChartConfig.h:51
void addXAxis()
void update()
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()
virtual 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()
static WLength Auto
double value() const
const WString & text() const
virtual void setMaxLength(int length)
virtual void setText(const WString &text)
WString toString(int value) const
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