|
Wt examples
3.3.5
|
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
1.7.6.1