more work on qtcharts
This commit is contained in:
parent
37c4ed0261
commit
65d983d5e3
@ -213,9 +213,39 @@ void LogsModelNg::logsReply(const QVariantMap &data)
|
|||||||
for (int i = 0; i < newBlock.count(); i++) {
|
for (int i = 0; i < newBlock.count(); i++) {
|
||||||
LogEntry *entry = newBlock.at(i);
|
LogEntry *entry = newBlock.at(i);
|
||||||
m_list.insert(offset + i, entry);
|
m_list.insert(offset + i, entry);
|
||||||
qDebug() << "Adding line series point:" << i << entry->timestamp().toSecsSinceEpoch() << entry->value().toReal();
|
|
||||||
if (m_graphSeries) {
|
if (m_graphSeries) {
|
||||||
m_graphSeries->insert(offset + i, QPointF(entry->timestamp().toMSecsSinceEpoch(), entry->value().toReal()));
|
Device *dev = m_engine->deviceManager()->devices()->getDevice(entry->deviceId());
|
||||||
|
if (dev && dev->deviceClass()->stateTypes()->getStateType(entry->typeId())->type() == "Bool") {
|
||||||
|
// We don't want bools painting triangles, add a toggle point to keep lines straight
|
||||||
|
if (i > 0) {
|
||||||
|
LogEntry *newerEntry = newBlock.at(i - 1);
|
||||||
|
if (newerEntry->value().toBool() != entry->value().toBool()) {
|
||||||
|
qDebug() << "Adding bool line series point:" << (newerEntry->timestamp().addSecs(-1)) << newerEntry->timestamp().addSecs(-1).toMSecsSinceEpoch() << (entry->value().toBool() ? 1 : 0) << "(correction)";
|
||||||
|
m_graphSeries->append(QPointF(newerEntry->timestamp().addSecs(-1).toMSecsSinceEpoch(), entry->value().toBool() ? 1 : 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (m_graphSeries->count() == 0) {
|
||||||
|
qDebug() << "Adding bool line series point:" << QDateTime::currentDateTime() << QDateTime::currentDateTime().toMSecsSinceEpoch() - 1 << (entry->value().toBool() ? 1 : 0) << "(beginning)";
|
||||||
|
m_graphSeries->append(QPointF(QDateTime::currentDateTime().toMSecsSinceEpoch(), 1));// entry->value().toBool() ? 1 : 0));
|
||||||
|
m_graphSeries->append(QPointF(QDateTime::currentDateTime().toMSecsSinceEpoch(), entry->value().toBool() ? 1 : 0));
|
||||||
|
}
|
||||||
|
qDebug() << "Adding bool line series point:" << entry->timestamp() << entry->timestamp().toMSecsSinceEpoch() << (entry->value().toBool() ? 1 : 0);
|
||||||
|
m_graphSeries->append(QPointF(entry->timestamp().toMSecsSinceEpoch(), entry->value().toBool() ? 1 : 0));
|
||||||
|
} else {
|
||||||
|
// if (i > 0) {
|
||||||
|
// LogEntry *newerEntry = newBlock.at(i - 1);
|
||||||
|
// if (newerEntry->value() != entry->value()) {
|
||||||
|
// qDebug() << "Adding line series point:" << (offset + i) << newerEntry->timestamp().toMSecsSinceEpoch() - 1 << (entry->value().toReal()) << "(correction)";
|
||||||
|
// m_graphSeries->append(QPointF(newerEntry->timestamp().toMSecsSinceEpoch() - 1, entry->value().toReal()));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
if (m_graphSeries->count() == 0) {
|
||||||
|
m_graphSeries->insert(0, QPointF(QDateTime::currentDateTime().toMSecsSinceEpoch(), entry->value().toReal()));
|
||||||
|
}
|
||||||
|
qDebug() << "Adding line series point:" << (offset + i) << entry->timestamp().toMSecsSinceEpoch() << (entry->value().toReal());
|
||||||
|
m_graphSeries->append(QPointF(entry->timestamp().toMSecsSinceEpoch(), entry->value().toReal()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!newMin.isValid() || newMin > entry->value()) {
|
if (!newMin.isValid() || newMin > entry->value()) {
|
||||||
newMin = entry->value().toReal();
|
newMin = entry->value().toReal();
|
||||||
@ -236,7 +266,7 @@ void LogsModelNg::logsReply(const QVariantMap &data)
|
|||||||
emit maxValueChanged();
|
emit maxValueChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_list.count() > 0 && m_list.last()->timestamp() > m_viewStartTime && canFetchMore()) {
|
if (m_viewStartTime.isValid() && m_list.count() > 0 && m_list.last()->timestamp() > m_viewStartTime && canFetchMore()) {
|
||||||
fetchMore();
|
fetchMore();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -246,8 +276,8 @@ void LogsModelNg::fetchMore(const QModelIndex &parent)
|
|||||||
Q_UNUSED(parent)
|
Q_UNUSED(parent)
|
||||||
qDebug() << "fetchMore called";
|
qDebug() << "fetchMore called";
|
||||||
|
|
||||||
if (!m_engine->jsonRpcClient()) {
|
if (!m_engine) {
|
||||||
qWarning() << "Cannot update. JsonRpcClient not set";
|
qWarning() << "Cannot update. Engine not set";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (m_busy) {
|
if (m_busy) {
|
||||||
@ -294,8 +324,8 @@ void LogsModelNg::fetchMore(const QModelIndex &parent)
|
|||||||
bool LogsModelNg::canFetchMore(const QModelIndex &parent) const
|
bool LogsModelNg::canFetchMore(const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
Q_UNUSED(parent)
|
Q_UNUSED(parent)
|
||||||
qDebug() << "canFetchMore" << m_canFetchMore;
|
qDebug() << "canFetchMore" << (m_engine && m_canFetchMore);
|
||||||
return m_canFetchMore;
|
return m_engine && m_canFetchMore;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogsModelNg::newLogEntryReceived(const QVariantMap &data)
|
void LogsModelNg::newLogEntryReceived(const QVariantMap &data)
|
||||||
|
|||||||
@ -127,5 +127,7 @@
|
|||||||
<file>translations/nymea-app-de_DE.qm</file>
|
<file>translations/nymea-app-de_DE.qm</file>
|
||||||
<file>translations/nymea-app-en_US.qm</file>
|
<file>translations/nymea-app-en_US.qm</file>
|
||||||
<file>../LICENSE</file>
|
<file>../LICENSE</file>
|
||||||
|
<file>ui/customviews/GenericTypeGraphPre110.qml</file>
|
||||||
|
<file>ui/customviews/GenericTypeGraph.qml</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|||||||
252
nymea-app/ui/customviews/GenericTypeGraph.qml
Normal file
252
nymea-app/ui/customviews/GenericTypeGraph.qml
Normal file
@ -0,0 +1,252 @@
|
|||||||
|
import QtQuick 2.9
|
||||||
|
import QtQuick.Controls 2.2
|
||||||
|
import QtQuick.Controls.Material 2.2
|
||||||
|
import QtQuick.Layouts 1.1
|
||||||
|
import Nymea 1.0
|
||||||
|
import "../components"
|
||||||
|
import "../customviews"
|
||||||
|
import QtCharts 2.2
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property var device: null
|
||||||
|
property var stateType: null
|
||||||
|
readonly property var deviceClass: engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId);
|
||||||
|
readonly property bool hasConnectable: deviceClass.interfaces.indexOf("connectable") >= 0
|
||||||
|
readonly property var connectedStateType: hasConnectable ? deviceClass.stateTypes.findByName("connected") : null
|
||||||
|
|
||||||
|
LogsModelNg {
|
||||||
|
id: logsModelNg
|
||||||
|
engine: _engine
|
||||||
|
deviceId: root.device.id
|
||||||
|
typeIds: [root.stateType.id]
|
||||||
|
live: true
|
||||||
|
graphSeries: lineSeries1
|
||||||
|
viewStartTime: xAxis.min
|
||||||
|
}
|
||||||
|
|
||||||
|
LogsModelNg {
|
||||||
|
id: connectedLogsModel
|
||||||
|
engine: root.hasConnectable ? _engine : null // don't even try to poll if we don't have a connectable interface
|
||||||
|
deviceId: root.device.id
|
||||||
|
typeIds: [root.connectedStateType.id]
|
||||||
|
live: true
|
||||||
|
graphSeries: connectedLineSeries
|
||||||
|
viewStartTime: xAxis.min
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: 0
|
||||||
|
RowLayout {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
HeaderButton {
|
||||||
|
imageSource: "../images/zoom-out.svg"
|
||||||
|
onClicked: {
|
||||||
|
var diff = xAxis.max.getTime() - xAxis.min.getTime()
|
||||||
|
var newTime = new Date(xAxis.min.getTime() - (diff / 4))
|
||||||
|
xAxis.min = newTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
Layout.preferredWidth: 100
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
text: {
|
||||||
|
var timeDiff = (xAxis.max.getTime() - xAxis.min.getTime()) / 1000;
|
||||||
|
if (timeDiff < 60) {
|
||||||
|
return qsTr("%1 seconds").arg(Math.round(timeDiff));
|
||||||
|
}
|
||||||
|
timeDiff = timeDiff / 60
|
||||||
|
if (timeDiff < 60) {
|
||||||
|
return qsTr("%1 minutes").arg(Math.round(timeDiff));
|
||||||
|
}
|
||||||
|
timeDiff = timeDiff / 60
|
||||||
|
if (timeDiff < 48) {
|
||||||
|
return qsTr("%1 hours").arg(Math.round(timeDiff));
|
||||||
|
}
|
||||||
|
timeDiff = timeDiff / 24;
|
||||||
|
if (timeDiff < 14) {
|
||||||
|
return qsTr("%1 days").arg(Math.round(timeDiff));
|
||||||
|
}
|
||||||
|
timeDiff = timeDiff / 7
|
||||||
|
if (timeDiff < 5) {
|
||||||
|
return qsTr("%1 weeks").arg(Math.round(timeDiff));
|
||||||
|
}
|
||||||
|
timeDiff * timeDiff * 7 / 30
|
||||||
|
if (timeDiff < 24) {
|
||||||
|
return qsTr("%1 months").arg(Math.round(timeDiff));
|
||||||
|
}
|
||||||
|
timeDiff = timeDiff * 30 / 356
|
||||||
|
return qsTr("%1 years").arg(Math.round(timeDiff))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HeaderButton {
|
||||||
|
imageSource: "../images/zoom-in.svg"
|
||||||
|
onClicked: {
|
||||||
|
var diff = xAxis.max.getTime() - xAxis.min.getTime()
|
||||||
|
var newTime = new Date(xAxis.min.getTime() + (diff / 4))
|
||||||
|
xAxis.min = newTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ChartView {
|
||||||
|
id: chartView
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
margins.top: 0
|
||||||
|
margins.bottom: 0
|
||||||
|
margins.left: 0
|
||||||
|
margins.right: 0
|
||||||
|
backgroundColor: Material.background
|
||||||
|
legend.labelColor: app.foregroundColor
|
||||||
|
|
||||||
|
animationDuration: 300
|
||||||
|
animationOptions: ChartView.SeriesAnimations
|
||||||
|
|
||||||
|
ValueAxis {
|
||||||
|
id: yAxis
|
||||||
|
min: logsModelNg.minValue
|
||||||
|
max: logsModelNg.maxValue
|
||||||
|
labelsFont.pixelSize: app.smallFont
|
||||||
|
labelsColor: app.foregroundColor
|
||||||
|
tickCount: chartView.height / 40
|
||||||
|
color: Qt.rgba(app.foregroundColor.r, app.foregroundColor.g, app.foregroundColor.b, .2)
|
||||||
|
gridLineColor: color
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueAxis {
|
||||||
|
id: connectedAxis
|
||||||
|
min: 0
|
||||||
|
max: 1
|
||||||
|
visible: false
|
||||||
|
}
|
||||||
|
|
||||||
|
DateTimeAxis {
|
||||||
|
id: xAxis
|
||||||
|
gridVisible: false
|
||||||
|
color: Qt.rgba(app.foregroundColor.r, app.foregroundColor.g, app.foregroundColor.b, .2)
|
||||||
|
tickCount: chartView.width / 70
|
||||||
|
labelsFont.pixelSize: app.smallFont
|
||||||
|
labelsColor: app.foregroundColor
|
||||||
|
titleText: {
|
||||||
|
if (xAxis.min.getYear() === xAxis.max.getYear()
|
||||||
|
&& xAxis.min.getMonth() === xAxis.max.getMonth()
|
||||||
|
&& xAxis.min.getDate() === xAxis.max.getDate()) {
|
||||||
|
return Qt.formatDate(xAxis.min)
|
||||||
|
}
|
||||||
|
return Qt.formatDate(xAxis.min) + " - " + Qt.formatDate(xAxis.max)
|
||||||
|
}
|
||||||
|
titleBrush: app.foregroundColor
|
||||||
|
format: {
|
||||||
|
var timeDiff = (xAxis.max.getTime() - xAxis.min.getTime()) / 1000
|
||||||
|
if (timeDiff < 60) { // one minute
|
||||||
|
return "mm:ss"
|
||||||
|
}
|
||||||
|
if (timeDiff < 60 * 60) { // one hour
|
||||||
|
return "hh:mm"
|
||||||
|
}
|
||||||
|
if (timeDiff < 60 * 60 * 24 * 2) { // two day
|
||||||
|
return "hh:mm"
|
||||||
|
}
|
||||||
|
if (timeDiff < 60 * 60 * 24 * 7) { // one week
|
||||||
|
return "ddd hh:mm"
|
||||||
|
}
|
||||||
|
if (timeDiff < 60 * 60 * 24 * 7 * 30) { // one month
|
||||||
|
return "dd.MM."
|
||||||
|
}
|
||||||
|
return "MMM yy"
|
||||||
|
}
|
||||||
|
|
||||||
|
min: {
|
||||||
|
var date = new Date();
|
||||||
|
date.setHours(date.getHours() - 6);
|
||||||
|
return date;
|
||||||
|
}
|
||||||
|
max: new Date()
|
||||||
|
}
|
||||||
|
|
||||||
|
AreaSeries {
|
||||||
|
axisX: xAxis
|
||||||
|
axisY: connectedAxis
|
||||||
|
name: qsTr("Not connected")
|
||||||
|
visible: root.hasConnectable
|
||||||
|
upperSeries: LineSeries {
|
||||||
|
XYPoint {x: xAxis.min.getTime(); y: 1}
|
||||||
|
XYPoint {x: xAxis.max.getTime(); y: 1}
|
||||||
|
}
|
||||||
|
|
||||||
|
lowerSeries: LineSeries {
|
||||||
|
id: connectedLineSeries
|
||||||
|
}
|
||||||
|
color: "#55ff0000"
|
||||||
|
}
|
||||||
|
|
||||||
|
AreaSeries {
|
||||||
|
axisX: xAxis
|
||||||
|
axisY: yAxis
|
||||||
|
name: root.stateType.displayName
|
||||||
|
borderColor: app.accentColor
|
||||||
|
borderWidth: 4
|
||||||
|
upperSeries: LineSeries {
|
||||||
|
id: lineSeries1
|
||||||
|
}
|
||||||
|
color: Qt.rgba(app.accentColor.r, app.accentColor.g, app.accentColor.b, .3)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
property int lastX: 0
|
||||||
|
property int lastY: 0
|
||||||
|
|
||||||
|
function scrollRightLimited(dx) {
|
||||||
|
chartView.animationOptions = ChartView.NoAnimation
|
||||||
|
var now = new Date()
|
||||||
|
// if we're already at the limit, don't even start scrolling
|
||||||
|
if (dx < 0 || xAxis.max < now) {
|
||||||
|
chartView.scrollRight(dx)
|
||||||
|
}
|
||||||
|
// figure out if we scrolled too far
|
||||||
|
var overshoot = xAxis.max.getTime() - now.getTime()
|
||||||
|
// print("overshoot is:", overshoot, "oldMax", xAxis.max, "newMax", now, "oldMin", xAxis.min, "newMin", new Date(xAxis.min.getTime() - overshoot))
|
||||||
|
if (overshoot > 0) {
|
||||||
|
var range = xAxis.max - xAxis.min
|
||||||
|
xAxis.max = now
|
||||||
|
xAxis.min = new Date(xAxis.max.getTime() - range)
|
||||||
|
}
|
||||||
|
chartView.animationOptions = ChartView.SeriesAnimations
|
||||||
|
}
|
||||||
|
|
||||||
|
function zoomInLimited(dy) {
|
||||||
|
chartView.animationOptions = ChartView.NoAnimation
|
||||||
|
var oldMax = xAxis.max;
|
||||||
|
chartView.scrollRight(dy);
|
||||||
|
var timeDiff = xAxis.max.getTime() - oldMax.getTime()
|
||||||
|
xAxis.min = new Date(xAxis.min.getTime() - timeDiff * 2)
|
||||||
|
chartView.animationOptions = ChartView.SeriesAnimations
|
||||||
|
}
|
||||||
|
|
||||||
|
onPressed: {
|
||||||
|
lastX = mouse.x
|
||||||
|
lastY = mouse.y
|
||||||
|
}
|
||||||
|
|
||||||
|
onWheel: {
|
||||||
|
scrollRightLimited(-wheel.pixelDelta.x)
|
||||||
|
// zoomInLimited(wheel.pixelDelta.y)
|
||||||
|
}
|
||||||
|
|
||||||
|
onPositionChanged: {
|
||||||
|
if (lastX !== mouse.x) {
|
||||||
|
scrollRightLimited(lastX - mouseX)
|
||||||
|
lastX = mouse.x
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
84
nymea-app/ui/customviews/GenericTypeGraphPre110.qml
Normal file
84
nymea-app/ui/customviews/GenericTypeGraphPre110.qml
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
import QtQuick 2.9
|
||||||
|
import QtQuick.Controls 2.2
|
||||||
|
import QtQuick.Controls.Material 2.2
|
||||||
|
import QtQuick.Layouts 1.1
|
||||||
|
import Nymea 1.0
|
||||||
|
import "../components"
|
||||||
|
import "../customviews"
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property var device: null
|
||||||
|
property var stateType: null
|
||||||
|
|
||||||
|
TabBar {
|
||||||
|
id: zoomTabBar
|
||||||
|
Layout.fillWidth: true
|
||||||
|
TabButton {
|
||||||
|
text: qsTr("6 h")
|
||||||
|
property int avg: ValueLogsProxyModel.AverageQuarterHour
|
||||||
|
property date startTime: {
|
||||||
|
var date = new Date();
|
||||||
|
date.setHours(new Date().getHours() - 6)
|
||||||
|
date.setMinutes(0)
|
||||||
|
date.setSeconds(0)
|
||||||
|
return date;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TabButton {
|
||||||
|
text: qsTr("24 h")
|
||||||
|
property int avg: ValueLogsProxyModel.AverageHourly
|
||||||
|
property date startTime: {
|
||||||
|
var date = new Date();
|
||||||
|
date.setHours(new Date().getHours() - 24);
|
||||||
|
date.setMinutes(0)
|
||||||
|
date.setSeconds(0)
|
||||||
|
return date;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TabButton {
|
||||||
|
text: qsTr("7 d")
|
||||||
|
property int avg: ValueLogsProxyModel.AverageDayTime
|
||||||
|
property date startTime: {
|
||||||
|
var date = new Date();
|
||||||
|
date.setDate(new Date().getDate() - 7);
|
||||||
|
date.setHours(0)
|
||||||
|
date.setMinutes(0)
|
||||||
|
date.setSeconds(0)
|
||||||
|
return date;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Graph {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
mode: settings.graphStyle
|
||||||
|
color: app.accentColor
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: updateTimer
|
||||||
|
interval: 10
|
||||||
|
repeat: false
|
||||||
|
onTriggered: {
|
||||||
|
graphModel.update()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
model: ValueLogsProxyModel {
|
||||||
|
id: graphModel
|
||||||
|
deviceId: root.device.id
|
||||||
|
typeIds: [stateType.id]
|
||||||
|
average: zoomTabBar.currentItem.avg
|
||||||
|
startTime: zoomTabBar.currentItem.startTime
|
||||||
|
Component.onCompleted: updateTimer.start();
|
||||||
|
onAverageChanged: updateTimer.start()
|
||||||
|
onStartTimeChanged: updateTimer.start();
|
||||||
|
engine: _engine
|
||||||
|
|
||||||
|
// Live doesn't work yet with ValueLogsProxyModel
|
||||||
|
// live: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,7 +5,6 @@ import QtQuick.Layouts 1.1
|
|||||||
import Nymea 1.0
|
import Nymea 1.0
|
||||||
import "../components"
|
import "../components"
|
||||||
import "../customviews"
|
import "../customviews"
|
||||||
import QtCharts 2.2
|
|
||||||
|
|
||||||
Page {
|
Page {
|
||||||
id: root
|
id: root
|
||||||
@ -24,7 +23,7 @@ Page {
|
|||||||
}
|
}
|
||||||
|
|
||||||
header: GuhHeader {
|
header: GuhHeader {
|
||||||
text: qsTr("History")
|
text: qsTr("History for %1").arg(root.stateType.displayName)
|
||||||
onBackPressed: pageStack.pop()
|
onBackPressed: pageStack.pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,8 +44,6 @@ Page {
|
|||||||
deviceId: root.device.id
|
deviceId: root.device.id
|
||||||
typeIds: [root.stateType.id]
|
typeIds: [root.stateType.id]
|
||||||
live: true
|
live: true
|
||||||
graphSeries: lineSeries1
|
|
||||||
viewStartTime: xAxis.min
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
@ -62,9 +59,6 @@ Page {
|
|||||||
TabButton {
|
TabButton {
|
||||||
text: qsTr("Graph")
|
text: qsTr("Graph")
|
||||||
}
|
}
|
||||||
TabButton {
|
|
||||||
text: qsTr("Graph NG")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SwipeView {
|
SwipeView {
|
||||||
@ -96,225 +90,19 @@ Page {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
Loader {
|
||||||
|
id: graphLoader
|
||||||
width: swipeView.width
|
width: swipeView.width
|
||||||
height: swipeView.height
|
height: swipeView.height
|
||||||
TabBar {
|
Component.onCompleted: {
|
||||||
id: zoomTabBar
|
var source;
|
||||||
Layout.fillWidth: true
|
if (engine.jsonRpcClient.ensureServerVersion("1.10")) {
|
||||||
TabButton {
|
source = Qt.resolvedUrl("../customviews/GenericTypeGraph.qml");
|
||||||
text: qsTr("6 h")
|
} else {
|
||||||
property int avg: ValueLogsProxyModel.AverageQuarterHour
|
source = Qt.resolvedUrl("../customviews/GenericTypeGraphPre110.qml");
|
||||||
property date startTime: {
|
|
||||||
var date = new Date();
|
|
||||||
date.setHours(new Date().getHours() - 6)
|
|
||||||
date.setMinutes(0)
|
|
||||||
date.setSeconds(0)
|
|
||||||
return date;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TabButton {
|
|
||||||
text: qsTr("24 h")
|
|
||||||
property int avg: ValueLogsProxyModel.AverageHourly
|
|
||||||
property date startTime: {
|
|
||||||
var date = new Date();
|
|
||||||
date.setHours(new Date().getHours() - 24);
|
|
||||||
date.setMinutes(0)
|
|
||||||
date.setSeconds(0)
|
|
||||||
return date;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TabButton {
|
|
||||||
text: qsTr("7 d")
|
|
||||||
property int avg: ValueLogsProxyModel.AverageDayTime
|
|
||||||
property date startTime: {
|
|
||||||
var date = new Date();
|
|
||||||
date.setDate(new Date().getDate() - 7);
|
|
||||||
date.setHours(0)
|
|
||||||
date.setMinutes(0)
|
|
||||||
date.setSeconds(0)
|
|
||||||
return date;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
setSource(source, {device: root.device, stateType: root.stateType})
|
||||||
}
|
}
|
||||||
|
|
||||||
Graph {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.fillHeight: true
|
|
||||||
mode: settings.graphStyle
|
|
||||||
color: app.accentColor
|
|
||||||
|
|
||||||
Timer {
|
|
||||||
id: updateTimer
|
|
||||||
interval: 10
|
|
||||||
repeat: false
|
|
||||||
onTriggered: {
|
|
||||||
graphModel.update()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
model: ValueLogsProxyModel {
|
|
||||||
id: graphModel
|
|
||||||
deviceId: root.device.id
|
|
||||||
typeIds: [stateType.id]
|
|
||||||
average: zoomTabBar.currentItem.avg
|
|
||||||
startTime: zoomTabBar.currentItem.startTime
|
|
||||||
Component.onCompleted: updateTimer.start();
|
|
||||||
onAverageChanged: updateTimer.start()
|
|
||||||
onStartTimeChanged: updateTimer.start();
|
|
||||||
engine: _engine
|
|
||||||
|
|
||||||
// Live doesn't work yet with ValueLogsProxyModel
|
|
||||||
// live: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Item {
|
|
||||||
width: swipeView.width
|
|
||||||
height: swipeView.height
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
anchors.fill: parent
|
|
||||||
RowLayout {
|
|
||||||
Layout.alignment: Qt.AlignRight
|
|
||||||
HeaderButton {
|
|
||||||
imageSource: "../images/zoom-in.svg"
|
|
||||||
onClicked: {
|
|
||||||
var diff = xAxis.max.getTime() - xAxis.min.getTime()
|
|
||||||
var newTime = new Date(xAxis.min.getTime() + (diff / 4))
|
|
||||||
xAxis.min = newTime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
HeaderButton {
|
|
||||||
imageSource: "../images/zoom-out.svg"
|
|
||||||
onClicked: {
|
|
||||||
var diff = xAxis.max.getTime() - xAxis.min.getTime()
|
|
||||||
var newTime = new Date(xAxis.min.getTime() - (diff / 4))
|
|
||||||
xAxis.min = newTime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ChartView {
|
|
||||||
id: chartView
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.fillHeight: true
|
|
||||||
margins.top: 0
|
|
||||||
margins.bottom: 0
|
|
||||||
margins.left: 0
|
|
||||||
margins.right: 0
|
|
||||||
backgroundColor: Material.background
|
|
||||||
animationDuration: 300
|
|
||||||
animationOptions: ChartView.SeriesAnimations
|
|
||||||
|
|
||||||
ValueAxis {
|
|
||||||
id: yAxis
|
|
||||||
min: logsModelNg.minValue
|
|
||||||
max: logsModelNg.maxValue
|
|
||||||
labelsFont.pixelSize: app.smallFont
|
|
||||||
tickCount: chartView.height / 40
|
|
||||||
}
|
|
||||||
|
|
||||||
DateTimeAxis {
|
|
||||||
id: xAxis
|
|
||||||
gridVisible: false
|
|
||||||
tickCount: chartView.width / 70
|
|
||||||
labelsFont.pixelSize: app.smallFont
|
|
||||||
format: {
|
|
||||||
var timeDiff = (xAxis.max.getTime() - xAxis.min.getTime()) / 1000
|
|
||||||
if (timeDiff < 60) { // one minute
|
|
||||||
return "mm:ss"
|
|
||||||
}
|
|
||||||
if (timeDiff < 60 * 60) { // one hour
|
|
||||||
return "hh:mm"
|
|
||||||
}
|
|
||||||
if (timeDiff < 60 * 60 * 24 * 2) { // two day
|
|
||||||
return "hh:mm"
|
|
||||||
}
|
|
||||||
if (timeDiff < 60 * 60 * 24 * 7) { // one week
|
|
||||||
return "ddd hh:mm"
|
|
||||||
}
|
|
||||||
if (timeDiff < 60 * 60 * 24 * 7 * 30) { // one month
|
|
||||||
return "dd.MM."
|
|
||||||
}
|
|
||||||
return "MMM yy"
|
|
||||||
}
|
|
||||||
|
|
||||||
min: {
|
|
||||||
var date = new Date();
|
|
||||||
date.setHours(date.getHours() - 6);
|
|
||||||
return date;
|
|
||||||
}
|
|
||||||
max: new Date()
|
|
||||||
}
|
|
||||||
|
|
||||||
AreaSeries {
|
|
||||||
axisX: xAxis
|
|
||||||
axisY: yAxis
|
|
||||||
name: root.stateType.displayName
|
|
||||||
borderColor: app.accentColor
|
|
||||||
borderWidth: 4
|
|
||||||
upperSeries: LineSeries {
|
|
||||||
id: lineSeries1
|
|
||||||
width: 4
|
|
||||||
}
|
|
||||||
color: Qt.rgba(app.accentColor.r, app.accentColor.g, app.accentColor.b, .3)
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
property int lastX: 0
|
|
||||||
property int lastY: 0
|
|
||||||
|
|
||||||
function scrollRightLimited(dx) {
|
|
||||||
chartView.animationOptions = ChartView.NoAnimation
|
|
||||||
var now = new Date()
|
|
||||||
// if we're already at the limit, don't even start scrolling
|
|
||||||
if (dx < 0 || xAxis.max < now) {
|
|
||||||
chartView.scrollRight(dx)
|
|
||||||
}
|
|
||||||
// figure out if we scrolled too far
|
|
||||||
var overshoot = xAxis.max.getTime() - now.getTime()
|
|
||||||
print("overshoot is:", overshoot, "oldMax", xAxis.max, "newMax", now, "oldMin", xAxis.min, "newMin", new Date(xAxis.min.getTime() - overshoot))
|
|
||||||
if (overshoot > 0) {
|
|
||||||
var range = xAxis.max - xAxis.min
|
|
||||||
xAxis.max = now
|
|
||||||
xAxis.min = new Date(xAxis.max.getTime() - range)
|
|
||||||
}
|
|
||||||
chartView.animationOptions = ChartView.SeriesAnimations
|
|
||||||
}
|
|
||||||
|
|
||||||
function zoomInLimited(dy) {
|
|
||||||
chartView.animationOptions = ChartView.NoAnimation
|
|
||||||
var oldMax = xAxis.max;
|
|
||||||
chartView.scrollRight(dy);
|
|
||||||
var timeDiff = xAxis.max.getTime() - oldMax.getTime()
|
|
||||||
xAxis.min = new Date(xAxis.min.getTime() - timeDiff * 2)
|
|
||||||
chartView.animationOptions = ChartView.SeriesAnimations
|
|
||||||
}
|
|
||||||
|
|
||||||
onPressed: {
|
|
||||||
lastX = mouse.x
|
|
||||||
lastY = mouse.y
|
|
||||||
}
|
|
||||||
|
|
||||||
onWheel: {
|
|
||||||
scrollRightLimited(-wheel.pixelDelta.x)
|
|
||||||
// zoomInLimited(wheel.pixelDelta.y)
|
|
||||||
}
|
|
||||||
|
|
||||||
onPositionChanged: {
|
|
||||||
if (lastX !== mouse.x) {
|
|
||||||
scrollRightLimited(lastX - mouseX)
|
|
||||||
lastX = mouse.x
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user