Loading...
Searching...
No Matches
Infographics.qml
/*
* Copyright (C) 2013-2016 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import "Gradient.js" as Gradient
import QtQuick 2.15
import Lomiri.Components 1.3
Item {
id: infographic
property var model
property int animDuration: 10
property int currentWeekDay
QtObject {
id: d
objectName: "infographicPrivate"
property bool useDotAnimation: true
property int circleModifier: useDotAnimation ? 1 : 2
property bool animating: dotHideAnimTimer.running
|| dotShowAnimTimer.running
|| circleChangeAnimTimer.running
}
QtObject {
id: whiteTheme
property color main: "white"
property color start: "white"
property color end: "white"
}
Connections {
target: model
ignoreUnknownSignals: model === undefined
function onDataAboutToAppear() { startHideAnimation() } // hide "no data" label
function onDataAppeared() { startShowAnimation() }
function onDataAboutToChange() { startHideAnimation() }
function onDataChanged() { startShowAnimation() }
function onDataAboutToDisappear() { startHideAnimation() }
function onDataDisappeared() { startShowAnimation() } // show "no data" label
}
LiveTimer {
frequency: LiveTimer.Hour
onTrigger: handleTimerTrigger()
}
function handleTimerTrigger(){
var today = new Date().getDay()
if(infographic.currentWeekDay !== today){
infographic.currentWeekDay = today
reloadUserData();
}
}
function reloadUserData(){
d.useDotAnimation = false
infographic.model.nextDataSource()
}
function startShowAnimation() {
dotHideAnimTimer.stop()
notification.hideAnim.stop()
if (d.useDotAnimation) {
dotShowAnimTimer.startFromBeginning()
}
notification.showAnim.start()
}
function startHideAnimation() {
dotShowAnimTimer.stop()
circleChangeAnimTimer.stop()
notification.showAnim.stop()
if (d.useDotAnimation) {
dotHideAnimTimer.startFromBeginning()
} else {
circleChangeAnimTimer.startFromBeginning()
}
notification.hideAnim.start()
}
visible: model.username !== ""
Component.onCompleted: {
currentWeekDay = new Date().getDay()
startShowAnimation()
}
Item {
id: dataCircle
objectName: "dataCircle"
property real divisor: 1.5
width: Math.min(parent.height, parent.width) / divisor
height: width
anchors.centerIn: parent
Timer {
id: circleChangeAnimTimer
property int pastCircleCounter
property int presentCircleCounter
interval: notification.duration
running: false
repeat: true
onTriggered: {
if (pastCircleCounter < pastCircles.count) {
var nextCircle = pastCircles.itemAt(pastCircleCounter++)
if (nextCircle !== null) nextCircle.pastCircleChangeAnim.start()
}
if (pastCircleCounter > pastCircles.count / 2) {
var nextCircle = presentCircles.itemAt(presentCircleCounter++)
if (nextCircle !== null) nextCircle.presentCircleChangeAnim.start()
}
if (presentCircleCounter > infographic.model.currentDay && pastCircleCounter >= pastCircles.count) {
stop()
}
}
function startFromBeginning() {
circleChangeAnimTimer.pastCircleCounter = 0
circleChangeAnimTimer.presentCircleCounter = 0
start()
}
}
Repeater {
id: pastCircles
objectName: "pastCircles"
model: infographic.model.secondMonth
delegate: ObjectPositioner {
property alias pastCircleChangeAnim: pastCircleChangeAnim
index: model.index
count: pastCircles.count
radius: dataCircle.width / 2
halfSize: pastCircle.width / 2
posOffset: 0.0
Circle {
id: pastCircle
objectName: "pastCircle" + index
property real divisor: 1.8
property real circleOpacity: 0.1
width: dataCircle.width / divisor
height: dataCircle.height / divisor
opacity: 0.0
circleScale: 0.0
visible: modelData !== undefined
color: "transparent"
centerCircle: dataCircle
SequentialAnimation {
id: pastCircleChangeAnim
loops: 1
ParallelAnimation {
PropertyAnimation {
target: pastCircle
property: "opacity"
to: pastCircle.circleOpacity
easing.type: Easing.OutCurve
duration: circleChangeAnimTimer.interval * d.circleModifier
}
PropertyAnimation {
target: pastCircle
property: "circleScale"
to: modelData
easing.type: Easing.OutCurve
duration: circleChangeAnimTimer.interval * d.circleModifier
}
ColorAnimation {
target: pastCircle
property: "color"
to: Gradient.threeColorByIndex(index, count, whiteTheme)
easing.type: Easing.OutCurve
duration: circleChangeAnimTimer.interval * d.circleModifier
}
}
}
}
}
}
Repeater {
id: presentCircles
objectName: "presentCircles"
model: infographic.model.firstMonth
delegate: ObjectPositioner {
property alias presentCircleChangeAnim: presentCircleChangeAnim
index: model.index
count: presentCircles.count
radius: dataCircle.width / 2
halfSize: presentCircle.width / 2
posOffset: 0.0
Circle {
id: presentCircle
objectName: "presentCircle" + index
property real divisor: 1.8
property real circleOpacity: 0.3
width: dataCircle.width / divisor
height: dataCircle.height / divisor
opacity: 0.0
circleScale: 0.0
visible: modelData !== undefined
color: "transparent"
centerCircle: dataCircle
SequentialAnimation {
id: presentCircleChangeAnim
loops: 1
ParallelAnimation {
PropertyAnimation {
target: presentCircle
property: "opacity"
to: presentCircle.circleOpacity
easing.type: Easing.OutCurve
duration: circleChangeAnimTimer.interval * d.circleModifier
}
PropertyAnimation {
target: presentCircle
property: "circleScale"
to: modelData
easing.type: Easing.OutCurve
duration: circleChangeAnimTimer.interval * d.circleModifier
}
ColorAnimation {
target: presentCircle
property: "color"
to: Gradient.threeColorByIndex(index, infographic.model.currentDay, whiteTheme)
easing.type: Easing.OutCurve
duration: circleChangeAnimTimer.interval * d.circleModifier
}
}
}
}
}
}
Timer {
id: dotShowAnimTimer
property int dotCounter: 0
interval: animDuration * 0.5; running: false; repeat: true
onTriggered: {
if (dotCounter < dots.count) {
var nextDot = dots.itemAt(dotCounter);
if (nextDot) {
nextDot.unlockAnimation.start();
if (++dotCounter == Math.round(dots.count / 2)) {
circleChangeAnimTimer.startFromBeginning();
}
}
} else {
stop()
}
}
function startFromBeginning() {
if (!dotShowAnimTimer.running)
dotCounter = 0
start()
}
}
Timer {
id: dotHideAnimTimer
property int dotCounter
interval: animDuration * 0.5
running: false
repeat: true
onTriggered: {
if (dotCounter >= 0) {
var nextDot = dots.itemAt(dotCounter--)
nextDot.changeAnimation.start()
} else {
stop()
}
if (dotCounter == 0) {
infographic.model.readyForDataChange()
}
}
function startFromBeginning() {
if (!dotHideAnimTimer.running)
dotCounter = dots.count - 1
start()
}
}
Repeater {
id: dots
objectName: "dots"
model: infographic.model.firstMonth
delegate: ObjectPositioner {
property alias unlockAnimation: dotUnlockAnim
property alias changeAnimation: dotChangeAnim
property int currentDay: infographic.model.currentDay
index: model.index
count: dots.count
radius: dataCircle.width / 2
halfSize: dot.width / 2
posOffset: radius / dot.width / 3
state: dot.state
Dot {
id: dot
objectName: "dot" + index
property real baseOpacity: 1
width: units.dp(5) * parent.radius / 200
height: units.dp(5) * parent.radius / 200
opacity: 0.0
smooth: true
state: index < currentDay ? "filled" : index == currentDay ? "pointer" : "unfilled"
PropertyAnimation {
id: dotUnlockAnim
target: dot
property: "opacity"
to: dot.baseOpacity
duration: dotShowAnimTimer.interval
}
PropertyAnimation {
id: dotChangeAnim
target: dot
property: "opacity"
to: 0.0
duration: dotHideAnimTimer.interval
}
}
}
}
Label {
id: notification
objectName: "label"
property alias hideAnim: decreaseOpacity
property alias showAnim: increaseOpacity
property real baseOpacity: 1
property real duration: dotShowAnimTimer.interval * 5
height: 0.7 * dataCircle.width
width: notification.height
anchors.centerIn: parent
text: infographic.model.label
wrapMode: Text.WordWrap
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
color: "white"
PropertyAnimation {
id: increaseOpacity
target: notification
property: "opacity"
from: 0.0
to: notification.baseOpacity
duration: notification.duration * dots.count
}
PropertyAnimation {
id: decreaseOpacity
target: notification
property: "opacity"
from: notification.baseOpacity
to: 0.0
duration: notification.duration * dots.count
onStopped: if (!d.useDotAnimation) infographic.model.readyForDataChange()
}
}
}
MouseArea {
anchors.fill: dataCircle
enabled: notification.text != ""
onDoubleClicked: {
if (!d.animating) {
reloadUserData()
}
}
}
}