2 * Copyright (C) 2013-2016 Canonical, Ltd.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 import "Gradient.js" as Gradient
19 import Ubuntu.Components 1.3
26 property int animDuration: 10
30 objectName: "infographicPrivate"
31 property bool useDotAnimation: true
32 property int circleModifier: useDotAnimation ? 1 : 2
33 property bool animating: dotHideAnimTimer.running
34 || dotShowAnimTimer.running
35 || circleChangeAnimTimer.running
40 property color main: "white"
41 property color start: "white"
42 property color end: "white"
47 ignoreUnknownSignals: model === undefined
49 onDataAboutToAppear: startHideAnimation() // hide "no data" label
50 onDataAppeared: startShowAnimation()
52 onDataAboutToChange: startHideAnimation()
53 onDataChanged: startShowAnimation()
55 onDataAboutToDisappear: startHideAnimation()
56 onDataDisappeared: startShowAnimation() // show "no data" label
59 function startShowAnimation() {
60 dotHideAnimTimer.stop()
61 notification.hideAnim.stop()
63 if (d.useDotAnimation) {
64 dotShowAnimTimer.startFromBeginning()
66 notification.showAnim.start()
69 function startHideAnimation() {
70 dotShowAnimTimer.stop()
71 circleChangeAnimTimer.stop()
72 notification.showAnim.stop()
74 if (d.useDotAnimation) {
75 dotHideAnimTimer.startFromBeginning()
77 circleChangeAnimTimer.startFromBeginning()
79 notification.hideAnim.start()
82 visible: model.username !== ""
84 Component.onCompleted: startShowAnimation()
88 objectName: "dataCircle"
90 property real divisor: 1.5
92 width: Math.min(parent.height, parent.width) / divisor
95 anchors.centerIn: parent
98 id: circleChangeAnimTimer
100 property int pastCircleCounter
101 property int presentCircleCounter
103 interval: notification.duration
107 if (pastCircleCounter < pastCircles.count) {
108 var nextCircle = pastCircles.itemAt(pastCircleCounter++)
109 if (nextCircle !== null) nextCircle.pastCircleChangeAnim.start()
111 if (pastCircleCounter > pastCircles.count / 2) {
112 var nextCircle = presentCircles.itemAt(presentCircleCounter++)
113 if (nextCircle !== null) nextCircle.presentCircleChangeAnim.start()
115 if (presentCircleCounter > infographic.model.currentDay && pastCircleCounter >= pastCircles.count) {
120 function startFromBeginning() {
121 circleChangeAnimTimer.pastCircleCounter = 0
122 circleChangeAnimTimer.presentCircleCounter = 0
129 objectName: "pastCircles"
130 model: infographic.model.secondMonth
132 delegate: ObjectPositioner {
133 property alias pastCircleChangeAnim: pastCircleChangeAnim
136 count: pastCircles.count
137 radius: dataCircle.width / 2
138 halfSize: pastCircle.width / 2
143 objectName: "pastCircle" + index
145 property real divisor: 1.8
146 property real circleOpacity: 0.1
148 width: dataCircle.width / divisor
149 height: dataCircle.height / divisor
152 visible: modelData !== undefined
154 centerCircle: dataCircle
156 SequentialAnimation {
157 id: pastCircleChangeAnim
164 to: pastCircle.circleOpacity
165 easing.type: Easing.OutCurve
166 duration: circleChangeAnimTimer.interval * d.circleModifier
170 property: "circleScale"
172 easing.type: Easing.OutCurve
173 duration: circleChangeAnimTimer.interval * d.circleModifier
178 to: Gradient.threeColorByIndex(index, count, whiteTheme)
179 easing.type: Easing.OutCurve
180 duration: circleChangeAnimTimer.interval * d.circleModifier
190 objectName: "presentCircles"
191 model: infographic.model.firstMonth
193 delegate: ObjectPositioner {
194 property alias presentCircleChangeAnim: presentCircleChangeAnim
197 count: presentCircles.count
198 radius: dataCircle.width / 2
199 halfSize: presentCircle.width / 2
204 objectName: "presentCircle" + index
206 property real divisor: 1.8
207 property real circleOpacity: 0.3
209 width: dataCircle.width / divisor
210 height: dataCircle.height / divisor
213 visible: modelData !== undefined
215 centerCircle: dataCircle
217 SequentialAnimation {
218 id: presentCircleChangeAnim
224 target: presentCircle
226 to: presentCircle.circleOpacity
227 easing.type: Easing.OutCurve
228 duration: circleChangeAnimTimer.interval * d.circleModifier
231 target: presentCircle
232 property: "circleScale"
234 easing.type: Easing.OutCurve
235 duration: circleChangeAnimTimer.interval * d.circleModifier
238 target: presentCircle
240 to: Gradient.threeColorByIndex(index, infographic.model.currentDay, whiteTheme)
241 easing.type: Easing.OutCurve
242 duration: circleChangeAnimTimer.interval * d.circleModifier
253 property int dotCounter: 0
255 interval: animDuration * 0.5; running: false; repeat: true
257 if (dotCounter < dots.count) {
258 var nextDot = dots.itemAt(dotCounter);
260 nextDot.unlockAnimation.start();
261 if (++dotCounter == Math.round(dots.count / 2)) {
262 circleChangeAnimTimer.startFromBeginning();
270 function startFromBeginning() {
271 if (!dotShowAnimTimer.running)
281 property int dotCounter
283 interval: animDuration * 0.5
287 if (dotCounter >= 0) {
288 var nextDot = dots.itemAt(dotCounter--)
289 nextDot.changeAnimation.start()
293 if (dotCounter == 0) {
294 infographic.model.readyForDataChange()
298 function startFromBeginning() {
299 if (!dotHideAnimTimer.running)
300 dotCounter = dots.count - 1
310 model: infographic.model.firstMonth
312 delegate: ObjectPositioner {
313 property alias unlockAnimation: dotUnlockAnim
314 property alias changeAnimation: dotChangeAnim
316 property int currentDay: infographic.model.currentDay
320 radius: dataCircle.width / 2
321 halfSize: dot.width / 2
322 posOffset: radius / dot.width / 3
327 objectName: "dot" + index
329 property real baseOpacity: 1
331 width: units.dp(5) * parent.radius / 200
332 height: units.dp(5) * parent.radius / 200
335 state: index < currentDay ? "filled" : index == currentDay ? "pointer" : "unfilled"
343 duration: dotShowAnimTimer.interval
352 duration: dotHideAnimTimer.interval
362 property alias hideAnim: decreaseOpacity
363 property alias showAnim: increaseOpacity
365 property real baseOpacity: 1
366 property real duration: dotShowAnimTimer.interval * 5
368 height: 0.7 * dataCircle.width
369 width: notification.height
370 anchors.centerIn: parent
372 text: infographic.model.label
374 wrapMode: Text.WordWrap
375 horizontalAlignment: Text.AlignHCenter
376 verticalAlignment: Text.AlignVCenter
385 to: notification.baseOpacity
386 duration: notification.duration * dots.count
394 from: notification.baseOpacity
396 duration: notification.duration * dots.count
397 onStopped: if (!d.useDotAnimation) infographic.model.readyForDataChange()
403 anchors.fill: dataCircle
404 enabled: notification.text != ""
408 d.useDotAnimation = false
409 infographic.model.nextDataSource()