Add graph animation; support for line graphs
[harbour-pedalo.git] / src / graph.cpp
index 338ab5e..d4a60d2 100644 (file)
@@ -11,9 +11,8 @@ Graph::Graph(QQuickItem *parent)
     , highlight(QColor("#0000ff"))
     , axisThickness(0.02)
     , bars(7)
+    , points(7)
     , gap(0.1)
-    , minmodel(0.0f)
-    , maxmodel(1.0f)
     , miny(0.0f)
     , maxy(1.0f)
     , stepy(0.1f)
@@ -21,7 +20,8 @@ Graph::Graph(QQuickItem *parent)
     , fontsize(24.0)
     , animate(1.0)
 {
-    model.clear();
+    bardata.clear();
+    linedata.clear();
     labelsx.clear();
     labelsy.clear();
 }
@@ -32,31 +32,46 @@ void Graph::paint(QPainter *painter) {
     float axiswidth;
     int count;
     int barfullwidth;
+    int pointfullwidth;
+    int labelfullwidth;
     float labelygap;
     float labelxgap;
-    int labels;
+    int labelsycount;
+    int labelsxcount;
     float labelheight;
+    float steps;
 
     QRectF size = contentsBoundingRect();
 
-    bars = model.length();
+    bars = bardata.length();
+    points = linedata.length();
+    labelsxcount = labelsx.length();
+
+    steps = labelsx.length();
+    if (steps == 0) {
+        steps = bars;
+    }
+
     labelygap = size.height() * 0.1l;
     labelxgap = size.width() * 0.11;
     axiswidth = qMin(size.width() * axisThickness, size.height() * axisThickness);
     barfullwidth = ((size.width() - labelxgap - axiswidth) / bars);
     barwidth = barfullwidth * (1.0 - gap);
-    labels = labelsy.length() > 0 ? labelsy.length() : 1 + (maxy - miny) / stepy;
-    labelheight = (size.height() - labelygap - axiswidth) / (labels - 0.5);
+    pointfullwidth = ((size.width() - labelxgap - axiswidth) / points);
+    labelsycount = labelsy.length() > 0 ? labelsy.length() : 1 + (maxy - miny) / stepy;
+    labelheight = (size.height() - labelygap - axiswidth) / (labelsycount - 0.5);
+    labelfullwidth = ((size.width() - labelxgap - axiswidth) / labelsxcount);
 
     QBrush axiscolour(primary);
     QBrush barcolour(secondary);
+    QBrush linecolour(highlight);
 
     painter->setBrush(axiscolour);
     painter->setPen(Qt::NoPen);
     painter->setRenderHint(QPainter::Antialiasing);
     painter->setOpacity(1.0);
 
-    const QPointF points[6] = {
+    const QPointF axis[6] = {
         QPointF(labelxgap, (labelheight / 2.0)),
         QPointF(labelxgap, size.height() - labelygap),
         QPointF(size.width(), size.height() - labelygap),
@@ -64,13 +79,13 @@ void Graph::paint(QPainter *painter) {
         QPointF(labelxgap + axiswidth, size.height() - labelygap - axiswidth),
         QPointF(labelxgap + axiswidth, (labelheight / 2.0))
     };
-    painter->drawPolygon(points, 6);
+    painter->drawPolygon(axis, 6);
 
     if (bars > 0) {
         painter->setBrush(barcolour);
 
         count = 0;
-        for (QList<float>::const_iterator iter = model.constBegin(); (count < bars) && (iter != model.constEnd()); iter++) {
+        for (QList<float>::const_iterator iter = bardata.constBegin(); (count < bars) && (iter != bardata.constEnd()); iter++) {
             float barheight = ((*iter) - miny) / (maxy - miny);
             barheight = qBound(0.0f, barheight, 1.0f) * (size.height() - labelygap - axiswidth - (labelheight / 2.0));
             barheight *= animate;
@@ -80,22 +95,42 @@ void Graph::paint(QPainter *painter) {
         }
     }
 
+    if (points > 0) {
+        QPen pen = QPen(linecolour, 8.0, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
+        painter->setPen(pen);
+        painter->setBrush(Qt::NoBrush);
+
+        QPointF point[points];
+        count = 0;
+        for (QList<float>::const_iterator iter = linedata.constBegin(); (count < points) && (iter != linedata.constEnd()); iter++) {
+            float lineheight = ((*iter) - miny) / (maxy - miny);
+            lineheight = qBound(0.0f, lineheight, 1.0f) * (size.height() - labelygap - axiswidth - (labelheight / 2.0));
+            point[count] = QPointF(labelxgap + axiswidth + (pointfullwidth * count) + (pointfullwidth / 2.0), size.height() - labelygap - lineheight - axiswidth);
+            count++;
+        }
+        painter->setClipRect(0, 0, labelxgap + axiswidth + (pointfullwidth / 2.0) - 8.0 + (size.width() - labelxgap - axiswidth - pointfullwidth + 16.0) * animate, size.height(), Qt::ReplaceClip);
+        painter->setClipping(true);
+        painter->drawPolyline(point, points);
+    }
+
+    painter->setClipping(false);
+
     QFont font = painter->font();
     font.setPixelSize(fontsize);
     painter->setFont(font);
     painter->setPen(primary);
     painter->setBrush(Qt::NoBrush);
 
-    if ((bars > 0) && (labelsx.length() == bars)) {
+    if (labelsxcount > 0) {
         for (count = 0; count < bars; count++) {
-            QRectF rect(labelxgap + axiswidth + (barfullwidth * count), size.height() - labelygap + 8.0, barfullwidth, labelygap - 8.0);
+            QRectF rect(labelxgap + axiswidth + (labelfullwidth * count), size.height() - labelygap + 8.0, labelfullwidth, labelygap - 8.0);
             painter->drawText(rect, Qt::AlignHCenter | Qt::NoClip | Qt::TextSingleLine, labelsx[count]);
             //painter->drawRect(rect);
         }
     }
 
     if (labelsy.length() > 0) {
-        for (count = 0; count < labels; count++) {
+        for (count = 0; count < labelsycount; count++) {
             QRectF rect(0, size.height() - (labelheight * (count + 0.5)) - labelygap, labelxgap - 8.0, labelheight);
             painter->drawText(rect, Qt::AlignVCenter | Qt::AlignRight | Qt::NoClip | Qt::TextSingleLine, labelsy[count]);
             //painter->drawRect(rect);
@@ -103,7 +138,7 @@ void Graph::paint(QPainter *painter) {
     }
     else {
         float labelvalue = miny;
-        for (count = 0; count < labels; count++) {
+        for (count = 0; count < labelsycount; count++) {
             QString labeltext = unitsy == "%" ? locale.toString(labelvalue * 100, 'f', 0) + "%" : locale.toString(labelvalue, 'g', 2) + unitsy;
             QRectF rect(0, size.height() - (labelheight * (count + 0.5)) - labelygap, labelxgap - 8.0, labelheight);
             painter->drawText(rect, Qt::AlignVCenter | Qt::AlignRight | Qt::NoClip | Qt::TextSingleLine, labeltext);
@@ -114,26 +149,22 @@ void Graph::paint(QPainter *painter) {
     }
 }
 
-QList<float> Graph::getModel() const {
-    return model;
+QList<float> Graph::getBarData() const {
+    return bardata;
 }
 
-void Graph::setModel(QList<float> value) {
-    model = value;
-    emit modelChanged();
-
-    if (model.length() > 0) {
-        minmodel = model[0];
-        maxmodel = minmodel;
-        foreach (int y, model) {
-            if (y < minmodel) {
-                minmodel = y;
-            }
-            if (y > maxmodel) {
-                maxmodel = y;
-            }
-        }
-    }
+void Graph::setBarData(QList<float> value) {
+    bardata = value;
+    emit barDataChanged();
+}
+
+QList<float> Graph::getLineData() const {
+    return linedata;
+}
+
+void Graph::setLineData(QList<float> value) {
+    linedata = value;
+    emit lineDataChanged();
 }
 
 QStringList Graph::getLabelsx() const {