Project

General

Profile

Improvements #12495 » WChartJSLibrary.h

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

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

#ifndef CHARTJSLIBRARY_H
#define CHARTJSLIBRARY_H

#include <Wt/WAbstractItemModel.h>
#include <Wt/WContainerWidget.h>
#include <Wt/Chart/WAbstractChartModel.h>
#include <Wt/Json/Array.h>
#include <Wt/Json/Object.h>
#include <Wt/WSignal.h>

enum class ChartJSType
{
BAR, BUBBLE, DOUGHNUT, PIE, LINE, POLAR, RADAR, SCATTER
};

enum class Location
{
TOP, BOTTOM, LEFT, RIGHT
};

enum class HeaderText {
HORIZONTAL = 'H', VERTICAL = 'V'
};
// typedef std::map<std::string, cpp17::any> SettingsMapType;

// Defaults set. Override if necessary
// chart colors are as follows
// red: 'rgb(255, 99, 132)',
// orange: 'rgb(255, 159, 64)',
// yellow: 'rgb(255, 205, 86)',
// green: 'rgb(75, 192, 192)',
// blue: 'rgb(54, 162, 235)',
// purple: 'rgb(153, 102, 255)',
// grey: 'rgb(201, 203, 207)'


// This class will always take on the same size as the parent container
class WChartJSLibrary : public Wt::WContainerWidget
{
public:
WChartJSLibrary(ChartJSType);
~WChartJSLibrary() override;

Wt::JSignal<int, int>& chartClicked() { return chartClicked_; }
// Returns the WStandardItemModel indexes
[[nodiscard]] std::pair<int, int> getModelCoordinates(int datasetIndex, int dataIndex) const;

// When calling this object, all desired options must be populated and
// completed with a call to showChart(). You cannot delay showing the chart if
// it's container is visible and this may show a malformed chart if you neglect
// this call at the end of initializing the data and options.
void buildAndShowChart();

// NOTE: This object tries to be as similar in operation to the Wt charts as
// possible in terms of the WStandardItemModel and Wt::Signals to change or update
// data through the Wt engines. Also incorporated is the WText/WString methods
// in order to maintain consistency with Wt translations. WSeries is too unique to
// Wt's javascript charting, so only the Model column is kept and serves as an index
// to series specific options.

std::string getChartJSType(ChartJSType);
void setModel(const std::shared_ptr<Wt::WAbstractItemModel>& model);
void setModel(const std::shared_ptr<Wt::Chart::WAbstractChartModel>& model);
std::shared_ptr<Wt::WAbstractItemModel> itemModel() const;
void addSeries(int modelColumn, bool countForLabels, Wt::Json::Object dataSeriesOptions, bool dependantIndependantSeries);
void addRawSeries(const Wt::Json::Object& rawSeries);
void resetSeries(int modelColumn);
void removeSeries(int modelColumn);
void removeLastRawSeries();
void updateExistingSeries();
void setXaxisLabels(const std::vector<std::string>&);
void updateChartTitleOnly(const Wt::WString& title);
void setOptions(const Wt::Json::Object& chartOptions);

protected:
void layoutSizeChanged(int width, int height) override;
void render(Wt::WFlags<Wt::RenderFlag> flags) override;
void modelChanged();
void updateModel();

private:
void defineJavaScript();
Wt::JSignal<int, int> chartClicked_;
Wt::Json::Object chartjsConfigObj{}; // This is where everything is defined
ChartJSType chartType_{};
std::string chartTypeName_{};
Wt::Json::Object chartOptions_{};
Wt::Json::Object plugins_{};
Wt::Json::Object chartData_{};
Wt::Json::Object netDataChangeJson_{}; // after chart creation to add net change
std::shared_ptr<Wt::Chart::WAbstractChartModel> model_ = nullptr;
std::shared_ptr<Wt::WAbstractItemModel> standardModel_ = nullptr;
// connections with the current model, used to disconnect from a model
// when the model changes.
std::vector<Wt::Signals::connection> modelConnections_{};

struct ModelColumnInfo
{
int modelColumnNumber{};
bool countForLabels{};
bool dependantIndependantSeries{};
int lastDataCount{};
};

std::vector<ModelColumnInfo> modelColumnsLoaded_{};
Wt::Json::Array series_{};
Wt::Json::Array dataLabels_{};
bool resized_ = false;
bool legendEnabled_ = false;
std::string legendLocation_{};
Wt::WStringStream legendOptions_{};
bool countForLabels_ = false;
bool titleEnabled_ = false;
Wt::WString titleText_{};
bool fullyRendered_ = false;
bool jsDefined_{};

template <typename T>
void set(T& m, const T& v);
};

template <typename T>
void WChartJSLibrary::set(T& m, const T& v) {
if (m != v) {
m = v;
}
}


#endif //CHARTJSLIBRARY_H
(3-3/9)