From f4ef1a08c947f3ee6fac05633ced2b8e7cd0846e Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Tue, 14 Dec 2021 23:47:12 +0100 Subject: [PATCH 1/2] Fix header blur --- nymea-app/ui/MainPage.qml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/nymea-app/ui/MainPage.qml b/nymea-app/ui/MainPage.qml index ffd9cc99..1651d433 100644 --- a/nymea-app/ui/MainPage.qml +++ b/nymea-app/ui/MainPage.qml @@ -239,13 +239,17 @@ Page { id: contentContainer anchors.fill: parent clip: true -// visible: false property int headerSize: 48 readonly property int scrollOffset: swipeView.currentItem.item.contentY readonly property int headerBlurSize: Math.min(headerSize, scrollOffset * 2) + Rectangle { + width: parent.width + height: contentContainer.headerBlurSize + color: Style.backgroundColor + } SwipeView { id: swipeView From 426e4f3ab188f5fb69214af8aaafbbeaa754cb31 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Wed, 15 Dec 2021 00:31:48 +0100 Subject: [PATCH 2/2] Blur chart tooltips --- nymea-app/resources.qrc | 1 + nymea-app/ui/StyleBase.qml | 2 + nymea-app/ui/components/NymeaToolTip.qml | 43 +++ .../ui/mainviews/energy/ConsumerStats.qml | 121 +++--- .../ui/mainviews/energy/ConsumersHistory.qml | 208 +++++----- .../ui/mainviews/energy/PowerBalanceStats.qml | 177 +++++---- .../energy/PowerConsumptionBalanceHistory.qml | 355 +++++++++--------- .../energy/PowerProductionBalanceHistory.qml | 340 ++++++++--------- 8 files changed, 640 insertions(+), 607 deletions(-) create mode 100644 nymea-app/ui/components/NymeaToolTip.qml diff --git a/nymea-app/resources.qrc b/nymea-app/resources.qrc index 46cdf94f..97cbb5bd 100644 --- a/nymea-app/resources.qrc +++ b/nymea-app/resources.qrc @@ -272,5 +272,6 @@ ui/mainviews/energy/StatsBase.qml ui/mainviews/energy/EnergySettingsPage.qml ui/mainviews/energy/ConsumersPieChart.qml + ui/components/NymeaToolTip.qml diff --git a/nymea-app/ui/StyleBase.qml b/nymea-app/ui/StyleBase.qml index 37377df4..22d28822 100644 --- a/nymea-app/ui/StyleBase.qml +++ b/nymea-app/ui/StyleBase.qml @@ -13,6 +13,8 @@ Item { property color tileOverlayForegroundColor: foregroundColor property color tileOverlayIconColor: iconColor + property color tooltipBackgroundColor: tileOverlayColor + property int cornerRadius: 6 property int smallCornerRadius: 4 diff --git a/nymea-app/ui/components/NymeaToolTip.qml b/nymea-app/ui/components/NymeaToolTip.qml new file mode 100644 index 00000000..f3705217 --- /dev/null +++ b/nymea-app/ui/components/NymeaToolTip.qml @@ -0,0 +1,43 @@ +import QtQuick 2.3 +import QtGraphicalEffects 1.0 +import Nymea 1.0 + +Item { + id: root + + property alias backgroundItem: blurEffectSource.sourceItem + property alias backgroundRect: blurEffectSource.sourceRect + + Behavior on x { NumberAnimation { duration: Style.animationDuration } } + Behavior on y { NumberAnimation { duration: Style.animationDuration } } + Behavior on width { NumberAnimation { duration: Style.animationDuration } } + Behavior on height { NumberAnimation { duration: Style.animationDuration } } + + Rectangle { + id: blurSource + anchors.fill: toolTip + color: Style.backgroundColor + visible: false + radius: Style.smallCornerRadius + + ShaderEffectSource { + id: blurEffectSource + anchors.fill: parent + } + } + + FastBlur { + anchors.fill: toolTip + source: blurSource + radius: 32 + visible: toolTip.visible + } + + Rectangle { + anchors.fill: parent + color: Style.tooltipBackgroundColor + opacity: .5 + radius: Style.smallCornerRadius + } + +} diff --git a/nymea-app/ui/mainviews/energy/ConsumerStats.qml b/nymea-app/ui/mainviews/energy/ConsumerStats.qml index 5aacd5c9..63de06c6 100644 --- a/nymea-app/ui/mainviews/energy/ConsumerStats.qml +++ b/nymea-app/ui/mainviews/energy/ConsumerStats.qml @@ -361,81 +361,72 @@ StatsBase { property var thingBarSetMap: ({}) } + } + } + MouseArea { + id: mouseArea + anchors.fill: parent + anchors.leftMargin: chartView.x + chartView.plotArea.x + anchors.topMargin: chartView.y + chartView.plotArea.y + anchors.rightMargin: chartView.width - chartView.plotArea.width - chartView.plotArea.x + anchors.bottomMargin: chartView.height - chartView.plotArea.height - chartView.plotArea.y - MouseArea { - id: mouseArea - anchors.fill: chartView - anchors.leftMargin: chartView.plotArea.x - anchors.topMargin: chartView.plotArea.y - anchors.rightMargin: chartView.width - chartView.plotArea.width - chartView.plotArea.x - anchors.bottomMargin: chartView.height - chartView.plotArea.height - chartView.plotArea.y + hoverEnabled: true - hoverEnabled: true + Timer { + interval: 300 + running: mouseArea.pressed + onTriggered: mouseArea.preventStealing = true + } + onReleased: mouseArea.preventStealing = false - Timer { - interval: 300 - running: mouseArea.pressed - onTriggered: mouseArea.preventStealing = true + NymeaToolTip { + id: toolTip + + backgroundItem: chartView + backgroundRect: Qt.rect(chartView.plotArea.x + toolTip.x, chartView.plotArea.y + toolTip.y, toolTip.width, toolTip.height) + + property int idx: Math.floor(mouseArea.mouseX * categoryAxis.count / mouseArea.width) + visible: mouseArea.containsMouse + + x: Math.min(idx * mouseArea.width / categoryAxis.count, mouseArea.width - width) + property double setMaxValue: { + var max = 0; + for (var i = 0; i < consumers.count; i++) { + var consumer = consumers.get(i) + max = barSeries.thingBarSetMap.hasOwnProperty(consumer.id) ? Math.max(max, barSeries.thingBarSetMap[consumer.id].at(idx)) : 0 } - onReleased: mouseArea.preventStealing = false + return max + } + y: Math.min(Math.max(mouseArea.height - (setMaxValue * mouseArea.height / valueAxis.max) - height - Style.smallMargins, 0), mouseArea.height - height) - Item { - id: toolTip - property int idx: Math.floor(mouseArea.mouseX * categoryAxis.count / mouseArea.width) - visible: mouseArea.containsMouse + width: tooltipLayout.implicitWidth + Style.smallMargins * 2 + height: tooltipLayout.implicitHeight + Style.smallMargins * 2 - x: Math.min(idx * mouseArea.width / categoryAxis.count, mouseArea.width - width) - property double setMaxValue: { - var max = 0; - for (var i = 0; i < consumers.count; i++) { - var consumer = consumers.get(i) - max = barSeries.thingBarSetMap.hasOwnProperty(consumer.id) ? Math.max(max, barSeries.thingBarSetMap[consumer.id].at(idx)) : 0 - } - return max - } - y: Math.min(Math.max(mouseArea.height - (setMaxValue * mouseArea.height / valueAxis.max) - height - Style.smallMargins, 0), mouseArea.height - height) + ColumnLayout { + id: tooltipLayout + anchors { + left: parent.left + top: parent.top + margins: Style.smallMargins + } + Label { + text: toolTip.idx >= 0 && categoryAxis.timestamps.length > toolTip.idx ? root.configs[selectionTabs.currentValue.config].toLongLabel(categoryAxis.timestamps[toolTip.idx]) : "" + font: Style.smallFont + } - width: tooltipLayout.implicitWidth + Style.smallMargins * 2 - height: tooltipLayout.implicitHeight + Style.smallMargins * 2 - - Behavior on x { NumberAnimation { duration: Style.animationDuration } } - Behavior on y { NumberAnimation { duration: Style.animationDuration } } - Behavior on width { NumberAnimation { duration: Style.animationDuration } } - Behavior on height { NumberAnimation { duration: Style.animationDuration } } - - Rectangle { - anchors.fill: parent - color: Style.tileOverlayColor - opacity: .8 - radius: Style.smallCornerRadius - } - - ColumnLayout { - id: tooltipLayout - anchors { - left: parent.left - top: parent.top - margins: Style.smallMargins + Repeater { + model: consumers + delegate: RowLayout { + Rectangle { + width: Style.extraSmallFont.pixelSize + height: width + color: index >= 0 ? root.colors[index % root.colors.length] : "white" } Label { - text: toolTip.idx >= 0 && categoryAxis.timestamps.length > toolTip.idx ? root.configs[selectionTabs.currentValue.config].toLongLabel(categoryAxis.timestamps[toolTip.idx]) : "" - font: Style.smallFont - } - - Repeater { - model: consumers - delegate: RowLayout { - Rectangle { - width: Style.extraSmallFont.pixelSize - height: width - color: index >= 0 ? root.colors[index % root.colors.length] : "white" - } - Label { - text: barSeries.thingBarSetMap.hasOwnProperty(model.id) ? "%1: %2 kWh".arg(model.name).arg(barSeries.thingBarSetMap[model.id].at(toolTip.idx).toFixed(2)) : "" - font: Style.extraSmallFont - } - } + text: barSeries.thingBarSetMap.hasOwnProperty(model.id) ? "%1: %2 kWh".arg(model.name).arg(barSeries.thingBarSetMap[model.id].at(toolTip.idx).toFixed(2)) : "" + font: Style.extraSmallFont } } } diff --git a/nymea-app/ui/mainviews/energy/ConsumersHistory.qml b/nymea-app/ui/mainviews/energy/ConsumersHistory.qml index ce456034..0a1d70b5 100644 --- a/nymea-app/ui/mainviews/energy/ConsumersHistory.qml +++ b/nymea-app/ui/mainviews/energy/ConsumersHistory.qml @@ -3,24 +3,12 @@ import QtCharts 2.3 import QtQuick.Layouts 1.2 import QtQuick.Controls 2.3 import Nymea 1.0 +import "qrc:/ui/components" -ChartView { +Item { id: root - backgroundColor: "transparent" - margins.left: 0 - margins.right: 0 - margins.bottom: 0 - margins.top: 0 property var colors: null - - title: qsTr("Consumers history") - titleColor: Style.foregroundColor - - legend.alignment: Qt.AlignBottom - legend.labelColor: Style.foregroundColor - legend.font: Style.extraSmallFont - property ThingsProxy consumers: null Connections { @@ -119,7 +107,7 @@ ChartView { thingPowerLogs.loadingInhibited = true; for (var thingId in d.thingsSeriesMap) { - root.removeSeries(d.thingsSeriesMap[thingId]) + chartView.removeSeries(d.thingsSeriesMap[thingId]) } d.thingsSeriesMap = ({}) @@ -130,17 +118,17 @@ ChartView { var baseSeries = zeroSeries; if (i > 0) { baseSeries = d.thingsSeriesMap[consumerThingIds[i-1]].upperSeries -// print("base for:", thing.name, "is", engine.thingManager.things.getThing(consumerThingIds[i-1]).name) + // print("base for:", thing.name, "is", engine.thingManager.things.getThing(consumerThingIds[i-1]).name) } - var series = root.createSeries(ChartView.SeriesTypeArea, thing.name, dateTimeAxis, valueAxis) + var series = chartView.createSeries(ChartView.SeriesTypeArea, thing.name, dateTimeAxis, valueAxis) series.lowerSeries = baseSeries series.upperSeries = lineSeriesComponent.createObject(series) series.color = root.colors[i % root.colors.length] series.borderWidth = 0; series.borderColor = series.color -// print("Adding thingId series", thing.id, thing.name) + // print("Adding thingId series", thing.id, thing.name) var map = d.thingsSeriesMap map[thing.id] = series d.thingsSeriesMap = map @@ -156,95 +144,116 @@ ChartView { LineSeries { } } - ValueAxis { - id: valueAxis - min: 0 - max: Math.ceil(powerBalanceLogs.maxValue / 1000) * 1000 - labelFormat: "" - gridLineColor: Style.tileOverlayColor - labelsVisible: false - lineVisible: false - titleVisible: false - shadesVisible: false - // visible: false + ChartView { + id: chartView + anchors.fill: parent - } + backgroundColor: "transparent" + margins.left: 0 + margins.right: 0 + margins.bottom: 0 + margins.top: 0 - Item { - id: labelsLayout - x: Style.smallMargins - y: root.plotArea.y - height: root.plotArea.height - width: plotArea.x - x - Repeater { - model: valueAxis.tickCount - delegate: Label { - y: parent.height / (valueAxis.tickCount - 1) * index - font.pixelSize / 2 - width: parent.width - Style.smallMargins - horizontalAlignment: Text.AlignRight - text: ((valueAxis.max - (index * valueAxis.max / (valueAxis.tickCount - 1))) / 1000).toFixed(2) + "kW" - verticalAlignment: Text.AlignTop - font: Style.extraSmallFont + + title: qsTr("Consumers history") + titleColor: Style.foregroundColor + + legend.alignment: Qt.AlignBottom + legend.labelColor: Style.foregroundColor + legend.font: Style.extraSmallFont + + + ValueAxis { + id: valueAxis + min: 0 + max: Math.ceil(powerBalanceLogs.maxValue / 1000) * 1000 + labelFormat: "" + gridLineColor: Style.tileOverlayColor + labelsVisible: false + lineVisible: false + titleVisible: false + shadesVisible: false + // visible: false + + } + + Item { + id: labelsLayout + x: Style.smallMargins + y: chartView.plotArea.y + height: chartView.plotArea.height + width: chartView.plotArea.x - x + Repeater { + model: valueAxis.tickCount + delegate: Label { + y: parent.height / (valueAxis.tickCount - 1) * index - font.pixelSize / 2 + width: parent.width - Style.smallMargins + horizontalAlignment: Text.AlignRight + text: ((valueAxis.max - (index * valueAxis.max / (valueAxis.tickCount - 1))) / 1000).toFixed(2) + "kW" + verticalAlignment: Text.AlignTop + font: Style.extraSmallFont + } } } - } - DateTimeAxis { - id: dateTimeAxis - property date now: new Date() - min: { - var date = new Date(now); - date.setTime(date.getTime() - (1000 * 60 * 60 * 24) + 2000); - return date; + DateTimeAxis { + id: dateTimeAxis + property date now: new Date() + min: { + var date = new Date(now); + date.setTime(date.getTime() - (1000 * 60 * 60 * 24) + 2000); + return date; + } + max: { + var date = new Date(now); + date.setTime(date.getTime() + 2000) + return date; + } + format: "hh:mm" + labelsFont: Style.extraSmallFont + gridVisible: false + minorGridVisible: false + lineVisible: false + shadesVisible: false + labelsColor: Style.foregroundColor } - max: { - var date = new Date(now); - date.setTime(date.getTime() + 2000) - return date; - } - format: "hh:mm" - labelsFont: Style.extraSmallFont - gridVisible: false - minorGridVisible: false - lineVisible: false - shadesVisible: false - labelsColor: Style.foregroundColor - } - AreaSeries { - id: consumptionSeries - axisX: dateTimeAxis - axisY: valueAxis - color: Style.gray - borderWidth: 0 - borderColor: color - name: qsTr("Unknown") + AreaSeries { + id: consumptionSeries + axisX: dateTimeAxis + axisY: valueAxis + color: Style.gray + borderWidth: 0 + borderColor: color + name: qsTr("Unknown") - lowerSeries: LineSeries { - id: zeroSeries - XYPoint { x: dateTimeAxis.min.getTime(); y: 0 } - XYPoint { x: dateTimeAxis.max.getTime(); y: 0 } - function update(timestamp) { - append(timestamp, 0); - removePoints(1,1); + lowerSeries: LineSeries { + id: zeroSeries + XYPoint { x: dateTimeAxis.min.getTime(); y: 0 } + XYPoint { x: dateTimeAxis.max.getTime(); y: 0 } + function update(timestamp) { + append(timestamp, 0); + removePoints(1,1); + } + } + upperSeries: LineSeries { + id: consumptionUpperSeries + } + + function addEntry(entry) { + consumptionUpperSeries.append(entry.timestamp.getTime(), entry.consumption) } } - upperSeries: LineSeries { - id: consumptionUpperSeries - } - function addEntry(entry) { - consumptionUpperSeries.append(entry.timestamp.getTime(), entry.consumption) - } } MouseArea { id: mouseArea anchors.fill: parent - anchors.leftMargin: root.plotArea.x - anchors.topMargin: root.plotArea.y - anchors.rightMargin: root.width - root.plotArea.width - root.plotArea.x - anchors.bottomMargin: root.height - root.plotArea.height - root.plotArea.y + anchors.leftMargin: chartView.plotArea.x + anchors.topMargin: chartView.plotArea.y + anchors.rightMargin: chartView.width - chartView.plotArea.width - chartView.plotArea.x + anchors.bottomMargin: chartView.height - chartView.plotArea.height - chartView.plotArea.y hoverEnabled: true @@ -263,10 +272,13 @@ ChartView { visible: mouseArea.containsMouse } - Item { + NymeaToolTip { id: toolTip visible: mouseArea.containsMouse + backgroundItem: chartView + backgroundRect: Qt.rect(mouseArea.x + toolTip.x, mouseArea.y + toolTip.y, toolTip.width, toolTip.height) + property int idx: consumptionUpperSeries.count - Math.floor(mouseArea.mouseX * consumptionUpperSeries.count / mouseArea.width) property int seriesIndex: consumptionUpperSeries.count - idx @@ -281,18 +293,6 @@ ChartView { property date timestamp: new Date(consumptionUpperSeries.at(seriesIndex).x) - Behavior on x { NumberAnimation { duration: Style.animationDuration } } - Behavior on y { NumberAnimation { duration: Style.animationDuration } } - Behavior on width { NumberAnimation { duration: Style.animationDuration } } - Behavior on height { NumberAnimation { duration: Style.animationDuration } } - - Rectangle { - anchors.fill: parent - color: Style.tileOverlayColor - opacity: .8 - radius: Style.smallCornerRadius - } - ColumnLayout { id: tooltipLayout anchors { diff --git a/nymea-app/ui/mainviews/energy/PowerBalanceStats.qml b/nymea-app/ui/mainviews/energy/PowerBalanceStats.qml index c66447ff..e815a9e9 100644 --- a/nymea-app/ui/mainviews/energy/PowerBalanceStats.qml +++ b/nymea-app/ui/mainviews/energy/PowerBalanceStats.qml @@ -316,107 +316,98 @@ StatsBase { } } } + } + } - MouseArea { - id: mouseArea - anchors.fill: chartView - anchors.leftMargin: chartView.plotArea.x - anchors.topMargin: chartView.plotArea.y - anchors.rightMargin: chartView.width - chartView.plotArea.width - chartView.plotArea.x - anchors.bottomMargin: chartView.height - chartView.plotArea.height - chartView.plotArea.y + MouseArea { + id: mouseArea + anchors.fill: parent + anchors.leftMargin: chartView.x + chartView.plotArea.x + anchors.topMargin: chartView.y + chartView.plotArea.y + anchors.rightMargin: chartView.width - chartView.plotArea.width - chartView.plotArea.x + anchors.bottomMargin: chartView.height - chartView.plotArea.height - chartView.plotArea.y - hoverEnabled: true + hoverEnabled: true - Timer { - interval: 300 - running: mouseArea.pressed - onTriggered: mouseArea.preventStealing = true + Timer { + interval: 300 + running: mouseArea.pressed + onTriggered: mouseArea.preventStealing = true + } + onReleased: mouseArea.preventStealing = false + + NymeaToolTip { + id: toolTip + + backgroundItem: chartView + backgroundRect: Qt.rect(chartView.plotArea.x + toolTip.x, chartView.plotArea.y + toolTip.y, toolTip.width, toolTip.height) + + property int idx: Math.floor(mouseArea.mouseX * categoryAxis.count / mouseArea.width) + visible: mouseArea.containsMouse + + x: Math.min(idx * mouseArea.width / categoryAxis.count, mouseArea.width - width) + property double setMaxValue: d.consumptionSet && d.productionSet && d.acquisitionSet && d.returnSet ? + Math.max(d.consumptionSet.at(idx), Math.max(d.productionSet.at(idx), Math.max(d.acquisitionSet.at(idx), d.returnSet.at(idx)))) + : 0 + y: Math.min(Math.max(mouseArea.height - (setMaxValue * mouseArea.height / valueAxis.max) - height - Style.smallMargins, 0), mouseArea.height - height) + width: tooltipLayout.implicitWidth + Style.smallMargins * 2 + height: tooltipLayout.implicitHeight + Style.smallMargins * 2 + + ColumnLayout { + id: tooltipLayout + anchors { + left: parent.left + top: parent.top + margins: Style.smallMargins } - onReleased: mouseArea.preventStealing = false - Item { - id: toolTip - property int idx: Math.floor(mouseArea.mouseX * categoryAxis.count / mouseArea.width) - visible: mouseArea.containsMouse - - x: Math.min(idx * mouseArea.width / categoryAxis.count, mouseArea.width - width) - property double setMaxValue: d.consumptionSet && d.productionSet && d.acquisitionSet && d.returnSet ? - Math.max(d.consumptionSet.at(idx), Math.max(d.productionSet.at(idx), Math.max(d.acquisitionSet.at(idx), d.returnSet.at(idx)))) - : 0 - y: Math.min(Math.max(mouseArea.height - (setMaxValue * mouseArea.height / valueAxis.max) - height - Style.smallMargins, 0), mouseArea.height - height) - width: tooltipLayout.implicitWidth + Style.smallMargins * 2 - height: tooltipLayout.implicitHeight + Style.smallMargins * 2 - - Behavior on x { NumberAnimation { duration: Style.animationDuration } } - Behavior on y { NumberAnimation { duration: Style.animationDuration } } - Behavior on width { NumberAnimation { duration: Style.animationDuration } } - Behavior on height { NumberAnimation { duration: Style.animationDuration } } + Label { + text: toolTip.idx >= 0 && categoryAxis.timestamps.length > toolTip.idx ? root.configs[selectionTabs.currentValue.config].toLongLabel(categoryAxis.timestamps[toolTip.idx]) : "" + font: Style.smallFont + } + RowLayout { Rectangle { - anchors.fill: parent - color: Style.tileOverlayColor - opacity: .8 - radius: Style.smallCornerRadius + width: Style.extraSmallFont.pixelSize + height: width + color: Style.blue } - - - ColumnLayout { - id: tooltipLayout - anchors { - left: parent.left - top: parent.top - margins: Style.smallMargins - } - - Label { - text: toolTip.idx >= 0 && categoryAxis.timestamps.length > toolTip.idx ? root.configs[selectionTabs.currentValue.config].toLongLabel(categoryAxis.timestamps[toolTip.idx]) : "" - font: Style.smallFont - } - - RowLayout { - Rectangle { - width: Style.extraSmallFont.pixelSize - height: width - color: Style.blue - } - Label { - text: d.consumptionSet ? qsTr("Consumed: %1 kWh").arg(d.consumptionSet.at(toolTip.idx).toFixed(2)) : "" - font: Style.extraSmallFont - } - } - RowLayout { - Rectangle { - width: Style.extraSmallFont.pixelSize - height: width - color: Style.green - } - Label { - text: d.productionSet ? qsTr("Produced: %1 kWh").arg(d.productionSet.at(toolTip.idx).toFixed(2)) : "" - font: Style.extraSmallFont - } - } - RowLayout { - Rectangle { - width: Style.extraSmallFont.pixelSize - height: width - color: Style.red - } - Label { - text: d.acquisitionSet ? qsTr("From grid: %1 kWh").arg(d.acquisitionSet.at(toolTip.idx).toFixed(2)) : "" - font: Style.extraSmallFont - } - } - RowLayout { - Rectangle { - width: Style.extraSmallFont.pixelSize - height: width - color: Style.orange - } - Label { - text: d.returnSet ? qsTr("To grid: %1 kWh").arg(d.returnSet.at(toolTip.idx).toFixed(2)) : "" - font: Style.extraSmallFont - } - } + Label { + text: d.consumptionSet ? qsTr("Consumed: %1 kWh").arg(d.consumptionSet.at(toolTip.idx).toFixed(2)) : "" + font: Style.extraSmallFont + } + } + RowLayout { + Rectangle { + width: Style.extraSmallFont.pixelSize + height: width + color: Style.green + } + Label { + text: d.productionSet ? qsTr("Produced: %1 kWh").arg(d.productionSet.at(toolTip.idx).toFixed(2)) : "" + font: Style.extraSmallFont + } + } + RowLayout { + Rectangle { + width: Style.extraSmallFont.pixelSize + height: width + color: Style.red + } + Label { + text: d.acquisitionSet ? qsTr("From grid: %1 kWh").arg(d.acquisitionSet.at(toolTip.idx).toFixed(2)) : "" + font: Style.extraSmallFont + } + } + RowLayout { + Rectangle { + width: Style.extraSmallFont.pixelSize + height: width + color: Style.orange + } + Label { + text: d.returnSet ? qsTr("To grid: %1 kWh").arg(d.returnSet.at(toolTip.idx).toFixed(2)) : "" + font: Style.extraSmallFont } } } diff --git a/nymea-app/ui/mainviews/energy/PowerConsumptionBalanceHistory.qml b/nymea-app/ui/mainviews/energy/PowerConsumptionBalanceHistory.qml index add87d75..18c4475e 100644 --- a/nymea-app/ui/mainviews/energy/PowerConsumptionBalanceHistory.qml +++ b/nymea-app/ui/mainviews/energy/PowerConsumptionBalanceHistory.qml @@ -2,22 +2,12 @@ import QtQuick 2.0 import QtCharts 2.3 import QtQuick.Layouts 1.2 import QtQuick.Controls 2.3 +import QtGraphicalEffects 1.0 import Nymea 1.0 +import "qrc:/ui/components" -ChartView { +Item { id: root - backgroundColor: "transparent" - margins.left: 0 - margins.right: 0 - margins.bottom: 0 - margins.top: 0 - - title: qsTr("My consumption history") - titleColor: Style.foregroundColor - - legend.alignment: Qt.AlignBottom - legend.labelColor: Style.foregroundColor - legend.font: Style.extraSmallFont property PowerBalanceLogs energyLogs: PowerBalanceLogs { id: powerBalanceLogs @@ -63,179 +53,198 @@ ChartView { } } - ValueAxis { - id: valueAxis - min: 0 - max: Math.ceil(powerBalanceLogs.maxValue / 1000) * 1000 - labelFormat: "" - gridLineColor: Style.tileOverlayColor - labelsVisible: false - lineVisible: false - titleVisible: false - shadesVisible: false -// visible: false + ChartView { + id: chartView + anchors.fill: parent + backgroundColor: "transparent" + margins.left: 0 + margins.right: 0 + margins.bottom: 0 + margins.top: 0 - } + title: qsTr("My consumption history") + titleColor: Style.foregroundColor - Item { - id: labelsLayout - x: Style.smallMargins - y: root.plotArea.y - height: root.plotArea.height - width: plotArea.x - x - Repeater { - model: valueAxis.tickCount - delegate: Label { - y: parent.height / (valueAxis.tickCount - 1) * index - font.pixelSize / 2 - width: parent.width - Style.smallMargins - horizontalAlignment: Text.AlignRight - text: ((valueAxis.max - (index * valueAxis.max / (valueAxis.tickCount - 1))) / 1000).toFixed(2) + "kW" - verticalAlignment: Text.AlignTop - font: Style.extraSmallFont + legend.alignment: Qt.AlignBottom + legend.labelColor: Style.foregroundColor + legend.font: Style.extraSmallFont + + + ValueAxis { + id: valueAxis + min: 0 + max: Math.ceil(powerBalanceLogs.maxValue / 1000) * 1000 + labelFormat: "" + gridLineColor: Style.tileOverlayColor + labelsVisible: false + lineVisible: false + titleVisible: false + shadesVisible: false + // visible: false + + } + + Item { + id: labelsLayout + x: Style.smallMargins + y: chartView.plotArea.y + height: chartView.plotArea.height + width: chartView.plotArea.x - x + Repeater { + model: valueAxis.tickCount + delegate: Label { + y: parent.height / (valueAxis.tickCount - 1) * index - font.pixelSize / 2 + width: parent.width - Style.smallMargins + horizontalAlignment: Text.AlignRight + text: ((valueAxis.max - (index * valueAxis.max / (valueAxis.tickCount - 1))) / 1000).toFixed(2) + "kW" + verticalAlignment: Text.AlignTop + font: Style.extraSmallFont + } + } + + } + + DateTimeAxis { + id: dateTimeAxis + property date now: new Date() + min: { + var date = new Date(now); + date.setTime(date.getTime() - (1000 * 60 * 60 * 24) + 2000); + return date; + } + max: { + var date = new Date(now); + date.setTime(date.getTime() + 2000) + return date; + } + format: "hh:mm" + labelsFont: Style.extraSmallFont + gridVisible: false + minorGridVisible: false + lineVisible: false + shadesVisible: false + labelsColor: Style.foregroundColor + } + + // For debugging, to see the total graph and check if the other maths line up + AreaSeries { + id: consumptionSeries + axisX: dateTimeAxis + axisY: valueAxis + color: "blue" + borderWidth: 0 + borderColor: color + opacity: .5 + visible: false + + lowerSeries: zeroSeries + upperSeries: LineSeries { + id: consumptionUpperSeries + } + + function calculateValue(entry) { + return entry.consumption + } + function addEntry(entry) { + consumptionUpperSeries.append(entry.timestamp.getTime(), calculateValue(entry)) } } - } - DateTimeAxis { - id: dateTimeAxis - property date now: new Date() - min: { - var date = new Date(now); - date.setTime(date.getTime() - (1000 * 60 * 60 * 24) + 2000); - return date; - } - max: { - var date = new Date(now); - date.setTime(date.getTime() + 2000) - return date; - } - format: "hh:mm" - labelsFont: Style.extraSmallFont - gridVisible: false - minorGridVisible: false - lineVisible: false - shadesVisible: false - labelsColor: Style.foregroundColor - } + AreaSeries { + id: selfProductionSeries + axisX: dateTimeAxis + axisY: valueAxis + color: Style.green + borderWidth: 0 + borderColor: color + name: qsTr("Self production") + // visible: false - // For debugging, to see the total graph and check if the other maths line up - AreaSeries { - id: consumptionSeries - axisX: dateTimeAxis - axisY: valueAxis - color: "blue" - borderWidth: 0 - borderColor: color - opacity: .5 - visible: false + lowerSeries: LineSeries { + id: zeroSeries + XYPoint { x: dateTimeAxis.min.getTime(); y: 0 } + XYPoint { x: dateTimeAxis.max.getTime(); y: 0 } + function update(timestamp) { + append(timestamp, 0); + removePoints(1,1); + } + } - lowerSeries: zeroSeries - upperSeries: LineSeries { - id: consumptionUpperSeries - } + upperSeries: LineSeries { + id: selfProductionUpperSeries + } - function calculateValue(entry) { - return entry.consumption - } - function addEntry(entry) { - consumptionUpperSeries.append(entry.timestamp.getTime(), calculateValue(entry)) - } - } + function calculateValue(entry) { + var value = entry.consumption - Math.max(0, entry.acquisition); + if (entry.storage < 0) { + value += entry.storage; + } + return value; + } - - AreaSeries { - id: selfProductionSeries - axisX: dateTimeAxis - axisY: valueAxis - color: Style.green - borderWidth: 0 - borderColor: color - name: qsTr("Self production") -// visible: false - - lowerSeries: LineSeries { - id: zeroSeries - XYPoint { x: dateTimeAxis.min.getTime(); y: 0 } - XYPoint { x: dateTimeAxis.max.getTime(); y: 0 } - function update(timestamp) { - append(timestamp, 0); - removePoints(1,1); + function addEntry(entry) { + selfProductionUpperSeries.append(entry.timestamp.getTime(), calculateValue(entry)) } } - upperSeries: LineSeries { - id: selfProductionUpperSeries - } + AreaSeries { + id: storageSeries + axisX: dateTimeAxis + axisY: valueAxis + color: Style.orange + borderWidth: 0 + borderColor: color + name: qsTr("From battery") + // visible: false - function calculateValue(entry) { - var value = entry.consumption - Math.max(0, entry.acquisition); - if (entry.storage < 0) { - value += entry.storage; + lowerSeries: selfProductionUpperSeries + upperSeries: LineSeries { + id: storageUpperSeries + } + + function calculateValue(entry) { + return selfProductionSeries.calculateValue(entry) + Math.abs(Math.min(0, entry.storage)); + } + + function addEntry(entry) { + storageUpperSeries.append(entry.timestamp.getTime(), calculateValue(entry)) } - return value; } - function addEntry(entry) { - selfProductionUpperSeries.append(entry.timestamp.getTime(), calculateValue(entry)) + + AreaSeries { + id: acquisitionSeries + axisX: dateTimeAxis + axisY: valueAxis + color: Style.red + borderWidth: 0 + borderColor: color + name: qsTr("From grid") + // visible: false + + lowerSeries: storageUpperSeries + upperSeries: LineSeries { + id: acquisitionUpperSeries + } + + function calculateValue(entry) { + return storageSeries.calculateValue(entry) + Math.max(0, entry.acquisition) + } + function addEntry(entry) { + acquisitionUpperSeries.append(entry.timestamp.getTime(), calculateValue(entry)) + } } } - AreaSeries { - id: storageSeries - axisX: dateTimeAxis - axisY: valueAxis - color: Style.orange - borderWidth: 0 - borderColor: color - name: qsTr("From battery") -// visible: false - - lowerSeries: selfProductionUpperSeries - upperSeries: LineSeries { - id: storageUpperSeries - } - - function calculateValue(entry) { - return selfProductionSeries.calculateValue(entry) + Math.abs(Math.min(0, entry.storage)); - } - - function addEntry(entry) { - storageUpperSeries.append(entry.timestamp.getTime(), calculateValue(entry)) - } - } - - - AreaSeries { - id: acquisitionSeries - axisX: dateTimeAxis - axisY: valueAxis - color: Style.red - borderWidth: 0 - borderColor: color - name: qsTr("From grid") -// visible: false - - lowerSeries: storageUpperSeries - upperSeries: LineSeries { - id: acquisitionUpperSeries - } - - function calculateValue(entry) { - return storageSeries.calculateValue(entry) + Math.max(0, entry.acquisition) - } - function addEntry(entry) { - acquisitionUpperSeries.append(entry.timestamp.getTime(), calculateValue(entry)) - } - } MouseArea { id: mouseArea - anchors.fill: parent - anchors.leftMargin: root.plotArea.x - anchors.topMargin: root.plotArea.y - anchors.rightMargin: root.width - root.plotArea.width - root.plotArea.x - anchors.bottomMargin: root.height - root.plotArea.height - root.plotArea.y + anchors.fill: chartView + anchors.leftMargin: chartView.plotArea.x + anchors.topMargin: chartView.plotArea.y + anchors.rightMargin: chartView.width - chartView.plotArea.width - chartView.plotArea.x + anchors.bottomMargin: chartView.height - chartView.plotArea.height - chartView.plotArea.y hoverEnabled: true @@ -254,10 +263,15 @@ ChartView { visible: mouseArea.containsMouse } - Item { + + NymeaToolTip { id: toolTip visible: mouseArea.containsMouse + backgroundItem: chartView + backgroundRect: Qt.rect(mouseArea.x + toolTip.x, mouseArea.y + toolTip.y, toolTip.width, toolTip.height) + + property int idx: consumptionUpperSeries.count - (Math.floor(mouseArea.mouseX * consumptionUpperSeries.count / mouseArea.width)) property int seriesIndex: consumptionUpperSeries.count - idx @@ -270,18 +284,6 @@ ChartView { width: tooltipLayout.implicitWidth + Style.smallMargins * 2 height: tooltipLayout.implicitHeight + Style.smallMargins * 2 - Behavior on x { NumberAnimation { duration: Style.animationDuration } } - Behavior on y { NumberAnimation { duration: Style.animationDuration } } - Behavior on width { NumberAnimation { duration: Style.animationDuration } } - Behavior on height { NumberAnimation { duration: Style.animationDuration } } - - Rectangle { - anchors.fill: parent - color: Style.tileOverlayColor - opacity: .8 - radius: Style.smallCornerRadius - } - ColumnLayout { id: tooltipLayout anchors { @@ -334,3 +336,4 @@ ChartView { } } } + diff --git a/nymea-app/ui/mainviews/energy/PowerProductionBalanceHistory.qml b/nymea-app/ui/mainviews/energy/PowerProductionBalanceHistory.qml index 5695518a..79f53881 100644 --- a/nymea-app/ui/mainviews/energy/PowerProductionBalanceHistory.qml +++ b/nymea-app/ui/mainviews/energy/PowerProductionBalanceHistory.qml @@ -3,21 +3,10 @@ import QtCharts 2.3 import QtQuick.Layouts 1.2 import QtQuick.Controls 2.3 import Nymea 1.0 +import "qrc:/ui/components" -ChartView { +Item { id: root - backgroundColor: "transparent" - margins.left: 0 - margins.right: 0 - margins.bottom: 0 - margins.top: 0 - - title: qsTr("My production history") - titleColor: Style.foregroundColor - - legend.alignment: Qt.AlignBottom - legend.labelColor: Style.foregroundColor - legend.font: Style.extraSmallFont property PowerBalanceLogs energyLogs: PowerBalanceLogs { id: powerBalanceLogs @@ -62,173 +51,192 @@ ChartView { } } - ValueAxis { - id: valueAxis - min: 0 - max: Math.ceil(-powerBalanceLogs.minValue / 1000) * 1000 - labelFormat: "" - gridLineColor: Style.tileOverlayColor - labelsVisible: false - lineVisible: false - titleVisible: false - shadesVisible: false - } + ChartView { + id: chartView + anchors.fill: parent - Item { - id: labelsLayout - x: Style.smallMargins - y: root.plotArea.y - height: root.plotArea.height - width: plotArea.x - x - Repeater { - model: valueAxis.tickCount - delegate: Label { - y: parent.height / (valueAxis.tickCount - 1) * index - font.pixelSize / 2 - width: parent.width - Style.smallMargins - horizontalAlignment: Text.AlignRight - text: ((valueAxis.max - (index * valueAxis.max / (valueAxis.tickCount - 1))) / 1000).toFixed(2) + "kW" - verticalAlignment: Text.AlignTop - font: Style.extraSmallFont - } - } - } + backgroundColor: "transparent" + margins.left: 0 + margins.right: 0 + margins.bottom: 0 + margins.top: 0 - DateTimeAxis { - id: dateTimeAxis - property date now: new Date() - min: { - var date = new Date(now); - date.setTime(date.getTime() - (1000 * 60 * 60 * 24) + 2000); - return date; - } - max: { - var date = new Date(now); - date.setTime(date.getTime() + 2000) - return date; - } - format: "hh:mm" - labelsFont: Style.extraSmallFont - gridVisible: false - minorGridVisible: false - lineVisible: false - shadesVisible: false - labelsColor: Style.foregroundColor - } + title: qsTr("My production history") + titleColor: Style.foregroundColor - // For debugging, to see if the other maths line up with the plain production graph - AreaSeries { - id: productionSeries - axisX: dateTimeAxis - axisY: valueAxis - color: "blue" - borderWidth: 0 - borderColor: color - opacity: .5 - name: "Total production" - visible: false + legend.alignment: Qt.AlignBottom + legend.labelColor: Style.foregroundColor + legend.font: Style.extraSmallFont - function calculateValue(entry) { - return Math.abs(Math.min(0, entry.production)) - } - function addEntry(entry) { - productionUpperSeries.append(entry.timestamp.getTime(), calculateValue(entry)) + + ValueAxis { + id: valueAxis + min: 0 + max: Math.ceil(-powerBalanceLogs.minValue / 1000) * 1000 + labelFormat: "" + gridLineColor: Style.tileOverlayColor + labelsVisible: false + lineVisible: false + titleVisible: false + shadesVisible: false } - lowerSeries: zeroSeries - upperSeries: LineSeries { - id: productionUpperSeries - } - } - - AreaSeries { - id: selfConsumptionSeries - axisX: dateTimeAxis - axisY: valueAxis - color: Style.red - borderWidth: 0 - borderColor: color - name: qsTr("Consumed") -// visible: false - - function calculateValue(entry) { - return Math.abs(Math.min(0, entry.production)) - Math.abs(Math.min(0, entry.acquisition)) - Math.max(0, entry.storage) - } - - function addEntry(entry) { - selfConsumptionUpperSeries.append(entry.timestamp.getTime(), calculateValue(entry)) - } - - lowerSeries: LineSeries { - id: zeroSeries - XYPoint { x: dateTimeAxis.min.getTime(); y: 0 } - XYPoint { x: dateTimeAxis.max.getTime(); y: 0 } - function update(timestamp) { - append(timestamp, 0); - removePoints(1,1); + Item { + id: labelsLayout + x: Style.smallMargins + y: chartView.plotArea.y + height: chartView.plotArea.height + width: chartView.plotArea.x - x + Repeater { + model: valueAxis.tickCount + delegate: Label { + y: parent.height / (valueAxis.tickCount - 1) * index - font.pixelSize / 2 + width: parent.width - Style.smallMargins + horizontalAlignment: Text.AlignRight + text: ((valueAxis.max - (index * valueAxis.max / (valueAxis.tickCount - 1))) / 1000).toFixed(2) + "kW" + verticalAlignment: Text.AlignTop + font: Style.extraSmallFont + } } } - upperSeries: LineSeries { - id: selfConsumptionUpperSeries - } - } - - AreaSeries { - id: storageSeries - axisX: dateTimeAxis - axisY: valueAxis - color: Style.orange - borderWidth: 0 - borderColor: color -// visible: false - name: qsTr("To battery") - - - function calculateValue(entry) { - return selfConsumptionSeries.calculateValue(entry) + Math.abs(Math.max(0, entry.storage)); + DateTimeAxis { + id: dateTimeAxis + property date now: new Date() + min: { + var date = new Date(now); + date.setTime(date.getTime() - (1000 * 60 * 60 * 24) + 2000); + return date; + } + max: { + var date = new Date(now); + date.setTime(date.getTime() + 2000) + return date; + } + format: "hh:mm" + labelsFont: Style.extraSmallFont + gridVisible: false + minorGridVisible: false + lineVisible: false + shadesVisible: false + labelsColor: Style.foregroundColor } - function addEntry(entry) { - storageUpperSeries.append(entry.timestamp.getTime(), calculateValue(entry)) + // For debugging, to see if the other maths line up with the plain production graph + AreaSeries { + id: productionSeries + axisX: dateTimeAxis + axisY: valueAxis + color: "blue" + borderWidth: 0 + borderColor: color + opacity: .5 + name: "Total production" + visible: false + + function calculateValue(entry) { + return Math.abs(Math.min(0, entry.production)) + } + function addEntry(entry) { + productionUpperSeries.append(entry.timestamp.getTime(), calculateValue(entry)) + } + + lowerSeries: zeroSeries + upperSeries: LineSeries { + id: productionUpperSeries + } } - lowerSeries: selfConsumptionUpperSeries - upperSeries: LineSeries { - id: storageUpperSeries - } - } + AreaSeries { + id: selfConsumptionSeries + axisX: dateTimeAxis + axisY: valueAxis + color: Style.red + borderWidth: 0 + borderColor: color + name: qsTr("Consumed") + // visible: false + function calculateValue(entry) { + return Math.abs(Math.min(0, entry.production)) - Math.abs(Math.min(0, entry.acquisition)) - Math.max(0, entry.storage) + } - AreaSeries { - id: acquisitionSeries - axisX: dateTimeAxis - axisY: valueAxis - color: Style.green - borderWidth: 0 - borderColor: color - name: qsTr("To grid") -// visible: false + function addEntry(entry) { + selfConsumptionUpperSeries.append(entry.timestamp.getTime(), calculateValue(entry)) + } - function calculateValue(entry) { - return storageSeries.calculateValue(entry) + Math.abs(Math.min(0, entry.acquisition)) - } - function addEntry(entry) { - acquisitionUpperSeries.append(entry.timestamp.getTime(), calculateValue(entry)) + lowerSeries: LineSeries { + id: zeroSeries + XYPoint { x: dateTimeAxis.min.getTime(); y: 0 } + XYPoint { x: dateTimeAxis.max.getTime(); y: 0 } + function update(timestamp) { + append(timestamp, 0); + removePoints(1,1); + } + } + + upperSeries: LineSeries { + id: selfConsumptionUpperSeries + } } - lowerSeries: storageUpperSeries - upperSeries: LineSeries { - id: acquisitionUpperSeries + AreaSeries { + id: storageSeries + axisX: dateTimeAxis + axisY: valueAxis + color: Style.orange + borderWidth: 0 + borderColor: color + // visible: false + name: qsTr("To battery") + + + function calculateValue(entry) { + return selfConsumptionSeries.calculateValue(entry) + Math.abs(Math.max(0, entry.storage)); + } + + function addEntry(entry) { + storageUpperSeries.append(entry.timestamp.getTime(), calculateValue(entry)) + } + + lowerSeries: selfConsumptionUpperSeries + upperSeries: LineSeries { + id: storageUpperSeries + } + } + + + AreaSeries { + id: acquisitionSeries + axisX: dateTimeAxis + axisY: valueAxis + color: Style.green + borderWidth: 0 + borderColor: color + name: qsTr("To grid") + // visible: false + + function calculateValue(entry) { + return storageSeries.calculateValue(entry) + Math.abs(Math.min(0, entry.acquisition)) + } + function addEntry(entry) { + acquisitionUpperSeries.append(entry.timestamp.getTime(), calculateValue(entry)) + } + + lowerSeries: storageUpperSeries + upperSeries: LineSeries { + id: acquisitionUpperSeries + } } } MouseArea { id: mouseArea anchors.fill: parent - anchors.leftMargin: root.plotArea.x - anchors.topMargin: root.plotArea.y - anchors.rightMargin: root.width - root.plotArea.width - root.plotArea.x - anchors.bottomMargin: root.height - root.plotArea.height - root.plotArea.y + anchors.leftMargin: chartView.plotArea.x + anchors.topMargin: chartView.plotArea.y + anchors.rightMargin: chartView.width - chartView.plotArea.width - chartView.plotArea.x + anchors.bottomMargin: chartView.height - chartView.plotArea.height - chartView.plotArea.y hoverEnabled: true @@ -247,10 +255,13 @@ ChartView { visible: mouseArea.containsMouse } - Item { + NymeaToolTip { id: toolTip visible: mouseArea.containsMouse + backgroundItem: chartView + backgroundRect: Qt.rect(mouseArea.x + toolTip.x, mouseArea.y + toolTip.y, toolTip.width, toolTip.height) + property int idx: productionUpperSeries.count - Math.floor(mouseArea.mouseX * productionUpperSeries.count / mouseArea.width) property int seriesIndex: productionUpperSeries.count - idx @@ -263,18 +274,6 @@ ChartView { width: tooltipLayout.implicitWidth + Style.smallMargins * 2 height: tooltipLayout.implicitHeight + Style.smallMargins * 2 - Behavior on x { NumberAnimation { duration: Style.animationDuration } } - Behavior on y { NumberAnimation { duration: Style.animationDuration } } - Behavior on width { NumberAnimation { duration: Style.animationDuration } } - Behavior on height { NumberAnimation { duration: Style.animationDuration } } - - Rectangle { - anchors.fill: parent - color: Style.tileOverlayColor - opacity: .8 - radius: Style.smallCornerRadius - } - ColumnLayout { id: tooltipLayout anchors { @@ -327,3 +326,6 @@ ChartView { } } } + + +