Wt examples  3.3.5
/usr/src/RPM/BUILD/wt-3.3.5-rc2/examples/charts/ChartsExample.C
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2008 Emweb bvba, Kessel-Lo, Belgium.
00003  *
00004  * See the LICENSE file for terms of use.
00005  */
00006 
00007 #include <math.h>
00008 #include <fstream>
00009 
00010 #include "ChartsExample.h"
00011 #include "ChartConfig.h"
00012 #include "CsvUtil.h"
00013 
00014 #include <Wt/WApplication>
00015 #include <Wt/WDate>
00016 #include <Wt/WEnvironment>
00017 #include <Wt/WItemDelegate>
00018 #include <Wt/WStandardItemModel>
00019 #include <Wt/WText>
00020 
00021 #include <Wt/WBorderLayout>
00022 #include <Wt/WFitLayout>
00023 
00024 #include <Wt/WStandardItem>
00025 #include <Wt/WTableView>
00026 
00027 #include <Wt/Chart/WCartesianChart>
00028 #include <Wt/Chart/WPieChart>
00029 
00030 using namespace Wt;
00031 using namespace Wt::Chart;
00032 
00033 namespace {
00034 
00035   /*
00036    * A standard item which converts text edits to numbers
00037    */
00038   class NumericItem : public WStandardItem {
00039   public:
00040     virtual NumericItem *clone() const {
00041       return new NumericItem();
00042     }
00043 
00044     virtual void setData(const boost::any &data, int role = UserRole) {
00045       boost::any dt;
00046 
00047       if (role == EditRole) {
00048         std::string s = Wt::asString(data).toUTF8();
00049         char *endptr;
00050         double d = strtod(s.c_str(), &endptr);
00051         if (*endptr == 0)
00052           dt = boost::any(d);
00053         else
00054           dt = data;
00055       }
00056 
00057       WStandardItem::setData(data, role);
00058     }
00059   };
00060 
00061   /*
00062    * Reads a CSV file as an (editable) standard item model.
00063    */
00064   WAbstractItemModel *readCsvFile(const std::string &fname,
00065                                   WContainerWidget *parent)
00066   {
00067     WStandardItemModel *model = new WStandardItemModel(0, 0, parent);
00068     model->setItemPrototype(new NumericItem());
00069     std::ifstream f(fname.c_str());
00070 
00071     if (f) {
00072       readFromCsv(f, model);
00073 
00074       for (int row = 0; row < model->rowCount(); ++row)
00075         for (int col = 0; col < model->columnCount(); ++col) {
00076           model->item(row, col)->setFlags(ItemIsSelectable | ItemIsEditable);
00077 
00078           /*
00079             Example of tool tips (disabled here because they are not updated
00080             when editing data)
00081            */
00082 
00083           /*
00084           WString toolTip = asString(model->headerData(col)) + ": "
00085             + asString(model->item(row, col)->data(DisplayRole), "%.f");
00086           model->item(row, col)->setToolTip(toolTip);
00087            */
00088         }
00089 
00090       return model;
00091     } else {
00092       WString error(WString::tr("error-missing-data"));
00093       error.arg(fname, UTF8);
00094       new WText(error, parent);
00095       return 0;
00096     }
00097   }
00098 }
00099 
00100 ChartsExample::ChartsExample(WContainerWidget *root)
00101   : WContainerWidget(root)
00102 {
00103   new WText(WString::tr("introduction"), this);
00104 
00105   new CategoryExample(this);
00106   new TimeSeriesExample(this);
00107   new ScatterPlotExample(this);
00108   new PieExample(this);
00109 }
00110 
00111 CategoryExample::CategoryExample(Wt::WContainerWidget *parent):
00112   WContainerWidget(parent)
00113 {
00114   new WText(WString::tr("category chart"), this);
00115 
00116   WAbstractItemModel *model
00117     = readCsvFile(WApplication::appRoot() + "category.csv", this);
00118 
00119   if (!model)
00120     return;
00121 
00122   // Show a view that allows editing of the model.
00123   WContainerWidget *w = new WContainerWidget(this);
00124   WTableView *table = new WTableView(w);
00125 
00126   table->setMargin(10, Top | Bottom);
00127   table->setMargin(WLength::Auto, Left | Right);
00128 
00129   table->setModel(model);
00130   table->setSortingEnabled(true);
00131   table->setColumnResizeEnabled(true);
00132   // table->setSelectionMode(ExtendedSelection);
00133   table->setAlternatingRowColors(true);
00134   table->setColumnAlignment(0, AlignCenter);
00135   table->setHeaderAlignment(0, AlignCenter);
00136   table->setRowHeight(22);
00137 
00138   // Editing does not really work without Ajax, it would require an
00139   // additional button somewhere to confirm the edited value.
00140   if (WApplication::instance()->environment().ajax()) {
00141     table->resize(600, 20 + 5*22);
00142     table->setEditTriggers(WAbstractItemView::SingleClicked);
00143   } else {
00144     table->resize(600, WLength::Auto);
00145     table->setEditTriggers(WAbstractItemView::NoEditTrigger);
00146   }
00147 
00148   // We use a single delegate for all items which rounds values to
00149   // the closest integer value.
00150   WItemDelegate *delegate = new WItemDelegate(this);
00151   delegate->setTextFormat("%.f");
00152   table->setItemDelegate(delegate);
00153 
00154   table->setColumnWidth(0, 80);
00155   for (int i = 1; i < model->columnCount(); ++i)
00156     table->setColumnWidth(i, 120);
00157 
00158   /*
00159    * Create the category chart.
00160    */
00161   WCartesianChart *chart = new WCartesianChart(this);
00162   chart->setModel(model);        // set the model
00163   chart->setXSeriesColumn(0);    // set the column that holds the categories
00164   chart->setLegendEnabled(true); // enable the legend
00165   chart->setZoomEnabled(true);
00166   chart->setPanEnabled(true);
00167 
00168   // Automatically layout chart (space for axes, legend, ...)
00169   chart->setAutoLayoutEnabled(true);
00170 
00171   chart->setBackground(WColor(200,200,200));
00172 
00173   /*
00174    * Add all (but first) column as bar series
00175    */
00176   for (int i = 1; i < model->columnCount(); ++i) {
00177     WDataSeries s(i, BarSeries);
00178     s.setShadow(WShadow(3, 3, WColor(0, 0, 0, 127), 3));
00179     chart->addSeries(s);
00180   }
00181 
00182   chart->resize(800, 400);
00183 
00184   chart->setMargin(10, Top | Bottom);
00185   chart->setMargin(WLength::Auto, Left | Right);
00186 
00187   /*
00188    * Provide a widget to manipulate chart properties
00189    */
00190   new ChartConfig(chart, this);
00191 }
00192 
00193 TimeSeriesExample::TimeSeriesExample(Wt::WContainerWidget *parent):
00194   WContainerWidget(parent)
00195 {
00196   new WText(WString::tr("scatter plot"), this);
00197 
00198   WAbstractItemModel *model = readCsvFile(
00199     WApplication::appRoot() + "timeseries.csv", this);
00200 
00201   if (!model)
00202     return;
00203 
00204   /*
00205    * Parses the first column as dates, to be able to use a date scale
00206    */
00207   for (int i = 0; i < model->rowCount(); ++i) {
00208     WString s = asString(model->data(i, 0));
00209     WDate d = WDate::fromString(s, "dd/MM/yy");
00210     model->setData(i, 0, d);
00211   }
00212 
00213   // Show a view that allows editing of the model.
00214   WContainerWidget *w = new WContainerWidget(this);
00215   WTableView *table = new WTableView(w);
00216 
00217   table->setMargin(10, Top | Bottom);
00218   table->setMargin(WLength::Auto, Left | Right);
00219 
00220   table->setModel(model);
00221   table->setSortingEnabled(false); // Does not make much sense for time series
00222   table->setColumnResizeEnabled(true);
00223   table->setSelectionMode(NoSelection);
00224   table->setAlternatingRowColors(true);
00225   table->setColumnAlignment(0, AlignCenter);
00226   table->setHeaderAlignment(0, AlignCenter);
00227   table->setRowHeight(22);
00228 
00229   // Editing does not really work without Ajax, it would require an
00230   // additional button somewhere to confirm the edited value.
00231   if (WApplication::instance()->environment().ajax()) {
00232     table->resize(800, 20 + 5*22);
00233     table->setEditTriggers(WAbstractItemView::SingleClicked);
00234   } else {
00235     table->resize(800, 20 + 5*22 + 25);
00236     table->setEditTriggers(WAbstractItemView::NoEditTrigger);
00237   }
00238 
00239   WItemDelegate *delegate = new WItemDelegate(this);
00240   delegate->setTextFormat("%.1f");
00241   table->setItemDelegate(delegate);
00242   table->setItemDelegateForColumn(0, new WItemDelegate(this));
00243 
00244   table->setColumnWidth(0, 80);
00245   for (int i = 1; i < model->columnCount(); ++i)
00246     table->setColumnWidth(i, 90);
00247 
00248   /*
00249    * Create the scatter plot.
00250    */
00251   WCartesianChart *chart = new WCartesianChart(this);
00252   //chart->setPreferredMethod(WPaintedWidget::PngImage);
00253   //chart->setBackground(gray);
00254   chart->setModel(model);        // set the model
00255   chart->setXSeriesColumn(0);    // set the column that holds the X data
00256   chart->setLegendEnabled(true); // enable the legend
00257   chart->setZoomEnabled(true);
00258   chart->setPanEnabled(true);
00259 
00260   chart->setType(ScatterPlot);            // set type to ScatterPlot
00261   chart->axis(XAxis).setScale(DateScale); // set scale of X axis to DateScale
00262 
00263   // Automatically layout chart (space for axes, legend, ...)
00264   chart->setAutoLayoutEnabled();
00265 
00266   chart->setBackground(WColor(200,200,200));
00267  /*
00268    * Add first two columns as line series
00269    */
00270   for (int i = 1; i < 3; ++i) {
00271     WDataSeries s(i, LineSeries);
00272     s.setShadow(WShadow(3, 3, WColor(0, 0, 0, 127), 3));
00273     chart->addSeries(s);
00274   }
00275 
00276   chart->resize(800, 400); // WPaintedWidget must be given explicit size
00277 
00278   chart->setMargin(10, Top | Bottom);            // add margin vertically
00279   chart->setMargin(WLength::Auto, Left | Right); // center horizontally
00280 
00281   new ChartConfig(chart, this);
00282 }
00283 
00284 ScatterPlotExample::ScatterPlotExample(WContainerWidget *parent):
00285   WContainerWidget(parent)
00286 {
00287   new WText(WString::tr("scatter plot 2"), this);
00288 
00289   WStandardItemModel *model = new WStandardItemModel(40, 2, this);
00290   model->setItemPrototype(new NumericItem());
00291   model->setHeaderData(0, WString("X"));
00292   model->setHeaderData(1, WString("Y = sin(X)"));
00293 
00294   for (unsigned i = 0; i < 40; ++i) {
00295     double x = (static_cast<double>(i) - 20) / 4;
00296 
00297     model->setData(i, 0, x);
00298     model->setData(i, 1, sin(x));
00299   }
00300  
00301   /*
00302    * Create the scatter plot.
00303    */
00304   WCartesianChart *chart = new WCartesianChart(this);
00305   chart->setModel(model);        // set the model
00306   chart->setXSeriesColumn(0);    // set the column that holds the X data
00307   chart->setLegendEnabled(true); // enable the legend
00308   chart->setZoomEnabled(true);
00309   chart->setPanEnabled(true);
00310   chart->setCrosshairEnabled(true);
00311 
00312   chart->setBackground(WColor(200,200,200));
00313 
00314   chart->setType(ScatterPlot);   // set type to ScatterPlot
00315 
00316   // Typically, for mathematical functions, you want the axes to cross
00317   // at the 0 mark:
00318   chart->axis(XAxis).setLocation(ZeroValue);
00319   chart->axis(YAxis).setLocation(ZeroValue);
00320 
00321   // Automatically layout chart (space for axes, legend, ...)
00322   chart->setAutoLayoutEnabled();
00323 
00324   // Add the curves
00325   WDataSeries s(1, CurveSeries);
00326   s.setShadow(WShadow(3, 3, WColor(0, 0, 0, 127), 3));
00327   chart->addSeries(s);
00328 
00329   chart->resize(800, 300); // WPaintedWidget must be given explicit size
00330 
00331   chart->setMargin(10, Top | Bottom);            // add margin vertically
00332   chart->setMargin(WLength::Auto, Left | Right); // center horizontally
00333 
00334   ChartConfig *config = new ChartConfig(chart, this);
00335   config->setValueFill(ZeroValueFill);
00336 }
00337 
00338 PieExample::PieExample(WContainerWidget *parent):
00339   WContainerWidget(parent)
00340 {
00341   new WText(WString::tr("pie chart"), this);
00342 
00343   WStandardItemModel *model = new WStandardItemModel(this);
00344   model->setItemPrototype(new NumericItem());
00345   
00346   //headers
00347   model->insertColumns(model->columnCount(), 2);
00348   model->setHeaderData(0, WString("Item"));
00349   model->setHeaderData(1, WString("Sales"));
00350 
00351   //data
00352   model->insertRows(model->rowCount(), 6);
00353   int row = 0;
00354   model->setData(row, 0, WString("Blueberry"));
00355   model->setData(row, 1, 120);
00356   // model->setData(row, 1, WString("Blueberry"), ToolTipRole);
00357   row++;
00358   model->setData(row, 0, WString("Cherry"));
00359   model->setData(row, 1, 30);
00360   row++;
00361   model->setData(row, 0, WString("Apple"));
00362   model->setData(row, 1, 260);
00363   row++;
00364   model->setData(row, 0, WString("Boston Cream"));
00365   model->setData(row, 1, 160);
00366   row++;
00367   model->setData(row, 0, WString("Other"));
00368   model->setData(row, 1, 40);
00369   row++;
00370   model->setData(row, 0, WString("Vanilla Cream"));
00371   model->setData(row, 1, 120);
00372   row++;
00373 
00374   //set all items to be editable and selectable
00375   for (int row = 0; row < model->rowCount(); ++row)
00376     for (int col = 0; col < model->columnCount(); ++col)
00377       model->item(row, col)->setFlags(ItemIsSelectable | ItemIsEditable);
00378 
00379   WContainerWidget *w = new WContainerWidget(this);
00380   WTableView* table = new WTableView(w);
00381 
00382   table->setMargin(10, Top | Bottom);
00383   table->setMargin(WLength::Auto, Left | Right);
00384   table->setSortingEnabled(true);
00385   table->setModel(model);
00386   table->setColumnWidth(1, 100);
00387   table->setRowHeight(22);
00388 
00389   if (WApplication::instance()->environment().ajax()) {
00390     table->resize(150 + 100 + 14, 20 + 6 * 22);
00391     table->setEditTriggers(WAbstractItemView::SingleClicked);
00392   } else {
00393     table->resize(150 + 100 + 14, WLength::Auto);
00394     table->setEditTriggers(WAbstractItemView::NoEditTrigger);    
00395   }
00396 
00397   /*
00398    * Create the pie chart.
00399    */
00400   WPieChart *chart = new WPieChart(this);
00401   chart->setModel(model);       // set the model
00402   chart->setLabelsColumn(0);    // set the column that holds the labels
00403   chart->setDataColumn(1);      // set the column that holds the data
00404 
00405   // configure location and type of labels
00406   chart->setDisplayLabels(Outside | TextLabel | TextPercentage);
00407 
00408   // enable a 3D and shadow effect
00409   chart->setPerspectiveEnabled(true, 0.2);
00410   chart->setShadowEnabled(true);
00411 
00412   // explode the first item
00413   chart->setExplode(0, 0.3);
00414 
00415   chart->resize(800, 300); // WPaintedWidget must be given an explicit size
00416 
00417   chart->setMargin(10, Top | Bottom);            // add margin vertically
00418   chart->setMargin(WLength::Auto, Left | Right); // center horizontally
00419 }
00420 

Generated on Tue Mar 22 2016 for the C++ Web Toolkit (Wt) by doxygen 1.7.6.1