Project

General

Profile

Improvements #12495 » WChartJSDataSeries.C

Mark Travis, 07/09/2026 07:46 PM

 
//
// Created by mark on 6/5/25.
//

#include <ReportsAndCharts//WChartJSDataSeries.h>

#include <Wt/Json/Value.h>
#include <Wt/Json/Object.h>

// This is a variadic template that can accept any number of types (Ts...).
// In our case, the types will be the unique types of our lambdas.
template<class... Ts>
struct overloaded : Ts... { // <--- (1) Inherits from all lambda types
using Ts::operator()...; // <--- (2) Brings all call operators into scope
};

// This is a "Class Template Argument Deduction" (CTAD) guide, added in C++17.
template<class... Ts>
overloaded(Ts...) -> overloaded<Ts...>; // <--- (3) Makes usage clean

WChartJSDataSeries::WChartJSDataSeries(ChartJSType type) : chartType_(type) {
setSeriesChartJSType(chartType_);
}

void WChartJSDataSeries::setSeriesChartJSType(ChartJSType type) {
// This is used primarily for mixed bar/line where you must tag the actual
// data series.
switch (chartType_) {
case ChartJSType::BAR:
seriesOptions_["type"] = Wt::Json::Value("bar");
break;
case ChartJSType::BUBBLE:
seriesOptions_["type"] = Wt::Json::Value("bubble");
break;
case ChartJSType::DOUGHNUT:
seriesOptions_["type"] = Wt::Json::Value("doughnut");
break;
case ChartJSType::PIE:
seriesOptions_["type"] = Wt::Json::Value("pie");
break;
case ChartJSType::LINE:
seriesOptions_["type"] = Wt::Json::Value("line");
break;
case ChartJSType::POLAR:
seriesOptions_["type"] = Wt::Json::Value("polarArea");
break;
case ChartJSType::RADAR:
seriesOptions_["type"] = Wt::Json::Value("radar");
break;
case ChartJSType::SCATTER:
seriesOptions_["type"] = Wt::Json::Value("scatter");
}
}
// Use the following method to add an option not covered, or one that requires
// a depth of Json structure more than the top level depth
void WChartJSDataSeries::addSeriesOption(const std::string& propertyName, const Wt::Json::Object& option) {
seriesOptions_[propertyName] = option;
}

Wt::Json::Object WChartJSDataSeries::getJson() {
return seriesOptions_;
}

void WChartJSDataSeries::disableYaxisAnimation() {
Wt::Json::Object animations;
Wt::Json::Object yAxis;
Wt::Json::Object yAxisOption;
yAxisOption["duration"] = 0;
yAxis["y"] = Wt::Json::Value(yAxisOption);
animations["animations"] = Wt::Json::Value(yAxis);
seriesOptions_["animation"] = Wt::Json::Value(animations);
}

// --- Common Dataset Options Implementation ---

void WChartJSDataSeries::setLineBarCircleSeriesColor(const std::string& color) {
lineBarCircleSeriesMainColor_ = color;
seriesOptions_["backgroundColor"] = getBackgroundColorAsJson();
}

void WChartJSDataSeries::setLineBarCircleSeriesColor(const std::vector<std::string>& colors) {
lineBarCircleSeriesMainColor_ = colors;
// Wt::Json::Array colorArray;
// for (const auto& color : lineBarCircleSeriesMainColor_) {
// colorArray.push_back(color);
// }
seriesOptions_["backgroundColor"] = getBackgroundColorAsJson();
}

Wt::Json::Value WChartJSDataSeries::getBackgroundColorAsJson() const {
// Create an instance of our visitor by passing it two lambdas.
// One for std::string, one for std::vector<std::string>.
auto visitor = overloaded {
// This lambda is called if the variant holds a std::string
[](const std::string& color) -> Wt::Json::Value {
return Wt::Json::Value(color);
},
// This lambda is called if the variant holds a std::vector<std::string>
[](const std::vector<std::string>& colors) -> Wt::Json::Value {
Wt::Json::Array colorArray;
for (const auto& color : colors) {
colorArray.push_back(Wt::Json::Value(color));
}
return Wt::Json::Value(colorArray);
}
};

// std::visit calls the appropriate lambda from our visitor
// based on the type currently held in lineBarCircleSeriesMainColor_.
return std::visit(visitor, lineBarCircleSeriesMainColor_);
}

Wt::Json::Value WChartJSDataSeries::getBorderColorAsJson() const {
// Create an instance of our visitor by passing it two lambdas.
// One for std::string, one for std::vector<std::string>.
auto visitor = overloaded {
// This lambda is called if the variant holds a std::string
[](const std::string& color) -> Wt::Json::Value {
return Wt::Json::Value(color);
},
// This lambda is called if the variant holds a std::vector<std::string>
[](const std::vector<std::string>& colors) -> Wt::Json::Value {
Wt::Json::Array colorArray;
for (const auto& color : colors) {
colorArray.push_back(Wt::Json::Value(color));
}
return Wt::Json::Value(colorArray);
}
};

// std::visit calls the appropriate lambda from our visitor
// based on the type currently held in lineBarCircleSeriesMainColor_.
return std::visit(visitor, lineBarCircleSeriesBorderColor_);
}

void WChartJSDataSeries::setLineBarCircleSeriesBorderColor(const std::string& color) {
lineBarCircleSeriesBorderColor_ = color;
seriesOptions_["borderColor"] = getBorderColorAsJson();
}

void WChartJSDataSeries::setBorderWidth(int width) {
borderWidth_ = width;
seriesOptions_["borderWidth"] = Wt::Json::Value(width);
}

void WChartJSDataSeries::setClip(int clip) {
clip_ = clip;
seriesOptions_["clip"] = Wt::Json::Value(clip);
}

void WChartJSDataSeries::setHidden(bool isHidden) {
hidden_ = isHidden;
seriesOptions_["hidden"] = Wt::Json::Value(isHidden);
}

void WChartJSDataSeries::setHoverBackgroundColor(const std::string& color) {
hoverBackgroundColor_ = color;
seriesOptions_["hoverBackgroundColor"] = Wt::Json::Value(color);
}

void WChartJSDataSeries::setHoverBorderColor(const std::string& color) {
hoverBorderColor_ = color;
seriesOptions_["hoverBorderColor"] = Wt::Json::Value(color);
}

void WChartJSDataSeries::setHoverBorderWidth(int width) {
hoverBorderWidth_ = width;
seriesOptions_["hoverBorderWidth"] = Wt::Json::Value(width);
}

void WChartJSDataSeries::setIndexAxis(const std::string& axis) {
indexAxis_ = axis;
seriesOptions_["indexAxis"] = Wt::Json::Value(axis);
}

void WChartJSDataSeries::setOrder(int order) {
order_ = order;
seriesOptions_["order"] = Wt::Json::Value(order);
}

void WChartJSDataSeries::setParsing(bool shouldParse) {
parsing_ = shouldParse;
seriesOptions_["parsing"] = Wt::Json::Value(shouldParse);
}

void WChartJSDataSeries::setStack(const std::string& stackId) {
stack_ = stackId;
seriesOptions_["stack"] = Wt::Json::Value(stackId);
}

void WChartJSDataSeries::setXAxisID(const std::string& id) {
xAxisID_ = id;
seriesOptions_["xAxisID"] = Wt::Json::Value(id);
}

void WChartJSDataSeries::setYAxisID(const std::string& id) {
yAxisID_ = id;
seriesOptions_["yAxisID"] = Wt::Json::Value(id);
}

void WChartJSDataSeries::setHeaderTextPosition(HeaderText headerOrientation) {
if (headerOrientation == HeaderText::HORIZONTAL) {
headerTextOrientation_ = 'H';
seriesOptions_["headerTextOrientation"] = "H";
} else {
seriesOptions_["headerTextOrientation"] = "V";
headerTextOrientation_ = 'V';
}
}

// --- Line Chart Specific Options Implementation ---

void WChartJSDataSeries::setBorderCapStyle(const std::string& style) {
if (chartType_ != ChartJSType::LINE) assert(false);
borderCapStyle_ = style;
seriesOptions_["borderCapStyle"] = Wt::Json::Value(style);
}

void WChartJSDataSeries::setBorderDash(const Wt::Json::Array& dashPattern) {
if (chartType_ != ChartJSType::LINE) assert(false);
borderDash_ = dashPattern;
seriesOptions_["borderDash"] = Wt::Json::Array(dashPattern);
}

void WChartJSDataSeries::setBorderDashOffset(double offset) {
if (chartType_ != ChartJSType::LINE) assert(false);
borderDashOffset_ = offset;
seriesOptions_["borderDashOffset"] = Wt::Json::Value(offset);
}

void WChartJSDataSeries::setBorderJoinStyle(const std::string& style) {
if (chartType_ != ChartJSType::LINE) assert(false);
borderJoinStyle_ = style;
seriesOptions_["borderJoinStyle"] = Wt::Json::Value(style);
}

void WChartJSDataSeries::setCubicInterpolationMode(const std::string& mode) {
if (chartType_ != ChartJSType::LINE) assert(false);
cubicInterpolationMode_ = mode;
seriesOptions_["cubicInterpolationMode"] = Wt::Json::Value(mode);
}

void WChartJSDataSeries::setFill(bool fill) {
if (chartType_ != ChartJSType::LINE) assert(false);
fill_ = fill;
seriesOptions_["fill"] = Wt::Json::Value(fill);
}

void WChartJSDataSeries::setFill(const std::string& fill) {
if (chartType_ != ChartJSType::LINE) assert(false);
fill_ = fill;
seriesOptions_["fill"] = Wt::Json::Value(fill);
}

void WChartJSDataSeries::setPointBackgroundColor(const std::string& color) {
if (chartType_ != ChartJSType::LINE) assert(false);
pointBackgroundColor_ = color;
seriesOptions_["pointBackgroundColor"] = Wt::Json::Value(color);
}

void WChartJSDataSeries::setPointBorderColor(const std::string& color) {
if (chartType_ != ChartJSType::LINE) assert(false);
pointBorderColor_ = color;
seriesOptions_["pointBorderColor"] = Wt::Json::Value(color);
}

void WChartJSDataSeries::setPointBorderWidth(int width) {
if (chartType_ != ChartJSType::LINE) assert(false);
pointBorderWidth_ = width;
seriesOptions_["pointBorderWidth"] = Wt::Json::Value(width);
}

void WChartJSDataSeries::setPointHitRadius(int radius) {
if (chartType_ != ChartJSType::LINE) assert(false);
pointHitRadius_ = radius;
seriesOptions_["pointHitRadius"] = Wt::Json::Value(radius);
}

void WChartJSDataSeries::setPointHoverBackgroundColor(const std::string& color) {
if (chartType_ != ChartJSType::LINE) assert(false);
pointHoverBackgroundColor_ = color;
seriesOptions_["pointHoverBackgroundColor"] = Wt::Json::Value(color);
}

void WChartJSDataSeries::setPointHoverBorderColor(const std::string& color) {
if (chartType_ != ChartJSType::LINE) assert(false);
pointHoverBorderColor_ = color;
seriesOptions_["pointHoverBorderColor"] = Wt::Json::Value(color);
}

void WChartJSDataSeries::setPointHoverBorderWidth(int width) {
if (chartType_ != ChartJSType::LINE) assert(false);
pointHoverBorderWidth_ = width;
seriesOptions_["pointHoverBorderWidth"] = Wt::Json::Value(width);
}

void WChartJSDataSeries::setPointHoverRadius(int radius) {
if (chartType_ != ChartJSType::LINE) assert(false);
pointHoverRadius_ = radius;
seriesOptions_["pointHoverRadius"] = Wt::Json::Value(radius);
}

void WChartJSDataSeries::setPointRadius(int radius) {
if (chartType_ != ChartJSType::LINE) assert(false);
pointRadius_ = radius;
seriesOptions_["pointRadius"] = Wt::Json::Value(radius);
}

void WChartJSDataSeries::setPointRotation(int angle) {
if (chartType_ != ChartJSType::LINE) assert(false);
pointRotation_ = angle;
seriesOptions_["pointRotation"] = Wt::Json::Value(angle);
}

void WChartJSDataSeries::setPointStyle(const std::string& style) {
if (chartType_ != ChartJSType::LINE) assert(false);
pointStyle_ = style;
seriesOptions_["pointStyle"] = Wt::Json::Value(style);
}

void WChartJSDataSeries::setShowLine(bool show) {
if (chartType_ != ChartJSType::LINE) assert(false);
showLine_ = show;
seriesOptions_["showLine"] = Wt::Json::Value(show);
}

void WChartJSDataSeries::setSpanGaps(bool span) {
if (chartType_ != ChartJSType::LINE) assert(false);
spanGaps_ = span;
seriesOptions_["spanGaps"] = Wt::Json::Value(span);
}

void WChartJSDataSeries::setStepped(bool stepped) {
if (chartType_ != ChartJSType::LINE) assert(false);
stepped_ = stepped;
seriesOptions_["stepped"] = Wt::Json::Value(stepped);
}

void WChartJSDataSeries::setStepped(const std::string& stepped) {
if (chartType_ != ChartJSType::LINE) assert(false);
stepped_ = stepped;
seriesOptions_["stepped"] = Wt::Json::Value(stepped);
}

void WChartJSDataSeries::setTension(double tension) {
if (chartType_ != ChartJSType::LINE) assert(false);
tension_ = tension;
seriesOptions_["tension"] = Wt::Json::Value(tension);
}


// --- Bar Chart Specific Options Implementation ---

void WChartJSDataSeries::setBase(double baseValue) {
if (chartType_ != ChartJSType::BAR) assert(false);
base_ = baseValue;
seriesOptions_["base"] = Wt::Json::Value(baseValue);
}

void WChartJSDataSeries::setBarPercentage(double percentage) {
if (chartType_ != ChartJSType::BAR) assert(false);
barPercentage_ = percentage;
seriesOptions_["barPercentage"] = Wt::Json::Value(percentage);
}

void WChartJSDataSeries::setCategoryPercentage(double percentage) {
if (chartType_ != ChartJSType::BAR) assert(false);
categoryPercentage_ = percentage;
seriesOptions_["categoryPercentage"] = Wt::Json::Value(percentage);
}

void WChartJSDataSeries::setBorderRadius(int radius) {
if (chartType_ != ChartJSType::BAR) assert(false);
borderRadius_ = radius;
seriesOptions_["borderRadius"] = Wt::Json::Value(radius);
}

void WChartJSDataSeries::setBorderSkipped(const std::string& edge) {
if (chartType_ != ChartJSType::BAR) assert(false);
borderSkipped_ = edge;
seriesOptions_["borderSkipped"] = Wt::Json::Value(edge);
}

void WChartJSDataSeries::setGrouped(bool isGrouped) {
if (chartType_ != ChartJSType::BAR) assert(false);
grouped_ = isGrouped;
seriesOptions_["grouped"] = Wt::Json::Value(isGrouped);
}

void WChartJSDataSeries::setMinBarLength(int length) {
if (chartType_ != ChartJSType::BAR) assert(false);
minBarLength_ = length;
seriesOptions_["minBarLength"] = Wt::Json::Value(length);
}


// --- Pie & Doughnut Chart Specific Options Implementation ---

void WChartJSDataSeries::setBorderAlign(const std::string& alignment) {
if (chartType_ != ChartJSType::PIE && chartType_ != ChartJSType::DOUGHNUT) assert(false);
borderAlign_ = alignment;
seriesOptions_["borderAlign"] = Wt::Json::Value(alignment);
}

void WChartJSDataSeries::setHoverOffset(int offset) {
if (chartType_ != ChartJSType::PIE && chartType_ != ChartJSType::DOUGHNUT) assert(false);
hoverOffset_ = offset;
seriesOptions_["hoverOffset"] = Wt::Json::Value(offset);
}

void WChartJSDataSeries::setOffset(int offset) {
if (chartType_ != ChartJSType::PIE && chartType_ != ChartJSType::DOUGHNUT) assert(false);
offset_ = offset;
seriesOptions_["offset"] = Wt::Json::Value(offset);
}

void WChartJSDataSeries::setSpacing(int spacing) {
if (chartType_ != ChartJSType::PIE && chartType_ != ChartJSType::DOUGHNUT) assert(false);
spacing_ = spacing;
seriesOptions_["spacing"] = Wt::Json::Value(spacing);
}

void WChartJSDataSeries::setWeight(double weight) {
if (chartType_ != ChartJSType::PIE && chartType_ != ChartJSType::DOUGHNUT) assert(false);
weight_ = weight;
seriesOptions_["weight"] = Wt::Json::Value(weight);
}

void WChartJSDataSeries::setCutout(const std::string& cutout) {
if (chartType_ != ChartJSType::PIE && chartType_ != ChartJSType::DOUGHNUT) assert(false);
cutout_ = cutout;
seriesOptions_["cutout"] = Wt::Json::Value(cutout);
}
(9-9/9)