A graph more interesting than a straight line

master
Jos van den Oever 2017-09-03 12:09:05 +02:00
parent 8893dc596b
commit 18d771d358
8 changed files with 226 additions and 118 deletions

View File

@ -131,15 +131,20 @@
"TimeSeries": {
"type": "List",
"itemProperties": {
"input": {
"type": "quint32",
"time": {
"type": "float",
"write": true,
"roles": [ [ "display", "edit" ] ]
},
"result": {
"type": "quint32",
"sin": {
"type": "float",
"write": true,
"roles": [ [], [ "display", "edit" ] ]
},
"cos": {
"type": "float",
"write": true,
"roles": [ [], [], [ "display", "edit" ] ]
}
}
}

View File

@ -4,12 +4,14 @@ import QtQuick.Controls 1.5
import QtQuick.Layouts 1.3
RowLayout {
anchors.fill: parent
Component {
id: editableDelegate
Item {
function round(v) {
return Math.round(1000 * v) / 1000
}
Text {
text: styleData.value
text: round(styleData.value)
visible: !styleData.selected
}
Loader {
@ -24,9 +26,11 @@ RowLayout {
var val = loaderEditor.item.text
var row = styleData.row
if (styleData.column === 0) {
demo.timeSeries.setInput(row, val)
demo.timeSeries.setTime(row, val)
} else if (styleData.column === 1) {
demo.timeSeries.setSin(row, val)
} else {
demo.timeSeries.setResult(row, val)
demo.timeSeries.setCos(row, val)
}
}
}
@ -36,7 +40,7 @@ RowLayout {
id: editor
TextInput {
id: textInput
text: styleData.value
text: round(styleData.value)
MouseArea {
anchors.fill: parent
hoverEnabled: true
@ -46,34 +50,41 @@ RowLayout {
}
}
}
TableView {
model: demo.timeSeries
Layout.fillHeight: true
TableViewColumn {
role: "input"
title: qsTr("input")
SplitView {
anchors.fill: parent
TableView {
model: demo.timeSeries
Layout.fillHeight: true
TableViewColumn {
role: "time"
title: qsTr("time")
}
TableViewColumn {
role: "sin"
title: qsTr("sin")
}
TableViewColumn {
role: "cos"
title: qsTr("cos")
}
itemDelegate: {
return editableDelegate
}
}
TableViewColumn {
role: "result"
title: qsTr("result")
}
itemDelegate: {
return editableDelegate
}
}
Item {
Layout.fillWidth: true
Layout.fillHeight: true
Text {
anchors.centerIn: parent
text: qsTr("QtChart is not available.")
visible: chartLoader.status !== Loader.Ready
}
Loader {
anchors.fill: parent
id: chartLoader
source: "chart.qml"
Item {
Layout.fillWidth: true
Layout.fillHeight: true
Text {
anchors.centerIn: parent
text: qsTr("QtChart is not available.")
visible: chartLoader.status !== Loader.Ready
}
Loader {
anchors.fill: parent
id: chartLoader
source: "chart.qml"
}
}
}
}

View File

@ -11,21 +11,19 @@ Item {
antialiasing: true
DateTimeAxis {
ValueAxis {
id: axisX
titleText: "Date"
format: "MMM yyyy"
tickCount: 10
titleText: qsTr("time [s]")
}
ValueAxis {
id: axisY
titleText: "Sunspots count"
titleText: qsTr("electric potential [V]")
}
LineSeries {
id: cpu
name: "CPU"
id: sin
name: "sin"
axisX: axisX
axisY: axisY
}
@ -34,7 +32,21 @@ Item {
model: demo.timeSeries
xColumn: 0
yColumn: 1
series: cpu
series: sin
}
LineSeries {
id: cos
name: "cos"
axisX: axisX
axisY: axisY
}
VXYModelMapper {
model: demo.timeSeries
xColumn: 0
yColumn: 2
series: cos
}
}
}

View File

@ -2,8 +2,9 @@ use interface::*;
#[derive(Default, Clone)]
struct TimeSeriesItem {
input: u32,
result: u32,
time: f32,
sin: f32,
cos: f32,
}
pub struct TimeSeries {
@ -18,9 +19,11 @@ impl TimeSeriesTrait for TimeSeries {
list: Vec::new(),
};
for i in 0..100 {
let x = i as f32 / 10.;
series.list.push(TimeSeriesItem {
input: i,
result: 2 * i,
time: x,
sin: x.sin(),
cos: x.cos(),
});
}
series
@ -31,18 +34,25 @@ impl TimeSeriesTrait for TimeSeries {
fn row_count(&self) -> usize {
self.list.len() as usize
}
fn input(&self, row: usize) -> u32 {
self.list[row as usize].input
fn time(&self, row: usize) -> f32 {
self.list[row as usize].time
}
fn set_input(&mut self, row: usize, v: u32) -> bool {
self.list[row as usize].input = v;
fn set_time(&mut self, row: usize, v: f32) -> bool {
self.list[row as usize].time = v;
true
}
fn result(&self, row: usize) -> u32 {
self.list[row as usize].result
fn sin(&self, row: usize) -> f32 {
self.list[row as usize].sin
}
fn set_result(&mut self, row: usize, v: u32) -> bool {
self.list[row as usize].result = v;
fn set_sin(&mut self, row: usize, v: f32) -> bool {
self.list[row as usize].sin = v;
true
}
fn cos(&self, row: usize) -> f32 {
self.list[row as usize].cos
}
fn set_cos(&mut self, row: usize, v: f32) -> bool {
self.list[row as usize].cos = v;
true
}
}

View File

@ -1087,10 +1087,12 @@ pub trait TimeSeriesTrait {
}
fn fetch_more(&mut self) {}
fn sort(&mut self, u8, SortOrder) {}
fn input(&self, item: usize) -> u32;
fn set_input(&mut self, item: usize, u32) -> bool;
fn result(&self, item: usize) -> u32;
fn set_result(&mut self, item: usize, u32) -> bool;
fn cos(&self, item: usize) -> f32;
fn set_cos(&mut self, item: usize, f32) -> bool;
fn sin(&self, item: usize) -> f32;
fn set_sin(&mut self, item: usize, f32) -> bool;
fn time(&self, item: usize) -> f32;
fn set_time(&mut self, item: usize, f32) -> bool;
}
#[no_mangle]
@ -1150,27 +1152,40 @@ pub unsafe extern "C" fn time_series_sort(
}
#[no_mangle]
pub unsafe extern "C" fn time_series_data_input(ptr: *const TimeSeries, row: c_int) -> u32 {
(&*ptr).input(row as usize).into()
pub unsafe extern "C" fn time_series_data_cos(ptr: *const TimeSeries, row: c_int) -> f32 {
(&*ptr).cos(row as usize).into()
}
#[no_mangle]
pub unsafe extern "C" fn time_series_set_data_input(
pub unsafe extern "C" fn time_series_set_data_cos(
ptr: *mut TimeSeries, row: c_int,
v: u32,
v: f32,
) -> bool {
(&mut *ptr).set_input(row as usize, v)
(&mut *ptr).set_cos(row as usize, v)
}
#[no_mangle]
pub unsafe extern "C" fn time_series_data_result(ptr: *const TimeSeries, row: c_int) -> u32 {
(&*ptr).result(row as usize).into()
pub unsafe extern "C" fn time_series_data_sin(ptr: *const TimeSeries, row: c_int) -> f32 {
(&*ptr).sin(row as usize).into()
}
#[no_mangle]
pub unsafe extern "C" fn time_series_set_data_result(
pub unsafe extern "C" fn time_series_set_data_sin(
ptr: *mut TimeSeries, row: c_int,
v: u32,
v: f32,
) -> bool {
(&mut *ptr).set_result(row as usize, v)
(&mut *ptr).set_sin(row as usize, v)
}
#[no_mangle]
pub unsafe extern "C" fn time_series_data_time(ptr: *const TimeSeries, row: c_int) -> f32 {
(&*ptr).time(row as usize).into()
}
#[no_mangle]
pub unsafe extern "C" fn time_series_set_data_time(
ptr: *mut TimeSeries, row: c_int,
v: f32,
) -> bool {
(&mut *ptr).set_time(row as usize, v)
}

View File

@ -716,10 +716,12 @@ extern "C" {
};
extern "C" {
uint time_series_data_input(const TimeSeries::Private*, int);
bool time_series_set_data_input(TimeSeries::Private*, int, uint);
uint time_series_data_result(const TimeSeries::Private*, int);
bool time_series_set_data_result(TimeSeries::Private*, int, uint);
float time_series_data_cos(const TimeSeries::Private*, int);
bool time_series_set_data_cos(TimeSeries::Private*, int, float);
float time_series_data_sin(const TimeSeries::Private*, int);
bool time_series_set_data_sin(TimeSeries::Private*, int, float);
float time_series_data_time(const TimeSeries::Private*, int);
bool time_series_set_data_time(TimeSeries::Private*, int, float);
void time_series_sort(TimeSeries::Private*, unsigned char column, Qt::SortOrder order = Qt::AscendingOrder);
int time_series_row_count(const TimeSeries::Private*);
@ -728,7 +730,7 @@ extern "C" {
}
int TimeSeries::columnCount(const QModelIndex &parent) const
{
return (parent.isValid()) ? 0 : 2;
return (parent.isValid()) ? 0 : 3;
}
bool TimeSeries::hasChildren(const QModelIndex &parent) const
@ -743,7 +745,7 @@ int TimeSeries::rowCount(const QModelIndex &parent) const
QModelIndex TimeSeries::index(int row, int column, const QModelIndex &parent) const
{
if (!parent.isValid() && row >= 0 && row < rowCount(parent) && column >= 0 && column < 2) {
if (!parent.isValid() && row >= 0 && row < rowCount(parent) && column >= 0 && column < 3) {
return createIndex(row, column, (quintptr)row);
}
return QModelIndex();
@ -779,20 +781,23 @@ Qt::ItemFlags TimeSeries::flags(const QModelIndex &i) const
if (i.column() == 1) {
flags |= Qt::ItemIsEditable;
}
if (i.column() == 2) {
flags |= Qt::ItemIsEditable;
}
return flags;
}
QVariant TimeSeries::input(int row) const
QVariant TimeSeries::cos(int row) const
{
QVariant v;
v = time_series_data_input(m_d, row);
v = time_series_data_cos(m_d, row);
return v;
}
bool TimeSeries::setInput(int row, const QVariant& value)
bool TimeSeries::setCos(int row, const QVariant& value)
{
bool set = false;
set = time_series_set_data_input(m_d, row, value.value<quint32>());
set = time_series_set_data_cos(m_d, row, value.value<float>());
if (set) {
QModelIndex index = createIndex(row, 0, row);
emit dataChanged(index, index);
@ -800,17 +805,35 @@ bool TimeSeries::setInput(int row, const QVariant& value)
return set;
}
QVariant TimeSeries::result(int row) const
QVariant TimeSeries::sin(int row) const
{
QVariant v;
v = time_series_data_result(m_d, row);
v = time_series_data_sin(m_d, row);
return v;
}
bool TimeSeries::setResult(int row, const QVariant& value)
bool TimeSeries::setSin(int row, const QVariant& value)
{
bool set = false;
set = time_series_set_data_result(m_d, row, value.value<quint32>());
set = time_series_set_data_sin(m_d, row, value.value<float>());
if (set) {
QModelIndex index = createIndex(row, 0, row);
emit dataChanged(index, index);
}
return set;
}
QVariant TimeSeries::time(int row) const
{
QVariant v;
v = time_series_data_time(m_d, row);
return v;
}
bool TimeSeries::setTime(int row, const QVariant& value)
{
bool set = false;
set = time_series_set_data_time(m_d, row, value.value<float>());
if (set) {
QModelIndex index = createIndex(row, 0, row);
emit dataChanged(index, index);
@ -824,19 +847,28 @@ QVariant TimeSeries::data(const QModelIndex &index, int role) const
switch (index.column()) {
case 0:
switch (role) {
case Qt::UserRole + 0:
return cos(index.row());
case Qt::UserRole + 1:
return sin(index.row());
case Qt::DisplayRole:
case Qt::EditRole:
case Qt::UserRole + 0:
return input(index.row());
case Qt::UserRole + 1:
return result(index.row());
case Qt::UserRole + 2:
return time(index.row());
}
case 1:
switch (role) {
case Qt::DisplayRole:
case Qt::EditRole:
case Qt::UserRole + 1:
return result(index.row());
return sin(index.row());
}
case 2:
switch (role) {
case Qt::DisplayRole:
case Qt::EditRole:
case Qt::UserRole + 0:
return cos(index.row());
}
}
return QVariant();
@ -844,8 +876,9 @@ QVariant TimeSeries::data(const QModelIndex &index, int role) const
QHash<int, QByteArray> TimeSeries::roleNames() const {
QHash<int, QByteArray> names = QAbstractItemModel::roleNames();
names.insert(Qt::UserRole + 0, "input");
names.insert(Qt::UserRole + 1, "result");
names.insert(Qt::UserRole + 0, "cos");
names.insert(Qt::UserRole + 1, "sin");
names.insert(Qt::UserRole + 2, "time");
return names;
}
QVariant TimeSeries::headerData(int section, Qt::Orientation orientation, int role) const
@ -868,16 +901,24 @@ bool TimeSeries::setHeaderData(int section, Qt::Orientation orientation, const Q
bool TimeSeries::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (index.column() == 0) {
if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::UserRole + 0) {
return setInput(index.row(), value);
if (role == Qt::UserRole + 0) {
return setCos(index.row(), value);
}
if (role == Qt::UserRole + 1) {
return setResult(index.row(), value);
return setSin(index.row(), value);
}
if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::UserRole + 2) {
return setTime(index.row(), value);
}
}
if (index.column() == 1) {
if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::UserRole + 1) {
return setResult(index.row(), value);
return setSin(index.row(), value);
}
}
if (index.column() == 2) {
if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::UserRole + 0) {
return setCos(index.row(), value);
}
}
return false;
@ -1037,7 +1078,7 @@ Demo::Demo(QObject *parent):
},
[](TimeSeries* o, quintptr first, quintptr last) {
o->dataChanged(o->createIndex(first, 0, first),
o->createIndex(last, 1, last));
o->createIndex(last, 2, last));
},
[](TimeSeries* o) {
o->beginResetModel();
@ -1394,7 +1435,7 @@ TimeSeries::TimeSeries(QObject *parent):
},
[](TimeSeries* o, quintptr first, quintptr last) {
o->dataChanged(o->createIndex(first, 0, first),
o->createIndex(last, 1, last));
o->createIndex(last, 2, last));
},
[](TimeSeries* o) {
o->beginResetModel();
@ -1429,6 +1470,7 @@ TimeSeries::~TimeSeries() {
}
}
void TimeSeries::initHeaderData() {
m_headerData.insert(qMakePair(0, Qt::DisplayRole), QVariant("input"));
m_headerData.insert(qMakePair(1, Qt::DisplayRole), QVariant("result"));
m_headerData.insert(qMakePair(0, Qt::DisplayRole), QVariant("time"));
m_headerData.insert(qMakePair(1, Qt::DisplayRole), QVariant("sin"));
m_headerData.insert(qMakePair(2, Qt::DisplayRole), QVariant("cos"));
}

View File

@ -237,10 +237,12 @@ public:
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role = Qt::EditRole) override;
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
Q_INVOKABLE QVariant input(int row) const;
Q_INVOKABLE bool setInput(int row, const QVariant& value);
Q_INVOKABLE QVariant result(int row) const;
Q_INVOKABLE bool setResult(int row, const QVariant& value);
Q_INVOKABLE QVariant cos(int row) const;
Q_INVOKABLE bool setCos(int row, const QVariant& value);
Q_INVOKABLE QVariant sin(int row) const;
Q_INVOKABLE bool setSin(int row, const QVariant& value);
Q_INVOKABLE QVariant time(int row) const;
Q_INVOKABLE bool setTime(int row, const QVariant& value);
signals:
// new data is ready to be made available to the model with fetchMore()

View File

@ -251,28 +251,39 @@ QWidget* createProcessesTab(Model* model) {
using namespace QtCharts;
QWidget* createChartTab(Model* model) {
QLineSeries *series = new QLineSeries();
series->setName("Line 1");
QVXYModelMapper *mapper = new QVXYModelMapper(series);
mapper->setXColumn(0);
mapper->setYColumn(1);
mapper->setSeries(series);
mapper->setModel(model->demo.timeSeries());
QLineSeries *sin = new QLineSeries();
sin->setName("sin");
QVXYModelMapper *sinMapper = new QVXYModelMapper(sin);
sinMapper->setXColumn(0);
sinMapper->setYColumn(1);
sinMapper->setSeries(sin);
sinMapper->setModel(model->demo.timeSeries());
QLineSeries *cos = new QLineSeries();
cos->setName("cos");
QVXYModelMapper *cosMapper = new QVXYModelMapper(cos);
cosMapper->setXColumn(0);
cosMapper->setYColumn(2);
cosMapper->setSeries(cos);
cosMapper->setModel(model->demo.timeSeries());
QChart* chart = new QChart;
chart->addSeries(series);
QDateTimeAxis *axisX = new QDateTimeAxis;
axisX->setTickCount(10);
axisX->setFormat("MMM yyyy");
axisX->setTitleText("Date");
chart->addSeries(sin);
chart->addSeries(cos);
QValueAxis *axisX = new QValueAxis;
axisX->setLabelFormat("%i");
axisX->setTitleText("time [s]");
chart->addAxis(axisX, Qt::AlignBottom);
series->attachAxis(axisX);
sin->attachAxis(axisX);
cos->attachAxis(axisX);
QValueAxis *axisY = new QValueAxis;
axisY->setLabelFormat("%i");
axisY->setTitleText("Sunspots count");
axisY->setTitleText("electric potential [V]");
chart->addAxis(axisY, Qt::AlignLeft);
series->attachAxis(axisY);
sin->attachAxis(axisY);
cos->attachAxis(axisY);
QWidget* view = new QWidget;
QTableView* data = new QTableView;