|
#include <Wt/WApplication>
|
|
#include <Wt/WStandardItemModel>
|
|
#include <Wt/WText>
|
|
#include <Wt/Chart/WCartesianChart>
|
|
#include <Wt/Dbo/Dbo>
|
|
#include <Wt/Dbo/backend/Sqlite3>
|
|
#include <Wt/Dbo/QueryModel>
|
|
#include <Wt/WDateTime>
|
|
#include <Wt/Dbo/WtSqlTraits>
|
|
#include <Wt/WCircleArea>
|
|
|
|
using namespace Wt;
|
|
|
|
constexpr int POINT_COUNT = 2000;
|
|
constexpr int NUM_DATE_TIMES = 20;
|
|
|
|
class DataPoint {
|
|
public:
|
|
int x;
|
|
int y;
|
|
std::string tooltip;
|
|
WDateTime dateTimes[NUM_DATE_TIMES];
|
|
|
|
template<class Action>
|
|
void persist(Action& a)
|
|
{
|
|
Dbo::field(a, x, "x");
|
|
Dbo::field(a, y, "y");
|
|
Dbo::field(a, tooltip, "tooltip");
|
|
for (int i = 0; i < NUM_DATE_TIMES; ++i) {
|
|
Dbo::field(a, dateTimes[i],
|
|
std::string("dt") + boost::lexical_cast<std::string>(i));
|
|
}
|
|
}
|
|
};
|
|
|
|
using DataPointPtr = Dbo::ptr<DataPoint>;
|
|
|
|
class DataPointQueryModel : public Dbo::QueryModel<DataPointPtr>
|
|
{
|
|
public:
|
|
DataPointQueryModel(WObject *parent = 0) :
|
|
Dbo::QueryModel<DataPointPtr>(parent) { }
|
|
|
|
boost::any data(const WModelIndex& index, int role) const
|
|
{
|
|
if (role == ToolTipRole && index.column() == 3)
|
|
return resultRow(index.row())->tooltip;
|
|
/*
|
|
* NOTE: The LinkRole is not currently supported for WCartesianCharts....
|
|
*/
|
|
else if (role == LinkRole && index.column() == 3)
|
|
return "https://duckduckgo.com";
|
|
else
|
|
return Dbo::QueryModel<DataPointPtr>::data(index, role);
|
|
}
|
|
};
|
|
|
|
class TestApplication : public WApplication
|
|
{
|
|
public:
|
|
TestApplication(const WEnvironment& env);
|
|
~TestApplication() { }
|
|
|
|
private:
|
|
Chart::WCartesianChart *chart_ = nullptr;
|
|
std::unique_ptr<Dbo::Session> session_;
|
|
std::unique_ptr<Dbo::backend::Sqlite3> sqlite3_;
|
|
};
|
|
|
|
TestApplication::TestApplication(const WEnvironment& env) : WApplication(env)
|
|
{
|
|
sqlite3_.reset(new Dbo::backend::Sqlite3(":memory:"));
|
|
session_.reset(new Dbo::Session);
|
|
session_->setConnection(*sqlite3_);
|
|
session_->mapClass<DataPoint>("data_point");
|
|
session_->createTables();
|
|
|
|
setTitle("WCartesianChart ToolTips CPU Usage Test");
|
|
|
|
new WText("<h5>Move mouse over chart and observe logged output for cpu time. Worst case is pausing mouse where there is no marker</h5>", root());
|
|
|
|
/*
|
|
* NOTE: An implementation based on map areas (wt 3.3.5) supports custom pointers when over a marker
|
|
*/
|
|
styleSheet().addRule(".test_chart area[shape=circle]", "cursor: pointer;");
|
|
|
|
{
|
|
Dbo::Transaction transaction(*session_);
|
|
for (int i = 0; i < POINT_COUNT; ++i) {
|
|
DataPoint *dp = new DataPoint();
|
|
dp->x = rand() % 1000;
|
|
dp->y = rand() % 1000;
|
|
dp->tooltip = std::string("Point number: ") + boost::lexical_cast<std::string>(i + 1);
|
|
|
|
for (int j = 0; j < NUM_DATE_TIMES; ++j)
|
|
dp->dateTimes[j] = WDateTime::currentDateTime();
|
|
|
|
session_->add(dp);
|
|
}
|
|
}
|
|
|
|
{
|
|
Dbo::Transaction transaction(*session_);
|
|
auto chartModel = new DataPointQueryModel(this);
|
|
chartModel->setQuery(session_->find<DataPoint>());
|
|
chartModel->addAllFieldsAsColumns();
|
|
|
|
/*
|
|
* NOTE: Enabling a large setBatchSize helps performance significantly
|
|
*/
|
|
// chartModel->setBatchSize(POINT_COUNT + 1);
|
|
|
|
chart_ = new Chart::WCartesianChart(Chart::ScatterPlot, root());
|
|
chart_->addStyleClass("test_chart");
|
|
chart_->resize(1100, 500);
|
|
chart_->setAutoLayoutEnabled();
|
|
chart_->setZoomEnabled();
|
|
chart_->setPanEnabled();
|
|
chart_->setModel(chartModel);
|
|
chart_->setXSeriesColumn(2);
|
|
chart_->addSeries(Chart::WDataSeries(3, Chart::PointSeries));
|
|
}
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
return WRun(argc, argv, [](const WEnvironment& env) {return new TestApplication(env);});
|
|
}
|