PieChart.cpp

#include "PieChart.h"

#include "textfunctions.h"

using namespace std;





/**
 *  Write the necessary junk for the top of the chart
 */
static void writeTopBoilerPlateOfPieChart( ostream& out) {
    out<<("<html>\n");
    out<<("<head>\n");
    out<<("<!--Load the AJAX API-->\n");
    out<<("<script type=\"text/javascript\"");
    out<<("src=\"https://www.google.com/jsapi\">");
    out<<("</script>\n");
    out<<("<script type=\"text/javascript\">\n");
    out<<("google.load('visualization', '1.0', {'packages':['corechart']});\n");
    out<<("google.setOnLoadCallback(drawChart);\n");
    out<<("function drawChart() {\n");
    out<<("var data = new google.visualization.DataTable();\n");
    out<<("data.addColumn('string', 'Label');\n");
    out<<("data.addColumn('number', 'Value');\n");
}


/**
 *  Write the intesting bit of the Pie Chart
 */
static void writeDataOfPieChart( ostream& out,
                                const vector<string>& labels,
                                const vector<double>& values) {
    out<< "data.addRows([\n";
    int nLabels = labels.size();
    for (int i=0; i<nLabels; i++) {
        string label = labels[i];
        double value = values[i];
        out<<"['"<<escapeJavascriptString(label)<<"', "<<value<<"]";
        if (i!=nLabels-1) {
            out<<",";
        }
        out<<"\n";
    }
    out<<"]);\n";
}

/**
 *  Write the boring bit at the bottom of a pie chart
 */
static void writeBottomBoilerPlateOfPieChart( ostream & out, std::string title ) {
    out<<"var options = {'title':'"<<escapeJavascriptString(title)<<"',\n";
    out<<"'width':400,\n";
    out<<"'height':300\n";
    out<<"};\n";
    out<<"var chart = new google.visualization.PieChart(document.getElementById('chart_div'));\n";
    out<<"chart.draw(data, options);\n";
    out<<"}\n";
    out<<"</script>\n";
    out<<"</head>\n";
    out<<"<body>\n";
    out<<"<div id='chart_div'>\n";
    out<<"</body>\n";
    out<<"</html>";
}


////////////////////////
// Pie Chart implementation
////////////////////////


PieChart::PieChart() :
    title("A Pie Chart") {
}



void PieChart::setTitle( const std::string& t ) {
    title = t;
}

void PieChart::addEntry( const string& label,
                         double value ) {
    labels.push_back( label );
    values.push_back( value );
}

void PieChart::writeAsHTML( ostream& out ) const {
    writeTopBoilerPlateOfPieChart(out);
    writeDataOfPieChart( out, labels, values );
    writeBottomBoilerPlateOfPieChart( out, title );
}


void PieChart::writeAsHTML( const string& file ) const {
    ofstream out;
    out.open(file.c_str());
    writeAsHTML( out );
    out.close();
}





///////////////////////////////////////////
//
//   Tests for pie chart
//
///////////////////////////////////////////



static void testPieChartData() {
    // this test automates the checking
    stringstream out;
    vector<string> labels(3);
    vector<double> vals(3);
    for (int i=0; i<3; i++) {
        stringstream ss;
        ss<<"A Label "<<i;
        labels[i] =ss.str();
        INFO( labels[i] );
        vals[i]=(double)i;
    }
    writeDataOfPieChart( out,
              labels,
              vals );
    string asString = out.str();

    stringstream expected;
    expected<<"data.addRows([\n";
    expected<<"['A Label 0', 0],\n";
    expected<<"['A Label 1', 1],\n";
    expected<<"['A Label 2', 2]\n";
    expected<<"]);\n";
    string expectedStr = expected.str();
    ASSERT( asString==expectedStr );
}

static void testPieChartClass() {
    // just checks that the class compiles etc.
    PieChart pieChart;
    pieChart.addEntry("Mushrooms",200);
    pieChart.addEntry("Salami",100);
    pieChart.addEntry("Spinach",150);
    pieChart.setTitle("Pizza Toppings");

    pieChart.writeAsHTML( "PizzaPie.html" );
}



void testPieChart() {
    TEST( testPieChartData );
    TEST( testPieChartClass );
}