Merge PR #730: Blur chart tooltips

This commit is contained in:
Jenkins nymea 2021-12-15 00:49:47 +01:00
commit e2e61b6637
9 changed files with 645 additions and 608 deletions

View File

@ -272,5 +272,6 @@
<file>ui/mainviews/energy/StatsBase.qml</file>
<file>ui/mainviews/energy/EnergySettingsPage.qml</file>
<file>ui/mainviews/energy/ConsumersPieChart.qml</file>
<file>ui/components/NymeaToolTip.qml</file>
</qresource>
</RCC>

View File

@ -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

View File

@ -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

View File

@ -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
}
}

View File

@ -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
}
}
}

View File

@ -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 {

View File

@ -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
}
}
}

View File

@ -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 {
}
}
}

View File

@ -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 {
}
}
}