79 fill_(FillRangeType::MinimumValue)
81 chart_->setLegendStyle(
chart_->legendFont(), WPen(WColor(
"black")),
82 WBrush(WColor(0xFF, 0xFA, 0xE5)));
84 PanelList *list = this->addWidget(std::make_unique<PanelList>());
86 std::shared_ptr<WIntValidator> sizeValidator
87 = std::make_shared<WIntValidator>(200,2000);
88 sizeValidator->setMandatory(
true);
98 std::shared_ptr<WStandardItemModel> orientation
99 = std::make_shared<WStandardItemModel>(0,1);
100 addEntry(orientation,
"Vertical");
101 addEntry(orientation,
"Horizontal");
103 std::shared_ptr<WStandardItemModel> legendLocation
104 = std::make_shared<WStandardItemModel>(0,1);
105 addEntry(legendLocation,
"Outside");
106 addEntry(legendLocation,
"Inside");
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");
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");
124 std::unique_ptr<WTable> chartConfig
125 = std::make_unique<WTable>();
126 chartConfig->setMargin(WLength::Auto, Side::Left | Side::Right);
129 chartConfig->elementAt(row, 0)->addWidget(std::make_unique<WText>(
"Title:"));
130 titleEdit_ = chartConfig->elementAt(row,1)->addWidget(std::make_unique<WLineEdit>());
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()));
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()));
152 chartConfig->elementAt(row, 0)->addWidget(std::make_unique<WText>(
"Orientation:"));
159 chartConfig->elementAt(row, 0)->addWidget(std::make_unique<WText>(
"Legend location:"));
160 legendLocationEdit_ = chartConfig->elementAt(row,1)->addWidget(std::make_unique<WComboBox>());
166 chartConfig->elementAt(row, 0)->addWidget(std::make_unique<WText>(
"Legend side:"));
167 legendSideEdit_ = chartConfig->elementAt(row,1)->addWidget(std::make_unique<WComboBox>());
173 chartConfig->elementAt(row, 0)->addWidget(std::make_unique<WText>(
"Legend alignment:"));
180 chartConfig->elementAt(row, 0)->addWidget(std::make_unique<WText>(
"Border:"));
181 borderEdit_ = chartConfig->elementAt(row,1)->addWidget(std::make_unique<WCheckBox>());
186 for (
int i = 0; i < chartConfig->rowCount(); ++i) {
187 chartConfig->elementAt(i, 0)->setStyleClass(
"tdhead");
188 chartConfig->elementAt(i, 1)->setStyleClass(
"tddata");
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);
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");
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");
224 xAxesModel_ = std::make_shared<WStandardItemModel>(0, 1);
227 yAxesModel_ = std::make_shared<WStandardItemModel>(0, 1);
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");
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");
252 seriesConfig->rowAt(0)->setStyleClass(
"trhead");
254 for (
int j = 1; j < chart->model()->columnCount(); ++j) {
257 seriesConfig->elementAt(j,0)->addWidget(std::make_unique<WText>(chart->model()->headerData(j)));
259 sc.
enabledEdit = seriesConfig->elementAt(j,1)->addWidget(std::make_unique<WCheckBox>());
262 sc.
typeEdit = seriesConfig->elementAt(j,2)->addWidget(std::make_unique<WComboBox>());
267 sc.
markerEdit = seriesConfig->elementAt(j,3)->addWidget(std::make_unique<WComboBox>());
272 sc.
xAxisEdit = seriesConfig->elementAt(j, 4)->addNew<WComboBox>();
277 sc.
yAxisEdit = seriesConfig->elementAt(j, 5)->addNew<WComboBox>();
282 sc.
legendEdit = seriesConfig->elementAt(j, 6)->addWidget(std::make_unique<WCheckBox>());
285 sc.
shadowEdit = seriesConfig->elementAt(j, 7)->addWidget(std::make_unique<WCheckBox>());
288 sc.
labelsEdit = seriesConfig->elementAt(j, 8)->addWidget(std::make_unique<WComboBox>());
293 int si = seriesIndexOf(chart, j);
297 const WDataSeries& s =
chart_->series(j);
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);
311 sc.
markerEdit->setCurrentIndex((
int)s.marker());
312 sc.
legendEdit->setChecked(s.isLegendEnabled());
313 sc.
shadowEdit->setChecked(s.shadow() != WShadow());
318 seriesConfig->rowAt(j)->setStyleClass(
"trdata");
321 p = list->
addWidget(
"Series properties", std::move(seriesConfig));
323 p->setMargin(WLength::Auto, Side::Left | Side::Right);
324 p->resize(1160, WLength::Auto);
325 p->setMargin(20, Side::Top | Side::Bottom);
329 yScales_ = std::make_shared<WStandardItemModel>(0, 1);
333 xScales_ = std::make_shared<WStandardItemModel>(0, 1);
339 auto axisConfig = std::make_unique<WContainerWidget>();
341 axisConfig_->setMargin(WLength::Auto, Side::Left | Side::Right);
362 WPushButton *addXAxisBtn =
363 axisConfig->addNew<WPushButton>(Wt::utf8(
"Add X axis"));
365 WPushButton *clearXAxesBtn =
366 axisConfig->addNew<WPushButton>(Wt::utf8(
"Clear X axes"));
368 WPushButton *addYAxisBtn =
369 axisConfig->addNew<WPushButton>(utf8(
"Add Y axis"));
371 WPushButton *clearYAxesBtn =
372 axisConfig->addNew<WPushButton>(utf8(
"Clear Y axes"));
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);
384 if (!WApplication::instance()->environment().javaScript()) {
385 auto *b = this->addWidget(std::make_unique<WPushButton>());
386 b->setText(
"Update chart");
388 b->setMargin(WLength::Auto, Side::Left | Side::Right);
400 bool haveLegend =
false;
401 std::vector<std::unique_ptr<WDataSeries>> series;
403 for (
int i = 1; i <
chart_->model()->columnCount(); ++i) {
407 std::unique_ptr<WDataSeries> s
408 = std::make_unique<WDataSeries>(i);
410 switch (sc.
typeEdit->currentIndex()) {
412 s->setType(SeriesType::Point);
417 s->setType(SeriesType::Line);
420 s->setType(SeriesType::Curve);
423 s->setType(SeriesType::Bar);
426 s->setType(SeriesType::Line);
427 s->setFillRange(
fill_);
430 s->setType(SeriesType::Curve);
431 s->setFillRange(
fill_);
434 s->setType(SeriesType::Bar);
438 s->setType(SeriesType::Line);
439 s->setFillRange(
fill_);
443 s->setType(SeriesType::Curve);
444 s->setFillRange(
fill_);
449 if(sc.
markerEdit->currentIndex() ==
static_cast<int>(MarkerType::Custom)){
450 WPainterPath pp = WPainterPath();
453 s->setCustomMarker(pp);
456 s->setMarker(
static_cast<MarkerType
>(sc.
markerEdit->currentIndex()));
458 s->bindToXAxis(sc.
xAxisEdit->currentIndex());
459 s->bindToYAxis(sc.
yAxisEdit->currentIndex());
462 s->setLegendEnabled(
true);
465 s->setLegendEnabled(
false);
468 s->setShadow(WShadow(3, 3, WColor(0, 0, 0, 127), 3));
470 s->setShadow(WShadow());
474 s->setLabelsEnabled(Axis::X);
477 s->setLabelsEnabled(Axis::Y);
480 s->setLabelsEnabled(Axis::X);
481 s->setLabelsEnabled(Axis::Y);
485 series.push_back(std::move(s));
489 chart_->setSeries(std::move(series));
493 WAxis& axis =
static_cast<int>(i) <
chart_->xAxisCount() ?
chart_->xAxis(i) :
chart_->yAxis(i -
chart_->xAxisCount());
499 if (axis.id() != Axis::X)
503 chart_->setType(ChartType::Category);
505 chart_->setType(ChartType::Scatter);
510 axis.setScale(AxisScale::Linear);
break;
512 axis.setScale(AxisScale::Log);
break;
514 axis.setScale(AxisScale::Date);
break;
519 axis.setAutoLimits(AxisValue::Minimum | AxisValue::Maximum);
521 if (!(axis.autoLimits() & (AxisValue::Minimum | AxisValue::Maximum)).empty()) {
523 .toString(axis.minimum()));
525 .toString(axis.maximum()));
532 if (axis.scale() == AxisScale::Log)
536 if (axis.scale() == AxisScale::Date){
538 WDate dMin = WDate(1900,1,1);
539 double gregDaysMin = (double)dMin.toJulianDay();
541 WDate dMax = WDate(3000,1,1);
542 double gregDaysMax = (double)dMax.toJulianDay();
544 bool greg_year_validation =
545 (min > gregDaysMin &&
550 if(!greg_year_validation){
556 axis.setRange(min, max);
564 axis.setLabelAngle(angle);
571 axis.setTitleOrientation(sc.
titleOrientationEdit->currentIndex() == 0 ? Orientation::Horizontal : Orientation::Vertical);
573 axis.setTickDirection(sc.
tickDirectionEdit->currentIndex() == 0 ? TickDirection::Outwards : TickDirection::Inwards);
577 axis.setLocation(AxisValue::Minimum);
580 axis.setLocation(AxisValue::Maximum);
583 axis.setLocation(AxisValue::Zero);
586 axis.setLocation(AxisValue::Both);
594 double width, height;
597 chart_->resize(width, height);
602 chart_->setOrientation(Orientation::Vertical);
break;
604 chart_->setOrientation(Orientation::Horizontal);
break;
607 chart_->setLegendEnabled(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;
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;
625 if (side == Side::Left || side == Side::Right) {
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;
642 chart_->setLegendLocation(location, side, alignment);
644 chart_->setLegendColumns((side == Side::Top || side == Side::Bottom ) ? 2 : 1,
649 chart_->setBorderPen(WPen());
651 chart_->setBorderPen(PenStyle::None);
694 int j = ax == Axis::X ? 1 + axisId : 1 +
chart_->xAxisCount() + axisId;
696 const WAxis& axis = ax == Axis::X ?
chart_->xAxis(axisId) :
chart_->yAxis(axisId);
700 axisConfig_->elementAt(j, 0)->addNew<WText>(axisName(axis.id(), axis.yAxisId()));
707 if (axis.scale() == AxisScale::Discrete)
710 if (axis.id() == Axis::X) {
712 sc.
scaleEdit->setCurrentIndex(
static_cast<int>(axis.scale()));
715 sc.
scaleEdit->setCurrentIndex(
static_cast<int>(axis.scale()) - 1);
720 bool autoValues = axis.autoLimits() == (AxisValue::Minimum | AxisValue::Maximum);
724 .toString(axis.minimum()));
731 .toString(axis.maximum()));
737 sc.
autoEdit->setChecked(autoValues);
774 if (axis.location() == AxisValue::Maximum) {
776 }
else if (axis.location() == AxisValue::Zero) {
781 WPushButton *removeAxisButton =
782 axisConfig_->elementAt(j, 12)->addNew<WPushButton>(utf8(
"x"));