circles 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +22 -0
- data/README.md +37 -0
- data/lib/circles.rb +8 -0
- data/lib/circles/version.rb +5 -0
- data/vendor/assets/javascripts/circles.js +338 -0
- metadata +77 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8566a705378583880c2d208929ca8717f91257cf
|
4
|
+
data.tar.gz: 0945d2cc9d42e78729faa283177c8abdc01fd247
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 59e85cd8610ab896630ce5da5ee5492ac92069147f9ed04551bbcf4471e76850c78ab89742b59c2898ad1145fcd6f9d6bf15092a7dd477ee091a3b31b84e8c14
|
7
|
+
data.tar.gz: 044233878b44650bc8bb2908a7e94fe4e807d3938f5b3e799c552c20243de25fd90c90061943cae241eeddcaf49e02ddf801f8e67d44255890b2da40769fa42a
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Julius Jung
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
22
|
+
|
data/README.md
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# Circles
|
2
|
+
|
3
|
+
The Circles gem wraps the [Circles.js](https://github.com/lugolabs/circles) library in a Rails engine for simple use with the asset pipeline.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'circles'
|
11
|
+
```
|
12
|
+
|
13
|
+
Add the following directive to your Javascript manifest file (application.js):
|
14
|
+
|
15
|
+
```javascript
|
16
|
+
//= require circles
|
17
|
+
```
|
18
|
+
|
19
|
+
And then execute:
|
20
|
+
|
21
|
+
$ bundle
|
22
|
+
|
23
|
+
Or install it yourself as:
|
24
|
+
|
25
|
+
$ gem install circles
|
26
|
+
|
27
|
+
## Usage
|
28
|
+
|
29
|
+
Check the original Circles [repository](https://github.com/lugolabs/circles.)
|
30
|
+
|
31
|
+
## Contributing
|
32
|
+
|
33
|
+
1. Fork it ( https://github.com/juljun14/circles/fork )
|
34
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
35
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
36
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
37
|
+
5. Create a new Pull Request
|
data/lib/circles.rb
ADDED
@@ -0,0 +1,338 @@
|
|
1
|
+
// circles
|
2
|
+
// copyright Artan Sinani
|
3
|
+
// https://github.com/lugolabs/circles
|
4
|
+
|
5
|
+
/*
|
6
|
+
Lightwheight JavaScript library that generates circular graphs in SVG.
|
7
|
+
|
8
|
+
Call Circles.create(options) with the following options:
|
9
|
+
|
10
|
+
id - the DOM element that will hold the graph
|
11
|
+
radius - the radius of the circles
|
12
|
+
width - the width of the ring (optional, has value 10, if not specified)
|
13
|
+
value - init value of the circle (optional, defaults to 0)
|
14
|
+
maxValue - maximum value of the circle (optional, defaults to 100)
|
15
|
+
text - the text to display at the centre of the graph (optional, the current "htmlified" value will be shown if not specified)
|
16
|
+
if `null` or an empty string, no text will be displayed
|
17
|
+
can also be a function: the returned value will be the displayed text
|
18
|
+
ex1. function(currentValue) {
|
19
|
+
return '$'+currentValue;
|
20
|
+
}
|
21
|
+
ex2. function() {
|
22
|
+
return this.getPercent() + '%';
|
23
|
+
}
|
24
|
+
colors - an array of colors, with the first item coloring the full circle
|
25
|
+
(optional, it will be `['#EEE', '#F00']` if not specified)
|
26
|
+
duration - value in ms of animation duration; (optional, defaults to 500);
|
27
|
+
if 0 or `null` is passed, the animation will not run
|
28
|
+
wrpClass - class name to apply on the generated element wrapping the whole circle.
|
29
|
+
textClass: - class name to apply on the generated element wrapping the text content.
|
30
|
+
|
31
|
+
API:
|
32
|
+
updateRadius(radius) - regenerates the circle with the given radius (see spec/responsive.html for an example hot to create a responsive circle)
|
33
|
+
updateWidth(width) - regenerates the circle with the given stroke width
|
34
|
+
updateColors(colors) - change colors used to draw the circle
|
35
|
+
update(value, duration) - update value of circle. If value is set to true, force the update of displaying
|
36
|
+
getPercent() - returns the percentage value of the circle, based on its current value and its max value
|
37
|
+
getValue() - returns the value of the circle
|
38
|
+
getMaxValue() - returns the max value of the circle
|
39
|
+
getValueFromPercent(percentage) - returns the corresponding value of the circle based on its max value and given percentage
|
40
|
+
htmlifyNumber(number, integerPartClass, decimalPartClass) - returned HTML representation of given number with given classes names applied on tags
|
41
|
+
|
42
|
+
*/
|
43
|
+
|
44
|
+
(function() {
|
45
|
+
"use strict";
|
46
|
+
|
47
|
+
var requestAnimFrame = window.requestAnimationFrame ||
|
48
|
+
window.webkitRequestAnimationFrame ||
|
49
|
+
window.mozRequestAnimationFrame ||
|
50
|
+
window.oRequestAnimationFrame ||
|
51
|
+
window.msRequestAnimationFrame ||
|
52
|
+
function (callback) {
|
53
|
+
setTimeout(callback, 1000 / 60);
|
54
|
+
},
|
55
|
+
|
56
|
+
Circles = window.Circles = function(options) {
|
57
|
+
var elId = options.id;
|
58
|
+
this._el = document.getElementById(elId);
|
59
|
+
|
60
|
+
if (this._el === null) return;
|
61
|
+
|
62
|
+
this._radius = options.radius || 10;
|
63
|
+
this._duration = options.duration === undefined ? 500 : options.duration;
|
64
|
+
|
65
|
+
this._value = 0;
|
66
|
+
this._maxValue = options.maxValue || 100;
|
67
|
+
|
68
|
+
this._text = options.text === undefined ? function(value){return this.htmlifyNumber(value);} : options.text;
|
69
|
+
this._strokeWidth = options.width || 10;
|
70
|
+
this._colors = options.colors || ['#EEE', '#F00'];
|
71
|
+
this._svg = null;
|
72
|
+
this._movingPath = null;
|
73
|
+
this._wrapContainer = null;
|
74
|
+
this._textContainer = null;
|
75
|
+
|
76
|
+
this._wrpClass = options.wrpClass || 'circles-wrp';
|
77
|
+
this._textClass = options.textClass || 'circles-text';
|
78
|
+
|
79
|
+
this._styleWrapper = options.styleWrapper === false ? false : true;
|
80
|
+
this._styleText = options.styleText === false ? false : true;
|
81
|
+
|
82
|
+
var endAngleRad = Math.PI / 180 * 270;
|
83
|
+
this._start = -Math.PI / 180 * 90;
|
84
|
+
this._startPrecise = this._precise(this._start);
|
85
|
+
this._circ = endAngleRad - this._start;
|
86
|
+
|
87
|
+
this._generate().update(options.value || 0);
|
88
|
+
};
|
89
|
+
|
90
|
+
Circles.prototype = {
|
91
|
+
VERSION: '0.0.6',
|
92
|
+
|
93
|
+
_generate: function() {
|
94
|
+
|
95
|
+
this._svgSize = this._radius * 2;
|
96
|
+
this._radiusAdjusted = this._radius - (this._strokeWidth / 2);
|
97
|
+
|
98
|
+
this._generateSvg()._generateText()._generateWrapper();
|
99
|
+
|
100
|
+
this._el.innerHTML = '';
|
101
|
+
this._el.appendChild(this._wrapContainer);
|
102
|
+
|
103
|
+
return this;
|
104
|
+
},
|
105
|
+
|
106
|
+
_setPercentage: function(percentage) {
|
107
|
+
this._movingPath.setAttribute('d', this._calculatePath(percentage, true));
|
108
|
+
this._textContainer.innerHTML = this._getText(this.getValueFromPercent(percentage));
|
109
|
+
},
|
110
|
+
|
111
|
+
_generateWrapper: function() {
|
112
|
+
this._wrapContainer = document.createElement('div');
|
113
|
+
this._wrapContainer.className = this._wrpClass;
|
114
|
+
|
115
|
+
if (this._styleWrapper) {
|
116
|
+
this._wrapContainer.style.position = 'relative';
|
117
|
+
this._wrapContainer.style.display = 'inline-block';
|
118
|
+
}
|
119
|
+
|
120
|
+
this._wrapContainer.appendChild(this._svg);
|
121
|
+
this._wrapContainer.appendChild(this._textContainer);
|
122
|
+
|
123
|
+
return this;
|
124
|
+
},
|
125
|
+
|
126
|
+
_generateText: function() {
|
127
|
+
|
128
|
+
this._textContainer = document.createElement('div');
|
129
|
+
this._textContainer.className = this._textClass;
|
130
|
+
|
131
|
+
if (this._styleText) {
|
132
|
+
var style = {
|
133
|
+
position: 'absolute',
|
134
|
+
top: 0,
|
135
|
+
left: 0,
|
136
|
+
textAlign: 'center',
|
137
|
+
width: '100%',
|
138
|
+
fontSize: (this._radius * .7) + 'px',
|
139
|
+
height: this._svgSize + 'px',
|
140
|
+
lineHeight: this._svgSize + 'px'
|
141
|
+
};
|
142
|
+
|
143
|
+
for(var prop in style) {
|
144
|
+
this._textContainer.style[prop] = style[prop];
|
145
|
+
}
|
146
|
+
}
|
147
|
+
|
148
|
+
this._textContainer.innerHTML = this._getText(0);
|
149
|
+
return this;
|
150
|
+
},
|
151
|
+
|
152
|
+
_getText: function(value) {
|
153
|
+
if (!this._text) return '';
|
154
|
+
|
155
|
+
if (value === undefined) value = this._value;
|
156
|
+
|
157
|
+
value = parseFloat(value.toFixed(2));
|
158
|
+
|
159
|
+
return typeof this._text === 'function' ? this._text.call(this, value) : this._text;
|
160
|
+
},
|
161
|
+
|
162
|
+
_generateSvg: function() {
|
163
|
+
|
164
|
+
this._svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
165
|
+
this._svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
|
166
|
+
this._svg.setAttribute('width', this._svgSize);
|
167
|
+
this._svg.setAttribute('height', this._svgSize);
|
168
|
+
|
169
|
+
this._generatePath(100, false, this._colors[0])._generatePath(1, true, this._colors[1]);
|
170
|
+
|
171
|
+
this._movingPath = this._svg.getElementsByTagName('path')[1];
|
172
|
+
|
173
|
+
return this;
|
174
|
+
},
|
175
|
+
|
176
|
+
_generatePath: function(percentage, open, color) {
|
177
|
+
var path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
178
|
+
path.setAttribute('fill', 'transparent');
|
179
|
+
path.setAttribute('stroke', color);
|
180
|
+
path.setAttribute('stroke-width', this._strokeWidth);
|
181
|
+
path.setAttribute('d', this._calculatePath(percentage, open));
|
182
|
+
|
183
|
+
this._svg.appendChild(path);
|
184
|
+
|
185
|
+
return this;
|
186
|
+
},
|
187
|
+
|
188
|
+
_calculatePath: function(percentage, open) {
|
189
|
+
var end = this._start + ((percentage / 100) * this._circ),
|
190
|
+
endPrecise = this._precise(end);
|
191
|
+
return this._arc(endPrecise, open);
|
192
|
+
},
|
193
|
+
|
194
|
+
_arc: function(end, open) {
|
195
|
+
var endAdjusted = end - 0.001,
|
196
|
+
longArc = end - this._startPrecise < Math.PI ? 0 : 1;
|
197
|
+
|
198
|
+
return [
|
199
|
+
'M',
|
200
|
+
this._radius + this._radiusAdjusted * Math.cos(this._startPrecise),
|
201
|
+
this._radius + this._radiusAdjusted * Math.sin(this._startPrecise),
|
202
|
+
'A', // arcTo
|
203
|
+
this._radiusAdjusted, // x radius
|
204
|
+
this._radiusAdjusted, // y radius
|
205
|
+
0, // slanting
|
206
|
+
longArc, // long or short arc
|
207
|
+
1, // clockwise
|
208
|
+
this._radius + this._radiusAdjusted * Math.cos(endAdjusted),
|
209
|
+
this._radius + this._radiusAdjusted * Math.sin(endAdjusted),
|
210
|
+
open ? '' : 'Z' // close
|
211
|
+
].join(' ');
|
212
|
+
},
|
213
|
+
|
214
|
+
_precise: function(value) {
|
215
|
+
return Math.round(value * 1000) / 1000;
|
216
|
+
},
|
217
|
+
|
218
|
+
/*== Public methods ==*/
|
219
|
+
|
220
|
+
htmlifyNumber: function(number, integerPartClass, decimalPartClass) {
|
221
|
+
|
222
|
+
integerPartClass = integerPartClass || 'circles-integer';
|
223
|
+
decimalPartClass = decimalPartClass || 'circles-decimals';
|
224
|
+
|
225
|
+
var parts = (number + '').split('.'),
|
226
|
+
html = '<span class="' + integerPartClass + '">' + parts[0]+'</span>';
|
227
|
+
|
228
|
+
if (parts.length > 1) {
|
229
|
+
html += '.<span class="' + decimalPartClass + '">' + parts[1].substring(0, 2) + '</span>';
|
230
|
+
}
|
231
|
+
return html;
|
232
|
+
},
|
233
|
+
|
234
|
+
updateRadius: function(radius) {
|
235
|
+
this._radius = radius;
|
236
|
+
|
237
|
+
return this._generate().update(true);
|
238
|
+
},
|
239
|
+
|
240
|
+
updateWidth: function(width) {
|
241
|
+
this._strokeWidth = width;
|
242
|
+
|
243
|
+
return this._generate().update(true);
|
244
|
+
},
|
245
|
+
|
246
|
+
updateColors: function(colors) {
|
247
|
+
this._colors = colors;
|
248
|
+
|
249
|
+
var paths = this._svg.getElementsByTagName('path');
|
250
|
+
|
251
|
+
paths[0].setAttribute('stroke', colors[0]);
|
252
|
+
paths[1].setAttribute('stroke', colors[1]);
|
253
|
+
|
254
|
+
return this;
|
255
|
+
},
|
256
|
+
|
257
|
+
getPercent: function() {
|
258
|
+
return (this._value * 100) / this._maxValue;
|
259
|
+
},
|
260
|
+
|
261
|
+
getValueFromPercent: function(percentage) {
|
262
|
+
return (this._maxValue * percentage) / 100;
|
263
|
+
},
|
264
|
+
|
265
|
+
getValue: function()
|
266
|
+
{
|
267
|
+
return this._value;
|
268
|
+
},
|
269
|
+
|
270
|
+
getMaxValue: function()
|
271
|
+
{
|
272
|
+
return this._maxValue;
|
273
|
+
},
|
274
|
+
|
275
|
+
update: function(value, duration) {
|
276
|
+
if (value === true) {//Force update with current value
|
277
|
+
this._setPercentage(this.getPercent());
|
278
|
+
return this;
|
279
|
+
}
|
280
|
+
|
281
|
+
if (this._value == value || isNaN(value)) return this;
|
282
|
+
if (duration === undefined) duration = this._duration;
|
283
|
+
|
284
|
+
var self = this,
|
285
|
+
oldPercentage = self.getPercent(),
|
286
|
+
delta = 1,
|
287
|
+
newPercentage, isGreater, steps, stepDuration;
|
288
|
+
|
289
|
+
this._value = Math.min(this._maxValue, Math.max(0, value));
|
290
|
+
|
291
|
+
if (!duration) {//No duration, we can't skip the animation
|
292
|
+
this._setPercentage(this.getPercent());
|
293
|
+
return this;
|
294
|
+
}
|
295
|
+
|
296
|
+
newPercentage = self.getPercent();
|
297
|
+
isGreater = newPercentage > oldPercentage;
|
298
|
+
|
299
|
+
delta += newPercentage % 1; //If new percentage is not an integer, we add the decimal part to the delta
|
300
|
+
steps = Math.floor(Math.abs(newPercentage - oldPercentage) / delta);
|
301
|
+
stepDuration = duration / steps;
|
302
|
+
|
303
|
+
|
304
|
+
(function animate(lastFrame) {
|
305
|
+
if (isGreater)
|
306
|
+
oldPercentage += delta;
|
307
|
+
else
|
308
|
+
oldPercentage -= delta;
|
309
|
+
|
310
|
+
if ((isGreater && oldPercentage >= newPercentage) || (!isGreater && oldPercentage <= newPercentage))
|
311
|
+
{
|
312
|
+
requestAnimFrame(function(){ self._setPercentage(newPercentage); });
|
313
|
+
return;
|
314
|
+
}
|
315
|
+
|
316
|
+
requestAnimFrame(function() { self._setPercentage(oldPercentage); });
|
317
|
+
|
318
|
+
var now = Date.now(),
|
319
|
+
deltaTime = now - lastFrame;
|
320
|
+
|
321
|
+
if (deltaTime >= stepDuration) {
|
322
|
+
animate(now);
|
323
|
+
} else {
|
324
|
+
setTimeout(function() {
|
325
|
+
animate(Date.now());
|
326
|
+
}, stepDuration - deltaTime);
|
327
|
+
}
|
328
|
+
|
329
|
+
})(Date.now());
|
330
|
+
|
331
|
+
return this;
|
332
|
+
}
|
333
|
+
};
|
334
|
+
|
335
|
+
Circles.create = function(options) {
|
336
|
+
return new Circles(options);
|
337
|
+
};
|
338
|
+
})();
|
metadata
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: circles
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.6
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Julius Jung
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-01-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.7'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
description:
|
42
|
+
email:
|
43
|
+
- juljun14@gmail.com
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- LICENSE
|
49
|
+
- README.md
|
50
|
+
- lib/circles.rb
|
51
|
+
- lib/circles/version.rb
|
52
|
+
- vendor/assets/javascripts/circles.js
|
53
|
+
homepage: https://github.com/juljun14/circles
|
54
|
+
licenses:
|
55
|
+
- MIT
|
56
|
+
metadata: {}
|
57
|
+
post_install_message:
|
58
|
+
rdoc_options: []
|
59
|
+
require_paths:
|
60
|
+
- lib
|
61
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
requirements: []
|
72
|
+
rubyforge_project:
|
73
|
+
rubygems_version: 2.4.5
|
74
|
+
signing_key:
|
75
|
+
specification_version: 4
|
76
|
+
summary: Generate circular graphs in SVG with animation
|
77
|
+
test_files: []
|