1 /*
2  * Copyright (C) 2008 Emweb bv, Herent, Belgium.
3  *
4  * See the LICENSE file for terms of use.
5  */
6 
7 #include <Wt/WPointF.h>
8 #include <Wt/Chart/WChartPalette.h>
9 #include <Wt/Chart/WDataSeries.h>
10 #include <Wt/Chart/WCartesianChart.h>
11 
12 namespace Wt {
13   namespace Chart {
14 
WDataSeries(int modelColumn,SeriesType type,Axis axis)15 WDataSeries::WDataSeries(int modelColumn, SeriesType type, Axis axis)
16   : chart_(nullptr),
17     model_(nullptr),
18     modelColumn_(modelColumn),
19     XSeriesColumn_(-1),
20     stacked_(false),
21     type_(type),
22     xAxis_(0),
23     yAxis_(axis == Axis::Y1 ? 0 : 1),
24     customFlags_(None),
25     fillRange_(FillRangeType::None),
26     marker_(type == SeriesType::Point ?
27             MarkerType::Circle : MarkerType::None),
28     markerSize_(6),
29     legend_(true),
30     xLabel_(false),
31     yLabel_(false),
32     barWidth_(0.8),
33     hidden_(false),
34     offset_(0.0),
35     scale_(1.0),
36     offsetDirty_(true),
37     scaleDirty_(true)
38 { }
39 
WDataSeries(int modelColumn,SeriesType type,int axis)40 WDataSeries::WDataSeries(int modelColumn, SeriesType type, int axis)
41   : chart_(nullptr),
42     model_(nullptr),
43     modelColumn_(modelColumn),
44     XSeriesColumn_(-1),
45     stacked_(false),
46     type_(type),
47     xAxis_(0),
48     yAxis_(axis),
49     customFlags_(None),
50     fillRange_(FillRangeType::None),
51     marker_(type == SeriesType::Point ?
52 	    MarkerType::Circle : MarkerType::None),
53     markerSize_(6),
54     legend_(true),
55     xLabel_(false),
56     yLabel_(false),
57     barWidth_(0.8),
58     hidden_(false),
59     offset_(0.0),
60     scale_(1.0),
61     offsetDirty_(true),
62     scaleDirty_(true)
63 { }
64 
~WDataSeries()65 WDataSeries::~WDataSeries()
66 {
67   if (model_) {
68     for (unsigned i = 0; i < modelConnections_.size(); ++i)
69       modelConnections_[i].disconnect();
70   }
71 }
72 
setBarWidth(const double width)73 void WDataSeries::setBarWidth(const double width)
74 {
75   barWidth_ = width;
76 }
77 
barWidth()78 double WDataSeries::barWidth() const
79 {
80   return barWidth_;
81 }
82 
setType(SeriesType type)83 void WDataSeries::setType(SeriesType type)
84 {
85   set(type_, type);
86 }
87 
setStacked(bool stacked)88 void WDataSeries::setStacked(bool stacked)
89 {
90   set(stacked_, stacked);
91 }
92 
setModelColumn(int modelColumn)93 void WDataSeries::setModelColumn(int modelColumn)
94 {
95   set(modelColumn_, modelColumn);
96 }
97 
bindToAxis(Axis axis)98 void WDataSeries::bindToAxis(Axis axis)
99 {
100   set(yAxis_, axis == Axis::Y1 ? 0 : 1);
101 }
102 
bindToXAxis(int xAxis)103 void WDataSeries::bindToXAxis(int xAxis)
104 {
105   set(xAxis_, xAxis);
106 }
107 
bindToYAxis(int yAxis)108 void WDataSeries::bindToYAxis(int yAxis)
109 {
110   set(yAxis_, yAxis);
111 }
112 
setCustomFlags(WFlags<CustomFlag> flags)113 void WDataSeries::setCustomFlags(WFlags<CustomFlag> flags)
114 {
115   set(customFlags_, flags);
116 }
117 
setPen(const WPen & pen)118 void WDataSeries::setPen(const WPen& pen)
119 {
120   set(pen_, pen);
121 
122   customFlags_ |= CustomFlag::Pen;
123 }
124 
setShadow(const WShadow & shadow)125 void WDataSeries::setShadow(const WShadow& shadow)
126 {
127   set(shadow_, shadow);
128 }
129 
shadow()130 const WShadow& WDataSeries::shadow() const
131 {
132   return shadow_;
133 }
134 
pen()135 WPen WDataSeries::pen() const
136 {
137   if (customFlags_.test(CustomFlag::Pen))
138     return pen_;
139   else
140     if (chart_)
141       if (type_ == SeriesType::Bar)
142 	return chart_->palette()
143 	  ->borderPen(chart_->seriesIndexOf(*this));
144       else
145 	return chart_->palette()
146 	  ->strokePen(chart_->seriesIndexOf(*this));
147     else {
148       WPen defaultPen;
149       defaultPen.setCapStyle(PenCapStyle::Round);
150       defaultPen.setJoinStyle(PenJoinStyle::Round);
151       return defaultPen;
152     }
153 }
154 
setBrush(const WBrush & brush)155 void WDataSeries::setBrush(const WBrush& brush)
156 {
157   set(brush_, brush);
158 
159   customFlags_ |= CustomFlag::Brush;
160 }
161 
brush()162 WBrush WDataSeries::brush() const
163 {
164   if (customFlags_.test(CustomFlag::Brush))
165     return brush_;
166   else
167     if (chart_)
168       return chart_->palette()->brush(chart_->seriesIndexOf(*this));
169     else
170       return WBrush();
171 }
172 
labelColor()173 WColor WDataSeries::labelColor() const
174 {
175   if (customFlags_.test(CustomFlag::LabelColor))
176     return labelColor_;
177   else
178     if (chart_)
179       return chart_->palette()->fontColor(chart_->seriesIndexOf(*this));
180     else
181       return WColor(StandardColor::Black);
182 }
183 
setLabelColor(const WColor & color)184 void WDataSeries::setLabelColor(const WColor& color)
185 {
186   set(labelColor_, color);
187 
188   customFlags_ |= CustomFlag::LabelColor;
189 }
190 
setFillRange(FillRangeType fillRange)191 void WDataSeries::setFillRange(FillRangeType fillRange)
192 {
193   set(fillRange_, fillRange);
194 }
195 
fillRange()196 FillRangeType WDataSeries::fillRange() const
197 {
198   if (type_ == SeriesType::Bar && fillRange_ == FillRangeType::None)
199     return FillRangeType::ZeroValue;
200   else
201     return fillRange_;
202 }
203 
setMarker(MarkerType marker)204 void WDataSeries::setMarker(MarkerType marker)
205 {
206   set(marker_, marker);
207 }
208 
setCustomMarker(const WPainterPath & path)209 void WDataSeries::setCustomMarker(const WPainterPath& path)
210 {
211   set(marker_, MarkerType::Custom);
212 
213   customMarker_ = path;
214 }
215 
setMarkerSize(double size)216 void WDataSeries::setMarkerSize(double size)
217 {
218   set(markerSize_, size);
219 }
220 
setMarkerPen(const WPen & pen)221 void WDataSeries::setMarkerPen(const WPen& pen)
222 {
223   set(markerPen_, pen);
224 
225   customFlags_ |= CustomFlag::MarkerPen;
226 }
227 
markerPen()228 WPen WDataSeries::markerPen() const
229 {
230   if (customFlags_.test(CustomFlag::MarkerPen))
231     return markerPen_;
232   else
233     return pen();
234 }
235 
setMarkerBrush(const WBrush & brush)236 void WDataSeries::setMarkerBrush(const WBrush& brush)
237 {
238   set(markerBrush_, brush);
239 
240   customFlags_ |= CustomFlag::MarkerBrush;
241 }
242 
markerBrush()243 WBrush WDataSeries::markerBrush() const
244 {
245   if (customFlags_.test(CustomFlag::MarkerBrush))
246     return markerBrush_;
247   else
248     return brush();
249 }
250 
setLegendEnabled(bool enabled)251 void WDataSeries::setLegendEnabled(bool enabled)
252 {
253   set(legend_, enabled);
254 }
255 
isLegendEnabled()256 bool WDataSeries::isLegendEnabled() const
257 {
258   if (!isHidden())
259     return legend_;
260   else
261     return false;
262 }
263 
setLabelsEnabled(Axis axis,bool enabled)264 void WDataSeries::setLabelsEnabled(Axis axis, bool enabled)
265 {
266   if (axis == Axis::X)
267     xLabel_ = enabled;
268   else
269     yLabel_ = enabled;
270 
271   update();
272 }
273 
isLabelsEnabled(Axis axis)274 bool WDataSeries::isLabelsEnabled(Axis axis) const
275 {
276   return axis == Axis::X ? xLabel_ : yLabel_;
277 }
278 
setHidden(bool hidden)279 void WDataSeries::setHidden(bool hidden)
280 {
281   hidden_ = hidden;
282 }
283 
isHidden()284 bool WDataSeries::isHidden() const
285 {
286   return hidden_;
287 }
288 
setChart(WCartesianChart * chart)289 void WDataSeries::setChart(WCartesianChart *chart)
290 {
291   chart_ = chart;
292 }
293 
update()294 void WDataSeries::update()
295 {
296   if (chart_)
297     chart_->update();
298 }
299 
mapFromDevice(const WPointF & deviceCoordinates)300 WPointF WDataSeries::mapFromDevice(const WPointF& deviceCoordinates) const
301 {
302   if (chart_)
303     return chart_->mapFromDevice(deviceCoordinates,
304                                  chart_->xAxis(xAxis_),
305                                  chart_->yAxis(yAxis_));
306   else
307     return WPointF();
308 }
309 
mapToDevice(const cpp17::any & xValue,const cpp17::any & yValue,int segment)310 WPointF WDataSeries::mapToDevice(const cpp17::any& xValue, const cpp17::any& yValue,
311 				 int segment) const
312 {
313   if (chart_)
314     return chart_->mapToDevice(xValue, yValue,
315                                chart_->xAxis(xAxis_),
316                                chart_->yAxis(yAxis_),
317                                segment);
318   else
319     return WPointF();
320 }
321 
setXSeriesColumn(int modelColumn)322 void WDataSeries::setXSeriesColumn(int modelColumn)
323 {
324   XSeriesColumn_ = modelColumn;
325 }
326 
setOffset(double offset)327 void WDataSeries::setOffset(double offset)
328 {
329   if (offset_ != offset) {
330     offset_ = offset;
331     update();
332   }
333   offsetDirty_ =  true;
334 }
335 
setScale(double scale)336 void WDataSeries::setScale(double scale)
337 {
338   if (scale_ != scale) {
339     scale_ = scale;
340     update();
341   }
342   scaleDirty_ = true;
343 }
344 
setModel(const std::shared_ptr<WAbstractChartModel> & model)345 void WDataSeries::setModel(const std::shared_ptr<WAbstractChartModel>& model)
346 {
347   if (model_) {
348     /* disconnect slots from previous model */
349     for (unsigned i = 0; i < modelConnections_.size(); ++i)
350       modelConnections_[i].disconnect();
351 
352     modelConnections_.clear();
353   }
354 
355   model_ = model;
356 
357   if (model_) {
358 #ifdef WT_TARGET_JAVA
359     modelConnections_.push_back(model_->changed().connect(this, std::bind(&WDataSeries::modelReset, this)));
360 #else // !WT_TARGET_JAVA
361     modelConnections_.push_back(model_->changed().connect(std::bind(&WDataSeries::modelReset, this)));
362 #endif // WT_TARGET_JAVA
363   }
364 
365   if (chart_)
366     chart_->update();
367 }
368 
modelReset()369 void WDataSeries::modelReset()
370 {
371   if (chart_)
372     chart_->modelReset();
373 }
374 
model()375 std::shared_ptr<WAbstractChartModel> WDataSeries::model() const
376 {
377   if (model_)
378     return model_;
379 
380   if (chart_)
381     return chart_->model();
382 
383   return nullptr;
384 }
385 
386   }
387 }
388