Classes | Public Member Functions | Private Member Functions | Static Private Member Functions | Private Attributes

ChartConfig Class Reference
[Charts example]

A class that allows configuration of a cartesian chart. More...

#include <ChartConfig.h>

Inherits Wt::WContainerWidget.

List of all members.

Classes

struct  AxisControl
 Struct that holds the controls for one axis. More...
struct  SeriesControl
 Struct that holds the controls for one series. More...

Public Member Functions

 ChartConfig (Wt::Chart::WCartesianChart *chart, Wt::WContainerWidget *parent)
 Constructor.
void setValueFill (Wt::Chart::FillRangeType fill)

Private Member Functions

void connectSignals (Wt::WFormWidget *w)
void update ()

Static Private Member Functions

static bool validate (Wt::WFormWidget *w)

Private Attributes

Wt::Chart::WCartesianChartchart_
Wt::Chart::FillRangeType fill_
std::vector< SeriesControlseriesControls_
 Controls for series.
std::vector< AxisControlaxisControls_
 Controls for axes.
Wt::WLineEdittitleEdit_
Wt::WLineEditchartWidthEdit_
Wt::WLineEditchartHeightEdit_
Wt::WComboBoxchartOrientationEdit_

Detailed Description

A class that allows configuration of a cartesian chart.

This widget provides forms for configuring chart, series, and axis properties and manipulates the chart according to user settings.

This widget is part of the Wt charts example.

Definition at line 37 of file ChartConfig.h.


Constructor & Destructor Documentation

ChartConfig::ChartConfig ( Wt::Chart::WCartesianChart chart,
Wt::WContainerWidget parent 
)

Constructor.

Definition at line 60 of file ChartConfig.C.

  : WContainerWidget(parent),
    chart_(chart),
    fill_(MinimumValueFill)
{
  chart->initLayout();

  PanelList *list = new PanelList(this);

  WIntValidator *sizeValidator = new WIntValidator(200, 2000, this);
  sizeValidator->setMandatory(true);

  WDoubleValidator *anyNumberValidator = new WDoubleValidator(this);
  anyNumberValidator->setMandatory(true);

  WDoubleValidator *angleValidator = new WDoubleValidator(-90, 90, this);
  angleValidator->setMandatory(true);

  // ---- Chart properties ----

  WStandardItemModel *orientation = new WStandardItemModel(0, 1, this);
  addEntry(orientation, "Vertical");
  addEntry(orientation, "Horizontal");

  WTable *chartConfig = new WTable();
  chartConfig->setMargin(WLength::Auto, Left | Right);

  int row = 0;
  chartConfig->elementAt(row, 0)->addWidget(new WText("Title:"));
  titleEdit_ = new WLineEdit(chartConfig->elementAt(row, 1));
  connectSignals(titleEdit_);
  ++row;

  chartConfig->elementAt(row, 0)->addWidget(new WText("Width:"));
  chartWidthEdit_ = new WLineEdit(chartConfig->elementAt(row, 1));
  chartWidthEdit_
    ->setText(boost::lexical_cast<std::string>(chart_->width().value()));
  chartWidthEdit_->setValidator(sizeValidator);
  chartWidthEdit_->setMaxLength(4);
  connectSignals(chartWidthEdit_);
  ++row;

  chartConfig->elementAt(row, 0)->addWidget(new WText("Height:"));
  chartHeightEdit_ = new WLineEdit(chartConfig->elementAt(row, 1));
  chartHeightEdit_
    ->setText(boost::lexical_cast<std::string>(chart_->height().value()));
  chartHeightEdit_->setValidator(sizeValidator);
  chartHeightEdit_->setMaxLength(4);
  connectSignals(chartHeightEdit_);
  ++row;

  chartConfig->elementAt(row, 0)->addWidget(new WText("Orientation:"));
  chartOrientationEdit_ = new WComboBox(chartConfig->elementAt(row, 1));
  chartOrientationEdit_->setModel(orientation);
  connectSignals(chartOrientationEdit_);
  ++row;

  for (int i = 0; i < chartConfig->rowCount(); ++i) {
    chartConfig->elementAt(i, 0)->setStyleClass("tdhead");
    chartConfig->elementAt(i, 1)->setStyleClass("tddata");
  }

  WPanel *p = list->addWidget("Chart properties", chartConfig);
  p->setMargin(WLength::Auto, Left | Right);
  p->resize(750, WLength::Auto);
  p->setMargin(20, Top | Bottom);

  if (chart_->isLegendEnabled())
    chart_->setPlotAreaPadding(200, Right);

  // ---- Series properties ----

  WStandardItemModel *types = new WStandardItemModel(0, 1, this);
  addEntry(types, "Points");
  addEntry(types, "Line");
  addEntry(types, "Curve");
  addEntry(types, "Bar");
  addEntry(types, "Line Area");
  addEntry(types, "Curve Area");
  addEntry(types, "Stacked Bar");
  addEntry(types, "Stacked Line Area");
  addEntry(types, "Stacked Curve Area");

  WStandardItemModel *markers = new WStandardItemModel(0, 1, this);
  addEntry(markers, "None");
  addEntry(markers, "Square");
  addEntry(markers, "Circle");
  addEntry(markers, "Cross");
  addEntry(markers, "X cross");
  addEntry(markers, "Triangle");

  WStandardItemModel *axes = new WStandardItemModel(0, 1, this);
  addEntry(axes, "1st Y axis");
  addEntry(axes, "2nd Y axis");

  WStandardItemModel *labels = new WStandardItemModel(0, 1, this);
  addEntry(labels, "None");
  addEntry(labels, "X");
  addEntry(labels, "Y");
  addEntry(labels, "X: Y");

  WTable *seriesConfig = new WTable();
  seriesConfig->setMargin(WLength::Auto, Left | Right);

  ::addHeader(seriesConfig, "Name");
  ::addHeader(seriesConfig, "Enabled");
  ::addHeader(seriesConfig, "Type");
  ::addHeader(seriesConfig, "Marker");
  ::addHeader(seriesConfig, "Y axis");
  ::addHeader(seriesConfig, "Legend");
  ::addHeader(seriesConfig, "Shadow");
  ::addHeader(seriesConfig, "Value labels");

  seriesConfig->rowAt(0)->setStyleClass("trhead");

  for (int j = 1; j < chart->model()->columnCount(); ++j) {
    SeriesControl sc;

    new WText(asString(chart->model()->headerData(j)),
              seriesConfig->elementAt(j, 0));

    sc.enabledEdit = new WCheckBox(seriesConfig->elementAt(j, 1));
    connectSignals(sc.enabledEdit);

    sc.typeEdit = new WComboBox(seriesConfig->elementAt(j, 2));
    sc.typeEdit->setModel(types);
    connectSignals(sc.typeEdit);

    sc.markerEdit = new WComboBox(seriesConfig->elementAt(j, 3));
    sc.markerEdit->setModel(markers);
    connectSignals(sc.markerEdit);

    sc.axisEdit = new WComboBox(seriesConfig->elementAt(j, 4));
    sc.axisEdit->setModel(axes);
    connectSignals(sc.axisEdit);

    sc.legendEdit = new WCheckBox(seriesConfig->elementAt(j, 5));
    connectSignals(sc.legendEdit);

    sc.shadowEdit = new WCheckBox(seriesConfig->elementAt(j, 6));
    connectSignals(sc.shadowEdit);

    sc.labelsEdit = new WComboBox(seriesConfig->elementAt(j, 7));
    sc.labelsEdit->setModel(labels);
    connectSignals(sc.labelsEdit);

    int si = seriesIndexOf(chart, j);

    if (si != -1) {
      sc.enabledEdit->setChecked();
      const WDataSeries& s = chart_->series(j);
      switch (s.type()) {
      case PointSeries:
        sc.typeEdit->setCurrentIndex(0); break;
      case LineSeries:
        sc.typeEdit->setCurrentIndex(s.fillRange() != NoFill ?
                                     (s.isStacked() ? 7 : 4) : 1); break;
      case CurveSeries:
        sc.typeEdit->setCurrentIndex(s.fillRange() != NoFill ?
                                     (s.isStacked() ? 8 : 5) : 2); break;
      case BarSeries:
        sc.typeEdit->setCurrentIndex(s.isStacked() ? 6 : 3);
      }

      sc.markerEdit->setCurrentIndex((int)s.marker());
      sc.legendEdit->setChecked(s.isLegendEnabled());
      sc.shadowEdit->setChecked(s.shadow() != WShadow());
    }

    seriesControls_.push_back(sc);

    seriesConfig->rowAt(j)->setStyleClass("trdata");
  }

  p = list->addWidget("Series properties", seriesConfig);
  p->expand();
  p->setMargin(WLength::Auto, Left | Right);
  p->resize(750, WLength::Auto);
  p->setMargin(20, Top | Bottom);

  // ---- Axis properties ----

  WStandardItemModel *yScales = new WStandardItemModel(0, 1, this);
  addEntry(yScales, "Linear scale");
  addEntry(yScales, "Log scale");

  WStandardItemModel *xScales = new WStandardItemModel(0, 1, this);
  addEntry(xScales, "Categories");
  addEntry(xScales, "Linear scale");
  addEntry(xScales, "Log scale");
  addEntry(xScales, "Date scale");

  WTable *axisConfig = new WTable();
  axisConfig->setMargin(WLength::Auto, Left | Right);

  ::addHeader(axisConfig, "Axis");
  ::addHeader(axisConfig, "Visible");
  ::addHeader(axisConfig, "Scale");
  ::addHeader(axisConfig, "Automatic");
  ::addHeader(axisConfig, "Minimum");
  ::addHeader(axisConfig, "Maximum");
  ::addHeader(axisConfig, "Gridlines");
  ::addHeader(axisConfig, "Label angle");

  axisConfig->rowAt(0)->setStyleClass("trhead");

  for (int i = 0; i < 3; ++i) {
    const char *axisName[] = { "X axis", "1st Y axis", "2nd Y axis" };
    int j = i + 1;

    const WAxis& axis = chart_->axis(static_cast<Axis>(i));
    AxisControl sc;

    new WText(WString(axisName[i], UTF8), axisConfig->elementAt(j, 0));

    sc.visibleEdit = new WCheckBox(axisConfig->elementAt(j, 1));
    sc.visibleEdit->setChecked(axis.isVisible());
    connectSignals(sc.visibleEdit);

    sc.scaleEdit = new WComboBox(axisConfig->elementAt(j, 2));
    if (axis.scale() == CategoryScale)
      sc.scaleEdit->addItem("Category scale");
    else {
      if (axis.id() == XAxis) {
        sc.scaleEdit->setModel(xScales);
        sc.scaleEdit->setCurrentIndex(axis.scale());
      } else {
        sc.scaleEdit->setModel(yScales);
        sc.scaleEdit->setCurrentIndex(axis.scale() - 1);
      }
    }
    connectSignals(sc.scaleEdit);

    bool autoValues = axis.autoLimits() == (MinimumValue | MaximumValue);

    sc.minimumEdit = new WLineEdit(axisConfig->elementAt(j, 4));
    sc.minimumEdit->setText(boost::lexical_cast<std::string>(axis.minimum()));
    sc.minimumEdit->setValidator(anyNumberValidator);
    sc.minimumEdit->setEnabled(!autoValues);
    connectSignals(sc.minimumEdit);

    sc.maximumEdit = new WLineEdit(axisConfig->elementAt(j, 5));
    sc.maximumEdit->setText(boost::lexical_cast<std::string>(axis.maximum()));
    sc.maximumEdit->setValidator(anyNumberValidator);
    sc.maximumEdit->setEnabled(!autoValues);
    connectSignals(sc.maximumEdit);

    sc.autoEdit = new WCheckBox(axisConfig->elementAt(j, 3));
    sc.autoEdit->setChecked(autoValues);
    connectSignals(sc.autoEdit);
    sc.autoEdit->checked().connect(SLOT(sc.maximumEdit, WLineEdit::disable));
    sc.autoEdit->unChecked().connect(SLOT(sc.maximumEdit, WLineEdit::enable));
    sc.autoEdit->checked().connect(SLOT(sc.minimumEdit, WLineEdit::disable));
    sc.autoEdit->unChecked().connect(SLOT(sc.minimumEdit, WLineEdit::enable));

    sc.gridLinesEdit = new WCheckBox(axisConfig->elementAt(j, 6));
    connectSignals(sc.gridLinesEdit);

    sc.labelAngleEdit = new WLineEdit(axisConfig->elementAt(j, 7));
    sc.labelAngleEdit->setText("0");
    sc.labelAngleEdit->setValidator(angleValidator);
    connectSignals(sc.labelAngleEdit);

    axisConfig->rowAt(j)->setStyleClass("trdata");

    axisControls_.push_back(sc);
  }

  p = list->addWidget("Axis properties", axisConfig);
  p->setMargin(WLength::Auto, Left | Right);
  p->resize(750, WLength::Auto);
  p->setMargin(20, Top | Bottom);

  /*
   * If we do not have JavaScript, then add a button to reflect changes to
   * the chart.
   */
  if (!WApplication::instance()->environment().javaScript()) {
    WPushButton *b = new WPushButton(this);
    b->setText("Update chart");
    b->setInline(false); // so we can add margin to center horizontally
    b->setMargin(WLength::Auto, Left | Right);
    b->clicked().connect(SLOT(this, ChartConfig::update));
  }
}


Member Function Documentation

void ChartConfig::connectSignals ( Wt::WFormWidget w  )  [private]

Definition at line 521 of file ChartConfig.C.

{
  w->changed().connect(SLOT(this, ChartConfig::update));
  if (dynamic_cast<WLineEdit *>(w))
    w->enterPressed().connect(SLOT(this, ChartConfig::update));
}

void ChartConfig::setValueFill ( Wt::Chart::FillRangeType  fill  ) 

Definition at line 346 of file ChartConfig.C.

{
  fill_ = fill;
}

void ChartConfig::update (  )  [private]

Definition at line 351 of file ChartConfig.C.

{
  bool haveLegend = false;
  std::vector<WDataSeries> series;

  for (int i = 1; i < chart_->model()->columnCount(); ++i) {
    SeriesControl& sc = seriesControls_[i-1];

    if (sc.enabledEdit->isChecked()) {
      WDataSeries s(i);

      switch (sc.typeEdit->currentIndex()) {
      case 0:
        s.setType(PointSeries);
        if (sc.markerEdit->currentIndex() == 0)
          sc.markerEdit->setCurrentIndex(1);
        break;
      case 1:
        s.setType(LineSeries);
        break;
      case 2:
        s.setType(CurveSeries);
        break;
      case 3:
        s.setType(BarSeries);
        break;
      case 4:
        s.setType(LineSeries);
        s.setFillRange(fill_);
        break;
      case 5:
        s.setType(CurveSeries);
        s.setFillRange(fill_);
        break;
      case 6:
        s.setType(BarSeries);
        s.setStacked(true);
        break;
      case 7:
        s.setType(LineSeries);
        s.setFillRange(fill_);
        s.setStacked(true);
        break;
      case 8:
        s.setType(CurveSeries);
        s.setFillRange(fill_);
        s.setStacked(true);     
      }

      s.setMarker(static_cast<MarkerType>(sc.markerEdit->currentIndex()));

      if (sc.axisEdit->currentIndex() == 1) {
        s.bindToAxis(Y2Axis);
      }

      if (sc.legendEdit->isChecked()) {
        s.setLegendEnabled(true);
        haveLegend = true;
      } else
        s.setLegendEnabled(false);

      if (sc.shadowEdit->isChecked()) {
        s.setShadow(WShadow(3, 3, WColor(0, 0, 0, 127), 3));
      } else
        s.setShadow(WShadow());

      switch (sc.labelsEdit->currentIndex()) {
      case 1:
        s.setLabelsEnabled(XAxis);
        break;
      case 2:
        s.setLabelsEnabled(YAxis);
        break;
      case 3:
        s.setLabelsEnabled(XAxis);      
        s.setLabelsEnabled(YAxis);
        break;
      }

      series.push_back(s);
    }
  }

  chart_->setSeries(series);

  for (int i = 0; i < 3; ++i) {
    AxisControl& sc = axisControls_[i];
    WAxis& axis = chart_->axis(static_cast<Axis>(i));

    axis.setVisible(sc.visibleEdit->isChecked());

    if (sc.scaleEdit->count() != 1) {
      int k = sc.scaleEdit->currentIndex();
      if (axis.id() != XAxis)
        k += 1;
      else {
        if (k == 0)
          chart_->setType(CategoryChart);
        else
          chart_->setType(ScatterPlot);
      }

      switch (k) {
      case 1:
        axis.setScale(LinearScale); break;
      case 2:
        axis.setScale(LogScale); break;
      case 3:
        axis.setScale(DateScale); break;
      }
    }

    if (sc.autoEdit->isChecked())
      axis.setAutoLimits(MinimumValue | MaximumValue);
    else {
      if (validate(sc.minimumEdit) && validate(sc.maximumEdit)) {
        double min, max;
        getDouble(sc.minimumEdit, min);
        getDouble(sc.maximumEdit, max);

        if (axis.scale() == LogScale)
          if (min <= 0)
            min = 0.0001;

        axis.setRange(min, max);
      }

    }

    if (validate(sc.labelAngleEdit)) {
      double angle;
      getDouble(sc.labelAngleEdit, angle);
      axis.setLabelAngle(angle);
    }

    axis.setGridLinesEnabled(sc.gridLinesEdit->isChecked());
  }

  chart_->setTitle(titleEdit_->text());

  if (validate(chartWidthEdit_) && validate(chartHeightEdit_)) {
    double width, height;
    getDouble(chartWidthEdit_, width);
    getDouble(chartHeightEdit_, height);
    chart_->resize(width, height);
  }

  switch (chartOrientationEdit_->currentIndex()) {
  case 0:
    chart_->setOrientation(Vertical); break;
  case 1:
    chart_->setOrientation(Horizontal); break;
  }

  chart_->setLegendEnabled(haveLegend);
  chart_->setPlotAreaPadding(haveLegend ? 200 : 40, Right);
}

bool ChartConfig::validate ( Wt::WFormWidget w  )  [static, private]

Definition at line 509 of file ChartConfig.C.

{
  bool valid = w->validate() == WValidator::Valid;

  if (!WApplication::instance()->environment().javaScript()) {
    w->setStyleClass(valid ? "" : "Wt-invalid");
    w->setToolTip(valid ? "" : "Invalid value");
  }

  return valid;
}


Member Data Documentation

std::vector<AxisControl> ChartConfig::axisControls_ [private]

Controls for axes.

Definition at line 76 of file ChartConfig.h.

Definition at line 47 of file ChartConfig.h.

Definition at line 80 of file ChartConfig.h.

Definition at line 81 of file ChartConfig.h.

Definition at line 79 of file ChartConfig.h.

Definition at line 48 of file ChartConfig.h.

Controls for series.

Definition at line 62 of file ChartConfig.h.

Definition at line 78 of file ChartConfig.h.


The documentation for this class was generated from the following files:

Generated on Mon Nov 29 2010 08:03:14 for Wt by doxygen 1.7.1