/* * Copyright (C) 2013 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 . */ import "../Components" import "Gradient.js" as Gradient import QtQuick 2.0 import Ubuntu.Components 0.1 Item { id: infographic property var model property int animDuration: 10 Connections { target: model onDataAppeared: startShowAnimation() onDataAboutToChange: startHideAnimation() onDataChanged: startShowAnimation() onDataAboutToDisappear: startHideAnimation() } function startShowAnimation() { dotShowAnimTimer.startFromBeginning() notification.showAnim.start() } function startHideAnimation() { dotHideAnimTimer.startFromBeginning() notification.hideAnim.start() } visible: model.label !== "" Component.onCompleted: 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: circleGrowAnimTimer property int pastCircleCounter property int presentCircleCounter interval: animDuration running: false repeat: true onTriggered: { if (pastCircleCounter < pastCircles.count) { var nextCircle = pastCircles.itemAt(pastCircleCounter++) if (nextCircle !== null) nextCircle.pastCircleGrowAnim.start() } if (pastCircleCounter > pastCircles.count / 2) { var nextCircle = presentCircles.itemAt(presentCircleCounter++) if (nextCircle !== null) nextCircle.presentCircleGrowAnim.start() } if (presentCircleCounter > infographic.model.currentDay) { stop() } } function startFromBeginning() { circleGrowAnimTimer.pastCircleCounter = 0 circleGrowAnimTimer.presentCircleCounter = 0 start() } } Timer { id: circleShrinkAnimTimer property int pastCircleCounter property int presentCircleCounter interval: animDuration running: false repeat: true onTriggered: { if (pastCircleCounter >= 0) { var nextCircle = pastCircles.itemAt(pastCircleCounter--) if (nextCircle !== null) nextCircle.pastCircleShrinkAnim.start() } if (pastCircleCounter < pastCircles.count / 2) { var nextCircle = presentCircles.itemAt(presentCircleCounter--) if (nextCircle !== null) nextCircle.presentCircleShrinkAnim.start() } if (presentCircleCounter < 0) { stop() infographic.model.readyForDataChange() } } function startFromBeginning() { pastCircleCounter = pastCircles.count - 1 presentCircleCounter = model.currentDay start() } } Repeater { id: pastCircles objectName: "pastCircles" model: infographic.model.secondMonth delegate: ObjectPositioner { property alias pastCircleGrowAnim: pastCircleGrowAnim property alias pastCircleShrinkAnim: pastCircleShrinkAnim index: model.index count: pastCircles.count radius: parent.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 scale: 0.0 visible: modelData !== undefined color: Gradient.threeColorByIndex(index, count, infographic.model.secondColor) SequentialAnimation { id: pastCircleGrowAnim loops: 1 ParallelAnimation { PropertyAnimation { target: pastCircle property: "opacity" from: 0.0 to: pastCircle.circleOpacity easing.type: Easing.OutCurve duration: circleGrowAnimTimer.interval * 4 } PropertyAnimation { target: pastCircle property: "scale" from: 0.0 to: modelData easing.type: Easing.OutCurve duration: circleGrowAnimTimer.interval * 4 } } } SequentialAnimation { id: pastCircleShrinkAnim loops: 1 ParallelAnimation { PropertyAnimation { target: pastCircle property: "opacity" from: pastCircle.circleOpacity to: 0.0 easing.type: Easing.OutCurve duration: circleShrinkAnimTimer.interval * 4 } PropertyAnimation { target: pastCircle property: "scale" from: modelData to: 0.0 easing.type: Easing.OutCurve duration: circleShrinkAnimTimer.interval * 4 } } } } } } Repeater { id: presentCircles objectName: "presentCircles" model: infographic.model.firstMonth delegate: ObjectPositioner { property alias presentCircleGrowAnim: presentCircleGrowAnim property alias presentCircleShrinkAnim: presentCircleShrinkAnim index: model.index count: presentCircles.count radius: parent.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 scale: 0.0 visible: modelData !== undefined color: Gradient.threeColorByIndex(index, infographic.model.currentDay, infographic.model.firstColor) SequentialAnimation { id: presentCircleGrowAnim loops: 1 ParallelAnimation { PropertyAnimation { target: presentCircle property: "opacity" to: presentCircle.circleOpacity easing.type: Easing.OutCurve duration: circleGrowAnimTimer.interval * 4 } PropertyAnimation { target: presentCircle property: "scale" to: modelData easing.type: Easing.OutCurve duration: circleGrowAnimTimer.interval * 4 } } } SequentialAnimation { id: presentCircleShrinkAnim loops: 1 ParallelAnimation { PropertyAnimation { target: presentCircle property: "opacity" to: 0.0 easing.type: Easing.OutCurve duration: circleShrinkAnimTimer.interval * 4 } PropertyAnimation { target: presentCircle property: "scale" to: 0.0 easing.type: Easing.OutCurve duration: circleShrinkAnimTimer.interval * 4 } } } } } } Image { id: backgroundCircle objectName: "backgroundCircle" anchors.fill: parent opacity: 0.9 source: "graphics/infographic_circle.png" } 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++) nextDot.unlockAnimation.start() } else { stop() } if (dotCounter == Math.round(dots.count / 2)) { circleGrowAnimTimer.startFromBeginning() } } 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 == Math.round(dots.count / 2)) { circleShrinkAnimTimer.startFromBeginning() } } 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: backgroundCircle.width / 2 halfSize: dot.width / 2 posOffset: radius / dot.width / 3 state: dot.state Dot { id: dot objectName: "dot" + index property real baseOpacity: 0.4 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 } } } } Text { id: notification objectName: "label" property alias hideAnim: decreaseOpacity property alias showAnim: increaseOpacity property real baseOpacity: 0.6 height: 0.7 * backgroundCircle.width width: notification.height anchors.centerIn: parent text: infographic.model.label font.pixelSize: notification.height / 12 wrapMode: Text.WordWrap horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter color: "white" font.weight: Font.Light PropertyAnimation { id: increaseOpacity target: notification property: "opacity" from: 0.0 to: notification.baseOpacity duration: dotShowAnimTimer.interval * dots.count * 5 } PropertyAnimation { id: decreaseOpacity target: notification property: "opacity" from: notification.baseOpacity to: 0.0 duration: dotShowAnimTimer.interval * dots.count * 5 } } } MouseArea { anchors.fill: dataCircle onDoubleClicked: { if (!dotHideAnimTimer.running && !dotShowAnimTimer.running && !circleShrinkAnimTimer.running && !circleGrowAnimTimer.running) infographic.model.nextDataSource() } } }