320 lines
7.5 KiB
JavaScript
320 lines
7.5 KiB
JavaScript
/**
|
|
* @package Liquid Meter
|
|
* @author Okler Themes
|
|
* @license Licensed under CC BY-NC-ND
|
|
*
|
|
* Copyright (c) 2014
|
|
* Inspired on dribble shot:
|
|
* http://dribbble.com/shots/1069484-Charging-Animation
|
|
*/
|
|
|
|
(function($) {
|
|
|
|
'use strict';
|
|
|
|
var defaultOptions = {
|
|
min: 0,
|
|
max: 100,
|
|
shape: 'circle',
|
|
color: '#82BF41',
|
|
background: '#4C4C52',
|
|
stroke: '#23282F',
|
|
textColor: '#FFFFFF',
|
|
fontFamily: 'Open Sans',
|
|
fontSize: '24px',
|
|
fontWeight: '600',
|
|
liquidOpacity: 0.9,
|
|
liquidPalette: ['#82BF41'],
|
|
speed: 3000,
|
|
animate: true
|
|
};
|
|
|
|
var LiquidMeter = function(el, options) {
|
|
|
|
if (typeof Snap == 'undefined') {
|
|
throw 'Snap.js not found.';
|
|
}
|
|
|
|
this.meter = $(el);
|
|
this.options = options;
|
|
this.options.text = this.meter.text();
|
|
this.init();
|
|
|
|
};
|
|
|
|
LiquidMeter.prototype = {
|
|
|
|
init: function(el, options) {
|
|
|
|
this.wrapper = this.meter.parent('.liquid-meter');
|
|
if ( !this.wrapper.get(0) ) {
|
|
var wrapper = $('<div>').attr({ 'class': 'liquid-meter' });
|
|
this.wrapper = this.meter.wrap( wrapper ).parent();
|
|
}
|
|
|
|
var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
svg.setAttribute('preserveAspectRatio', 'xMidYMid meet');
|
|
svg.setAttribute('viewBox', '0 0 220 220');
|
|
this.wrapper.prepend(svg);
|
|
|
|
this.svg = $(svg).attr({
|
|
width: '100%',
|
|
height: '100%'
|
|
});
|
|
|
|
this.frames = [
|
|
[6, -6, -10, 6, 13, -10], // 1
|
|
[6, -5, -13, 4, 31, -5], // 2
|
|
[7, -5, -9, 0, 31, -5], // 3
|
|
[7, -5, -9, -6, 30, -6], // 4
|
|
[6, -10, -10, -10, 33, -4], // 5
|
|
[8, -4, -8, -13, 38, 7], // 6
|
|
[8, -8, -5, -15, 55, 11], // 7
|
|
[7, -19, -2, -16, 33, 16], // 8
|
|
[3, -23, -2, -16, 42, 21], // 9
|
|
[3, -22, 7, -18, 27, 21], // 10
|
|
[2, -26, 15, -18, 25, 20] , // 11
|
|
[-3, -23, 18, -18, 26, 19] , // 12
|
|
[-6, -40, 18, -18, 22, 22] , // 13
|
|
[-15, -16, 23, -13, 37, 22], // 14
|
|
[-15, -16, 23, -13, 37, 22], // 15
|
|
[-17, -16, 23, -10, 33, 22], // 16
|
|
[-18, -16, 23, -10, 35, 21], // 17
|
|
[-20, -12, 23, -5, 34, 20], // 18
|
|
[-22, -13, 20, -1, 35, 22], // 19
|
|
[-22, -13, 20, 5, 32, 21], // 20
|
|
[-21, -16, 19, 8, 34, 15], // 21
|
|
[-23, -16, 16, 10, 36, 9], // 22
|
|
[-22, -23, 13, 10, 48, 0], // 23
|
|
[-23, -20, 13, 8, 45, -6], // 24
|
|
[-20, -22, 7, 10, 44, -6], // 25
|
|
[-20, -22, 5, 10, 42, -7], // 26
|
|
[-18, -20, 0, 10, 41, -8], // 27
|
|
[-15, -22, -7, 10, 41, -8], // 28
|
|
[-11, -33, -8, 10, 41, -8], // 29
|
|
[-7, -36, -6, 10, 15, -11], // 30
|
|
[0, -39, -8, 10, 15, -11], // 31
|
|
[0, -36, -8, 7, 15, -11], // 32
|
|
];
|
|
|
|
this.paper = Snap(svg);
|
|
|
|
this.draw();
|
|
this.observe();
|
|
if ( this.options.animate ) {
|
|
this.animate();
|
|
} else {
|
|
this.drawFrame(1);
|
|
}
|
|
|
|
this.wrapper.addClass( 'liquid-meter-loaded' );
|
|
|
|
return this;
|
|
},
|
|
|
|
draw: function() {
|
|
this.min = parseInt(this.meter.attr('min'), 10);
|
|
this.max = parseInt(this.meter.attr('max'), 10);
|
|
this.value = parseInt(this.meter.val() || this.meter.attr('value'), 10);
|
|
|
|
var paper = this.paper;
|
|
|
|
this.recipient = paper.circle(110, 110, 95);
|
|
|
|
var background = this.makeGradient(this.options.background);
|
|
|
|
this.recipient.attr({
|
|
fill: background,
|
|
stroke: this.options.stroke,
|
|
strokeWidth: 15
|
|
});
|
|
|
|
var mask = paper.circle(110, 110, 87);
|
|
mask.attr({
|
|
fill: '#FFFFFF'
|
|
});
|
|
|
|
this.liquid = paper.path();
|
|
|
|
this.liquid.attr({
|
|
id: 'front',
|
|
fill: this.options.color,
|
|
mask: mask,
|
|
stroke: lighten(this.options.color, 20),
|
|
strokeWidth: 1
|
|
});
|
|
|
|
this.label = paper.text('50%', '50%', [this.value, '%']);
|
|
this.label.attr({
|
|
fill: this.options.textColor,
|
|
dy: '.4em',
|
|
'font-family': this.options.fontFamily,
|
|
'font-size': this.options.fontSize,
|
|
'font-weight': this.options.fontWeight,
|
|
'text-anchor': 'middle',
|
|
stroke: this.options.textColor
|
|
});
|
|
this.label.selectAll('tspan:nth-child(2)').attr({
|
|
'font-size': '24',
|
|
stroke: 'none'
|
|
});
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
observe: function() {
|
|
var _self = this;
|
|
|
|
this.meter.on('change', function() {
|
|
_self.set( $(this).val() );
|
|
});
|
|
},
|
|
|
|
set: function( val ) {
|
|
var value = parseInt( val, 10 );
|
|
this.meter.val( value );
|
|
this.value = value;
|
|
this.label.node.textContent = value + '%';
|
|
},
|
|
|
|
liquidPalette: function( val ) {
|
|
this.options.liquidPalette = val;
|
|
},
|
|
|
|
background: function( val ) {
|
|
this.options.background = val;
|
|
},
|
|
|
|
stroke: function( val ) {
|
|
this.options.stroke = val;
|
|
},
|
|
|
|
color: function( val ) {
|
|
this.options.color = val;
|
|
|
|
this.liquid.attr({
|
|
fill: this.options.color,
|
|
stroke: lighten(this.options.color, 20)
|
|
});
|
|
},
|
|
|
|
makeGradient: function(color) {
|
|
return this.paper.gradient(Snap.format('L(0, 0, 100, 100){color.top}-{color.bottom}', {
|
|
color: {
|
|
top: lighten(color, 6),
|
|
bottom: color
|
|
}
|
|
}));
|
|
},
|
|
|
|
makePath: function(value, t1, x1, y1, t2, x2, y2) {
|
|
var top = ((100 - ((value*100)/this.max)) * 1.76) + 22;
|
|
return Snap.format('M0,{left} C{curve.x1},{curve.y1} {curve.x2},{curve.y2} 220,{right} L220,220 L0,220 z', {
|
|
left: top - (t1 || 0),
|
|
right: top - (t2 || 0),
|
|
curve: {
|
|
x1: x1 + top,
|
|
y1: y1 + top,
|
|
x2: x2 + top,
|
|
y2: y2 + top
|
|
}
|
|
});
|
|
},
|
|
|
|
drawFrame: function(number) {
|
|
var frame = this.frames[number - 1],
|
|
t1 = frame[0],
|
|
x1 = frame[1],
|
|
y1 = frame[2],
|
|
t2 = frame[3],
|
|
x2 = frame[4],
|
|
y2 = frame[5];
|
|
this.liquid.attr({ d: this.makePath( this.value, t1, x1, y1, t2, x2, y2 )});
|
|
},
|
|
|
|
animate: function() {
|
|
var requestAnimationFrame = window.requestAnimationFrame ||
|
|
window.webkitRequestAnimationFrame ||
|
|
window.mozRequestAnimationFrame ||
|
|
window.oRequestAnimationFrame ||
|
|
window.msRequestAnimationFrame ||
|
|
function (callback) {
|
|
setTimeout(callback, 0);
|
|
},
|
|
frames = this.frames.length,
|
|
interval = this.options.speed / frames,
|
|
currentFrame = 1,
|
|
drawFrame = this.drawFrame.bind(this);
|
|
|
|
function loop() {
|
|
requestAnimationFrame(function() {
|
|
draw();
|
|
});
|
|
setTimeout(loop, interval);
|
|
}
|
|
|
|
function draw() {
|
|
drawFrame(currentFrame);
|
|
currentFrame++;
|
|
if (currentFrame >= frames) {
|
|
currentFrame = 1;
|
|
}
|
|
}
|
|
|
|
loop();
|
|
|
|
return this;
|
|
}
|
|
|
|
};
|
|
|
|
/**
|
|
* liquidMeter jQuery plugin - public method
|
|
* @param - {Object} options - Passed options extending defaultOptions
|
|
* @return - {Selector} - Array of elements
|
|
*/
|
|
$.fn.liquidMeter = function(options, value) {
|
|
var isSetter = (typeof options === 'string' && !!value);
|
|
|
|
if ( !isSetter ) {
|
|
options = $.extend({}, defaultOptions, options);
|
|
}
|
|
return this.map(function () {
|
|
|
|
// preventing against multiple instantiations
|
|
var instance = $(this).data('liquid-meter');
|
|
if (!instance) {
|
|
instance = new LiquidMeter(this, options);
|
|
$(this).data('liquid-meter', instance);
|
|
}
|
|
if ( isSetter ) {
|
|
instance[ options ]( value );
|
|
}
|
|
return instance;
|
|
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Util function for lightening the colour with a %
|
|
* @param - string - colour with leading #
|
|
* @param - number - percentage to lighten by
|
|
*/
|
|
function lighten(color, percent) {
|
|
var n = parseInt(color.slice(1), 16),
|
|
a = Math.round(2.55 * percent || 0),
|
|
// Bitshift 16 bits to the left
|
|
r = (n >> 16) + a,
|
|
// Bitshift 8 bits to the left based on blue
|
|
b = (n >> 8 & 0x00FF) + a,
|
|
//
|
|
g = (n & 0x0000FF) + a;
|
|
// Calculate
|
|
return '#' + (
|
|
0x1000000 + (r < 255 ? r < 1 ? 0 : r : 255) * 0x10000 +
|
|
(b < 255 ? b < 1 ? 0 : b : 255) * 0x100 + (g < 255 ? g < 1 ? 0 : g : 255)
|
|
).toString(16).slice(1).toUpperCase();
|
|
};
|
|
|
|
}(jQuery)); |