circular-sliders-rails 1.1.0 → 1.5.0

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 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
- }