circular-sliders-rails 1.1.0 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3000aa1e741be8f5446ac688f5ab4061140854f4b17c236ee0dd8e59d429a823
4
- data.tar.gz: 78910adf596adcf0d9dcc08360996899904182eecdbb31a3bdcc4fbe2e47da9a
3
+ metadata.gz: fd234f98547b315390249c7ef09874c4ea09c3d988fde25b5f185bb59fbb4525
4
+ data.tar.gz: 39535784adb7521b8be9c47d00d70d208ea3ad796bd61987e6fa193cef2bf13b
5
5
  SHA512:
6
- metadata.gz: eea4757df78b3c3ce8f5c23a56ad34dbb65fb894c34a7f9982f82206058992e8949935247faeeadf88f9e0609d608c804feddf565ca7902abd63bc76291851ff
7
- data.tar.gz: e4f7f82df671a0d0681c1e14cae41bb796b5073aa5d1e025fa0c052de0825db23b9b065911a22b8c076f36fe7eea4285daf7fe6fed8b2bd7eb8236be482aaf55
6
+ metadata.gz: c8de5094ead6c0b5f4ab070d0b4da155e2616a1f10b9c7dfe0bbf70e3edce640380bf51e67c090f9165b413f8a9492e8b7a6f56de22507e36ff41ed4592933c2
7
+ data.tar.gz: 6db569d5174ebb882a3dbcf92ffbed92022d1e71e5ba6944ddfa1bf2eb17981b02165d2e9bfa33017e97112eb968338d0cfe205d8c0e084a6d5230587a2cfc79
data/.gitignore CHANGED
@@ -1,11 +1,4 @@
1
1
  /.bundle/
2
- /.yardoc
3
- /Gemfile.lock
4
- /_yardoc/
5
- /coverage/
6
- /doc/
7
2
  /pkg/
8
- /spec/reports/
9
3
  /tmp/
10
- spec.txt
11
4
  improvements.txt
data/README.md CHANGED
@@ -1,8 +1,6 @@
1
- # Circular Sliders for Rails
1
+ # Jquery Circular Sliders for Rails
2
2
 
3
- A Ruby on Rails gem which allows you to draw concentric responsive circular sliders with jQuery. Requires jQuery.
4
-
5
- ![Circular sliders](../assets/circular-sliders-rails.gif?raw=true)
3
+ Provides integration of [Jquery Circular Sliders](https://github.com/speterlin/jquery.circular-sliders) with Rails Asset Pipeline.
6
4
 
7
5
  ## Installation
8
6
 
@@ -24,118 +22,9 @@ Or install it yourself as:
24
22
 
25
23
  Include in your application.js file:
26
24
 
27
- //= require circular-sliders
28
-
29
- Create a canvas element in the view where you would like the sliders to go:
30
-
31
- <canvas id="sliders" width="1200" height="300" style="border:1px solid;"></canvas>
32
-
33
- Use jQuery to add circular sliders to the canvas area. Pass slider settings as objects in an array. Create multiple sliders or just a single slider. With the settings below you should see something like the picture above.
34
-
35
- <script>
36
- $('#sliders').sliders([
37
- {
38
- name: "Age",
39
- centerX: 175,
40
- minValue: 18,
41
- maxValue: 66,
42
- step: 1,
43
- units: "years",
44
- color: "#FF7F50",
45
- legendColor: "#FF7F50"
46
- },
47
- {
48
- name: "Daily activity",
49
- units: "miles",
50
- minValue: 0,
51
- maxValue: 25,
52
- step: 1,
53
- color: "#FF7F50",
54
- legendColor: "#FF7F50"
55
- },
56
- {
57
- name: "Height",
58
- color: "#FFDEAD",
59
- type: "Height",
60
- centerX: 375,
61
- minValue: 0,
62
- maxValue: 250,
63
- step: 2,
64
- units: "cm",
65
- radius: 100
66
- },
67
- {
68
- name: "Weight",
69
- color: "#A52A2A",
70
- type: "Weight",
71
- minValue: 0,
72
- maxValue: 150,
73
- radius: 100,
74
- centerX: 600,
75
- step: 5,
76
- units: "kg",
77
- lineWidth: 10,
78
- gradientFill: false
79
- },
80
- {
81
- name: "Waist size",
82
- color: "#A0522D",
83
- type: "Waist",
84
- centerX: 825,
85
- radius: 100,
86
- minValue: 0,
87
- maxValue: 50,
88
- lineWidth: 10,
89
- step: 2,
90
- units: "cm",
91
- ballColor: "#A0522D"
92
- },
93
- {
94
- name: "Shoe size",
95
- type: "Shoe",
96
- centerX: 1050,
97
- radius: 100,
98
- lineWidth: 10,
99
- minValue: 10,
100
- maxValue: 60,
101
- step: 1,
102
- legendColor: "#0000FF"
103
- },
104
- {
105
- name: "Desired price",
106
- priceUnits: "£",
107
- legendColor: "#0000FF",
108
- step: 5
109
- }
110
- ]);
111
- </script>
112
-
113
- Slider settings:
114
-
115
- | Name | Type | Default | Description |
116
- | --------------- | ------- | ----------------------------------- | ------------------------------------------------------ |
117
- | name | String | Slider n | Name your slider |
118
- | type | String | Plain | Pick between various types for interesting graphics at the center of the slider: 'Height', 'Weight', 'Shoe', 'Waist', and more to come |
119
- | centerX | Float | Center of canvas or previous slider | Specify the x value for the center of the slider |
120
- | centerY | Float | Center of canvas or previous slider | Specify the y value for the center of the slider |
121
- | color | String | "#0000FF" | Specify the color of the arc fill |
122
- | minValue | Float | 0 | The minimum value of your slider |
123
- | maxValue | Float | 100 | The maximum value of your slider |
124
- | step | Float | 10 | The amount the value is incremented |
125
- | units | String | "" | The units your value is displayed in |
126
- | priceUnits | String | "" | Adds price ('$', '€', '£' ...) before value |
127
- | radius | Float | 40 or (previous slider radius + previous slider lineWidth + default slider lineWidth) | The radius of your slider |
128
- | lineWidth | Float | 5 | The slider and arc width |
129
- | strokeColor | String | "#D3D3D3" | The color of the dashes on the slider |
130
- | ballColor | String | "#000000" | The color of the slider ball |
131
- | gradientFill | Boolean | true | Specify whether you would like the image in the center (for specified type) of the slider to fill with the slider's color as you scale the slider |
132
- | legend | Boolean | true | Specify whether you would like the slider name, value and units listed in the top left corner of the canvas |
133
- | legendFont | Boolean | "12px Arial" | Specify the font for the slider legend |
134
- | legendColor | String | "#000000" | The color of the slider legend |
135
-
136
- Retrieve values of individual sliders by calling:
137
-
138
- $('#sliders').data('slider_name');
25
+ //= require jquery.circular-sliders
26
+
27
+ For more options and style customization, please, see [Jquery Circular Sliders](https://github.com/speterlin/jquery.circular-sliders)
139
28
 
140
29
  <!-- ## Development -->
141
30
 
@@ -9,8 +9,8 @@ Gem::Specification.new do |spec|
9
9
  spec.authors = ["Sebastian Peterlin"]
10
10
  spec.email = ["speterlin@gmail.com"]
11
11
 
12
- spec.summary = %q{Draw concentric circles and responsively set each value.}
13
- spec.description = %q{A Ruby on Rails gem which allows you to draw concentric responsive circular sliders with jQuery. Requires jQuery.}
12
+ spec.summary = %q{Provides jQuery Circular Sliders for Rails Asset Pipeline.}
13
+ spec.description = %q{Provides jQuery Circular Sliders for Rails Asset Pipeline.}
14
14
  spec.homepage = "https://github.com/speterlin/circular-sliders-rails"
15
15
  spec.license = "MIT"
16
16
 
@@ -27,9 +27,9 @@ Gem::Specification.new do |spec|
27
27
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
28
  spec.require_paths = ["lib"]
29
29
 
30
+ spec.add_dependency "railties", ">= 3.2.0"
31
+
30
32
  spec.add_development_dependency "bundler", "~> 1.12"
31
33
  spec.add_development_dependency "rake", "~> 10.0"
32
34
  spec.add_development_dependency "rspec", "~> 3.0"
33
-
34
- spec.add_dependency "rails", "~> 5.0"
35
35
  end
@@ -1,7 +1,7 @@
1
1
  module Circular
2
2
  module Sliders
3
3
  module Rails
4
- VERSION = "1.1.0"
4
+ VERSION = "1.5.0"
5
5
  end
6
6
  end
7
7
  end
@@ -0,0 +1,307 @@
1
+ /*
2
+ * JqueryCircularSliders.js
3
+ * Add concentric circles with jquery and responsively set each value.
4
+ * git+https://github.com/speterlin/jquery.circular-sliders.js.git
5
+ * v1.0.0
6
+ * MIT License
7
+ */
8
+
9
+ (function (global, factory) {
10
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(require('jquery')) :
11
+ typeof define === 'function' && define.amd ? define(['jquery'], factory) :
12
+ (factory(global.$));
13
+ }(this, (function ($) { 'use strict';
14
+
15
+ $ = $ && $.hasOwnProperty('default') ? $['default'] : $;
16
+
17
+ function renderShoeWithGradient(ctx, slider) {
18
+ ctx.moveTo(slider.centerX - 0.8 * slider.radius, slider.centerY - 0.5 * slider.radius);
19
+ ctx.arc(slider.centerX - 0.5 * slider.radius, slider.centerY - 0.5 * slider.radius, slider.radius * 0.3, Math.PI, 0, true);
20
+ ctx.lineTo(slider.centerX + 0.6 * slider.radius, slider.centerY - 0.1 * slider.radius);
21
+ ctx.arc(slider.centerX + 0.7 * slider.radius, slider.centerY + 0.1 * slider.radius, slider.radius * 0.2, -(Math.PI / 2), Math.PI / 2, false);
22
+ ctx.lineTo(slider.centerX - 0.8 * slider.radius, slider.centerY + 0.3 * slider.radius);
23
+ ctx.lineTo(slider.centerX - 0.8 * slider.radius, slider.centerY - 0.5 * slider.radius);
24
+ return ctx.createLinearGradient(slider.centerX - 0.8 * slider.radius, slider.centerY + 0.3 * slider.radius, slider.centerX - 0.8 * slider.radius, slider.centerY - 0.5 * slider.radius);
25
+ }
26
+
27
+ function renderWaistWithGradient(ctx, slider) {
28
+ // maybe refactor, wanted to eyeball it without using math, also maybe move up, could put back in (slight difference at edge): ctx.moveTo(slider.centerX - 0.5 * slider.radius, slider.centerY + 0.05 * slider.radius);
29
+ ctx.arc(slider.centerX, slider.centerY - 0.8 * slider.radius, slider.radius, Math.PI * (2 / 3), Math.PI * (1 / 3), true);
30
+ // refactor, need to send to 0.85 * slider.radius instead of 0.9 * slider.radius since there is a sharp v bend if not
31
+ ctx.lineTo(slider.centerX + 0.2 * slider.radius, slider.centerY + 0.85 * slider.radius);
32
+ ctx.arc(slider.centerX + 0.1 * slider.radius, slider.centerY + 0.9 * slider.radius, slider.radius * 0.1, 0, Math.PI, true);
33
+ ctx.lineTo(slider.centerX, slider.centerY + 0.4 * slider.radius);
34
+ ctx.arc(slider.centerX - 0.1 * slider.radius, slider.centerY + 0.9 * slider.radius, slider.radius * 0.1, 0, Math.PI, true);
35
+ // maybe refactor moveTo, need it to avoid sharp v bend at base of arc
36
+ ctx.moveTo(slider.centerX - 0.2 * slider.radius, slider.centerY + 0.9 * slider.radius);
37
+ ctx.lineTo(slider.centerX - 0.5 * slider.radius, slider.centerY + 0.05 * slider.radius);
38
+ return ctx.createLinearGradient(slider.centerX - 0.2 * slider.radius, slider.centerY + 0.9 * slider.radius, slider.centerX - 0.2 * slider.radius, slider.centerY + 0.05 * slider.radius);
39
+ }
40
+
41
+ function renderPersonWithGradient(ctx, slider, options = {}) {
42
+ ctx.arc(slider.centerX, slider.centerY - 0.6 * slider.radius, slider.radius * 0.2, 0, Math.PI * 2, false);
43
+ ctx.moveTo(slider.centerX + 0.08 * slider.radius, slider.centerY - 0.32 * slider.radius);
44
+ ctx.arc(slider.centerX, slider.centerY - 0.3 * slider.radius, slider.radius * 0.08, 0, Math.PI * 2, false);
45
+ ctx.moveTo(slider.centerX + 0.05 * slider.radius, slider.centerY - 0.25 * slider.radius);
46
+ // maybe refactor and add arms, ctx.lineTo(slider.centerX + 0.25 * slider.radius, slider.centerY - 0.1 * slider.radius);
47
+ ctx.lineTo(slider.centerX + 0.05 * slider.radius, slider.centerY + 0.1 * slider.radius);
48
+ ctx.arc(slider.centerX, slider.centerY + 0.2 * slider.radius, slider.radius * 0.1, -(Math.PI / 3), Math.PI / 3, false);
49
+ ctx.lineTo(slider.centerX + 0.05 * slider.radius, slider.centerY + 0.8 * slider.radius);
50
+ ctx.lineTo(slider.centerX - 0.2 * slider.radius, slider.centerY + 0.8 * slider.radius);
51
+ ctx.arc(slider.centerX - 0.15 * slider.radius, slider.centerY + 0.8 * slider.radius, slider.radius * 0.05, Math.PI, -(Math.PI / 2), false);
52
+ ctx.lineTo(slider.centerX - 0.05 * slider.radius, slider.centerY + 0.75 * slider.radius);
53
+ if (options.style === 'Weight') {
54
+ ctx.lineTo(slider.centerX - 0.05 * slider.radius, slider.centerY + 0.15 * slider.radius);
55
+ ctx.arc(slider.centerX - 0.05 * slider.radius, slider.centerY, slider.radius * 0.15, Math.PI / 2, -(Math.PI / 2), false);
56
+ ctx.lineTo(slider.centerX - 0.05 * slider.radius, slider.centerY - 0.25 * slider.radius);
57
+ } else {
58
+ ctx.lineTo(slider.centerX - 0.05 * slider.radius, slider.centerY - 0.25 * slider.radius);
59
+ }
60
+ return ctx.createLinearGradient(slider.centerX - 0.05 * slider.radius, slider.centerY + 0.8 * slider.radius, slider.centerX - 0.05 * slider.radius, slider.centerY - 0.8 * slider.radius);
61
+ }
62
+
63
+ function renderLegend(ctx, slider, sliderIndex, movingSliderBall) {
64
+ ctx.beginPath();
65
+ if (movingSliderBall) { ctx.font = `bold ${slider.legend.font}`; } else { ctx.font = slider.legend.font; }
66
+ ctx.fillStyle = slider.legend.color;
67
+ // maybe refactor, 20px vertical spacing by default, could be an issue if set font above 20px
68
+ ctx.fillText(`${slider.name}: ${slider.priceUnits}${slider.value} ${slider.units}`, 10, 20 * (sliderIndex + 1));
69
+ ctx.closePath();
70
+ }
71
+
72
+ function renderCanvas(canvas, movingBall = false) {
73
+ const ctx = canvas.getContext('2d');
74
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
75
+ const sliders = canvas.sliders;
76
+ sliders.forEach((slider, index) => {
77
+ slider.__render(ctx);
78
+ if (slider.legend.display) {
79
+ renderLegend(ctx, slider, index, movingBall && slider === canvas.selectedSlider);
80
+ }
81
+ });
82
+ }
83
+
84
+ let isMouseDown = false;
85
+
86
+ function roundToStep(value, step) {
87
+ return Math.round(value / step) * step;
88
+ }
89
+
90
+ function ballLocationForAngle(slider) {
91
+ return [slider.centerX + slider.radius * Math.cos(slider.angle), slider.centerY + slider.radius * Math.sin(slider.angle)];
92
+ }
93
+
94
+ function angleForValue(slider) {
95
+ return (2 * Math.PI * (slider.value - slider.minValue) / slider.range) - (Math.PI / 2);
96
+ }
97
+
98
+ function moveBall(mouseX, mouseY, canvas) {
99
+ const slider = canvas.selectedSlider;
100
+ const dx = mouseX - slider.centerX;
101
+ // if draw out in x-y coordinates correct way would be slider.centerY - mouseY, but because top of circle -π / 2, have to do negative of angle which is the same as doing below
102
+ const dy = mouseY - slider.centerY;
103
+ slider.angle = Math.atan(dy / dx);
104
+ // to cover other half of circle, Math.atan only calculates angles between -π/2 and π/2
105
+ if (dx < 0) { slider.angle += Math.PI; }
106
+ [slider.ball.x, slider.ball.y] = ballLocationForAngle(slider);
107
+ // add π / 2 because 0˚ (top of circle) starts at -π / 2, divide by 2π because this is 360˚ in radians, this is reverse of #angleForValue
108
+ const value = slider.minValue + slider.range * ((slider.angle + (Math.PI / 2)) / (2 * Math.PI));
109
+ // refactor - bug if give step value below 0.5
110
+ const roundedValue = roundToStep(value, slider.step);
111
+ slider.value = roundedValue;
112
+ renderCanvas(canvas, true);
113
+ }
114
+
115
+ function moveBallToStep(canvas) {
116
+ const slider = canvas.selectedSlider;
117
+ slider.angle = angleForValue(slider);
118
+ [slider.ball.x, slider.ball.y] = ballLocationForAngle(slider);
119
+ renderCanvas(canvas);
120
+ }
121
+
122
+ function setMouse(e) {
123
+ const canvas = e.target;
124
+ // $(window).scrollLeft() and $(window).scrollTop() to account for page scrolling
125
+ return [parseInt(e.clientX - canvas.offsetLeft + $(window).scrollLeft(), 10), parseInt(e.clientY - canvas.offsetTop + $(window).scrollTop(), 10)];
126
+ }
127
+
128
+ function onBall(x, y, slider) {
129
+ if (x > (slider.ball.x - slider.ball.radius) && x < (slider.ball.x + slider.ball.radius) && y > (slider.ball.y - slider.ball.radius) && y < (slider.ball.y + slider.ball.radius)) {
130
+ return true;
131
+ }
132
+ return false;
133
+ }
134
+
135
+ function handleMouseDown(e) {
136
+ e.preventDefault();
137
+ isMouseDown = true;
138
+ const [mouseX, mouseY] = setMouse(e);
139
+ const sliders = e.target.sliders;
140
+ sliders.forEach((slider) => {
141
+ if (onBall(mouseX, mouseY, slider)) {
142
+ e.target.selectedSlider = slider;
143
+ }
144
+ });
145
+ }
146
+
147
+ function handleMouseUp(e) {
148
+ e.preventDefault();
149
+ isMouseDown = false;
150
+ moveBallToStep(e.target);
151
+ }
152
+
153
+ function handleMouseMove(e) {
154
+ if (!isMouseDown) {
155
+ return;
156
+ }
157
+ e.preventDefault();
158
+ const [mouseX, mouseY] = setMouse(e);
159
+ moveBall(mouseX, mouseY, e.target);
160
+ }
161
+
162
+ class Ball {
163
+ constructor(slider, ballColor) {
164
+ [this.x, this.y] = ballLocationForAngle(slider);
165
+ this.radius = slider.lineWidth;
166
+ this.color = ballColor;
167
+ }
168
+ }
169
+
170
+ function renderSlider(ctx, slider) {
171
+ ctx.beginPath();
172
+ ctx.lineWidth = slider.lineWidth;
173
+ ctx.strokeStyle = slider.strokeColor;
174
+ ctx.setLineDash([slider.lineDashLength, slider.lineDashSpacing]);
175
+ ctx.arc(slider.centerX, slider.centerY, slider.radius, 0, Math.PI * 2, false);
176
+ ctx.stroke();
177
+ ctx.closePath();
178
+ if (slider.type !== 'Plain') {
179
+ ctx.beginPath();
180
+ ctx.setLineDash([10, 0]);
181
+ ctx.lineWidth = 5;
182
+ let myGradient = null;
183
+ if (slider.type === 'Shoe') {
184
+ myGradient = renderShoeWithGradient(ctx, slider);
185
+ } else if (slider.type === 'Waist') {
186
+ myGradient = renderWaistWithGradient(ctx, slider);
187
+ } else if (slider.type === 'Height') {
188
+ myGradient = renderPersonWithGradient(ctx, slider);
189
+ } else if (slider.type === 'Weight') {
190
+ myGradient = renderPersonWithGradient(ctx, slider, { style: 'Weight' });
191
+ }
192
+ if (slider.gradientFill) {
193
+ const scale = (slider.value - slider.minValue) / slider.range;
194
+ myGradient.addColorStop(0, slider.color);
195
+ myGradient.addColorStop(scale, '#ffffff');
196
+ ctx.fillStyle = myGradient;
197
+ ctx.fill();
198
+ }
199
+ ctx.stroke();
200
+ ctx.closePath();
201
+ }
202
+ }
203
+
204
+ function renderArc(ctx, slider) {
205
+ // add this if want arc to stop at edge of ball: let angleOffset = Math.atan(slider.ball.radius / slider.radius), then also need check for (π / 2) + slider.angle) < angleOffset) for when go past the 0˚ mark at top of circle, π / 2 + slider.angle since angle starts at -π / 2 at top of circle
206
+ ctx.beginPath();
207
+ ctx.arc(slider.centerX, slider.centerY, slider.radius, -(Math.PI / 2), slider.angle, false);
208
+ ctx.lineWidth = slider.lineWidth;
209
+ ctx.strokeStyle = slider.color;
210
+ // have to set lineDashLength to a number > 0 for arc to be completely full in browsers like Safari
211
+ ctx.setLineDash([10, 0]);
212
+ ctx.stroke();
213
+ ctx.closePath();
214
+ }
215
+
216
+ function renderBall(ctx, slider) {
217
+ ctx.beginPath();
218
+ ctx.arc(slider.ball.x, slider.ball.y, slider.ball.radius, 0, Math.PI * 2);
219
+ ctx.fillStyle = slider.ball.color;
220
+ ctx.fill();
221
+ ctx.closePath();
222
+ }
223
+
224
+ class CircularSlider {
225
+ constructor(settings) {
226
+ const slider = this;
227
+ Object.keys(settings).forEach((key) => {
228
+ slider[key] = settings[key];
229
+ });
230
+ // centerX, centerY, and radius should be set in defaults (in for loop) or options
231
+ this.value = this.value || this.minValue;
232
+ // calculated / created attributes
233
+ this.range = this.maxValue - this.minValue;
234
+ this.angle = angleForValue(this);
235
+ // maybe refactor, I like 2/3 and 1/3 for now
236
+ const arcSegment = 2 * Math.PI * this.radius / (this.range / this.step);
237
+ this.lineDashLength = (2 / 3) * arcSegment;
238
+ this.lineDashSpacing = (1 / 3) * arcSegment;
239
+ this.ball = new Ball(this, settings.ballColor);
240
+ }
241
+
242
+ __render(ctx) {
243
+ renderSlider(ctx, this);
244
+ renderArc(ctx, this);
245
+ renderBall(ctx, this);
246
+ }
247
+ }
248
+ // $.fn.sliders.CircularSlider = CircularSlider;
249
+
250
+ if (typeof $ === 'undefined') {
251
+ throw new Error('jQuery.CircularSliders requires jQuery');
252
+ }
253
+
254
+ $.fn.sliders = function (slidersOptions) {
255
+ this.each(function () {
256
+ if (!$(this).is('canvas')) { throw new Error('Circular Sliders must be called on a Canvas.'); }
257
+ const canvas = this;
258
+ const sliders = [];
259
+ const canvasDefaults = {};
260
+ [canvasDefaults.centerX, canvasDefaults.centerY, canvasDefaults.radius] = [canvas.width / 2, canvas.height / 2, Math.min(canvas.width, canvas.height) / 4];
261
+ slidersOptions.forEach((sliderOptions, index) => {
262
+ canvasDefaults.name = `Slider ${index + 1}`;
263
+ if (index > 0) {
264
+ [canvasDefaults.centerX, canvasDefaults.centerY] = [sliders[index - 1].centerX, sliders[index - 1].centerY];
265
+ canvasDefaults.radius = sliders[index - 1].radius + sliders[index - 1].lineWidth + $.fn.sliders.defaults.lineWidth;
266
+ }
267
+ const sliderDefaults = $.extend({}, $.fn.sliders.defaults, canvasDefaults);
268
+ // true for deep merge
269
+ const settings = $.extend(true, {}, sliderDefaults, sliderOptions);
270
+ sliders.push(new CircularSlider(settings));
271
+ });
272
+ // maybe look at https://stackoverflow.com/questions/10149963/adding-event-listener-cross-browser
273
+ canvas.addEventListener('mousedown', handleMouseDown);
274
+ canvas.addEventListener('mouseup', handleMouseUp);
275
+ canvas.addEventListener('mousemove', handleMouseMove);
276
+
277
+ [canvas.sliders, canvas.selectedSlider] = [sliders, sliders[0]];
278
+
279
+ renderCanvas(canvas);
280
+ });
281
+ };
282
+
283
+ // TODO: add configure(options) and config: config
284
+ $.fn.sliders.defaults = {
285
+ name: 'Slider',
286
+ type: 'Plain',
287
+ color: '#0000FF',
288
+ minValue: 0,
289
+ maxValue: 100,
290
+ step: 10,
291
+ units: '',
292
+ priceUnits: '',
293
+ // centerX, centerY, and radius set in Canvas because they are specific/modified to each canvas
294
+ lineWidth: 5,
295
+ strokeColor: '#D3D3D3',
296
+ ballColor: '#000000',
297
+ gradientFill: true,
298
+ legend: { display: true, font: '12px Arial', color: '#000000' },
299
+ };
300
+
301
+ $.fn.findSliderByName = function (name) {
302
+ if (!this.is('canvas')) { throw new Error('findSliderByName must be called on a Canvas.'); }
303
+ const canvas = this[0];
304
+ return canvas.sliders.filter(slider => slider.name === name)[0];
305
+ };
306
+
307
+ })));
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: circular-sliders-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sebastian Peterlin
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-08-05 00:00:00.000000000 Z
11
+ date: 2018-08-28 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: railties
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 3.2.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 3.2.0
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: bundler
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -52,22 +66,7 @@ dependencies:
52
66
  - - "~>"
53
67
  - !ruby/object:Gem::Version
54
68
  version: '3.0'
55
- - !ruby/object:Gem::Dependency
56
- name: rails
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: '5.0'
62
- type: :runtime
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: '5.0'
69
- description: A Ruby on Rails gem which allows you to draw concentric responsive circular
70
- sliders with jQuery. Requires jQuery.
69
+ description: Provides jQuery Circular Sliders for Rails Asset Pipeline.
71
70
  email:
72
71
  - speterlin@gmail.com
73
72
  executables: []
@@ -87,8 +86,7 @@ files:
87
86
  - circular-sliders-rails.gemspec
88
87
  - lib/circular/sliders/rails.rb
89
88
  - lib/circular/sliders/rails/version.rb
90
- - vendor/assets/javascripts/circular-sliders.js
91
- - vendor/assets/javascripts/shapes.js
89
+ - vendor/assets/javascripts/jquery.circular-sliders.js
92
90
  homepage: https://github.com/speterlin/circular-sliders-rails
93
91
  licenses:
94
92
  - MIT
@@ -113,5 +111,5 @@ rubyforge_project:
113
111
  rubygems_version: 2.7.6
114
112
  signing_key:
115
113
  specification_version: 4
116
- summary: Draw concentric circles and responsively set each value.
114
+ summary: Provides jQuery Circular Sliders for Rails Asset Pipeline.
117
115
  test_files: []
@@ -1,234 +0,0 @@
1
- //= require shapes
2
-
3
- (function ( $ ) {
4
- 'use strict';
5
-
6
- // private global variables
7
- var isMouseDown = false;
8
- var defaults = {
9
- name: "Slider",
10
- type: "Plain",
11
- color: "#0000FF",
12
- minValue: 0,
13
- maxValue: 100,
14
- step: 10,
15
- units: "",
16
- priceUnits: "",
17
- // centerX, centerY, and radius set in $.fn.sliders() because they are specific/modified to each canvas
18
- lineWidth: 5,
19
- strokeColor: "#D3D3D3",
20
- ballColor: "#000000",
21
- gradientFill: true,
22
- legend: true,
23
- legendFont: "12px Arial",
24
- legendColor: "#000000"
25
- }
26
-
27
- $.fn.sliders = function(slidersOptions) {
28
- this.each(function() {
29
- var canvas = this;
30
- canvas.sliders = [];
31
- [defaults.centerX, defaults.centerY, defaults.radius] = [canvas.width / 2, canvas.height / 2, 40];
32
- // maybe refactor, add container option if there are multiple containers
33
- for (var i = 0; i < slidersOptions.length; i++) {
34
- defaults.name = "Slider " + (i + 1);
35
- if (i > 0) {
36
- defaults.centerX = canvas.sliders[i-1].centerX;
37
- defaults.centerY = canvas.sliders[i-1].centerY;
38
- defaults.radius = canvas.sliders[i-1].radius + canvas.sliders[i-1].lineWidth + defaults.lineWidth;
39
- }
40
- var sliderSettings = $.extend( {}, defaults, slidersOptions[i] );
41
- canvas.sliders.push(new Slider (sliderSettings));
42
- // maybe refactor, visible if have it like this: elem.attr('data-'+sliders[i].name.split(" ").join("_"), sliders[i].minValue);
43
- $(canvas).data(canvas.sliders[i].name.split(" ").join("_"), canvas.sliders[i].value);
44
- }
45
- canvas.selectedSlider = canvas.sliders[0];
46
- draw(canvas);
47
- canvas.addEventListener("mousedown", handleMouseDown);
48
- canvas.addEventListener("mouseup", handleMouseUp);
49
- canvas.addEventListener("mousemove", handleMouseMove);
50
- })
51
- }
52
-
53
- function Slider(settings) {
54
- this.name = settings.name;
55
- this.type = settings.type;
56
- this.centerX = settings.centerX;
57
- this.centerY = settings.centerY;
58
- this.color = settings.color;
59
- this.minValue = settings.minValue;
60
- this.maxValue = settings.maxValue;
61
- this.step = settings.step;
62
- this.units = settings.units;
63
- this.priceUnits = settings.priceUnits;
64
- this.radius = settings.radius;
65
- this.lineWidth = settings.lineWidth;
66
- this.strokeColor = settings.strokeColor;
67
- this.value = settings.minValue;
68
- this.gradientFill = settings.gradientFill;
69
- this.legend = settings.legend;
70
- this.legendFont = settings.legendFont;
71
- this.legendColor = settings.legendColor;
72
- // ball starts at top of circle which is - π / 2
73
- this.angle = -(Math.PI / 2);
74
- this.range = this.maxValue - this.minValue;
75
- // maybe refactor, I like 2/3 and 1/3 for now
76
- var arcSegment = 2 * Math.PI * this.radius / (this.range / this.step);
77
- this.lineDashLength = (2 / 3) * arcSegment;
78
- this.lineDashSpacing = (1 / 3) * arcSegment;
79
- this.ball = new Ball (settings);
80
- }
81
-
82
- function Ball(sliderSettings) {
83
- this.x = sliderSettings.centerX;
84
- // ball starts at top of circle
85
- this.y = sliderSettings.centerY - sliderSettings.radius;
86
- this.radius = sliderSettings.lineWidth;
87
- this.color = sliderSettings.ballColor;
88
- }
89
-
90
- function draw(canvas, movingBall = false) {
91
- var ctx = canvas.getContext("2d");
92
- // in the future want to be able to clear only the slider using, maybe with svg groups
93
- ctx.clearRect(0, 0, canvas.width, canvas.height);
94
- var sliders = canvas.sliders;
95
- for (var i = 0; i < sliders.length; i++) {
96
- drawSlider(ctx, sliders[i]);
97
- drawArc(ctx, sliders[i]);
98
- drawBall(ctx, sliders[i]);
99
- if (sliders[i].legend) { drawLegend(ctx, sliders[i], i, movingBall && sliders[i] == canvas.selectedSlider); }
100
- }
101
- }
102
-
103
- function drawSlider(ctx, slider) {
104
- ctx.lineWidth = slider.lineWidth;
105
- ctx.strokeStyle = slider.strokeColor;
106
- ctx.setLineDash([slider.lineDashLength, slider.lineDashSpacing]);
107
- ctx.beginPath();
108
- ctx.arc(slider.centerX, slider.centerY, slider.radius, 0, Math.PI * 2, false);
109
- ctx.stroke();
110
- ctx.closePath();
111
- if (slider.type != "Plain") {
112
- ctx.beginPath();
113
- ctx.setLineDash([10, 0]);
114
- ctx.lineWidth = 5;
115
- var my_gradient = null;
116
- if (slider.type == "Shoe") {
117
- my_gradient = drawShoeWithGradient(ctx, slider);
118
- } else if (slider.type == "Waist") {
119
- my_gradient = drawWaistWithGradient(ctx, slider);
120
- } else if (slider.type == "Height") {
121
- my_gradient = drawPersonWithGradient(ctx, slider);
122
- } else if (slider.type == "Weight") {
123
- my_gradient = drawPersonWithGradient(ctx, slider, {style: "Weight"});
124
- }
125
- if (slider.gradientFill) {
126
- var scale = (slider.value - slider.minValue) / slider.range;
127
- my_gradient.addColorStop(0,slider.color);
128
- my_gradient.addColorStop(scale,"#ffffff");
129
- ctx.fillStyle = my_gradient;
130
- ctx.fill();
131
- }
132
- ctx.stroke();
133
- ctx.closePath();
134
- }
135
- }
136
-
137
- function drawBall(ctx, slider) {
138
- ctx.beginPath();
139
- ctx.arc(slider.ball.x, slider.ball.y, slider.ball.radius, 0, Math.PI * 2);
140
- ctx.fillStyle = slider.ball.color;
141
- ctx.fill();
142
- ctx.closePath();
143
- }
144
-
145
- function drawArc(ctx, slider) {
146
- // add this if want arc to stop at edge of ball: var angleOffset = Math.atan(slider.ball.radius / slider.radius), then also need check for (π / 2) + slider.angle) < angleOffset) for when go past the 0˚ mark at top of circle, π / 2 + slider.angle since angle starts at -π / 2 at top of circle
147
- ctx.beginPath();
148
- ctx.arc(slider.centerX, slider.centerY, slider.radius, -(Math.PI / 2), slider.angle, false);
149
- ctx.lineWidth = slider.lineWidth;
150
- ctx.strokeStyle = slider.color;
151
- // have to set lineDashLength to a number > 0 for arc to be completely full in browsers like Safari, set it arbitrarily to 10 here
152
- ctx.setLineDash([10, 0]);
153
- ctx.stroke();
154
- ctx.closePath();
155
- }
156
-
157
- function drawLegend(ctx, slider, sliderIndex, movingSliderBall) {
158
- ctx.beginPath();
159
- if (movingSliderBall) {ctx.font = "bold " + slider.legendFont;} else {ctx.font = slider.legendFont;}
160
- ctx.fillStyle = slider.legendColor;
161
- // maybe refactor, 20px vertical spacing by default, could be an issue if set font above 20px
162
- ctx.fillText(slider.name + ": " + slider.priceUnits + slider.value + " " + slider.units, 10, 20 * (sliderIndex + 1));
163
- ctx.closePath();
164
- }
165
-
166
- function moveBall(mouseX, mouseY, canvas) {
167
- var slider = canvas.selectedSlider;
168
- var dx = mouseX - slider.centerX;
169
- var dy = mouseY - slider.centerY;
170
- slider.angle = Math.atan(dy / dx);
171
- if (dx < 0) { slider.angle += Math.PI; }
172
- slider.ball.x = slider.centerX + slider.radius * Math.cos(slider.angle);
173
- slider.ball.y = slider.centerY + slider.radius * Math.sin(slider.angle);
174
- slider.value = slider.minValue + slider.range * ((slider.angle + (Math.PI / 2)) / (2 * Math.PI)); //add π / 2 because 0˚ starts at -π / 2, divide by 2π because this is 360˚ in radians
175
- // refactor - bug if give step value below 0.5
176
- var roundedValue = roundToStep(slider.value, slider.step);
177
- $(canvas).data(slider.name.split(" ").join("_"), roundedValue);
178
- slider.value = roundedValue;
179
- draw(canvas, true);
180
- }
181
-
182
- function moveBallToStep(canvas) {
183
- var slider = canvas.selectedSlider;
184
- slider.angle = (2 * Math.PI * (slider.value - slider.minValue) / slider.range) - (Math.PI / 2)
185
- slider.ball.x = slider.centerX + slider.radius * Math.cos(slider.angle);
186
- slider.ball.y = slider.centerY + slider.radius * Math.sin(slider.angle);
187
- draw(canvas);
188
- }
189
-
190
- function handleMouseDown(e) {
191
- e.preventDefault();
192
- isMouseDown = true;
193
- var [mouseX, mouseY] = setMouse(e);
194
- var sliders = e.target.sliders;
195
- for (var i = 0; i < sliders.length; i++) {
196
- if (onBall(mouseX, mouseY, sliders[i])) {
197
- e.target.selectedSlider = sliders[i];
198
- }
199
- }
200
- }
201
-
202
- function handleMouseUp(e) {
203
- e.preventDefault();
204
- isMouseDown = false;
205
- moveBallToStep(e.target);
206
- }
207
-
208
- function handleMouseMove(e) {
209
- if (!isMouseDown) {
210
- return;
211
- }
212
- e.preventDefault();
213
- var [mouseX, mouseY] = setMouse(e);
214
- moveBall(mouseX, mouseY, e.target);
215
- }
216
-
217
- function roundToStep(value, step) {
218
- return Math.ceil(value / step) * step;
219
- }
220
-
221
- function onBall(x, y, slider) {
222
- if (x > (slider.ball.x - slider.ball.radius) && x < (slider.ball.x + slider.ball.radius) && y > (slider.ball.y - slider.ball.radius) && y < (slider.ball.y + slider.ball.radius)) {
223
- return true;
224
- }
225
- return false;
226
- }
227
-
228
- function setMouse(e) {
229
- var canvas = e.target;
230
- // $(window).scrollLeft() and $(window).scrollTop() to account for page scrolling
231
- return [parseInt(e.clientX - canvas.offsetLeft + $(window).scrollLeft()), parseInt(e.clientY - canvas.offsetTop + $(window).scrollTop())];
232
- }
233
-
234
- }( jQuery ));
@@ -1,46 +0,0 @@
1
- // maybe refactor and include these in a react like module, would have to worry about browser support, https://stackoverflow.com/questions/950087/how-do-i-include-a-javascript-file-in-another-javascript-file
2
- function drawShoeWithGradient(ctx, slider) {
3
- ctx.moveTo(slider.centerX - 0.8 * slider.radius, slider.centerY - 0.5 * slider.radius);
4
- ctx.arc(slider.centerX - 0.5 * slider.radius, slider.centerY - 0.5 * slider.radius, slider.radius * 0.3, Math.PI, 0, true);
5
- ctx.lineTo(slider.centerX + 0.6 * slider.radius, slider.centerY - 0.1 * slider.radius);
6
- ctx.arc(slider.centerX + 0.7 * slider.radius, slider.centerY + 0.1 * slider.radius, slider.radius * 0.2, -(Math.PI / 2), Math.PI / 2, false);
7
- ctx.lineTo(slider.centerX - 0.8 * slider.radius, slider.centerY + 0.3 * slider.radius);
8
- ctx.lineTo(slider.centerX - 0.8 * slider.radius, slider.centerY - 0.5 * slider.radius);
9
- return ctx.createLinearGradient(slider.centerX - 0.8 * slider.radius, slider.centerY + 0.3 * slider.radius, slider.centerX - 0.8 * slider.radius, slider.centerY - 0.5 * slider.radius);
10
- }
11
-
12
- function drawWaistWithGradient(ctx, slider) {
13
- // maybe refactor, wanted to eyeball it without using math, also maybe move up, could put back in (slight difference at edge): ctx.moveTo(slider.centerX - 0.5 * slider.radius, slider.centerY + 0.05 * slider.radius);
14
- ctx.arc(slider.centerX, slider.centerY - 0.8 * slider.radius, slider.radius, Math.PI * (2 / 3), Math.PI * (1 / 3), true);
15
- // refactor, need to send to 0.85 * slider.radius instead of 0.9 * slider.radius since there is a sharp v bend if not
16
- ctx.lineTo(slider.centerX + 0.2 * slider.radius, slider.centerY + 0.85 * slider.radius);
17
- ctx.arc(slider.centerX + 0.1 * slider.radius, slider.centerY + 0.9 * slider.radius, slider.radius * 0.1, 0, Math.PI, true);
18
- ctx.lineTo(slider.centerX, slider.centerY + 0.4 * slider.radius);
19
- ctx.arc(slider.centerX - 0.1 * slider.radius, slider.centerY + 0.9 * slider.radius, slider.radius * 0.1, 0, Math.PI, true);
20
- // maybe refactor moveTo, need it to avoid sharp v bend at base of arc
21
- ctx.moveTo(slider.centerX - 0.2 * slider.radius, slider.centerY + 0.9 * slider.radius);
22
- ctx.lineTo(slider.centerX - 0.5 * slider.radius, slider.centerY + 0.05 * slider.radius);
23
- return ctx.createLinearGradient(slider.centerX - 0.2 * slider.radius, slider.centerY + 0.9 * slider.radius, slider.centerX - 0.2 * slider.radius, slider.centerY + 0.05 * slider.radius);
24
- }
25
-
26
- function drawPersonWithGradient(ctx, slider, options = {}) {
27
- ctx.arc(slider.centerX, slider.centerY - 0.6 * slider.radius, slider.radius * 0.2, 0, Math.PI * 2, false);
28
- ctx.moveTo(slider.centerX + 0.08 * slider.radius, slider.centerY - 0.32 * slider.radius);
29
- ctx.arc(slider.centerX, slider.centerY - 0.3 * slider.radius, slider.radius * 0.08, 0, Math.PI * 2, false);
30
- ctx.moveTo(slider.centerX + 0.05 * slider.radius, slider.centerY - 0.25 * slider.radius);
31
- // maybe refactor and add arms, ctx.lineTo(slider.centerX + 0.25 * slider.radius, slider.centerY - 0.1 * slider.radius);
32
- ctx.lineTo(slider.centerX + 0.05 * slider.radius, slider.centerY + 0.1 * slider.radius);
33
- ctx.arc(slider.centerX, slider.centerY + 0.2 * slider.radius, slider.radius * 0.1, -(Math.PI / 3), Math.PI / 3, false);
34
- ctx.lineTo(slider.centerX + 0.05 * slider.radius, slider.centerY + 0.8 * slider.radius);
35
- ctx.lineTo(slider.centerX - 0.2 * slider.radius, slider.centerY + 0.8 * slider.radius);
36
- ctx.arc(slider.centerX - 0.15 * slider.radius, slider.centerY + 0.8 * slider.radius, slider.radius * 0.05, Math.PI, -(Math.PI / 2), false);
37
- ctx.lineTo(slider.centerX - 0.05 * slider.radius, slider.centerY + 0.75 * slider.radius);
38
- if (options.style == "Weight") {
39
- ctx.lineTo(slider.centerX - 0.05 * slider.radius, slider.centerY + 0.15 * slider.radius);
40
- ctx.arc(slider.centerX - 0.05 * slider.radius, slider.centerY, slider.radius * 0.15, Math.PI / 2, -(Math.PI / 2), false);
41
- ctx.lineTo(slider.centerX - 0.05 * slider.radius, slider.centerY - 0.25 * slider.radius);
42
- } else {
43
- ctx.lineTo(slider.centerX - 0.05 * slider.radius, slider.centerY - 0.25 * slider.radius);
44
- }
45
- return ctx.createLinearGradient(slider.centerX - 0.05 * slider.radius, slider.centerY + 0.8 * slider.radius, slider.centerX - 0.05 * slider.radius, slider.centerY - 0.8 * slider.radius);
46
- }