Skip to content

Instantly share code, notes, and snippets.

@hanigamal
Created January 24, 2015 10:26
Show Gist options
  • Save hanigamal/bd57b97394363546366e to your computer and use it in GitHub Desktop.
Save hanigamal/bd57b97394363546366e to your computer and use it in GitHub Desktop.
Stats animation.
<!--Graph charts inspired by https://dribbble.com/shots/1876534-Stats-animation?list=following&offset=4-->
<h1>Stats animation remake of Virgil Pana dribbble shot<br><p>by Jonas Badalic</p></h1>
<p class="original">Original: http://drbl.in/nrZk</p>
<div class="charts-container cf">
<div class="chart" id="graph-1-container">
<h2 class="title">Hours worked</h2>
<div class="chart-svg">
<svg class="chart-line" id="chart-1" viewBox="0 0 80 40">
<defs>
<clipPath id="clip" x="0" y="0" width="80" height="40" >
<rect id="clip-rect" x="-80" y="0" width="77" height="38.7"/>
</clipPath>
<linearGradient id="gradient-1">
<stop offset="0" stop-color="#00d5bd" />
<stop offset="100" stop-color="#24c1ed" />
</linearGradient>
<linearGradient id="gradient-2">
<stop offset="0" stop-color="#954ce9" />
<stop offset="0.3" stop-color="#954ce9" />
<stop offset="0.6" stop-color="#24c1ed" />
<stop offset="1" stop-color="#24c1ed" />
</linearGradient>
<linearGradient id="gradient-3" x1="0%" y1="0%" x2="0%" y2="100%">>
<stop offset="0" stop-color="rgba(0, 213, 189, 1)" stop-opacity="0.07"/>
<stop offset="0.5" stop-color="rgba(0, 213, 189, 1)" stop-opacity="0.13"/>
<stop offset="1" stop-color="rgba(0, 213, 189, 1)" stop-opacity="0"/>
</linearGradient>
<linearGradient id="gradient-4" x1="0%" y1="0%" x2="0%" y2="100%">>
<stop offset="0" stop-color="rgba(149, 76, 233, 1)" stop-opacity="0.07"/>
<stop offset="0.5" stop-color="rgba(149, 76, 233, 1)" stop-opacity="0.13"/>
<stop offset="1" stop-color="rgba(149, 76, 233, 1)" stop-opacity="0"/>
</linearGradient>
</defs>
</svg>
<h3 class="valueX">time</h3>
</div>
<div class="chart-values">
<p class="h-value">1689h</p>
<p class="percentage-value"></p>
<p class="total-gain"></p>
</div>
<div class="triangle green"></div>
</div>
<div class="chart" id="graph-2-container">
<h2 class="title">Hours worked</h2>
<div class="chart-svg">
<svg class="chart-line" id="chart-2" viewBox="0 0 80 40">
</svg>
<h3 class="valueX">time</h3>
</div>
<div class="chart-values">
<p class="h-value">322h</p>
<p class="percentage-value"></p>
<p class="total-gain"></p>
</div>
<div class="triangle red"></div>
</div>
<div class="chart circle" id="circle-1">
<h2 class="title">IBApps Website</h2>
<div class="chart-svg align-center">
<h2 class="circle-percentage"></h2>
<svg class="chart-circle" id="chart-3" width="50%" viewBox="0 0 100 100">
<path class="underlay" d="M5,50 A45,45,0 1 1 95,50 A45,45,0 1 1 5,50"/>
</svg>
</div>
<div class="triangle green"></div>
</div>
<div class="chart circle" id="circle-2">
<h2 class="title">IBApps Website</h2>
<div class="chart-svg align-center">
<h2 class="circle-percentage"></h2>
<svg class="chart-circle" id="chart-4" width="50%" viewBox="0 0 100 100">
<path class="underlay" d="M5,50 A45,45,0 1 1 95,50 A45,45,0 1 1 5,50"/>
</svg>
</div>
<div class="triangle red"></div>
</div>
</div>
<!-- IRRELEVANT - SOCIAL HTML -->
<div class="heartIt">
<p>If you like it - use it, heart it, fork it, share it!</p>
<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/176026/heart292_(1).png" alt="heart this pen" />
<p>Thanks!</p>
</div>
<div class="followlinks">
<a href="http://www.badalic.com">website </a>
<a href="https://twitter.com/JonasBadalic"><svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="32px" height="32px" viewBox="0 0 16 16" enable-background="new 0 0 32 32" xml:space="preserve">
<path d="M8,0C3.582,0,0,3.582,0,8s3.582,8,8,8s8-3.582,8-8C16,3.581,12.418,0,8,0z M11.98,6.204l0.006,0.255
c0,2.604-1.981,5.604-5.604,5.604c-1.112,0-2.147-0.326-3.019-0.885c0.154,0.018,0.311,0.028,0.47,0.028
c0.923,0,1.772-0.315,2.446-0.843c-0.862-0.016-1.589-0.586-1.84-1.368C4.56,9.018,4.682,9.029,4.81,9.029
c0.18,0,0.354-0.023,0.519-0.068c-0.901-0.182-1.58-0.977-1.58-1.931V7.005c0.266,0.148,0.569,0.236,0.892,0.247
C4.113,6.899,3.765,6.296,3.765,5.613c0-0.361,0.097-0.699,0.266-0.99c0.971,1.192,2.423,1.976,4.06,2.058
C8.057,6.537,8.04,6.386,8.04,6.232c0-1.087,0.882-1.969,1.97-1.969c0.566,0,1.078,0.239,1.438,0.622
c0.448-0.089,0.87-0.253,1.251-0.478c-0.147,0.46-0.459,0.846-0.866,1.09c0.397-0.047,0.778-0.154,1.131-0.31
C12.7,5.581,12.365,5.928,11.98,6.204z"/>
</svg></a>
</div>
/*
I loved Virgil's Dribble shot and decided to remake
it with some SVG animations :) I didn't really want
to recreate the curvy line since I believe straight
lines are more accurate. Sorry Virgil, I might make
them curvy one day :)! With a bit of time on my
hands I could make it even more detailed.
I hope you like it and post some feedback on how to
make this better :)!
Don't forget to check out the original at
http://goo.gl/0aKiS0
Kudos Virgil!*/
var chart_h = 40;
var chart_w = 80;
var stepX = 77 / 14;
var chart_1_y = [
15, 25, 40, 30, 45, 40, 35, 55, 37, 50, 60, 45,70, 78
];
var chart_2_y = [
80, 65, 65, 40, 55, 34, 54, 50, 60, 64, 55, 27, 24, 30
];
function point(x, y) {
x: 0;
y: 0;
}
/* DRAW GRID */
function drawGrid(graph) {
var graph = Snap(graph);
var g = graph.g();
g.attr('id', 'grid');
for (i = 0; i <= stepX + 2; i++) {
var horizontalLine = graph.path(
"M" + 0 + "," + stepX * i + " " +
"L" + 77 + "," + stepX * i);
horizontalLine.attr('class', 'horizontal');
g.add(horizontalLine);
};
for (i = 0; i <= 14; i++) {
var horizontalLine = graph.path(
"M" + stepX * i + "," + 38.7 + " " +
"L" + stepX * i + "," + 0)
horizontalLine.attr('class', 'vertical');
g.add(horizontalLine);
};
}
drawGrid('#chart-2');
drawGrid('#chart-1');
function drawLineGraph(graph, points, container, id) {
var graph = Snap(graph);
/*END DRAW GRID*/
/* PARSE POINTS */
var myPoints = [];
var shadowPoints = [];
function parseData(points) {
for (i = 0; i < points.length; i++) {
var p = new point();
var pv = points[i] / 100 * 40;
p.x = 83.7 / points.length * i + 1;
p.y = 40 - pv;
if (p.x > 78) {
p.x = 78;
}
myPoints.push(p);
}
}
var segments = [];
function createSegments(p_array) {
for (i = 0; i < p_array.length; i++) {
var seg = "L" + p_array[i].x + "," + p_array[i].y;
if (i === 0) {
seg = "M" + p_array[i].x + "," + p_array[i].y;
}
segments.push(seg);
}
}
function joinLine(segments_array, id) {
var line = segments_array.join(" ");
var line = graph.path(line);
line.attr('id', 'graph-' + id);
var lineLength = line.getTotalLength();
line.attr({
'stroke-dasharray': lineLength,
'stroke-dashoffset': lineLength
});
}
function calculatePercentage(points, graph) {
var initValue = points[0];
var endValue = points[points.length - 1];
var sum = endValue - initValue;
var prefix;
var percentageGain;
var stepCount = 1300 / sum;
function findPrefix() {
if (sum > 0) {
prefix = "+";
} else {
prefix = "";
}
}
var percentagePrefix = "";
function percentageChange() {
percentageGain = initValue / endValue * 100;
if(percentageGain > 100){
console.log('over100');
percentageGain = Math.round(percentageGain * 100*10) / 100;
}else if(percentageGain < 100){
console.log('under100');
percentageGain = Math.round(percentageGain * 10) / 10;
}
if (initValue > endValue) {
percentageGain = endValue/initValue*100-100;
percentageGain = percentageGain.toFixed(2);
percentagePrefix = "";
$(graph).find('.percentage-value').addClass('negative');
} else {
percentagePrefix = "+";
}
if(endValue > initValue){
percentageGain = endValue/initValue*100;
percentageGain = Math.round(percentageGain);
}
};
percentageChange();
findPrefix();
var percentage = $(graph).find('.percentage-value');
var totalGain = $(graph).find('.total-gain');
var hVal = $(graph).find('.h-value');
function count(graph, sum) {
var totalGain = $(graph).find('.total-gain');
var i = 0;
var time = 1300;
var intervalTime = Math.abs(time / sum);
var timerID = 0;
if (sum > 0) {
var timerID = setInterval(function () {
i++;
totalGain.text(percentagePrefix + i);
if (i === sum) clearInterval(timerID);
}, intervalTime);
} else if (sum < 0) {
var timerID = setInterval(function () {
i--;
totalGain.text(percentagePrefix + i);
if (i === sum) clearInterval(timerID);
}, intervalTime);
}
}
count(graph, sum);
percentage.text(percentagePrefix + percentageGain + "%");
totalGain.text("0%");
setTimeout(function () {
percentage.addClass('visible');
hVal.addClass('visible');
}, 1300);
}
function showValues() {
var val1 = $(graph).find('.h-value');
var val2 = $(graph).find('.percentage-value');
val1.addClass('visible');
val2.addClass('visible');
}
function drawPolygon(segments, id) {
var lastel = segments[segments.length - 1];
var polySeg = segments.slice();
polySeg.push([78, 38.4], [1, 38.4]);
var polyLine = polySeg.join(' ').toString();
var replacedString = polyLine.replace(/L/g, '').replace(/M/g, "");
var poly = graph.polygon(replacedString);
var clip = graph.rect(-80, 0, 80, 40);
poly.attr({
'id': 'poly-' + id,
/*'clipPath':'url(#clip)'*/
'clipPath': clip
});
clip.animate({
transform: 't80,0'
}, 1300, mina.linear);
}
parseData(points);
createSegments(myPoints);
calculatePercentage(points, container);
joinLine(segments,id);
drawPolygon(segments, id);
/*$('#poly-'+id).attr('class','show');*/
/* function drawPolygon(segments,id){
var polySeg = segments;
polySeg.push([80,40],[0,40]);
var polyLine = segments.join(' ').toString();
var replacedString = polyLine.replace(/L/g,'').replace(/M/g,"");
var poly = graph.polygon(replacedString);
poly.attr('id','poly-'+id)
}
drawPolygon(segments,id);*/
}
function drawCircle(container,id,progress,parent){
var paper = Snap(container);
var prog = paper.path("M5,50 A45,45,0 1 1 95,50 A45,45,0 1 1 5,50");
var lineL = prog.getTotalLength();
var oneUnit = lineL/100;
var toOffset = lineL - oneUnit * progress;
var myID = 'circle-graph-'+id;
prog.attr({
'stroke-dashoffset':lineL,
'stroke-dasharray':lineL,
'id':myID
});
var animTime = 1300/*progress / 100*/
prog.animate({
'stroke-dashoffset':toOffset
},animTime,mina.easein);
function countCircle(animtime,parent,progress){
var textContainer = $(parent).find('.circle-percentage');
var i = 0;
var time = 1300;
var intervalTime = Math.abs(time / progress);
var timerID = setInterval(function () {
i++;
textContainer.text(i+"%");
if (i === progress) clearInterval(timerID);
}, intervalTime);
}
countCircle(animTime,parent,progress);
}
$(window).on('load',function(){
drawCircle('#chart-3',1,77,'#circle-1');
drawCircle('#chart-4',2,53,'#circle-2');
drawLineGraph('#chart-1', chart_1_y, '#graph-1-container', 1);
drawLineGraph('#chart-2', chart_2_y, '#graph-2-container', 2);
});

Stats animation.

I loved Virgil's Dribble shot and decided to remake it with some SVG animations :) I didn't really want to recreate the curvy line since I believe straight lines are more accurate. Sorry Virgil, I might make them curvy one day :)! With a bit of time on my hands I could make it even more detailed. I hope you like it and post some feedback on how to make this better :)! Don't forget to check out the original at http://goo.gl/0aKiS0

Kudos Virgil!

Forked from Jonas Badalic's Pen Stats animation..

Forked from Jonas Badalic's Pen Stats animation..

A Pen by Hani Gamal on CodePen.

License.

@import "compass/css3";
$bgc:#24303a;
$chart-bg:#1e2730;
$chart-txt:#4a667a;
$green:#48c15e;
$red:#ef6670;
@import url(http://fonts.googleapis.com/css?family=Lato:400,700);
@font-face{
font-family:Lato;
src:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/176026/ProximaNova-Regular.otf);
font-weight:300;
}
body,html{
font-family:Lato;
}
h1{
font-size:28px;
line-height:40px;
margin-top:20px;
a{
text-decoration:none;
color:$green;
}
p{
font-size:22px;
}
}
#grid{
@include transform(translate(1px,0px));
}
/* GRAPH - 1 */
#graph-1{
stroke:url(#gradient-1);
stroke-width:1.5;
fill:transparent;
stroke-linecap:round;
stroke-linejoin:round;
@include animation (lineani 1.3s linear forwards);
}
#graph-2{
stroke:url(#gradient-2);
stroke-width:1.5;
fill:transparent;
stroke-linecap:round;
stroke-linejoin:round;
@include animation (lineani 1.3s linear forwards);
}
#poly-1{
fill:url(#gradient-3);
}
#poly-2{
fill:url(#gradient-4);
}
@include keyframes (lineani){
to{
stroke-dashoffset:0;
}
}
.underlay{
stroke-width:5;
fill:transparent;
stroke-linecap:round;
stroke-linejoin:round;
stroke:$bgc;
}
#circle-graph-1{
stroke:url(#gradient-1);
stroke-width:5;
fill:transparent;
stroke-linecap:round;
stroke-linejoin:round;
}
.chart-circle{
@include transform(rotate(90deg));
}
#circle-graph-2{
stroke:url(#gradient-2);
stroke-width:5;
fill:transparent;
stroke-linecap:round;
stroke-linejoin:round;
}
body{
background-color: $bgc;
color:white;
text-align:center;
}
.charts-container{
padding:20px;
width:100%;
max-width:1024px;
display:inline-block;
@include box-sizing(border-box);
}
.chart{
color:$chart-txt;
text-align:left;
position: relative;
height:auto;
background-color: $chart-bg;
display:inline-block;
float:left;
position:relative;
@include box-sizing(border-box);
margin:10px;
padding:15px 20px 65px 20px;
&.circle{
padding:15px 20px 40px 20px;
}
@media screen and (max-width:700px){
width:calc(100% - 20px);
}
@media screen and (min-width:700px){
width:calc(50% - 20px);
}
}
.title{
font-size: 22px;
margin-bottom:12px;
}
.chart-circle{
display:inline-block;
position: relative;
}
.chart-svg{
position:relative;
}
.circle-percentage{
position:absolute;
color:white;
font-size: 48px;
left:50%;
top:50%;
@include transform(translate(-50%,-50%));
@media screen and (max-width:480px){
font-size:32px;
}
}
.align-center{
text-align:center;
}
.chart-line{
width:80%;
}
.valueX{
font-size:14px;
}
.chart-values{
text-align:right;
font-size:18px;
position:absolute;
right:0;
bottom:0;
padding:15px;
}
.h-value{
@include transition(700ms ease-in-out);
opacity:0;
&.visible{
opacity:1;
}
}
.percentage-value{
@include transition(700ms ease-in-out);
color:$green;
margin-top:2px;
opacity:0;
&.negative{
color:$red;
}
&.visible{
opacity:1;
}
}
.total-gain{
color:white;
font-size:48px;
}
.triangle{
width: 0;
height: 0;
border-style: solid;
border-width: 28px 0 0 28px;
position:absolute;
left:0;
bottom:0;
&.red{
border-color: transparent transparent transparent $red;
}
&.green{
border-color: transparent transparent transparent $green;
}
}
.horizontal,
.vertical{
stroke-width:0.1;
stroke:$chart-txt;
}
/* CLEARFIX HELPER */
.cf:before,
.cf:after {
content: " "; /* 1 */
display: table; /* 2 */
}
.cf:after {clear: both;
}
/**
* For IE 6/7 only
* Include this rule to trigger hasLayout and contain floats.
*/
.cf {
*zoom: 1;
}
/*IRRELEVANT CSS*/
.followlinks{
position:fixed;
right:35px;
bottom:15px;
display:table;
a {
display:table-cell;
vertical-align:middle;
padding-left:10px;
color:white;
svg path{
fill:white;
}
}
}
.heartIt{
margin-top:50px;
margin-bottom:80px;
p{
font-size:24px;
line-height:40px;
}
img{
width:64px;
height:auto;
opacity:0.7;
@include filter(invert(100%));
}
}
.original{
color:$red;
font-size: 14px;
}
@rdgfarias
Copy link

Hi man,
so i found this project about drawCircles great, but i need this circles start to complete themselves when i range a specific part of my page.
and i tried every methods and i couldn't do this. so, you can help me?
thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment