aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--barchart.cpp137
-rw-r--r--barchart.h23
-rw-r--r--main.cpp4
3 files changed, 120 insertions, 44 deletions
diff --git a/barchart.cpp b/barchart.cpp
index 3adf441..fb98219 100644
--- a/barchart.cpp
+++ b/barchart.cpp
@@ -1,6 +1,7 @@
#include "barchart.h"
#include <algorithm>
+#include <cmath>
#include <numeric>
#include <QOpenGLPaintDevice>
@@ -14,7 +15,9 @@
static const QColor OUTLINE_COLOR(0, 0, 0);
static const QColor BRUSH_COLOR(0, 0, 0);
static const QColor BAR_COLOR(128, 128, 128);
-static const QColor SELECTION_COLOR(128, 128, 128, 96);
+static const QColor PRESELECTION_COLOR(128, 128, 128, 96);
+static const QColor SELECTION_VISIBLE_COLOR(128, 128, 128, 96);
+static const QColor SELECTION_INVISIBLE_COLOR(0, 0, 0, 0);
static const float DEFAULT_OPACITY = 0.8f;
@@ -27,10 +30,11 @@ static inline T clamp(T value, T min, T max)
BarChart::BarChart(QQuickItem *parent)
: QQuickItem(parent)
, m_shouldUpdateBars(false)
- , m_brushedItem(-1)
- , m_shouldUpdateSelectionRect(false)
+ , m_shouldUpdatePreSelection(false)
, m_dragStartPos(-1.0f)
, m_dragLastPos(-1.0f)
+ , m_shouldUpdateSelection(false)
+ , m_brushedItem(-1)
, m_colorScale(ContinuousColorScale::builtin(ContinuousColorScale::HEATED_OBJECTS))
, m_scale(0.0f, 1.0f, 0.0f, 1.0f)
{
@@ -70,6 +74,7 @@ void BarChart::setValues(const arma::vec &values)
}
emit valuesChanged(values);
+ m_shouldUpdateSelection = true;
m_shouldUpdateBars = true;
update();
}
@@ -88,15 +93,15 @@ void BarChart::setColorScale(const ColorScale &scale)
void BarChart::setSelection(const std::vector<bool> &selection)
{
- if (m_selection.size() != selection.size()) {
- return;
- }
-
m_selection = selection;
emit selectionChanged(m_selection);
- m_shouldUpdateSelectionRect = true;
- update();
+ // Our selection changed but we don't want to display it unless we have the
+ // right number of values
+ if (m_values.size() == m_selection.size()) {
+ m_shouldUpdateSelection = true;
+ update();
+ }
}
void BarChart::brushItem(int item)
@@ -120,16 +125,28 @@ void BarChart::brushItem(int item)
QSGNode *BarChart::newSceneGraph() const
{
// NOTE: scene graph structure is as follows:
- // root [ barsNode [ ... ] selectionNode brushNode ]
+ // root [
+ // barsNode [
+ // barNode ...
+ // ]
+ // selectedBarsNode [
+ // selectedBarNode ...
+ // ]
+ // preSelectionNode
+ // brushNode
+ // ]
QSGTransformNode *root = new QSGTransformNode;
// The node that has all bars as children
root->appendChildNode(new QSGNode);
- // The node for drawing the selection rect
- QSGSimpleRectNode *selectionRectNode = new QSGSimpleRectNode;
- selectionRectNode->setColor(SELECTION_COLOR);
- root->appendChildNode(selectionRectNode);
+ // The node that has all selected bars as children
+ root->appendChildNode(new QSGNode);
+
+ // The node for the preselection
+ QSGSimpleRectNode *preSelectionNode = new QSGSimpleRectNode;
+ preSelectionNode->setColor(PRESELECTION_COLOR);
+ root->appendChildNode(preSelectionNode);
// The node for drawing the brush
QSGGeometryNode *brushGeomNode = new QSGGeometryNode;
@@ -184,6 +201,12 @@ QSGNode *BarChart::newBarNode() const
return opacityNode;
}
+QSGNode *BarChart::newSelectionBarNode() const
+{
+ QSGSimpleRectNode *node = new QSGSimpleRectNode;
+ return node;
+}
+
void BarChart::updateViewport(QSGNode *root) const
{
QSGTransformNode *viewportNode = static_cast<QSGTransformNode *>(root);
@@ -195,7 +218,7 @@ void BarChart::updateViewport(QSGNode *root) const
void BarChart::updateBarNodeGeom(QSGNode *barNode,
float x,
float barWidth,
- float barHeight)
+ float barHeight) const
{
float y = 1.0f - barHeight;
@@ -210,7 +233,7 @@ void BarChart::updateBarNodeGeom(QSGNode *barNode,
//outlineGeomNode->markDirty(QSGNode::DirtyGeometry);
}
-void BarChart::updateBarNodeColor(QSGNode *barNode, const QColor &color)
+void BarChart::updateBarNodeColor(QSGNode *barNode, const QColor &color) const
{
QSGGeometryNode *barGeomNode =
static_cast<QSGGeometryNode *>(barNode->firstChild());
@@ -221,7 +244,7 @@ void BarChart::updateBarNodeColor(QSGNode *barNode, const QColor &color)
barGeomNode->markDirty(QSGNode::DirtyMaterial);
}
-void BarChart::updateBars(QSGNode *node)
+void BarChart::updateBars(QSGNode *node) const
{
int numValues = (int) m_values.n_elem;
float barWidth = 1.0f / numValues;
@@ -248,7 +271,53 @@ void BarChart::updateBars(QSGNode *node)
}
}
-void BarChart::updateBrush(QSGNode *node)
+void BarChart::updateSelectionBar(QSGNode *node,
+ float x,
+ float barWidth,
+ const QColor &color) const
+{
+ QSGSimpleRectNode *barNode = static_cast<QSGSimpleRectNode *>(node);
+ barNode->setRect(x, 0, barWidth, 1.0f);
+ barNode->setColor(color);
+}
+
+void BarChart::updateSelectionBars(QSGNode *node) const
+{
+ int numValues = (int) m_values.n_elem;
+ float barWidth = 1.0f / numValues;
+
+ // First, make sure we have the same number of values & bars
+ while (numValues > node->childCount()) {
+ QSGNode *barNode = newSelectionBarNode();
+ node->prependChildNode(barNode);
+ }
+ while (numValues < node->childCount()) {
+ // NOTE: as stated in docs, QSGNode's children are stored in a
+ // linked list. Hence, this operation should be as fast as expected
+ node->removeChildNode(node->firstChild());
+ }
+
+ // Update each bar, displaying it (using a visible color) only if it is a
+ // selected item
+ float x = 0;
+ node = node->firstChild();
+ for (auto it = m_originalIndices.cbegin(); it != m_originalIndices.cend(); it++) {
+ updateSelectionBar(node, x, barWidth,
+ m_selection[*it] ? SELECTION_VISIBLE_COLOR
+ : SELECTION_INVISIBLE_COLOR);
+ x += barWidth;
+ node = node->nextSibling();
+ }
+}
+
+void BarChart::updatePreSelection(QSGNode *node) const
+{
+ QSGSimpleRectNode *preSelectionNode = static_cast<QSGSimpleRectNode *>(node);
+ preSelectionNode->setRect(std::min(m_dragStartPos, m_dragLastPos), 0.0f,
+ fabs(m_dragLastPos - m_dragStartPos), 1.0f);
+}
+
+void BarChart::updateBrush(QSGNode *node) const
{
float barWidth = 1.0f / m_values.n_elem;
QSGGeometryNode *brushGeomNode = static_cast<QSGGeometryNode *>(node);
@@ -260,18 +329,6 @@ void BarChart::updateBrush(QSGNode *node)
brushGeomNode->markDirty(QSGNode::DirtyGeometry);
}
-void BarChart::updateSelectionRect(QSGNode *node)
-{
- QSGSimpleRectNode *selectionGeomNode =
- static_cast<QSGSimpleRectNode *>(node);
-
- float x = m_dragStartPos,
- y = 0.0f,
- width = m_dragLastPos - m_dragStartPos,
- height = 1.0f;
- selectionGeomNode->setRect(x, y, width, height);
-}
-
QSGNode *BarChart::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
{
QSGNode *root = oldNode ? oldNode : newSceneGraph();
@@ -284,9 +341,15 @@ QSGNode *BarChart::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
}
node = node->nextSibling();
- if (m_shouldUpdateSelectionRect) {
- updateSelectionRect(node);
- m_shouldUpdateSelectionRect = false;
+ if (m_shouldUpdateSelection) {
+ updateSelectionBars(node);
+ m_shouldUpdateSelection = false;
+ }
+ node = node->nextSibling();
+
+ if (m_shouldUpdatePreSelection) {
+ updatePreSelection(node);
+ m_shouldUpdatePreSelection = false;
}
node = node->nextSibling();
@@ -369,7 +432,7 @@ void BarChart::mousePressEvent(QMouseEvent *event)
m_dragLastPos = pos;
}
- m_shouldUpdateSelectionRect = true;
+ m_shouldUpdatePreSelection = true;
update();
}
@@ -382,7 +445,7 @@ void BarChart::mouseMoveEvent(QMouseEvent *event)
float pos = float(event->pos().x()) / width();
m_dragLastPos = clamp(pos, 0.0f, 1.0f);
- m_shouldUpdateSelectionRect = true;
+ m_shouldUpdatePreSelection = true;
update();
}
@@ -401,6 +464,8 @@ void BarChart::mouseReleaseEvent(QMouseEvent *event)
interactiveSelection(m_dragStartPos, m_dragLastPos);
}
- m_shouldUpdateSelectionRect = true;
+ m_dragStartPos = -1.0f;
+ m_dragLastPos = -1.0f;
+ m_shouldUpdatePreSelection = true;
update();
}
diff --git a/barchart.h b/barchart.h
index e9de96d..98e3521 100644
--- a/barchart.h
+++ b/barchart.h
@@ -46,21 +46,28 @@ protected:
private:
QSGNode *newSceneGraph() const;
QSGNode *newBarNode() const;
+ QSGNode *newSelectionBarNode() const;
void updateViewport(QSGNode *root) const;
- void updateBarNodeGeom(QSGNode *barNode, float x, float width, float height);
- void updateBarNodeColor(QSGNode *barNode, const QColor &color);
- void updateBars(QSGNode *node);
- void updateBrush(QSGNode *node);
+ void updateBarNodeGeom(QSGNode *barNode, float x, float width, float height) const;
+ void updateBarNodeColor(QSGNode *barNode, const QColor &color) const;
+ void updateBars(QSGNode *node) const;
bool m_shouldUpdateBars;
- int m_brushedItem;
- void updateSelectionRect(QSGNode *node);
- bool m_shouldUpdateSelectionRect;
- void interactiveSelection(float start, float end);
+ void updatePreSelection(QSGNode *node) const;
+ bool m_shouldUpdatePreSelection;
float m_dragStartPos, m_dragLastPos;
+
+ void updateSelectionBar(QSGNode *node, float x, float barWidth, const QColor &color) const;
+ void updateSelectionBars(QSGNode *node) const;
+ bool m_shouldUpdateSelection;
+
+ void interactiveSelection(float start, float end);
std::vector<bool> m_selection;
+ void updateBrush(QSGNode *node) const;
+ int m_brushedItem;
+
int itemAt(float x, bool includeSelectorWidth = false) const;
arma::vec m_values;
diff --git a/main.cpp b/main.cpp
index a124ac3..6eed197 100644
--- a/main.cpp
+++ b/main.cpp
@@ -212,6 +212,8 @@ int main(int argc, char **argv)
&cpSelectionHandler, &SelectionHandler::setSelection);
QObject::connect(&cpSelectionHandler, &SelectionHandler::selectionChanged,
m->cpPlot, &Scatterplot::setSelection);
+ QObject::connect(&cpSelectionHandler, &SelectionHandler::selectionChanged,
+ m->cpBarChart, &BarChart::setSelection);
SelectionHandler rpSelectionHandler(X.n_rows - cpIndices.n_elem);
QObject::connect(m->rpPlot, &Scatterplot::selectionInteractivelyChanged,
@@ -220,6 +222,8 @@ int main(int argc, char **argv)
&rpSelectionHandler, &SelectionHandler::setSelection);
QObject::connect(&rpSelectionHandler, &SelectionHandler::selectionChanged,
m->rpPlot, &Scatterplot::setSelection);
+ QObject::connect(&rpSelectionHandler, &SelectionHandler::selectionChanged,
+ m->rpBarChart, &BarChart::setSelection);
// Brushing between bar chart and respective scatterplot
BrushingHandler cpBrushHandler;