├── demo
├── p.gif
├── s.gif
├── arch.png
├── pathbuilder.png
├── pathslider.png
├── colorpicker
│ ├── blank.gif
│ ├── slider.png
│ ├── select2.png
│ ├── custom_hex.png
│ ├── custom_hsb_b.png
│ ├── custom_hsb_h.png
│ ├── custom_hsb_s.png
│ ├── custom_indic.gif
│ ├── custom_rgb_b.png
│ ├── custom_rgb_g.png
│ ├── custom_rgb_r.png
│ ├── custom_submit.png
│ ├── colorpicker_overlay.png
│ ├── colorpicker_select.gif
│ ├── custom_background.png
│ ├── colorpicker.css
│ └── colorpicker.js
├── wiki
│ ├── coordinate-system.png
│ └── pathslider-points.png
├── demo.css
└── demo.js
├── images
├── chrome1.png
└── chrome2.png
├── .gitattributes
├── LICENSE
├── package.json
├── Gruntfile.js
├── .gitignore
├── index.html
├── README.md
├── dist
├── pathslider.min.css
├── jquery.pathslider.min.js
├── pathslider.css
└── jquery.pathslider.js
├── css
└── pathslider.css
└── js
├── jquery.pathslider.builder.js
└── jquery.pathslider.js
/demo/p.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mottie/Pathslider/HEAD/demo/p.gif
--------------------------------------------------------------------------------
/demo/s.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mottie/Pathslider/HEAD/demo/s.gif
--------------------------------------------------------------------------------
/demo/arch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mottie/Pathslider/HEAD/demo/arch.png
--------------------------------------------------------------------------------
/demo/pathbuilder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mottie/Pathslider/HEAD/demo/pathbuilder.png
--------------------------------------------------------------------------------
/demo/pathslider.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mottie/Pathslider/HEAD/demo/pathslider.png
--------------------------------------------------------------------------------
/images/chrome1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mottie/Pathslider/HEAD/images/chrome1.png
--------------------------------------------------------------------------------
/images/chrome2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mottie/Pathslider/HEAD/images/chrome2.png
--------------------------------------------------------------------------------
/demo/colorpicker/blank.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mottie/Pathslider/HEAD/demo/colorpicker/blank.gif
--------------------------------------------------------------------------------
/demo/colorpicker/slider.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mottie/Pathslider/HEAD/demo/colorpicker/slider.png
--------------------------------------------------------------------------------
/demo/colorpicker/select2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mottie/Pathslider/HEAD/demo/colorpicker/select2.png
--------------------------------------------------------------------------------
/demo/colorpicker/custom_hex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mottie/Pathslider/HEAD/demo/colorpicker/custom_hex.png
--------------------------------------------------------------------------------
/demo/wiki/coordinate-system.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mottie/Pathslider/HEAD/demo/wiki/coordinate-system.png
--------------------------------------------------------------------------------
/demo/wiki/pathslider-points.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mottie/Pathslider/HEAD/demo/wiki/pathslider-points.png
--------------------------------------------------------------------------------
/demo/colorpicker/custom_hsb_b.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mottie/Pathslider/HEAD/demo/colorpicker/custom_hsb_b.png
--------------------------------------------------------------------------------
/demo/colorpicker/custom_hsb_h.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mottie/Pathslider/HEAD/demo/colorpicker/custom_hsb_h.png
--------------------------------------------------------------------------------
/demo/colorpicker/custom_hsb_s.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mottie/Pathslider/HEAD/demo/colorpicker/custom_hsb_s.png
--------------------------------------------------------------------------------
/demo/colorpicker/custom_indic.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mottie/Pathslider/HEAD/demo/colorpicker/custom_indic.gif
--------------------------------------------------------------------------------
/demo/colorpicker/custom_rgb_b.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mottie/Pathslider/HEAD/demo/colorpicker/custom_rgb_b.png
--------------------------------------------------------------------------------
/demo/colorpicker/custom_rgb_g.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mottie/Pathslider/HEAD/demo/colorpicker/custom_rgb_g.png
--------------------------------------------------------------------------------
/demo/colorpicker/custom_rgb_r.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mottie/Pathslider/HEAD/demo/colorpicker/custom_rgb_r.png
--------------------------------------------------------------------------------
/demo/colorpicker/custom_submit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mottie/Pathslider/HEAD/demo/colorpicker/custom_submit.png
--------------------------------------------------------------------------------
/demo/colorpicker/colorpicker_overlay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mottie/Pathslider/HEAD/demo/colorpicker/colorpicker_overlay.png
--------------------------------------------------------------------------------
/demo/colorpicker/colorpicker_select.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mottie/Pathslider/HEAD/demo/colorpicker/colorpicker_select.gif
--------------------------------------------------------------------------------
/demo/colorpicker/custom_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mottie/Pathslider/HEAD/demo/colorpicker/custom_background.png
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 | *.sln merge=union
7 | *.csproj merge=union
8 | *.vbproj merge=union
9 | *.fsproj merge=union
10 | *.dbproj merge=union
11 |
12 | # Standard to msysgit
13 | *.doc diff=astextplain
14 | *.DOC diff=astextplain
15 | *.docx diff=astextplain
16 | *.DOCX diff=astextplain
17 | *.dot diff=astextplain
18 | *.DOT diff=astextplain
19 | *.pdf diff=astextplain
20 | *.PDF diff=astextplain
21 | *.rtf diff=astextplain
22 | *.RTF diff=astextplain
23 | *.md diss=astextplain
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2016 Rob Garrison
2 |
3 | MIT License
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to use,
8 | copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
9 | Software, and to permit persons to whom the Software is furnished to do so,
10 | 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, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pathslider",
3 | "title": "Pathslider",
4 | "description": "A jQuery numerical slider that follows a bezier path",
5 | "version": "1.0.0-beta",
6 | "author": {
7 | "name": "Rob Garrison",
8 | "url": "https://github.com/Mottie",
9 | "email": "wowmotty@gmail.com"
10 | },
11 | "license": "MIT",
12 | "dependencies": {
13 | "jquery": ">=1.4.4"
14 | },
15 | "keywords": [
16 | "slider",
17 | "number",
18 | "bezier",
19 | "path",
20 | "jquery-plugin"
21 | ],
22 | "homepage": "https://github.com/Mottie/Pathslider",
23 | "demo": "http://mottie.github.io/Pathslider/",
24 | "docs": "https://github.com/Mottie/Pathslider/wiki",
25 | "bugs": "https://github.com/Mottie/Pathslider/issues",
26 | "main": "dist/jquery.pathslider.js",
27 | "files": [
28 | "dist/*"
29 | ],
30 | "repository": {
31 | "type": "git",
32 | "url": "git://github.com/Mottie/pathslider.git"
33 | },
34 | "devDependencies": {
35 | "grunt": "^1.0.1",
36 | "grunt-cli": "^1.1.0",
37 | "grunt-contrib-clean": "^1.0.0",
38 | "grunt-contrib-copy": "^1.0.0",
39 | "grunt-contrib-cssmin": "^1.0.1",
40 | "grunt-contrib-jshint": "^1.0.0",
41 | "grunt-contrib-uglify": "^2.0.0"
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | /*global module:false */
2 | module.exports = function(grunt) {
3 | 'use strict';
4 |
5 | // Project configuration.
6 | grunt.initConfig({
7 | pkg: grunt.file.readJSON('package.json'),
8 |
9 | clean: {
10 | dist: {
11 | src: ['dist/*', 'dist/**/*']
12 | }
13 | },
14 |
15 | copy: {
16 | dist: {
17 | files : [{
18 | expand: true,
19 | dot: true,
20 | flatten: true,
21 | src: [ 'css/pathslider.css', 'js/jquery.pathslider.js' ],
22 | dest: 'dist/'
23 | }]
24 | }
25 | },
26 |
27 | jshint: {
28 | core: {
29 | options: {
30 | "jquery": true,
31 | "browser": true
32 | },
33 | src: [ 'js/jquery.*.js' ]
34 | }
35 | },
36 |
37 | cssmin: {
38 | target: {
39 | files: [{
40 | expand: true,
41 | flatten: true,
42 | src: ['css/*.css'],
43 | dest: 'dist/',
44 | ext: '.min.css'
45 | }]
46 | }
47 | },
48 |
49 | uglify: {
50 | options: {
51 | preserveComments: function( node, comment ) {
52 | return /^!/.test( comment.value );
53 | },
54 | report: 'gzip'
55 | },
56 | dist: {
57 | files: [{
58 | expand: true,
59 | cwd: '',
60 | src: [ 'js/jquery*.js', '!js/*builder.js' ],
61 | dest: 'dist/',
62 | ext: '.min.js',
63 | extDot: 'last',
64 | flatten: true
65 | }]
66 | }
67 | },
68 |
69 | watch: {
70 | scripts: {
71 | files: ['js/*.js'],
72 | tasks: ['build']
73 | }
74 | }
75 |
76 | });
77 |
78 | grunt.loadNpmTasks('grunt-contrib-clean');
79 | grunt.loadNpmTasks('grunt-contrib-copy');
80 | grunt.loadNpmTasks('grunt-contrib-cssmin');
81 | grunt.loadNpmTasks('grunt-contrib-jshint');
82 | grunt.loadNpmTasks('grunt-contrib-uglify');
83 |
84 | // Default task.
85 | grunt.registerTask('default', [
86 | 'clean',
87 | 'jshint',
88 | 'copy',
89 | 'cssmin',
90 | 'uglify'
91 | ]);
92 |
93 | };
94 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | #################
2 | ## Eclipse
3 | #################
4 |
5 | *.pydevproject
6 | .project
7 | .metadata
8 | bin/
9 | tmp/
10 | *_test*.*
11 | *_idea*.*
12 | *.tmp
13 | *.bak
14 | *.swp
15 | *~.nib
16 | local.properties
17 | .classpath
18 | .settings/
19 | .loadpath
20 |
21 | # External tool builders
22 | .externalToolBuilders/
23 |
24 | # Locally stored "Eclipse launch configurations"
25 | *.launch
26 |
27 | # CDT-specific
28 | .cproject
29 |
30 | # PDT-specific
31 | .buildpath
32 |
33 |
34 | #################
35 | ## Visual Studio
36 | #################
37 |
38 | ## Ignore Visual Studio temporary files, build results, and
39 | ## files generated by popular Visual Studio add-ons.
40 |
41 | # User-specific files
42 | *.suo
43 | *.user
44 | *.sln.docstates
45 |
46 | # Build results
47 | [Dd]ebug/
48 | [Rr]elease/
49 | node_modules/
50 | *_i.c
51 | *_p.c
52 | *.ilk
53 | *.log
54 | *.meta
55 | *.obj
56 | *.pch
57 | *.pdb
58 | *.pgc
59 | *.pgd
60 | *.rsp
61 | *.sbr
62 | *.tlb
63 | *.tli
64 | *.tlh
65 | *.tmp
66 | *.vspscc
67 | .builds
68 | *.dotCover
69 |
70 | ## TODO: If you have NuGet Package Restore enabled, uncomment this
71 | #packages/
72 |
73 | # Visual C++ cache files
74 | ipch/
75 | *.aps
76 | *.ncb
77 | *.opensdf
78 | *.sdf
79 |
80 | # Visual Studio profiler
81 | *.psess
82 | *.vsp
83 |
84 | # ReSharper is a .NET coding add-in
85 | _ReSharper*
86 |
87 | # Installshield output folder
88 | [Ee]xpress
89 |
90 | # DocProject is a documentation generator add-in
91 | DocProject/buildhelp/
92 | DocProject/Help/*.HxT
93 | DocProject/Help/*.HxC
94 | DocProject/Help/*.hhc
95 | DocProject/Help/*.hhk
96 | DocProject/Help/*.hhp
97 | DocProject/Help/Html2
98 | DocProject/Help/html
99 |
100 | # Click-Once directory
101 | publish
102 |
103 | # Others
104 | [Bb]in
105 | [Oo]bj
106 | sql
107 | TestResults
108 | *.Cache
109 | ClientBin
110 | stylecop.*
111 | ~$*
112 | *.dbmdl
113 | Generated_Code #added for RIA/Silverlight projects
114 |
115 | # Backup & report files from converting an old project file to a newer
116 | # Visual Studio version. Backup files are not needed, because we have git ;-)
117 | _UpgradeReport_Files/
118 | Backup*/
119 | UpgradeLog*.XML
120 |
121 |
122 |
123 | ############
124 | ## Windows
125 | ############
126 |
127 | # Windows image file caches
128 | Thumbs.db
129 |
130 | # Folder config file
131 | Desktop.ini
132 |
133 |
134 | #############
135 | ## Python
136 | #############
137 |
138 | *.py[co]
139 |
140 | # Packages
141 | *.egg
142 | *.egg-info
143 | build
144 | eggs
145 | parts
146 | bin
147 | var
148 | sdist
149 | develop-eggs
150 | .installed.cfg
151 |
152 | # Installer logs
153 | pip-log.txt
154 |
155 | # Unit test / coverage reports
156 | .coverage
157 | .tox
158 |
159 | #Translations
160 | *.mo
161 |
162 | #Mr Developer
163 | .mr.developer.cfg
164 |
165 | # Mac crap
166 | .DS_Store
167 |
--------------------------------------------------------------------------------
/demo/colorpicker/colorpicker.css:
--------------------------------------------------------------------------------
1 | .colorpicker {
2 | width: 356px;
3 | height: 176px;
4 | overflow: hidden;
5 | position: absolute;
6 | background: url(custom_background.png);
7 | font-family: Arial, Helvetica, sans-serif;
8 | display: none;
9 | }
10 | .colorpicker_color {
11 | width: 150px;
12 | height: 150px;
13 | left: 14px;
14 | top: 13px;
15 | position: absolute;
16 | background: #f00;
17 | overflow: hidden;
18 | cursor: crosshair;
19 | }
20 | .colorpicker_color div {
21 | position: absolute;
22 | top: 0;
23 | left: 0;
24 | width: 150px;
25 | height: 150px;
26 | background: url(colorpicker_overlay.png);
27 | }
28 | .colorpicker_color div div {
29 | position: absolute;
30 | top: 0;
31 | left: 0;
32 | width: 11px;
33 | height: 11px;
34 | overflow: hidden;
35 | background: url(colorpicker_select.gif);
36 | margin: -5px 0 0 -5px;
37 | }
38 | .colorpicker_hue {
39 | position: absolute;
40 | top: 13px;
41 | left: 171px;
42 | width: 35px;
43 | height: 150px;
44 | cursor: n-resize;
45 | }
46 | .colorpicker_hue div {
47 | position: absolute;
48 | width: 35px;
49 | height: 9px;
50 | overflow: hidden;
51 | background: url(custom_indic.gif) left top;
52 | margin: -4px 0 0 0;
53 | left: 0px;
54 | }
55 | .colorpicker_new_color {
56 | position: absolute;
57 | width: 60px;
58 | height: 30px;
59 | left: 213px;
60 | top: 13px;
61 | background: #f00;
62 | }
63 | .colorpicker_current_color {
64 | position: absolute;
65 | width: 60px;
66 | height: 30px;
67 | left: 283px;
68 | top: 13px;
69 | background: #f00;
70 | }
71 | .colorpicker input {
72 | background-color: transparent;
73 | border: 1px solid transparent;
74 | position: absolute;
75 | font-size: 10px;
76 | font-family: Arial, Helvetica, sans-serif;
77 | color: #898989;
78 | top: 4px;
79 | right: 11px;
80 | text-align: right;
81 | margin: 0;
82 | padding: 0;
83 | height: 11px;
84 | }
85 | .colorpicker_hex {
86 | position: absolute;
87 | width: 72px;
88 | height: 22px;
89 | background: url(custom_hex.png) top;
90 | left: 212px;
91 | top: 142px;
92 | }
93 | .colorpicker_hex input {
94 | right: 6px;
95 | }
96 | .colorpicker_field {
97 | height: 22px;
98 | width: 62px;
99 | background-position: top;
100 | position: absolute;
101 | }
102 | .colorpicker_field span {
103 | position: absolute;
104 | width: 12px;
105 | height: 22px;
106 | overflow: hidden;
107 | top: 0;
108 | right: 0;
109 | cursor: n-resize;
110 | }
111 | .colorpicker_rgb_r {
112 | background-image: url(custom_rgb_r.png);
113 | top: 52px;
114 | left: 212px;
115 | }
116 | .colorpicker_rgb_g {
117 | background-image: url(custom_rgb_g.png);
118 | top: 82px;
119 | left: 212px;
120 | }
121 | .colorpicker_rgb_b {
122 | background-image: url(custom_rgb_b.png);
123 | top: 112px;
124 | left: 212px;
125 | }
126 | .colorpicker_hsb_h {
127 | background-image: url(custom_hsb_h.png);
128 | top: 52px;
129 | left: 282px;
130 | }
131 | .colorpicker_hsb_s {
132 | background-image: url(custom_hsb_s.png);
133 | top: 82px;
134 | left: 282px;
135 | }
136 | .colorpicker_hsb_b {
137 | background-image: url(custom_hsb_b.png);
138 | top: 112px;
139 | left: 282px;
140 | }
141 | .colorpicker_submit {
142 | position: absolute;
143 | width: 22px;
144 | height: 22px;
145 | background: url(custom_submit.png) top;
146 | left: 322px;
147 | top: 142px;
148 | overflow: hidden;
149 | }
150 | .colorpicker_focus {
151 | background-position: center;
152 | }
153 | .colorpicker_hex.colorpicker_focus {
154 | background-position: bottom;
155 | }
156 | .colorpicker_submit.colorpicker_focus {
157 | background-position: bottom;
158 | }
159 | .colorpicker_slider {
160 | background-position: bottom;
161 | }
162 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | jQuery Pathslider
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
41 |
95 |
96 |
97 |
98 |
99 |
100 |
105 |
106 |
107 |
108 |
109 |
Basic Curve
110 |
111 |
112 |
113 |
114 |
"P" Curve
115 |
116 |
117 |
118 |
119 |
"S" Curve
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
141 |
142 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | A jQuery numerical slider that follows a bezier path.
2 |
3 | [![devDependency Status][david-dev-image]][david-dev-url] [![MIT][license-image]][license-url]
4 |
5 | ## Features
6 |
7 | * Numerical slider similar to the [jQuery UI Slider](http://jqueryui.com/demos/slider/) - currently it only works with percentages (0-100%)
8 | * This slider follows a bezier path. The parameters are set using the pathslider builder.
9 | * Designed to work in older browsers (no canvas support), just add the path as a background image.
10 | * Get and set the slider position dynamically.
11 | * Slider handle (grip) can be set to rotate along with the angle of the curve (uses css3).
12 | * Callback events are available: create, update, start, slide, change, and stop.
13 | * The slider itself works in all browsers: IE6+, Opera, Chrome, Firefox and Safari (known issues below)
14 | * [Pathslider demo](http://mottie.github.com/Pathslider/index.html).
15 | * [Pathslider Builder](http://mottie.github.com/Pathslider/builder.html).
16 |
17 | ## Documentation
18 |
19 | Wiki:
20 | [Home](https://github.com/Mottie/Pathslider/wiki/Home) |
21 | [FAQ](https://github.com/Mottie/Pathslider/wiki/FAQ) |
22 | [Setup](https://github.com/Mottie/Pathslider/wiki/Setup) |
23 | [Options](https://github.com/Mottie/Pathslider/wiki/Options) |
24 | [Events](https://github.com/Mottie/Pathslider/wiki/Events) |
25 | [Theme](https://github.com/Mottie/Pathslider/wiki/Theme) |
26 | [Change](https://github.com/Mottie/Pathslider/wiki/Change)
27 |
28 | ## To Do:
29 |
30 | * Add min, max and step options to use values, other than zero to one hundred percent, with the slider.
31 | * Add enable, disable, destroy methods.
32 | * Smooth out sliding by improving grip position calculation
33 | * The grip jumps around quite a bit with some settings
34 | * This can be minimized by adjusting the tolerance & range settings, but it needs a better method.
35 | * Add more default handle (grip) styles in the css.
36 | * Add ability to make a gradient/patterned stroke style of the curve; I'm not sure it will follow the path of the curve or just be a static background. Needs more testing!
37 | * Add keyboard control to the slider when it has focus - arrows, page up/down, home and end.
38 | * Add a circular path
39 | * I don't plan on making it go continuously around in a circle. It will have a starting and stopping point.
40 | * If you need a continuous circle slider, check out [this one](http://www.eleqtriq.com/2009/12/javascriptdialcontrol/), and [this one](http://www.baijs.nl/tinycircleslider/).
41 | * Combine multiple beziers to make extended shapes - my math skills are a bit lacking so this may take a while, unless someone out there is willing to help ;)
42 | * Consider switching from using canvas to svg.
43 |
44 | ## Dependencies
45 |
46 | * jQuery 1.4.4+
47 | * A browser that supports canvas (needed for the builder; optional for the pathslider plugin itself).
48 | * A browser that supports css3 transforms (necessary to rotate the grip).
49 |
50 | ## Known Bugs
51 |
52 | * The grip/handle will work if the loop folds back on itself - try these points to see an example: 75,200,200,-125,-200,0,225,200
53 | * The S-Curve demo seems to get stuck near 100% but only in Firefox and on the demo page. It works fine when isolated. The grip isn't staying centered under the cursor like it does in Chrome.
54 | * Safari for Windows likes to start with the grip in the upper left corner of the slider box... most of the time when I hover over it, it jumps to where it should be... wow that is so weird. Also, the "S" curve demo doesn't want to work at all...
55 |
56 | [david-dev-url]: https://david-dm.org/Mottie/pathslider?type=dev
57 | [david-dev-image]: https://img.shields.io/david/dev/Mottie/pathslider.svg
58 | [license-url]: https://github.com/Mottie/Pathslider/blob/master/LICENSE
59 | [license-image]: https://img.shields.io/badge/license-MIT-blue.svg
60 |
61 | ## Change Log
62 |
63 | ### Version 1.0.0-alpha (8/19/2016) (mis-released as beta)
64 |
65 | * Core:
66 | * Use window load event for jQuery v3.0+ compatibility.
67 | * Add `drawCanvas` callback & update curve color options. Fixes [issue #8](https://github.com/Mottie/Pathslider/issues/8).
68 | * Add `finishCurve` function. For use inside of the `drawCanvas` callback.
69 | * Add `redraw` method. See [issue #8](https://github.com/Mottie/Pathslider/issues/8).
70 | * Clean up CSS & use image URI.
71 | * Builder:
72 | * Switch to using `drawCanvas` callback.
73 | * Use `finishCurve` function.
74 | * Add curve shift controls.
75 | * Docs & Readme:
76 | * Update libraries & colors.
77 | * Make MIT license more prominent.
78 | * Optimize png images.
79 | * Extras:
80 | * Add `.git` files.
81 | * Remove BOM from all files.
82 | * Add grunt build script & dist folder.
83 |
84 | ### Version 0.9.1 alpha (12/7/2011)
85 |
86 | * Added touch device compatibility.
87 | * Changed the grip "data-degree" attribute to "data-angle". This attribute contains the angle of transformation to rotate the grip.
88 | * Changed the grip "data-position" attribute to "data-percent". This attribute contains the current percentage distance along the curve of the grip.
89 | * Added some images for the wiki documentation.
90 |
91 | ### Version 0.9 alpha (12/5/2011)
92 |
93 | * Initial commit
94 |
--------------------------------------------------------------------------------
/dist/pathslider.min.css:
--------------------------------------------------------------------------------
1 | #slider{width:200px;height:200px}.pathslider-grip{width:30px;height:15px;position:absolute;top:0;left:0;background:#ddd;font-size:1px;z-index:10;cursor:move;border:1px solid;border-radius:7px;-webkit-box-shadow:0 1px 3px rgba(000,000,000,.5),inset 0 0 1px rgba(255,255,255,.6);box-shadow:0 1px 3px rgba(000,000,000,.5),inset 0 0 1px rgba(255,255,255,.6)}.pathslider-grip.sliding,.pathslider-grip:hover{border-color:#8ce;-webkit-box-shadow:0 0 15px #8ce;box-shadow:0 0 15px #8ce}.pathslider{position:relative}.silver{border-color:#949494;background-color:#ebebeb;background-image:-webkit-linear-gradient(top,#fff 0,#ebebeb 50%,#dbdbdb 50%,#b5b5b5);background-image:linear-gradient(top,#fff 0,#ebebeb 50%,#dbdbdb 50%,#b5b5b5)}.black{border-color:#000
2 | background-color: #3b3b3b;background-image:-webkit-linear-gradient(top,#a3a3a3 0,#3b3b3b 50%,#242424 50%,#000);background-image:linear-gradient(top,#a3a3a3 0,#3b3b3b 50%,#242424 50%,#000)}.pathslider-grip.chrome1{width:18px;height:18px;border:0;border-radius:0;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAABI1BMVEUAAADHx8fNzc/29vbCwsOVlpfFxsbb29vp6enm5eX19vb6+vr///+vr6/Dw8K4uLjGxsbQ0NDR0dHh4eHl5uaqq6qlpaWoqqy+vr+9vb3e4OGTk5TIyMiSkpO9vb2kpabDw8SampzDw8O9vb62tratra7Ly8vW1tbk5OTKysrv8fLt7e3c3Nzi4uLd3d309PTv7+/o6Ojm5ufy8vPu7+/r6+zX2NnT09XS0tTk5Obh4eHP0NLKy83DxMX5+fr19fXz8/Xl5ube3+Dd3d/c3N7Z2tvW19jU1de+vr/3+Pjp6ura29zNztG7vL65uruztLWvsLGtra329vbw8PDh4uPLzc/HyMqysrLs7e3o6Orj4+PV1dfQ0dO4uLmoqKn7+/ujo6WIZbNwAAAAMXRSTlMA/v4F/v79kzcuFgkC9vHmsI9+ZRL99fHw7+7u7Ovj4+Hg19bNzMCooJ+Yi4p5SSYjiIrjEAAAASVJREFUGNMVz0OCxAAUANGfpG2MbSu27aTtmfufYtK1fLuCJgBg72g831bO3hoYQAuKvl+PPGkznWXHL/Um7KvfxVIUoZw9cZGLj0YhX93YZTkx4kJ9rArIZwvqDykTMi4nshZOKr9cZwiDtkQIhs2KrED5ikIlPehuDZzgDUdc4yNfG5NoBzKPx+mAsDhT9SlC4BkEcs80CHzJO0QgMBtxbVcgT6coy7qMaVqcNJuJjgz5LollRHJ0fcVPQsZyEEj/0kSObBxXF2ONpEi2BDe7uTy1ljRBajRN+mqpBNUsl0KexnVKIYOFap9UofZ0mBhBQfRI0ShBrhaTtV7bc80VQY20CVN5/oEibHBaLmceIs/LV8ODApotwGr9x9vL8+v7/h7gH5fyPZ6I/Z3zAAAAAElFTkSuQmCC) center center no-repeat;-webkit-box-shadow:0 0 0;box-shadow:0 0 0}.pathslider-grip.chrome2{width:57px;height:35px;border:0;border-radius:0;background:url(data:image/png;base64,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) center center no-repeat;-webkit-box-shadow:0 0 0;box-shadow:0 0 0}
--------------------------------------------------------------------------------
/dist/jquery.pathslider.min.js:
--------------------------------------------------------------------------------
1 | !function(a){a.pathslider=function(b,c){var d,e=this;e.$el=a(b).addClass("pathslider"),e.el=b,e.$el.data("pathslider",e),e.init=function(){var b;e.options=d=a.extend(!0,{},a.pathslider.defaults,c),b=document.createElement("canvas"),e.hasCanvas=!(!b.getContext||!b.getContext("2d")),e.hasTouch=document.hasOwnProperty("ontouchend"),e.$grip=a("").appendTo(e.$el),e.points=[],e.pointsxy=[],e.arrayX=[],e.arrayY=[],e.arrayP=[],e.rad2deg=180/Math.PI,e.sliding=!1,e.lastPercent=e.percent=d.value,a.each("create update start slide change stop".split(" "),function(b,c){a.isFunction(d[c])&&e.$el.bind(c+".pathslider",d[c])}),a(document).bind(e.hasTouch?"touchend.pathslider touchcancel.pathslider":"mouseup.pathslider mouseleave.pathslider",function(a){e.sliding&&(e.$el.trigger("stop.pathslider",[e]),e.lastPercent!==e.percent&&(e.lastPercent=e.percent,e.$el.trigger("change.pathslider",[e]))),e.$grip.removeClass("sliding"),e.sliding=!1}).bind((e.hasTouch?"touchmove":"mousemove")+".pathslider",function(a){e.sliding&&e.setSlider(e.findPos(a),null,!0)}),a(window).bind("resize.pathslider",function(){e.update()}).bind("load",function(){e.sliderDim[0]=e.$el.offset().left,e.sliderDim[1]=e.$el.offset().top}),e.$grip.bind((e.hasTouch?"touchstart":"mousedown")+".pathslider",function(b){return e.sliding=!0,a(this).addClass("sliding"),e.$el.trigger("start.pathslider",[e]),!1}).bind("click",function(){return!1}),e.redraw(),e.$el.trigger("create.pathslider",[e])},e.update=function(){e.$grip.attr("class","pathslider-grip "+d.gripClass),e.ctx&&e.ctx.clearRect(0,0,e.sliderDim[2],e.sliderDim[3]),e.sliderDim=[e.$el.offset().left,e.$el.offset().top,e.$el.width(),e.$el.height()];var b=window.getComputedStyle(e.$grip[0]);e.gripCenter=[parseInt(b.width,10)/2,parseInt(b.height,10)/2],e.dataPoints=d.dataPoints,e.makeArray();var c=a.inArray(e.percent,e.arrayP);e.position=c===-1?Math.round(e.percent/100*e.dataPoints):c,e.setSlider(e.percent,null,!0),e.hasCanvas&&d.useCanvas&&e.drawCurve()},e.setSlider=function(a,b,c){if(!isNaN(a)){a=parseFloat(a,10),a=a>100?100:a<0?0:a;var f,g,h=e.calcBezier(a/100,e.pointsxy),i=a-2>0?e.calcBezier((a-2)/100,e.pointsxy):h,j=a+2<100?e.calcBezier((a+2)/100,e.pointsxy):h,k=j[0]-i[0]===0?90:(j[1]-i[1])/(j[0]-i[0]);e.angle=parseInt(Math.atan(k)*e.rad2deg,10),g="rotate("+e.angle+"deg)",f=d.rotateGrip?{"-webkit-transform":g,transform:g}:{},f.left=h[0]-e.gripCenter[0],f.top=h[1]-e.gripCenter[1],e.$grip.attr({"data-angle":e.angle,"data-percent":a}).css(f),e.percent=a,(a===e.lastPercent||e.sliding)&&c||e.$el.trigger("change.pathslider",[e])}"function"==typeof b&&b(e)},e.mousePos=function(a){return[(a.originalEvent.touches?a.originalEvent.touches[0].pageX:a.pageX)-e.sliderDim[0],(a.originalEvent.touches?a.originalEvent.touches[0].pageY:a.pageY)-e.sliderDim[1]]},e.findPos=function(a){var b,c,f,g,h=[],i=[],j=e.position,k=parseInt(d.tolerance+1,10)||2,l=parseInt(d.range,10)||e.gripCenter[0],m=e.mousePos(a);for(b=0;b1)return e.returnPos(h[0]);if(1===i.length&&h.length>1)return e.returnPos(i[0])}return e.returnPos(j)},e.returnPos=function(a){var b=e.position===a;return e.percent=e.arrayP[a],e.position=a,b||(e.hasCanvas&&d.useCanvas&&e.drawCurve(),e.$el.trigger("slide.pathslider",[e])),e.percent},e.makeArray=function(){var a,b,c=e.pointsxy,d=e.dataPoints;for(a=0;a').appendTo(e.$el),e.$canvas=e.$el.find("canvas").attr({width:e.sliderDim[2],height:e.sliderDim[3]}),e.canvas=e.$canvas[0],e.ctx=e.canvas.getContext("2d")),b=e.ctx,b.clearRect(0,0,e.sliderDim[2],e.sliderDim[3]),b.lineCap=d.curve.cap,b.lineJoin=d.curve.cap,b.lineWidth=d.curve.width,a.isArray(d.curve.color)?(c=b.createLinearGradient(g[0],g[1],g[6],g[7]),f=e.percent/100,c.addColorStop(0,d.curve.color[0]),c.addColorStop(f,d.curve.color[0]),f+.01<=1&&(f+=.01),c.addColorStop(f,d.curve.color[1]),c.addColorStop(1,d.curve.color[1]),b.strokeStyle=c):b.strokeStyle=d.curve.color,f=!0,"function"==typeof d.drawCanvas&&(f=d.drawCanvas(e,b,g)!==!1,b=e.ctx),f===!0&&e.finishCurve(b,g)},e.finishCurve=function(a,b){a=a||e.ctx,b=b||e.pointsxy,a.beginPath(),a.moveTo(b[0],b[1]),a.bezierCurveTo(b[2],b[3],b[4],b[5],b[6],b[7]),a.stroke()},e.init()},a.pathslider.defaults={gripClass:"",rotateGrip:!0,useCanvas:!0,curve:{width:4,color:"#333",cap:"round"},points:[0,50,50,-50,-50,-50,250,50],value:50,dataPoints:100,tolerance:3,range:30},a.fn.pathslider=function(b,c){return this.each(function(){var d,e=a(this).data("pathslider");if((typeof b).match("object|undefined")){if(e)return e.redraw();new a.pathslider(this,b)}else/\d/.test(b)&&!isNaN(b)&&e&&(d="number"==typeof b?b:parseInt(a.trim(b),10),d>=0&&d<=100&&e.setSlider(d,c))})},a.fn.getpathslider=function(){return this.data("pathslider")}}(jQuery);
--------------------------------------------------------------------------------
/demo/demo.css:
--------------------------------------------------------------------------------
1 | html,body { margin: 0; height: 100%; }
2 |
3 | body { background: #ddd; color: #333; }
4 | a:link { color: #ddd; text-decoration: none; }
5 | a:hover { color: #fff; }
6 | a:visited, a:active { color: #ccc; }
7 |
8 | h1.hide { display: none; }
9 | .oldie h1.hide { display: block; margin: 50px; color: #000; }
10 | h1.hide, .oldie .builder .wrapper, .oldie .builder .footer { display: none; }
11 |
12 | header, .header {
13 | min-height: 100px;
14 | background: #789;
15 | background: -moz-radial-gradient(center top, ellipse farthest-corner, #789, #677 40%);
16 | background: -webkit-radial-gradient(center top, ellipse farthest-corner, #789, #677 40%);
17 | background: -o-radial-gradient(center top, ellipse farthest-corner, #789, #677 40%);
18 | background: -ms-radial-gradient(center top, ellipse farthest-corner, #789, #677 40%);
19 | box-shadow: inset 0 0 10px #567;
20 | }
21 |
22 | h1 {
23 | color: #ddd;
24 | margin: 0;
25 | text-align: center;
26 | font-size: 3.5em;
27 | font-family: 'Paytone One', sans-serif;
28 | text-shadow: #555 1px 1px, #555 2px 2px;
29 | }
30 |
31 | header a, .header a {
32 | position: absolute;
33 | top: 25px;
34 | width: 50px;
35 | height: 50px;
36 | display: block;
37 | text-indent: -999em;
38 | }
39 | header a.current, .header a.current {
40 | -webkit-box-shadow: inset 0 0 20px #59b;
41 | -moz-box-shadow: inset 0 0 20px #59b;
42 | box-shadow: inset 0 0 20px #59b;
43 | border-radius: 15px;
44 | -moz-border-radius: 15px;
45 | -webkit-border-radius: 15px;
46 | }
47 |
48 | a.home {
49 | left: 20px;
50 | background: url(../demo/pathslider.png) center center no-repeat;
51 | }
52 | a.builder {
53 | left: 75px;
54 | background: url(../demo/pathbuilder.png) center center no-repeat;
55 | }
56 |
57 | .wrapper {
58 | min-height: 100%;
59 | height: auto !important;
60 | height: 100%;
61 | margin: 0 auto -100px; /* the bottom margin is the negative value of the footer's height */
62 | }
63 |
64 | .content {
65 | width: 50%;
66 | margin: 10px auto;
67 | }
68 |
69 | .builder .content {
70 | width: 80%;
71 |
72 | }
73 |
74 | #slider {
75 | margin: 0 auto;
76 | background: #eee;
77 | width: 300px;
78 | height: 300px;
79 | }
80 |
81 | .builder canvas.pathslider-canvas {
82 | border: #555 1px solid;
83 | }
84 |
85 | /* index.html */
86 | .demo {
87 | color: #777;
88 | margin: 0;
89 | padding: 20px;
90 | font-size: 2.5em;
91 | font-family: 'Paytone One', sans-serif;
92 | white-space: nowrap;
93 | text-align: center;
94 | text-shadow: #555 1px 1px, #555 2px 2px;
95 | clear: both;
96 | }
97 |
98 | .demo .slider {
99 | margin: 0 auto;
100 | }
101 |
102 | /* builder.html */
103 | #tabs, footer, div.footer {
104 | background: #677;
105 | margin-top: 10px;
106 | min-width: 565px; /*** make this dynamic in the next version ***/
107 | }
108 |
109 | #tabs .tab {
110 | color: #eee;
111 | }
112 |
113 | p {
114 | line-height: 2em;
115 | }
116 |
117 | blockquote {
118 | margin: 5px 40px;
119 | }
120 |
121 | h4, .message {
122 | margin: 5px;
123 | }
124 |
125 | h4, strong {
126 | color: #fff;
127 | }
128 |
129 | .message {
130 | min-height: 50px;
131 | }
132 |
133 | img#save {
134 | border: #ff0 1px solid;
135 | width: 15px;
136 | height: 15px;
137 | }
138 |
139 | .moving {
140 | cursor: move;
141 | }
142 |
143 | .corner {
144 | background: url(data:image/gif;base64,R0lGODlhCgAKAJEAAOvr64CAgP///wAAACH5BAEAAAIALAAAAAAKAAoAAAIWlG+BK8CqWJsHioicTrfjuQHWaIRgAQA7) no-repeat;
145 | width: 10px;
146 | height: 10px;
147 | position: absolute;
148 | bottom: 0;
149 | right: 0;
150 | cursor: nw-resize;
151 | }
152 |
153 | .events {
154 | width: 30%;
155 | position: relative;
156 | margin-bottom: 10px;
157 | float: right;
158 | }
159 | .move-controls {
160 | display: inline-block;
161 | height: 70px;
162 | margin-left: 40px;
163 | }
164 | .move-controls input {
165 | width: 40px;
166 | }
167 |
168 | textarea.code {
169 | background: #ddd;
170 | font-family: 'courier';
171 | width: 100%;
172 | }
173 |
174 | /* builder inputs */
175 | .points { width: 20em; }
176 | .position, .angle, .tolerance.text, .range.text, .thickness.text, .grid.text { width: 35px; }
177 | .gripColor, .curveColor { width: 100px; }
178 | .bkgd { width: 90%; }
179 |
180 | /* readme colors */
181 | .sxy { color: hsl(120,60%,85%); }
182 | .scxy { color: hsl(120,80%,75%); }
183 | .ecxy { color: hsl(0,40%,85%); }
184 | .exy { color: hsl(0,55%,75%); }
185 |
186 | footer, div.footer, .push {
187 | height: 100px;
188 | font-size: 20px;
189 | text-align: center;
190 | clear: both;
191 | padding: 10px 0 30px 0;
192 | }
193 |
194 | footer, div.footer {
195 | background: #789;
196 | background: -moz-radial-gradient(center bottom, ellipse farthest-corner, #789, #677 40%);
197 | background: -webkit-radial-gradient(center bottom, ellipse farthest-corner, #789, #677 40%);
198 | background: -o-radial-gradient(center bottom, ellipse farthest-corner, #789, #677 40%);
199 | background: -ms-radial-gradient(center bottom, ellipse farthest-corner, #789, #677 40%);
200 | box-shadow: inset 0 0 10px #567;
201 | }
202 |
203 | .blog {
204 | font-size: 0.8em;
205 | color: #ccc;
206 | text-shadow: #aaa inset 0px 3px 3px;
207 | }
208 |
209 | #tooltip {
210 | max-width: 400px;
211 | font-size: 1.1em;
212 | color: #222;
213 | background: #ddd;
214 | border: 1px solid #aaa;
215 | padding: 10px;
216 | display: none;
217 | opacity: 0.95;
218 | filter: alpha(opacity=95);
219 | text-align: left;
220 | border-radius: 8px;
221 | -moz-border-radius: 8px;
222 | -webkit-border-radius: 8px;
223 | }
224 |
225 | #tooltip .close {
226 | display: none;
227 | }
--------------------------------------------------------------------------------
/css/pathslider.css:
--------------------------------------------------------------------------------
1 | /* set slider dimension here */
2 | #slider {
3 | width: 200px;
4 | height: 200px;
5 | }
6 |
7 | /* Basic solid color slider grip */
8 | .pathslider-grip {
9 | width: 30px;
10 | height: 15px;
11 | position: absolute;
12 | top: 0;
13 | left: 0;
14 | background: #ddd;
15 | font-size: 1px;
16 | z-index: 10;
17 | cursor: move;
18 | border: 1px solid;
19 | border-radius: 7px;
20 | -webkit-box-shadow: 0px 1px 3px rgba(000,000,000,0.5), inset 0px 0px 1px rgba(255,255,255,0.6);
21 | box-shadow: 0px 1px 3px rgba(000,000,000,0.5), inset 0px 0px 1px rgba(255,255,255,0.6);
22 | }
23 |
24 | /* grip hover/sliding state */
25 | .pathslider-grip.sliding, .pathslider-grip:hover {
26 | border-color: #8ce;
27 | -webkit-box-shadow: 0 0 15px #8ce;
28 | box-shadow: 0 0 15px #8ce;
29 | }
30 |
31 | /* slider extra css - same as #slider above */
32 | .pathslider {
33 | position: relative;
34 | }
35 |
36 | /*************
37 | grip styles
38 | add these using the gripClass option
39 | *************/
40 | /* shiny silver - sorta */
41 | .silver {
42 | border-color: #949494;
43 | background-color: #ebebeb;
44 | background-image: -webkit-linear-gradient(top,#ffffff 0%,#ebebeb 50%,#dbdbdb 50%,#b5b5b5);
45 | background-image: linear-gradient(top,#ffffff 0%,#ebebeb 50%,#dbdbdb 50%,#b5b5b5);
46 | }
47 |
48 | /* shiny black */
49 | .black {
50 | border-color: #000000
51 | background-color: #3b3b3b;
52 | background-image: -webkit-linear-gradient(top,#a3a3a3 0%,#3b3b3b 50%,#242424 50%,#000000);
53 | background-image: linear-gradient(top,#a3a3a3 0%,#3b3b3b 50%,#242424 50%,#000000);
54 | }
55 |
56 | /* Small circular chrome knob
57 | including ".pathslider-grip" to remove border & box shadow
58 | */
59 | .pathslider-grip.chrome1 {
60 | width: 18px;
61 | height: 18px;
62 | border: 0;
63 | border-radius: 0;
64 | background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAABI1BMVEUAAADHx8fNzc/29vbCwsOVlpfFxsbb29vp6enm5eX19vb6+vr///+vr6/Dw8K4uLjGxsbQ0NDR0dHh4eHl5uaqq6qlpaWoqqy+vr+9vb3e4OGTk5TIyMiSkpO9vb2kpabDw8SampzDw8O9vb62tratra7Ly8vW1tbk5OTKysrv8fLt7e3c3Nzi4uLd3d309PTv7+/o6Ojm5ufy8vPu7+/r6+zX2NnT09XS0tTk5Obh4eHP0NLKy83DxMX5+fr19fXz8/Xl5ube3+Dd3d/c3N7Z2tvW19jU1de+vr/3+Pjp6ura29zNztG7vL65uruztLWvsLGtra329vbw8PDh4uPLzc/HyMqysrLs7e3o6Orj4+PV1dfQ0dO4uLmoqKn7+/ujo6WIZbNwAAAAMXRSTlMA/v4F/v79kzcuFgkC9vHmsI9+ZRL99fHw7+7u7Ovj4+Hg19bNzMCooJ+Yi4p5SSYjiIrjEAAAASVJREFUGNMVz0OCxAAUANGfpG2MbSu27aTtmfufYtK1fLuCJgBg72g831bO3hoYQAuKvl+PPGkznWXHL/Um7KvfxVIUoZw9cZGLj0YhX93YZTkx4kJ9rArIZwvqDykTMi4nshZOKr9cZwiDtkQIhs2KrED5ikIlPehuDZzgDUdc4yNfG5NoBzKPx+mAsDhT9SlC4BkEcs80CHzJO0QgMBtxbVcgT6coy7qMaVqcNJuJjgz5LollRHJ0fcVPQsZyEEj/0kSObBxXF2ONpEi2BDe7uTy1ljRBajRN+mqpBNUsl0KexnVKIYOFap9UofZ0mBhBQfRI0ShBrhaTtV7bc80VQY20CVN5/oEibHBaLmceIs/LV8ODApotwGr9x9vL8+v7/h7gH5fyPZ6I/Z3zAAAAAElFTkSuQmCC');
65 | background-position: center center;
66 | background-repeat: no-repeat;
67 | -webkit-box-shadow: 0 0 0;
68 | box-shadow: 0 0 0;
69 | }
70 |
71 | /* Large curvy chrome slide */
72 | .pathslider-grip.chrome2 {
73 | width: 57px;
74 | height: 35px;
75 | border: 0;
76 | border-radius: 0;
77 | background: url('data:image/png;base64,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');
78 | background-position: center center;
79 | background-repeat: no-repeat;
80 | -webkit-box-shadow: 0 0 0;
81 | box-shadow: 0 0 0;
82 | }
--------------------------------------------------------------------------------
/dist/pathslider.css:
--------------------------------------------------------------------------------
1 | /* set slider dimension here */
2 | #slider {
3 | width: 200px;
4 | height: 200px;
5 | }
6 |
7 | /* Basic solid color slider grip */
8 | .pathslider-grip {
9 | width: 30px;
10 | height: 15px;
11 | position: absolute;
12 | top: 0;
13 | left: 0;
14 | background: #ddd;
15 | font-size: 1px;
16 | z-index: 10;
17 | cursor: move;
18 | border: 1px solid;
19 | border-radius: 7px;
20 | -webkit-box-shadow: 0px 1px 3px rgba(000,000,000,0.5), inset 0px 0px 1px rgba(255,255,255,0.6);
21 | box-shadow: 0px 1px 3px rgba(000,000,000,0.5), inset 0px 0px 1px rgba(255,255,255,0.6);
22 | }
23 |
24 | /* grip hover/sliding state */
25 | .pathslider-grip.sliding, .pathslider-grip:hover {
26 | border-color: #8ce;
27 | -webkit-box-shadow: 0 0 15px #8ce;
28 | box-shadow: 0 0 15px #8ce;
29 | }
30 |
31 | /* slider extra css - same as #slider above */
32 | .pathslider {
33 | position: relative;
34 | }
35 |
36 | /*************
37 | grip styles
38 | add these using the gripClass option
39 | *************/
40 | /* shiny silver - sorta */
41 | .silver {
42 | border-color: #949494;
43 | background-color: #ebebeb;
44 | background-image: -webkit-linear-gradient(top,#ffffff 0%,#ebebeb 50%,#dbdbdb 50%,#b5b5b5);
45 | background-image: linear-gradient(top,#ffffff 0%,#ebebeb 50%,#dbdbdb 50%,#b5b5b5);
46 | }
47 |
48 | /* shiny black */
49 | .black {
50 | border-color: #000000
51 | background-color: #3b3b3b;
52 | background-image: -webkit-linear-gradient(top,#a3a3a3 0%,#3b3b3b 50%,#242424 50%,#000000);
53 | background-image: linear-gradient(top,#a3a3a3 0%,#3b3b3b 50%,#242424 50%,#000000);
54 | }
55 |
56 | /* Small circular chrome knob
57 | including ".pathslider-grip" to remove border & box shadow
58 | */
59 | .pathslider-grip.chrome1 {
60 | width: 18px;
61 | height: 18px;
62 | border: 0;
63 | border-radius: 0;
64 | background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAABI1BMVEUAAADHx8fNzc/29vbCwsOVlpfFxsbb29vp6enm5eX19vb6+vr///+vr6/Dw8K4uLjGxsbQ0NDR0dHh4eHl5uaqq6qlpaWoqqy+vr+9vb3e4OGTk5TIyMiSkpO9vb2kpabDw8SampzDw8O9vb62tratra7Ly8vW1tbk5OTKysrv8fLt7e3c3Nzi4uLd3d309PTv7+/o6Ojm5ufy8vPu7+/r6+zX2NnT09XS0tTk5Obh4eHP0NLKy83DxMX5+fr19fXz8/Xl5ube3+Dd3d/c3N7Z2tvW19jU1de+vr/3+Pjp6ura29zNztG7vL65uruztLWvsLGtra329vbw8PDh4uPLzc/HyMqysrLs7e3o6Orj4+PV1dfQ0dO4uLmoqKn7+/ujo6WIZbNwAAAAMXRSTlMA/v4F/v79kzcuFgkC9vHmsI9+ZRL99fHw7+7u7Ovj4+Hg19bNzMCooJ+Yi4p5SSYjiIrjEAAAASVJREFUGNMVz0OCxAAUANGfpG2MbSu27aTtmfufYtK1fLuCJgBg72g831bO3hoYQAuKvl+PPGkznWXHL/Um7KvfxVIUoZw9cZGLj0YhX93YZTkx4kJ9rArIZwvqDykTMi4nshZOKr9cZwiDtkQIhs2KrED5ikIlPehuDZzgDUdc4yNfG5NoBzKPx+mAsDhT9SlC4BkEcs80CHzJO0QgMBtxbVcgT6coy7qMaVqcNJuJjgz5LollRHJ0fcVPQsZyEEj/0kSObBxXF2ONpEi2BDe7uTy1ljRBajRN+mqpBNUsl0KexnVKIYOFap9UofZ0mBhBQfRI0ShBrhaTtV7bc80VQY20CVN5/oEibHBaLmceIs/LV8ODApotwGr9x9vL8+v7/h7gH5fyPZ6I/Z3zAAAAAElFTkSuQmCC');
65 | background-position: center center;
66 | background-repeat: no-repeat;
67 | -webkit-box-shadow: 0 0 0;
68 | box-shadow: 0 0 0;
69 | }
70 |
71 | /* Large curvy chrome slide */
72 | .pathslider-grip.chrome2 {
73 | width: 57px;
74 | height: 35px;
75 | border: 0;
76 | border-radius: 0;
77 | background: url('data:image/png;base64,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');
78 | background-position: center center;
79 | background-repeat: no-repeat;
80 | -webkit-box-shadow: 0 0 0;
81 | box-shadow: 0 0 0;
82 | }
--------------------------------------------------------------------------------
/demo/demo.js:
--------------------------------------------------------------------------------
1 | $(function(){
2 |
3 | var i, s, t, pathslider = $('#slider'),
4 | points = $('.points'),
5 | position = $('.position'),
6 | angle = $('.angle'),
7 | code = $('textarea.code'),
8 | m = $('.message'),
9 | presets = {
10 | '0' : [ 25,150,50,-50,-50,-50,275,150 ], // arch
11 | '1' : [ 25,275,25,-25,-25,25,275,25 ], // diagonal
12 | '2' : [ 25,275,250,0,-250,0,275,25 ], // s-shape
13 | '3' : [ 100,200,200,25,-100,-275,100,275 ], // p-shape
14 | '4' : [ 75,200,200,-125,-200,-125,225,200 ] // loop
15 | },
16 | // update code box
17 | updateOptions = function(s){
18 | var t;
19 | if (s) {
20 | if (s.hasOwnProperty('builderInitialized') && s.builderInitialized) { code.val( s.getCode().replace(/url\(\)/, $('.bkgd').val()) ); }
21 | $('.rotate')[0].checked = s.options.rotateGrip; // I would use prop, but want to make it work with jQuery 1.4.4
22 | $('.tolerance').val(s.options.tolerance).filter('.isRange').next().html( s.options.tolerance );
23 | $('.range').val( s.options.range ).filter('.isRange').next().html( s.options.range + ' px' );
24 | $('.edit')[0].checked = s.options.edit;
25 | $('.grid').val( s.options.grid ).filter('.isRange').next().html( s.options.grid === 1 ? 'off' : s.options.grid + ' px' );
26 | $('.snap')[0].checked = s.options.snap;
27 | $('.thickness').val( s.options.curve.width ).filter('.isRange').next().html( s.options.curve.width + ' px' );
28 | t = $('.gripColor'); t.val( checkColor(t, t.val()) );
29 | $('.curveColor').each(function(indx, el){
30 | var $el = $(el);
31 | $el.val( checkColor($el) );
32 | });
33 | }
34 | },
35 | checkColor = function(t,c){
36 | var c = c || t.val(),
37 | d = (/^(#[\da-fA-F]{6}$)/.test(c)) ? c : t.attr('data-last');
38 | t.attr('data-last', d);
39 | return d;
40 | },
41 | // t = jQuery object, d = default value
42 | checkRange = function(t,d){
43 | // parseInt($('.tolerance').val(), 10) || 3;
44 | var v = parseInt(t.val(), 10) || d,
45 | min = parseInt(t.attr('min'), 10),
46 | max = parseInt(t.attr('max'), 10);
47 | return (v < min) ? min : (v > max) ? max : v;
48 | };
49 |
50 | $('#tabs').tabs({
51 | show: function(e,ui){
52 | if (ui.tab.innerHTML === "Code") {
53 | var s = pathslider.data('pathslider');
54 | updateOptions(s);
55 | if (s && s.hasOwnProperty('updateCanvasImage')) {
56 | // update save canvas image
57 | s.updateCanvasImage();
58 | }
59 | }
60 | }
61 | });
62 |
63 | // add preset buttons
64 | i = 0; t = '';
65 | while (presets.hasOwnProperty(i)) {
66 | t += '';
67 | i++;
68 | }
69 | $('.presets').html(t);
70 |
71 | // check input type support
72 | $('.tolerance, .range, .grid, .thickness').each(function(){
73 | if (this.type !== 'range') {
74 | $(this)
75 | .addClass('text')
76 | .next()
77 | .html(' range (' + $(this).attr('min') + '-' + $(this).attr('max') + ')');
78 | } else {
79 | $(this).addClass('isRange');
80 | }
81 | });
82 |
83 | // update all pathslider options
84 | $('.set').change(function(){
85 | var t;
86 | s.options.rotateGrip = $('.rotate')[0].checked;
87 | s.options.tolerance = checkRange( $('.tolerance'), 3);
88 | s.options.range = checkRange( $('.range'), 30);
89 | s.options.edit = $('.edit')[0].checked;
90 | s.options.grid = checkRange( $('.grid'), 25);
91 | s.options.snap = $('.snap')[0].checked;
92 | $('.pathslider-grip').attr('style',''); // clear rotation
93 | s.options.points = points.val().split(',');
94 | s.options.curve.width = checkRange( $('.thickness'), 4);
95 | s.options.curve.cap = $('.capStyle').val().toLowerCase();
96 |
97 | t = $('.curveColor').map(function(){
98 | return checkColor($(this));
99 | }).get();
100 | if (t[0] === t[1]) {
101 | t = t[0];
102 | }
103 | // a color array => linear gradient in v1.0.0
104 | s.options.curve.color = t;
105 |
106 | if ($('.gripStyle')[0].selectedIndex === 0) {
107 | $('.gripColor')[0].disabled = false;
108 | t = checkColor( $('.gripColor') );
109 | s.options.gripClass = ''; // update for code tab
110 | $('.pathslider-grip')
111 | .attr('class', 'pathslider-grip')
112 | .css('background-color', t);
113 | } else {
114 | t = $('.gripStyle').val().toLowerCase().replace(/\s+/g,'');
115 | s.options.gripClass = t;
116 | $('.gripColor')[0].disabled = true;
117 | $('.pathslider-grip')
118 | .attr('class', 'pathslider-grip ' + t)
119 | .css('background-color', '');
120 | }
121 |
122 | // background - remove ";" because it breaks if you don't
123 | t = $('.bkgd').val().replace(/\;/g,'');
124 | $('.bkgd').val(t);
125 | $('#slider').css('background', t );
126 |
127 | updateOptions(s);
128 | s.updateBuilder();
129 | });
130 |
131 | // set up pathslider
132 | $('#slider')
133 | .pathslider({
134 | rotateGrip : true,
135 | // points : [ 50,300, 0,250, 180,250, 300,50 ],
136 | points : [ 0,50, 50,-50, -50,-50, 250,50 ],
137 |
138 | create : function(e,slider){
139 | points.val(slider.points);
140 | position.val(slider.percent);
141 | angle.text( slider.angle );50
142 | },
143 | update : function(e,slider){
144 | points.val(slider.points);
145 | updateOptions(slider);
146 | },
147 | slide : function(e,slider){
148 | position.val(slider.percent);
149 | angle.text( slider.angle );
150 | }
151 | })
152 | .pathbuilder({
153 | edit : true,
154 | snap : true,
155 | grid : 25,
156 | canvasImage : $('#save')
157 | });
158 |
159 | // Select all text in the points input
160 | points.mouseup(function(){
161 | this.select();
162 | });
163 |
164 | // shift points
165 | $('.shift').click(function(){
166 | var x, y,
167 | $el = $(this),
168 | isX = $el.filter('.x').length,
169 | dir = $el.filter('.left, .up').length ? -1 : 1;
170 | amount = parseInt($(isX ? '.movex' : '.movey').val(), 10) || 10;
171 |
172 | x = isX ? dir * amount : 0;
173 | y = isX ? 0 : dir * amount;
174 | s.points = s.options.points = s.shift(x, y);
175 | s.updateBuilder();
176 | });
177 |
178 | // "Set" points
179 | $('.setpoints').click(function(){
180 | var p, pts = points.val().split(',');
181 | if (pts.length === 8) {
182 | s.options.points = pts;
183 | s.updateBuilder();
184 | }
185 | });
186 |
187 | // "Set" position
188 | $('.setpos').click(function(){
189 | s.setSlider( parseFloat(position.val()), function(s){
190 | // no need to validate, just replace the value
191 | position.val( s.percent );
192 | } );
193 | });
194 |
195 | // presets
196 | $('.presets button').click(function(){
197 | t = parseInt($(this).text(), 10) - 1;
198 | points.val(s.options.points = presets[t]);
199 | s.updateBuilder();
200 | });
201 |
202 | // Add events
203 | pathslider.bind('create.pathslider update.pathslider start.pathslider slide.pathslider change.pathslider stop.pathslider',function(e,s){
204 | m.append('' + e.type + ' : ' + s.percent + '');
205 | var l = m.find('li');
206 | if (l.length > 10) { l.eq(0).remove(); }
207 | });
208 |
209 | // Color styles
210 | $('.gripColor, .curveColor').ColorPicker({
211 | onSubmit: function(hsb, hex, rgb, el) {
212 | $(el).val('#' + hex);
213 | $(el).ColorPickerHide();
214 | $(el).trigger('change');
215 | },
216 | onBeforeShow: function () {
217 | $(this).ColorPickerSetColor(this.value.slice(1));
218 | }
219 | })
220 | .bind('keyup', function(){
221 | $(this).ColorPickerSetColor(this.value.slice(1));
222 | });
223 |
224 | // Make info links (tooltips) unclickable
225 | $('a.info').click(function(){
226 | if (this.target === "") { return false; }
227 | });
228 |
229 | // set up tooltips
230 | $.jatt({ direction : 'ne' });
231 |
232 | s = pathslider.data('pathslider');
233 |
234 | });
--------------------------------------------------------------------------------
/js/jquery.pathslider.builder.js:
--------------------------------------------------------------------------------
1 | /* jQuery Pathslider Builder v0.9.1 alpha
2 | * By Rob Garrison (Mottie)
3 | * MIT License
4 | *
5 | * Code based on the bezier curve demo by Craig Buckler (http://twitter.com/craigbuckler)
6 | * http://blogs.sitepointstatic.com/examples/tech/canvas-curves/bezier-curve.html
7 | */
8 | (function($){
9 |
10 | $.pathbuilderdefaults = {
11 | edit : true, // allows user to move bezier curve
12 | snap : true,
13 | grid : 10,
14 | // default canvas styles
15 | // control point line (cpline) & point are used in edit mode
16 | style : {
17 | cpline : { width: 1, color: "#00c" },
18 | // start point
19 | start : { width: 2, color: "hsl(120,100%,30%)", fill: "hsla(120,100%,30%,0.3)", radius: 10, arc1: 0, arc2: 2 * Math.PI },
20 | // start control point
21 | cstart : { width: 2, color: "hsl(120,100%,30%)", fill: "hsla(120,100%,30%,0.5)", radius: 10, arc1: 0, arc2: 2 * Math.PI },
22 | // end control point
23 | cend : { width: 2, color: "hsl(0,100%,30%)", fill: "hsla(0,100%,30%,0.5)", radius: 10, arc1: 0, arc2: 2 * Math.PI },
24 | // end point
25 | end : { width: 2, color: "hsl(0,100%,30%)", fill: "hsla(0,100%,30%,0.3)", radius: 10, arc1: 0, arc2: 2 * Math.PI },
26 | grid : { width: 1, color: "hsla(0,0%,60%,0.5)" }
27 | },
28 | canvasImage : null // jQuery object of img that the canvas is saved into - see base.updateCanvasImage
29 | };
30 |
31 | $.fn.pathbuilder = function(options) {
32 | return this.each(function(){
33 | // make sure pathslider is attached
34 | var o, base = $(this).data('pathslider');
35 | if (!base) { return; }
36 |
37 | base.builderInit = function(){
38 | base.options = o = $.extend(true, base.options, $.pathbuilderdefaults, options);
39 | base.drag = null;
40 |
41 | base.options.drawCanvas = function(b, ctx, points) {
42 | base.drawControls(ctx, points);
43 | // prevent redrawing the curve
44 | return false;
45 | };
46 |
47 | if (!base.hasCanvas) { return; } // too bad IE!
48 |
49 | // Add resizable corner to allow resizing of the canvas
50 | $('')
51 | .appendTo(base.$el)
52 | .mousedown(function(e) {
53 | $(document)
54 | .unbind('mousemove.pathbuilder touchmove.pathbuilder')
55 | .bind((base.hasTouch ? 'touchmove' : 'mousemove') + '.pathbuilder', function(e) {
56 | var ww = $(window).width(),
57 | wh = $(window).height(),
58 | l = base.$canvas.offset().left,
59 | t = base.$canvas.offset().top,
60 | w = (e.originalEvent.touches ? e.originalEvent.touches[0].pageX : e.pageX) - l,
61 | h = (e.originalEvent.touches ? e.originalEvent.touches[0].pageY : e.pageY) - t;
62 | w = (w < 100) ? 100 : w > ww-l ? ww-l : w;
63 | h = (h < 100) ? 100 : h > wh-t ? wh-t : h; // min w & h
64 | base.$canvas.attr({ width : w, height: h });
65 | base.$el.css({ width : w, height: h });
66 | base.sliderDim = [ base.$el.position().left, base.$el.position().top, w, h ];
67 | // Add bezier curve & controls
68 | base.drawCurve();
69 | })
70 | .bind((base.hasTouch ? 'touchend' : 'mouseup') + '.pathbuilder', function(){
71 | $(document).unbind('mousemove.pathbuilder touchmove.pathbuilder');
72 | });
73 | });
74 |
75 | base.updateBuilder(true);
76 | base.builderInitialized = true; // initialization flag
77 | base.$el.trigger('update.pathslider', [base] );
78 |
79 | };
80 |
81 | base.updateBuilder = function(internal) {
82 | // make sure all of the points are numerical
83 | base.points = o.points = $.map(o.points, function(v,i){
84 | return parseInt(v*100,10)/100;
85 | });
86 | // convert control point offsets to x/y positions
87 | base.redraw( (base.builderInitialized) ? base.points : base.shift(25,100) );
88 | if (o.edit) {
89 | base.$canvas
90 | .unbind('.pathbuilder')
91 | .bind((base.hasTouch ? 'touchstart' : 'mousedown') + '.pathbuilder', function(e){ base.dragStart(e); })
92 | .bind((base.hasTouch ? 'touchmove' : 'mousemove') + '.pathbuilder', function(e){ base.dragging(e); })
93 | .bind((base.hasTouch ? 'touchend.pathbuilder touchcancel' : 'mouseup.pathbuilder mouseleave') + '.pathbuilder', function(e){ base.dragEnd(e); });
94 | }
95 | if (!internal) {
96 | base.$el.trigger('update.pathslider', [base]);
97 | }
98 | };
99 |
100 | // Make purdy stuff
101 | base.drawControls = function(c, b) {
102 | var i, j, x, y, t, p, s = o.style,
103 | // c = base.ctx, b = base.pointsxy,
104 | w = base.sliderDim[2], h = base.sliderDim[3];
105 | base.points = base.convert();
106 | clearTimeout(base.timer);
107 | c.clearRect(0, 0, w, h);
108 |
109 | // finish drawing curve - don't let drawCanvas do this because
110 | // we're changing the colors for the control handles
111 | base.finishCurve(c, b);
112 | c.beginPath();
113 | c.moveTo(b[0], b[1]);
114 | c.bezierCurveTo(b[2], b[3], b[4], b[5], b[6], b[7]);
115 | c.stroke();
116 |
117 | // Edit mode = add grid, control points/lines
118 | if (o.edit) {
119 | // make grid
120 | if (o.grid >= 2) {
121 | c.prop({
122 | lineWidth : s.grid.width,
123 | strokeStyle : s.grid.color
124 | })
125 | .beginPath();
126 | for (x = o.grid; x < w; x += o.grid) {
127 | c.moveTo(x, 0).lineTo(x, h);
128 | }
129 | for (y = o.grid; y < h; y += o.grid) {
130 | c.moveTo(0, y).lineTo(w, y);
131 | }
132 | c.stroke();
133 | }
134 |
135 | j = 0;
136 | base.controls = b;
137 | base.controlNames = ['start', 'cstart', 'cend', 'end'];
138 |
139 | // Add control lines
140 | c.prop({
141 | lineWidth : s.cpline.width,
142 | strokeStyle : s.cpline.color
143 | })
144 | .beginPath()
145 | .moveTo(b[0], b[1])
146 | .lineTo(b[2], b[3])
147 | .moveTo(b[6], b[7])
148 | .lineTo(b[4], b[5])
149 | .stroke();
150 | // Add control points
151 | for (i=0; i < 8; i++) {
152 | c.prop({
153 | lineWidth : s[base.controlNames[j]].width,
154 | strokeStyle : s[base.controlNames[j]].color,
155 | fillStyle : s[base.controlNames[j]].fill
156 | })
157 | .beginPath()
158 | .arc(
159 | b[i++],
160 | b[i],
161 | s[base.controlNames[j]].radius,
162 | s[base.controlNames[j]].arc1,
163 | s[base.controlNames[j]].arc2,
164 | true
165 | )
166 | .fill()
167 | .stroke();
168 | j += i%2;
169 | }
170 | }
171 |
172 | // thottle resizing window
173 | base.timer = setTimeout(function(){
174 | base.makeArray();
175 | base.setSlider(base.percent, null, true);
176 | }, 100);
177 |
178 | };
179 |
180 | base.updateCanvasImage = function(){
181 | if (o.canvasImage.length) {
182 | clearTimeout(base.timer);
183 | base.ctx.clearRect(0, 0, base.sliderDim[2], base.sliderDim[3]);
184 | base.drawCurve();
185 | o.canvasImage.attr('src', base.canvas.toDataURL());
186 | base.updateBuilder();
187 | }
188 | };
189 |
190 | // start dragging points on canvas
191 | base.dragStart = function(event){
192 | if (!o.edit) { return; }
193 | var e = base.mousePos(event),
194 | l = base.controls.length,
195 | i, j = 0, r, dx, dy;
196 | for (i=0; i < l; i++) {
197 | dx = base.controls[i++] - e[0];
198 | dy = base.controls[i] - e[1];
199 | r = o.style[base.controlNames[j]].radius + o.grid/2;
200 | if ((dx * dx) + (dy * dy) < r * r) {
201 | base.drag = i-1;
202 | base.dPoint = e;
203 | base.$canvas.addClass('moving');
204 | return;
205 | }
206 | j += i%2;
207 | }
208 | };
209 |
210 | // dragging points on canvas
211 | base.dragging = function(event){
212 | if (o.edit && base.drag !== null) {
213 | var i, g = o.grid || 1,
214 | e = base.mousePos(event),
215 | c = base.controls,
216 | l = c.length,
217 | x = e[0] - base.dPoint[0],
218 | y = e[1] - base.dPoint[1];
219 | // Move whole thing
220 | if (event.shiftKey) {
221 | if (x > o.grid || y > o.grid) { base.dPoint = e; }
222 | for (i=0; i < l; i++) {
223 | // *** SHIFT-snap to grid needs improvement ***
224 | c[i] = (o.snap) ? Math.round((c[i] + x)/g)*g : c[i] + x;
225 | c[++i] = (o.snap) ? Math.round((c[i] + y)/g)*g : c[i] + y;
226 | }
227 | base.dPoint = e;
228 | } else {
229 | // only move the one point
230 | c[base.drag] = (o.snap) ? Math.round((base.dPoint[0] + x)/g)*g : base.dPoint[0] + x;
231 | c[base.drag+1] = (o.snap) ? Math.round((base.dPoint[1] + y)/g)*g : base.dPoint[1] + y;
232 | }
233 | // Add bezier curve & controls
234 | base.drawCurve();
235 |
236 | base.$el.trigger('update.pathslider', [base]);
237 | }
238 | };
239 |
240 | // end dragging
241 | base.dragEnd = function(e){
242 | if (o.edit && base.drag !== null) {
243 | base.drag = null;
244 | base.$canvas.removeClass('moving');
245 | o.points = base.points;
246 | base.updateBuilder(true);
247 | }
248 | };
249 |
250 | base.crop = function(){
251 | o.points = base.points;
252 | base.updateBuilder(true);
253 | // include curve width when cropping
254 | var w = o.curve.width * 2;
255 | return [
256 | Math.min.apply(this,base.arrayX) - w, // min X
257 | Math.min.apply(this,base.arrayY) - w, // min Y
258 | Math.max.apply(this,base.arrayX) + w, // max X
259 | Math.max.apply(this,base.arrayY) + w // max Y
260 | ];
261 | };
262 |
263 | // base.pointsxy = [ sx,sy, csx,csy, cex,cey, ex,ey ] to
264 | // base.points = [ sx,sy, csxo,csyo, cexo,ceyo, ex,ey ]
265 | base.convert = function(p){
266 | p = p || base.pointsxy;
267 | return [
268 | p[0], p[1], // start x,y
269 | p[2] - p[0], p[3] - p[1], // start control x,y
270 | p[4] - p[6], p[5] - p[7], // end control x,y
271 | p[6], p[7] // end x,y
272 | ];
273 | };
274 |
275 | // shift all points so coords based from origin
276 | // example: base.shift(-10, +10);
277 | base.shift = function(x,y){
278 | // b = [ sx,sy, csx,csy, cex,cey, ex,ey ]
279 | var b = base.points;
280 | return [
281 | Math.round(b[0]+x), Math.round(b[1]+y),
282 | b[2], b[3],
283 | b[4], b[5],
284 | Math.round(b[6]+x), Math.round(b[7]+y)
285 | ];
286 | };
287 |
288 | base.getCode = function(){
289 | var dim = base.crop(),
290 | points = base.shift(-dim[0],-dim[1]),
291 | txt = '\n' +
298 | '';
313 | return txt;
314 | };
315 |
316 | // Run initializer
317 | base.builderInit();
318 |
319 | });
320 | };
321 |
322 | })(jQuery);
323 |
324 | /* jshint ignore:start */
325 | /**
326 | * Chainvas: Make APIs chainable
327 | * @author Lea Verou
328 | * MIT license http://www.opensource.org/licenses/mit-license.php
329 | */
330 | (function(){var e=window.Chainvas={chainable:function(a){return function(){var b=a.apply(this,arguments);return b===void 0?this:b}},chainablizeOne:function(a,b){try{e.utils.hasOwnProperty(a,b)&&e.utils.isFunction(a[b])&&(a[b]=e.chainable(a[b]))}catch(c){}return this},chainablize:function(a,b){var c=a.prototype;if(b)for(var d=b.length;d--;)e.chainablizeOne(c,b[d]);else for(d in c)e.chainablizeOne(c,d);return this},helpers:function(a,b){var c=a.prototype,d;for(d in e.methods)c&&!(d in c)&&(c[d]=e.methods[d]);
331 | e.extend(c,b);return this},extend:function(a,b){return Chainvas.methods.prop.call(a,b)},global:function(a,b,c){typeof a==="string"&&(a=[a]);for(var d=a.length;d--;){var f=window[a[d]];f&&e.chainablize(f,c).helpers(f,b)}},methods:{prop:function(){if(arguments.length===1){var a=arguments[0],b;for(b in a)this[b]=a[b]}else arguments.length===2&&(this[arguments[0]]=arguments[1]);return this}},utils:{isFunction:function(a){var b=Object.prototype.toString.call(a);return b==="[object Function]"||b==="[object Object]"&&
332 | "call"in a&&"apply"in a&&/^\s*\bfunction\s+\w+\([\w,]*\) \{/.test(a+"")},hasOwnProperty:function(a,b){try{return a.hasOwnProperty(b)}catch(c){return b in a&&(!a.prototype||!(b in a.prototype)||a.prototype[b]!==a[b])}}}}})();
333 |
334 | /**
335 | * Chainvas module: Canvas
336 | */
337 | Chainvas.global("CanvasRenderingContext2D",{circle:function(a,b,d){return this.beginPath().arc(a,b,d,0,2*Math.PI,!1).closePath()},roundRect:function(a,b,d,e,c){return this.beginPath().moveTo(a+c,b).lineTo(a+d-c,b).quadraticCurveTo(a+d,b,a+d,b+c).lineTo(a+d,b+e-c).quadraticCurveTo(a+d,b+e,a+d-c,b+e).lineTo(a+c,b+e).quadraticCurveTo(a,b+e,a,b+e-c).lineTo(a,b+c).quadraticCurveTo(a,b,a+c,b).closePath()}});
338 | /* jshint ignore:end */
339 |
--------------------------------------------------------------------------------
/js/jquery.pathslider.js:
--------------------------------------------------------------------------------
1 | /* jQuery Pathslider v1.0.0 alpha
2 | * By Rob Garrison (Mottie)
3 | * MIT License
4 | */
5 | (function($){
6 | $.pathslider = function(el, options){
7 |
8 | // To avoid scope issues, use 'base' instead of 'this'
9 | // to reference this class from internal events and functions.
10 | var base = this, o;
11 |
12 | // Access to jQuery and DOM versions of element
13 | base.$el = $(el).addClass('pathslider');
14 | base.el = el;
15 |
16 | // Add a reverse reference to the DOM object
17 | base.$el.data("pathslider", base);
18 |
19 | base.init = function(){
20 | var t;
21 | base.options = o = $.extend(true, {}, $.pathslider.defaults, options);
22 |
23 | // Is there a canvas?
24 | t = document.createElement('canvas');
25 | base.hasCanvas = !!(t.getContext && t.getContext('2d'));
26 | base.hasTouch = document.hasOwnProperty("ontouchend");
27 |
28 | // add grip
29 | base.$grip = $('').appendTo(base.$el);
30 |
31 | // store array of x & y positions for cross reference
32 | base.points = [];
33 | base.pointsxy = [];
34 | base.arrayX = [];
35 | base.arrayY = [];
36 | base.arrayP = [];
37 |
38 | base.rad2deg = 180 / Math.PI; // convert radians to degrees (multiply radian by this value)
39 | base.sliding = false; // flag for dragging element
40 | base.lastPercent = base.percent = o.value;
41 |
42 | // Callbacks
43 | // slide triggered on EVERY mouse move; change triggered on slide stop
44 | $.each('create update start slide change stop'.split(' '), function(i,f){
45 | if ($.isFunction(o[f])){
46 | base.$el.bind(f + '.pathslider', o[f]);
47 | }
48 | });
49 |
50 | $(document)
51 | .bind( base.hasTouch ? 'touchend.pathslider touchcancel.pathslider' : 'mouseup.pathslider mouseleave.pathslider', function(e){
52 | if (base.sliding) { // && ($(e.target).closest('.pathslider').length || e.type === 'mouseleave')) {
53 | base.$el.trigger('stop.pathslider', [base]);
54 | if (base.lastPercent !== base.percent) {
55 | base.lastPercent = base.percent;
56 | base.$el.trigger('change.pathslider', [base]);
57 | }
58 | }
59 | base.$grip.removeClass('sliding');
60 | base.sliding = false;
61 | })
62 | .bind( (base.hasTouch ? 'touchmove' : 'mousemove') + '.pathslider', function(e){
63 | if (base.sliding) {
64 | base.setSlider( base.findPos(e), null, true );
65 | }
66 | });
67 |
68 | $(window)
69 | .bind('resize.pathslider', function(){
70 | base.update();
71 | })
72 | .bind('load', function(){
73 | // needed because loading images/fonts will shift the page
74 | base.sliderDim[0] = base.$el.offset().left;
75 | base.sliderDim[1] = base.$el.offset().top;
76 | });
77 |
78 | base.$grip
79 | .bind( (base.hasTouch ? 'touchstart' : 'mousedown') + '.pathslider', function(e){
80 | base.sliding = true;
81 | $(this).addClass('sliding');
82 | base.$el.trigger('start.pathslider', [base]);
83 | return false;
84 | })
85 | .bind('click', function(){
86 | return false;
87 | });
88 |
89 | base.redraw();
90 |
91 | base.$el.trigger('create.pathslider', [base]);
92 |
93 | };
94 |
95 | // update dimensions & grip position
96 | base.update = function(){
97 |
98 | // using attr to remove other css grip classes when updating
99 | base.$grip.attr('class', 'pathslider-grip ' + o.gripClass);
100 |
101 | if (base.ctx) {
102 | // clear canvas *before* setting new dimensions
103 | // just in case the new size is smaller than the previous
104 | base.ctx.clearRect(0, 0, base.sliderDim[2], base.sliderDim[3]);
105 | }
106 |
107 | base.sliderDim = [
108 | base.$el.offset().left,
109 | base.$el.offset().top,
110 | base.$el.width(),
111 | base.$el.height()
112 | ];
113 |
114 | // get grip dimensions; jQuery v3+ width() & height() return the rotated dimensions
115 | // which we don't want!
116 | var computedStyle = window.getComputedStyle(base.$grip[0]);
117 | // for centering grip
118 | base.gripCenter = [ parseInt(computedStyle.width, 10)/2, parseInt(computedStyle.height, 10)/2 ];
119 |
120 | // number of data points to store - increase to smooth the animation (based on slider size)
121 | base.dataPoints = o.dataPoints;
122 | // in next update add min/max/step
123 | // base.range = o.max - o.min;
124 | // base.dataPoints = base.range * o.step;
125 |
126 | base.makeArray();
127 | // save the position in the array of the starting value (roughly)
128 | var t = $.inArray(base.percent, base.arrayP);
129 | base.position = (t === -1) ? Math.round(base.percent/100 * base.dataPoints) : t;
130 |
131 | base.setSlider(base.percent, null, true);
132 | if (base.hasCanvas && o.useCanvas) { base.drawCurve(); }
133 |
134 | };
135 |
136 | // set position of slider
137 | base.setSlider = function(percent, callback, internal) {
138 | if (!isNaN(percent)) {
139 | // find position on bezier curve; p = percent (range 0 - 100)
140 | // set position of slider without using the array (more precision)
141 | percent = parseFloat(percent, 10);
142 | percent = (percent > 100) ? 100 : percent < 0 ? 0 : percent;
143 | var css, angle,
144 | // pos = $.inArray(percent, base.arrayP),
145 | p = base.calcBezier(percent/100, base.pointsxy),
146 | pm1 = (percent - 2 > 0) ? base.calcBezier( (percent-2)/100, base.pointsxy ) : p,
147 | pp1 = (percent + 2 < 100) ? base.calcBezier( (percent+2)/100, base.pointsxy ) : p,
148 | // m = slope of tangent - used to change rotation angle of the grip
149 | // yes, I could have used the cubic derivative, but this is less math
150 | m = (pp1[0] - pm1[0] === 0) ? 90 : (pp1[1] - pm1[1])/(pp1[0] - pm1[0]);
151 | base.angle = parseInt(Math.atan(m) * base.rad2deg, 10);
152 | angle = 'rotate(' + base.angle + 'deg)';
153 | css = (o.rotateGrip) ? {
154 | '-webkit-transform' : angle,
155 | 'transform' : angle
156 | } : {};
157 | css.left = p[0] - base.gripCenter[0];
158 | css.top = p[1] - base.gripCenter[1];
159 | base.$grip
160 | .attr({
161 | 'data-angle' : base.angle,
162 | 'data-percent' : percent
163 | })
164 | .css(css);
165 | // find closest percent in the array - this relies on there being a factor
166 | // of 100 datapoints, so it'll need changing when we have a min/max/step
167 | base.percent = percent; // Math.round(percent*r)/r;
168 | if ((percent !== base.lastPercent && !base.sliding) || !internal) {
169 | base.$el.trigger('change.pathslider', [base]);
170 | }
171 | }
172 | if (typeof callback === 'function') { callback(base); }
173 | };
174 |
175 | // relative mouse position
176 | base.mousePos = function(e) {
177 | return [
178 | (e.originalEvent.touches ? e.originalEvent.touches[0].pageX : e.pageX) - base.sliderDim[0],
179 | (e.originalEvent.touches ? e.originalEvent.touches[0].pageY : e.pageY) - base.sliderDim[1]
180 | ];
181 | };
182 |
183 | // find percentage given the x,y coordinates
184 | // searching through a set array of points starting from the last known position
185 | // This allows the curve to loop over itself without mixing up intersecting points
186 | // The biggest issue is a very sharp turn
187 | base.findPos = function(event) {
188 | var i, j, dx, dy, px = [], py = [],
189 | last = base.position, //* base.dataPoints / 100,
190 | // check x & y cross ref based on nearby positions (+/- tolerance)
191 | t = parseInt(o.tolerance + 1, 10) || 2, // tolerance of 1 is too small
192 | r = parseInt(o.range, 10) || base.gripCenter[0], // set to 1/2 width of grip
193 | pos = base.mousePos(event);
194 | // save percent
195 | for ( i=0; i < r; i++ ){
196 | px = []; py = [];
197 | for ( j=0; j < t + 1; j++ ){
198 | // check positive direction
199 | dx = Math.abs(base.arrayX[last+j] - pos[0]) <= i;
200 | dy = Math.abs(base.arrayY[last+j] - pos[1]) <= i;
201 | if (dx && dy) { return base.returnPos(last+j); }
202 | if (dx) { px.push(last+j); }
203 | if (dy) { py.push(last+j); }
204 | // check in negative direction
205 | dx = Math.abs(base.arrayX[last-j] - pos[0]) <= i;
206 | dy = Math.abs(base.arrayY[last-j] - pos[1]) <= i;
207 | if (dx && dy) { return base.returnPos(last-j); }
208 | if (dx) { px.push(last-j); }
209 | if (dy) { py.push(last-j); }
210 | }
211 | if (px.length === 1 && py.length > 1) { return base.returnPos(px[0]); }
212 | if (py.length === 1 && px.length > 1) { return base.returnPos(py[0]); }
213 | }
214 | return base.returnPos(last);
215 | };
216 |
217 | // return found position & trigger slide event
218 | base.returnPos = function(p) {
219 | var t = base.position === p;
220 | base.percent = base.arrayP[p];
221 | base.position = p;
222 | if (!t) {
223 | if (base.hasCanvas && o.useCanvas) {
224 | base.drawCurve();
225 | }
226 | base.$el.trigger('slide.pathslider', [base] );
227 | }
228 | return base.percent;
229 | };
230 |
231 | // build cross-ref array - find position based on x,y coords
232 | base.makeArray = function(){
233 | var i, t, b = base.pointsxy,
234 | n = base.dataPoints;
235 | for ( i=0; i < n+1; i++ ){
236 | t = base.calcBezier(i/n, b);
237 | base.arrayX[i] = t[0];
238 | base.arrayY[i] = t[1];
239 | base.arrayP[i] = t[2];
240 | }
241 | };
242 |
243 | // Calculate bezier x & y based on percentage (p)
244 | // cubic bezier = start(p^3) + cstart(3*p^2*(1−p)) + cend(3*p*(1−p)^2) + end(1−p)^3
245 | // b = [ startx,starty, cstartx,cstarty, cendx,cendy, endx,endy ]
246 | base.calcBezier = function(p,b){
247 | var p2 = p*p,
248 | omp = (1-p), // omp = one minus p - smart naming ftw!
249 | omp2 = omp*omp,
250 | f1 = omp*omp2,
251 | f2 = 3*p*omp2,
252 | f3 = 3*p2*omp,
253 | f4 = p*p2;
254 | return [
255 | Math.round(b[0]*f1 + b[2]*f2 + b[4]*f3 + b[6]*f4), // bezier x
256 | Math.round(b[1]*f1 + b[3]*f2 + b[5]*f3 + b[7]*f4), // bezier y
257 | Math.round(p*1000)/10 // percentage with one decimal place
258 | ];
259 | };
260 |
261 | // base.points = [ sx,sy, csxo,csyo, cexo,ceyo, ex,ey ]
262 | // sx,sy = start x & y
263 | // csxo,csyo = control start x & y offset from start point
264 | // cexo,ceyo = control end x & y offset from end point
265 | // ex,ey = end x & y
266 | // convert needed for canvas - using the offset just makes the code easier to read
267 | // base.pointsxy = [ sx, sy, csx, csy, cex, cey, ex, ey ]
268 | base.convert2xy = function(p){
269 | p = p || base.points;
270 | return [
271 | p[0], p[1], // start x,y
272 | p[0] + p[2], p[1] + p[3], // start control x,y
273 | p[6] + p[4], p[7] + p[5], // end control x,y
274 | p[6], p[7] // end x,y
275 | ];
276 | };
277 |
278 | base.redraw = function(points) {
279 | // update from options
280 | base.points = base.options.points = points || base.options.points;
281 | // store array of x & y positions for cross reference
282 | base.pointsxy = base.convert2xy();
283 | // update grip
284 | base.update();
285 | // update curve
286 | base.drawCurve();
287 | base.setSlider(base.percent, null, true);
288 | };
289 |
290 | // Make purdy curve
291 | base.drawCurve = function() {
292 | var ctx, grad, tmp,
293 | points = base.pointsxy;
294 | if (!base.$el.find('canvas').length) {
295 | $('').appendTo(base.$el);
296 | // size in attribute needed to keep canvas size in proportion
297 | base.$canvas = base.$el.find('canvas').attr({ width: base.sliderDim[2], height: base.sliderDim[3] });
298 | base.canvas = base.$canvas[0];
299 | base.ctx = base.canvas.getContext("2d");
300 | }
301 | ctx = base.ctx;
302 | ctx.clearRect(0, 0, base.sliderDim[2], base.sliderDim[3]);
303 | ctx.lineCap = o.curve.cap;
304 | ctx.lineJoin = o.curve.cap;
305 | ctx.lineWidth = o.curve.width;
306 | // this can be a gradient or image as well. See
307 | // https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Applying_styles_and_colors
308 | if ($.isArray(o.curve.color)) {
309 | grad = ctx.createLinearGradient(points[0], points[1], points[6], points[7]);
310 | tmp = base.percent/100;
311 | grad.addColorStop(0, o.curve.color[0]);
312 | grad.addColorStop(tmp, o.curve.color[0]);
313 | if (tmp + 0.01 <= 1) { tmp += 0.01; }
314 | grad.addColorStop(tmp, o.curve.color[1]);
315 | grad.addColorStop(1, o.curve.color[1]);
316 | ctx.strokeStyle = grad;
317 | } else {
318 | ctx.strokeStyle = o.curve.color;
319 | }
320 | tmp = true;
321 | if (typeof o.drawCanvas === 'function') {
322 | // return anything except false to continue drawing the curve
323 | tmp = o.drawCanvas(base, ctx, points) !== false;
324 | ctx = base.ctx;
325 | }
326 | // tmp returned from drawCanvas; if
327 | if (tmp === true) {
328 | base.finishCurve(ctx, points);
329 | }
330 | };
331 |
332 | base.finishCurve = function(ctx, points) {
333 | ctx = ctx || base.ctx;
334 | points = points || base.pointsxy;
335 | ctx.beginPath();
336 | ctx.moveTo(points[0], points[1]);
337 | ctx.bezierCurveTo(points[2], points[3], points[4], points[5], points[6], points[7]);
338 | ctx.stroke();
339 | };
340 |
341 | // Run initializer
342 | base.init();
343 |
344 | };
345 |
346 | $.pathslider.defaults = {
347 |
348 | // Appearance
349 | gripClass : '', // class added to the grip/handle
350 | rotateGrip : true, // when true, the grip will rotate based on the shape of the path
351 |
352 | // canvas curve styling
353 | useCanvas : true,
354 | curve : { width: 4, color: "#333", cap: "round" },
355 |
356 | // Usability
357 | // sx,sy = start x & y
358 | // csxo,csyo = control start x & y offset from start point
359 | // cexo,ceyo = control end x & y offset from end point
360 | // ex,ey = end x & y
361 | // [ sx,sy, csxo,csyo, cexo,ceyo, ex,ey ]
362 | points : [ 0,50, 50,-50, -50,-50, 250,50 ],
363 |
364 | value : 50, // starting value - range 0 - 100%
365 | // min : 0, // minimum value on the slider
366 | // max : 100, // maximum value on the slider
367 | // step : 1, // step to use between min and max
368 |
369 | // Tweaking
370 | dataPoints: 100, // Total number of points of the curve to save; increase in increments of 100 to smooth out the grip movement, but not more than 500 (it slows everything down)
371 | tolerance : 3, // distance on the curve from the last position to check; increase this to scroll faster
372 | range : 30 // distance, in pixels, from the cursor to a matching x/y on the curve (should be about the same size as the grip)
373 |
374 | };
375 |
376 | $.fn.pathslider = function(options, callback){
377 | return this.each(function(){
378 | var percent, slider = $(this).data('pathslider');
379 |
380 | // initialize the slider but prevent multiple initializations
381 | if ((typeof(options)).match('object|undefined')){
382 | if (!slider) {
383 | (new $.pathslider(this, options));
384 | } else {
385 | return slider.redraw();
386 | }
387 | // If options is a number, set percentage
388 | } else if (/\d/.test(options) && !isNaN(options) && slider) {
389 | percent = (typeof(options) === "number") ? options : parseInt($.trim(options),10); // accepts " 2 "
390 | // ignore out of bound percentages
391 | if ( percent >= 0 && percent <= 100 ) {
392 | slider.setSlider(percent, callback); // set percent & callback
393 | }
394 | }
395 | });
396 | };
397 |
398 | $.fn.getpathslider = function(){
399 | return this.data('pathslider');
400 | };
401 |
402 | })(jQuery);
403 |
--------------------------------------------------------------------------------
/dist/jquery.pathslider.js:
--------------------------------------------------------------------------------
1 | /* jQuery Pathslider v1.0.0 alpha
2 | * By Rob Garrison (Mottie)
3 | * MIT License
4 | */
5 | (function($){
6 | $.pathslider = function(el, options){
7 |
8 | // To avoid scope issues, use 'base' instead of 'this'
9 | // to reference this class from internal events and functions.
10 | var base = this, o;
11 |
12 | // Access to jQuery and DOM versions of element
13 | base.$el = $(el).addClass('pathslider');
14 | base.el = el;
15 |
16 | // Add a reverse reference to the DOM object
17 | base.$el.data("pathslider", base);
18 |
19 | base.init = function(){
20 | var t;
21 | base.options = o = $.extend(true, {}, $.pathslider.defaults, options);
22 |
23 | // Is there a canvas?
24 | t = document.createElement('canvas');
25 | base.hasCanvas = !!(t.getContext && t.getContext('2d'));
26 | base.hasTouch = document.hasOwnProperty("ontouchend");
27 |
28 | // add grip
29 | base.$grip = $('').appendTo(base.$el);
30 |
31 | // store array of x & y positions for cross reference
32 | base.points = [];
33 | base.pointsxy = [];
34 | base.arrayX = [];
35 | base.arrayY = [];
36 | base.arrayP = [];
37 |
38 | base.rad2deg = 180 / Math.PI; // convert radians to degrees (multiply radian by this value)
39 | base.sliding = false; // flag for dragging element
40 | base.lastPercent = base.percent = o.value;
41 |
42 | // Callbacks
43 | // slide triggered on EVERY mouse move; change triggered on slide stop
44 | $.each('create update start slide change stop'.split(' '), function(i,f){
45 | if ($.isFunction(o[f])){
46 | base.$el.bind(f + '.pathslider', o[f]);
47 | }
48 | });
49 |
50 | $(document)
51 | .bind( base.hasTouch ? 'touchend.pathslider touchcancel.pathslider' : 'mouseup.pathslider mouseleave.pathslider', function(e){
52 | if (base.sliding) { // && ($(e.target).closest('.pathslider').length || e.type === 'mouseleave')) {
53 | base.$el.trigger('stop.pathslider', [base]);
54 | if (base.lastPercent !== base.percent) {
55 | base.lastPercent = base.percent;
56 | base.$el.trigger('change.pathslider', [base]);
57 | }
58 | }
59 | base.$grip.removeClass('sliding');
60 | base.sliding = false;
61 | })
62 | .bind( (base.hasTouch ? 'touchmove' : 'mousemove') + '.pathslider', function(e){
63 | if (base.sliding) {
64 | base.setSlider( base.findPos(e), null, true );
65 | }
66 | });
67 |
68 | $(window)
69 | .bind('resize.pathslider', function(){
70 | base.update();
71 | })
72 | .bind('load', function(){
73 | // needed because loading images/fonts will shift the page
74 | base.sliderDim[0] = base.$el.offset().left;
75 | base.sliderDim[1] = base.$el.offset().top;
76 | });
77 |
78 | base.$grip
79 | .bind( (base.hasTouch ? 'touchstart' : 'mousedown') + '.pathslider', function(e){
80 | base.sliding = true;
81 | $(this).addClass('sliding');
82 | base.$el.trigger('start.pathslider', [base]);
83 | return false;
84 | })
85 | .bind('click', function(){
86 | return false;
87 | });
88 |
89 | base.redraw();
90 |
91 | base.$el.trigger('create.pathslider', [base]);
92 |
93 | };
94 |
95 | // update dimensions & grip position
96 | base.update = function(){
97 |
98 | // using attr to remove other css grip classes when updating
99 | base.$grip.attr('class', 'pathslider-grip ' + o.gripClass);
100 |
101 | if (base.ctx) {
102 | // clear canvas *before* setting new dimensions
103 | // just in case the new size is smaller than the previous
104 | base.ctx.clearRect(0, 0, base.sliderDim[2], base.sliderDim[3]);
105 | }
106 |
107 | base.sliderDim = [
108 | base.$el.offset().left,
109 | base.$el.offset().top,
110 | base.$el.width(),
111 | base.$el.height()
112 | ];
113 |
114 | // get grip dimensions; jQuery v3+ width() & height() return the rotated dimensions
115 | // which we don't want!
116 | var computedStyle = window.getComputedStyle(base.$grip[0]);
117 | // for centering grip
118 | base.gripCenter = [ parseInt(computedStyle.width, 10)/2, parseInt(computedStyle.height, 10)/2 ];
119 |
120 | // number of data points to store - increase to smooth the animation (based on slider size)
121 | base.dataPoints = o.dataPoints;
122 | // in next update add min/max/step
123 | // base.range = o.max - o.min;
124 | // base.dataPoints = base.range * o.step;
125 |
126 | base.makeArray();
127 | // save the position in the array of the starting value (roughly)
128 | var t = $.inArray(base.percent, base.arrayP);
129 | base.position = (t === -1) ? Math.round(base.percent/100 * base.dataPoints) : t;
130 |
131 | base.setSlider(base.percent, null, true);
132 | if (base.hasCanvas && o.useCanvas) { base.drawCurve(); }
133 |
134 | };
135 |
136 | // set position of slider
137 | base.setSlider = function(percent, callback, internal) {
138 | if (!isNaN(percent)) {
139 | // find position on bezier curve; p = percent (range 0 - 100)
140 | // set position of slider without using the array (more precision)
141 | percent = parseFloat(percent, 10);
142 | percent = (percent > 100) ? 100 : percent < 0 ? 0 : percent;
143 | var css, angle,
144 | // pos = $.inArray(percent, base.arrayP),
145 | p = base.calcBezier(percent/100, base.pointsxy),
146 | pm1 = (percent - 2 > 0) ? base.calcBezier( (percent-2)/100, base.pointsxy ) : p,
147 | pp1 = (percent + 2 < 100) ? base.calcBezier( (percent+2)/100, base.pointsxy ) : p,
148 | // m = slope of tangent - used to change rotation angle of the grip
149 | // yes, I could have used the cubic derivative, but this is less math
150 | m = (pp1[0] - pm1[0] === 0) ? 90 : (pp1[1] - pm1[1])/(pp1[0] - pm1[0]);
151 | base.angle = parseInt(Math.atan(m) * base.rad2deg, 10);
152 | angle = 'rotate(' + base.angle + 'deg)';
153 | css = (o.rotateGrip) ? {
154 | '-webkit-transform' : angle,
155 | 'transform' : angle
156 | } : {};
157 | css.left = p[0] - base.gripCenter[0];
158 | css.top = p[1] - base.gripCenter[1];
159 | base.$grip
160 | .attr({
161 | 'data-angle' : base.angle,
162 | 'data-percent' : percent
163 | })
164 | .css(css);
165 | // find closest percent in the array - this relies on there being a factor
166 | // of 100 datapoints, so it'll need changing when we have a min/max/step
167 | base.percent = percent; // Math.round(percent*r)/r;
168 | if ((percent !== base.lastPercent && !base.sliding) || !internal) {
169 | base.$el.trigger('change.pathslider', [base]);
170 | }
171 | }
172 | if (typeof callback === 'function') { callback(base); }
173 | };
174 |
175 | // relative mouse position
176 | base.mousePos = function(e) {
177 | return [
178 | (e.originalEvent.touches ? e.originalEvent.touches[0].pageX : e.pageX) - base.sliderDim[0],
179 | (e.originalEvent.touches ? e.originalEvent.touches[0].pageY : e.pageY) - base.sliderDim[1]
180 | ];
181 | };
182 |
183 | // find percentage given the x,y coordinates
184 | // searching through a set array of points starting from the last known position
185 | // This allows the curve to loop over itself without mixing up intersecting points
186 | // The biggest issue is a very sharp turn
187 | base.findPos = function(event) {
188 | var i, j, dx, dy, px = [], py = [],
189 | last = base.position, //* base.dataPoints / 100,
190 | // check x & y cross ref based on nearby positions (+/- tolerance)
191 | t = parseInt(o.tolerance + 1, 10) || 2, // tolerance of 1 is too small
192 | r = parseInt(o.range, 10) || base.gripCenter[0], // set to 1/2 width of grip
193 | pos = base.mousePos(event);
194 | // save percent
195 | for ( i=0; i < r; i++ ){
196 | px = []; py = [];
197 | for ( j=0; j < t + 1; j++ ){
198 | // check positive direction
199 | dx = Math.abs(base.arrayX[last+j] - pos[0]) <= i;
200 | dy = Math.abs(base.arrayY[last+j] - pos[1]) <= i;
201 | if (dx && dy) { return base.returnPos(last+j); }
202 | if (dx) { px.push(last+j); }
203 | if (dy) { py.push(last+j); }
204 | // check in negative direction
205 | dx = Math.abs(base.arrayX[last-j] - pos[0]) <= i;
206 | dy = Math.abs(base.arrayY[last-j] - pos[1]) <= i;
207 | if (dx && dy) { return base.returnPos(last-j); }
208 | if (dx) { px.push(last-j); }
209 | if (dy) { py.push(last-j); }
210 | }
211 | if (px.length === 1 && py.length > 1) { return base.returnPos(px[0]); }
212 | if (py.length === 1 && px.length > 1) { return base.returnPos(py[0]); }
213 | }
214 | return base.returnPos(last);
215 | };
216 |
217 | // return found position & trigger slide event
218 | base.returnPos = function(p) {
219 | var t = base.position === p;
220 | base.percent = base.arrayP[p];
221 | base.position = p;
222 | if (!t) {
223 | if (base.hasCanvas && o.useCanvas) {
224 | base.drawCurve();
225 | }
226 | base.$el.trigger('slide.pathslider', [base] );
227 | }
228 | return base.percent;
229 | };
230 |
231 | // build cross-ref array - find position based on x,y coords
232 | base.makeArray = function(){
233 | var i, t, b = base.pointsxy,
234 | n = base.dataPoints;
235 | for ( i=0; i < n+1; i++ ){
236 | t = base.calcBezier(i/n, b);
237 | base.arrayX[i] = t[0];
238 | base.arrayY[i] = t[1];
239 | base.arrayP[i] = t[2];
240 | }
241 | };
242 |
243 | // Calculate bezier x & y based on percentage (p)
244 | // cubic bezier = start(p^3) + cstart(3*p^2*(1−p)) + cend(3*p*(1−p)^2) + end(1−p)^3
245 | // b = [ startx,starty, cstartx,cstarty, cendx,cendy, endx,endy ]
246 | base.calcBezier = function(p,b){
247 | var p2 = p*p,
248 | omp = (1-p), // omp = one minus p - smart naming ftw!
249 | omp2 = omp*omp,
250 | f1 = omp*omp2,
251 | f2 = 3*p*omp2,
252 | f3 = 3*p2*omp,
253 | f4 = p*p2;
254 | return [
255 | Math.round(b[0]*f1 + b[2]*f2 + b[4]*f3 + b[6]*f4), // bezier x
256 | Math.round(b[1]*f1 + b[3]*f2 + b[5]*f3 + b[7]*f4), // bezier y
257 | Math.round(p*1000)/10 // percentage with one decimal place
258 | ];
259 | };
260 |
261 | // base.points = [ sx,sy, csxo,csyo, cexo,ceyo, ex,ey ]
262 | // sx,sy = start x & y
263 | // csxo,csyo = control start x & y offset from start point
264 | // cexo,ceyo = control end x & y offset from end point
265 | // ex,ey = end x & y
266 | // convert needed for canvas - using the offset just makes the code easier to read
267 | // base.pointsxy = [ sx, sy, csx, csy, cex, cey, ex, ey ]
268 | base.convert2xy = function(p){
269 | p = p || base.points;
270 | return [
271 | p[0], p[1], // start x,y
272 | p[0] + p[2], p[1] + p[3], // start control x,y
273 | p[6] + p[4], p[7] + p[5], // end control x,y
274 | p[6], p[7] // end x,y
275 | ];
276 | };
277 |
278 | base.redraw = function(points) {
279 | // update from options
280 | base.points = base.options.points = points || base.options.points;
281 | // store array of x & y positions for cross reference
282 | base.pointsxy = base.convert2xy();
283 | // update grip
284 | base.update();
285 | // update curve
286 | base.drawCurve();
287 | base.setSlider(base.percent, null, true);
288 | };
289 |
290 | // Make purdy curve
291 | base.drawCurve = function() {
292 | var ctx, grad, tmp,
293 | points = base.pointsxy;
294 | if (!base.$el.find('canvas').length) {
295 | $('').appendTo(base.$el);
296 | // size in attribute needed to keep canvas size in proportion
297 | base.$canvas = base.$el.find('canvas').attr({ width: base.sliderDim[2], height: base.sliderDim[3] });
298 | base.canvas = base.$canvas[0];
299 | base.ctx = base.canvas.getContext("2d");
300 | }
301 | ctx = base.ctx;
302 | ctx.clearRect(0, 0, base.sliderDim[2], base.sliderDim[3]);
303 | ctx.lineCap = o.curve.cap;
304 | ctx.lineJoin = o.curve.cap;
305 | ctx.lineWidth = o.curve.width;
306 | // this can be a gradient or image as well. See
307 | // https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Applying_styles_and_colors
308 | if ($.isArray(o.curve.color)) {
309 | grad = ctx.createLinearGradient(points[0], points[1], points[6], points[7]);
310 | tmp = base.percent/100;
311 | grad.addColorStop(0, o.curve.color[0]);
312 | grad.addColorStop(tmp, o.curve.color[0]);
313 | if (tmp + 0.01 <= 1) { tmp += 0.01; }
314 | grad.addColorStop(tmp, o.curve.color[1]);
315 | grad.addColorStop(1, o.curve.color[1]);
316 | ctx.strokeStyle = grad;
317 | } else {
318 | ctx.strokeStyle = o.curve.color;
319 | }
320 | tmp = true;
321 | if (typeof o.drawCanvas === 'function') {
322 | // return anything except false to continue drawing the curve
323 | tmp = o.drawCanvas(base, ctx, points) !== false;
324 | ctx = base.ctx;
325 | }
326 | // tmp returned from drawCanvas; if
327 | if (tmp === true) {
328 | base.finishCurve(ctx, points);
329 | }
330 | };
331 |
332 | base.finishCurve = function(ctx, points) {
333 | ctx = ctx || base.ctx;
334 | points = points || base.pointsxy;
335 | ctx.beginPath();
336 | ctx.moveTo(points[0], points[1]);
337 | ctx.bezierCurveTo(points[2], points[3], points[4], points[5], points[6], points[7]);
338 | ctx.stroke();
339 | };
340 |
341 | // Run initializer
342 | base.init();
343 |
344 | };
345 |
346 | $.pathslider.defaults = {
347 |
348 | // Appearance
349 | gripClass : '', // class added to the grip/handle
350 | rotateGrip : true, // when true, the grip will rotate based on the shape of the path
351 |
352 | // canvas curve styling
353 | useCanvas : true,
354 | curve : { width: 4, color: "#333", cap: "round" },
355 |
356 | // Usability
357 | // sx,sy = start x & y
358 | // csxo,csyo = control start x & y offset from start point
359 | // cexo,ceyo = control end x & y offset from end point
360 | // ex,ey = end x & y
361 | // [ sx,sy, csxo,csyo, cexo,ceyo, ex,ey ]
362 | points : [ 0,50, 50,-50, -50,-50, 250,50 ],
363 |
364 | value : 50, // starting value - range 0 - 100%
365 | // min : 0, // minimum value on the slider
366 | // max : 100, // maximum value on the slider
367 | // step : 1, // step to use between min and max
368 |
369 | // Tweaking
370 | dataPoints: 100, // Total number of points of the curve to save; increase in increments of 100 to smooth out the grip movement, but not more than 500 (it slows everything down)
371 | tolerance : 3, // distance on the curve from the last position to check; increase this to scroll faster
372 | range : 30 // distance, in pixels, from the cursor to a matching x/y on the curve (should be about the same size as the grip)
373 |
374 | };
375 |
376 | $.fn.pathslider = function(options, callback){
377 | return this.each(function(){
378 | var percent, slider = $(this).data('pathslider');
379 |
380 | // initialize the slider but prevent multiple initializations
381 | if ((typeof(options)).match('object|undefined')){
382 | if (!slider) {
383 | (new $.pathslider(this, options));
384 | } else {
385 | return slider.redraw();
386 | }
387 | // If options is a number, set percentage
388 | } else if (/\d/.test(options) && !isNaN(options) && slider) {
389 | percent = (typeof(options) === "number") ? options : parseInt($.trim(options),10); // accepts " 2 "
390 | // ignore out of bound percentages
391 | if ( percent >= 0 && percent <= 100 ) {
392 | slider.setSlider(percent, callback); // set percent & callback
393 | }
394 | }
395 | });
396 | };
397 |
398 | $.fn.getpathslider = function(){
399 | return this.data('pathslider');
400 | };
401 |
402 | })(jQuery);
403 |
--------------------------------------------------------------------------------
/demo/colorpicker/colorpicker.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * Color picker
4 | * Author: Stefan Petre www.eyecon.ro
5 | *
6 | * Dual licensed under the MIT and GPL licenses
7 | *
8 | */
9 | (function ($) {
10 | var ColorPicker = function () {
11 | var
12 | ids = {},
13 | inAction,
14 | charMin = 65,
15 | visible,
16 | tpl = '',
17 | defaults = {
18 | eventName: 'click',
19 | onShow: function () {},
20 | onBeforeShow: function(){},
21 | onHide: function () {},
22 | onChange: function () {},
23 | onSubmit: function () {},
24 | color: 'ff0000',
25 | livePreview: true,
26 | flat: false
27 | },
28 | fillRGBFields = function (hsb, cal) {
29 | var rgb = HSBToRGB(hsb);
30 | $(cal).data('colorpicker').fields
31 | .eq(1).val(rgb.r).end()
32 | .eq(2).val(rgb.g).end()
33 | .eq(3).val(rgb.b).end();
34 | },
35 | fillHSBFields = function (hsb, cal) {
36 | $(cal).data('colorpicker').fields
37 | .eq(4).val(hsb.h).end()
38 | .eq(5).val(hsb.s).end()
39 | .eq(6).val(hsb.b).end();
40 | },
41 | fillHexFields = function (hsb, cal) {
42 | $(cal).data('colorpicker').fields
43 | .eq(0).val(HSBToHex(hsb)).end();
44 | },
45 | setSelector = function (hsb, cal) {
46 | $(cal).data('colorpicker').selector.css('backgroundColor', '#' + HSBToHex({h: hsb.h, s: 100, b: 100}));
47 | $(cal).data('colorpicker').selectorIndic.css({
48 | left: parseInt(150 * hsb.s/100, 10),
49 | top: parseInt(150 * (100-hsb.b)/100, 10)
50 | });
51 | },
52 | setHue = function (hsb, cal) {
53 | $(cal).data('colorpicker').hue.css('top', parseInt(150 - 150 * hsb.h/360, 10));
54 | },
55 | setCurrentColor = function (hsb, cal) {
56 | $(cal).data('colorpicker').currentColor.css('backgroundColor', '#' + HSBToHex(hsb));
57 | },
58 | setNewColor = function (hsb, cal) {
59 | $(cal).data('colorpicker').newColor.css('backgroundColor', '#' + HSBToHex(hsb));
60 | },
61 | keyDown = function (ev) {
62 | var pressedKey = ev.charCode || ev.keyCode || -1;
63 | if ((pressedKey > charMin && pressedKey <= 90) || pressedKey == 32) {
64 | return false;
65 | }
66 | var cal = $(this).parent().parent();
67 | if (cal.data('colorpicker').livePreview === true) {
68 | change.apply(this);
69 | }
70 | },
71 | change = function (ev) {
72 | var cal = $(this).parent().parent(), col;
73 | if (this.parentNode.className.indexOf('_hex') > 0) {
74 | cal.data('colorpicker').color = col = HexToHSB(fixHex(this.value));
75 | } else if (this.parentNode.className.indexOf('_hsb') > 0) {
76 | cal.data('colorpicker').color = col = fixHSB({
77 | h: parseInt(cal.data('colorpicker').fields.eq(4).val(), 10),
78 | s: parseInt(cal.data('colorpicker').fields.eq(5).val(), 10),
79 | b: parseInt(cal.data('colorpicker').fields.eq(6).val(), 10)
80 | });
81 | } else {
82 | cal.data('colorpicker').color = col = RGBToHSB(fixRGB({
83 | r: parseInt(cal.data('colorpicker').fields.eq(1).val(), 10),
84 | g: parseInt(cal.data('colorpicker').fields.eq(2).val(), 10),
85 | b: parseInt(cal.data('colorpicker').fields.eq(3).val(), 10)
86 | }));
87 | }
88 | if (ev) {
89 | fillRGBFields(col, cal.get(0));
90 | fillHexFields(col, cal.get(0));
91 | fillHSBFields(col, cal.get(0));
92 | }
93 | setSelector(col, cal.get(0));
94 | setHue(col, cal.get(0));
95 | setNewColor(col, cal.get(0));
96 | cal.data('colorpicker').onChange.apply(cal, [col, HSBToHex(col), HSBToRGB(col)]);
97 | },
98 | blur = function (ev) {
99 | var cal = $(this).parent().parent();
100 | cal.data('colorpicker').fields.parent().removeClass('colorpicker_focus');
101 | },
102 | focus = function () {
103 | charMin = this.parentNode.className.indexOf('_hex') > 0 ? 70 : 65;
104 | $(this).parent().parent().data('colorpicker').fields.parent().removeClass('colorpicker_focus');
105 | $(this).parent().addClass('colorpicker_focus');
106 | },
107 | downIncrement = function (ev) {
108 | var field = $(this).parent().find('input').focus();
109 | var current = {
110 | el: $(this).parent().addClass('colorpicker_slider'),
111 | max: this.parentNode.className.indexOf('_hsb_h') > 0 ? 360 : (this.parentNode.className.indexOf('_hsb') > 0 ? 100 : 255),
112 | y: ev.pageY,
113 | field: field,
114 | val: parseInt(field.val(), 10),
115 | preview: $(this).parent().parent().data('colorpicker').livePreview
116 | };
117 | $(document).bind('mouseup', current, upIncrement);
118 | $(document).bind('mousemove', current, moveIncrement);
119 | },
120 | moveIncrement = function (ev) {
121 | ev.data.field.val(Math.max(0, Math.min(ev.data.max, parseInt(ev.data.val + ev.pageY - ev.data.y, 10))));
122 | if (ev.data.preview) {
123 | change.apply(ev.data.field.get(0), [true]);
124 | }
125 | return false;
126 | },
127 | upIncrement = function (ev) {
128 | change.apply(ev.data.field.get(0), [true]);
129 | ev.data.el.removeClass('colorpicker_slider').find('input').focus();
130 | $(document).unbind('mouseup', upIncrement);
131 | $(document).unbind('mousemove', moveIncrement);
132 | return false;
133 | },
134 | downHue = function (ev) {
135 | var current = {
136 | cal: $(this).parent(),
137 | y: $(this).offset().top
138 | };
139 | current.preview = current.cal.data('colorpicker').livePreview;
140 | $(document).bind('mouseup', current, upHue);
141 | $(document).bind('mousemove', current, moveHue);
142 | },
143 | moveHue = function (ev) {
144 | change.apply(
145 | ev.data.cal.data('colorpicker')
146 | .fields
147 | .eq(4)
148 | .val(parseInt(360*(150 - Math.max(0,Math.min(150,(ev.pageY - ev.data.y))))/150, 10))
149 | .get(0),
150 | [ev.data.preview]
151 | );
152 | return false;
153 | },
154 | upHue = function (ev) {
155 | fillRGBFields(ev.data.cal.data('colorpicker').color, ev.data.cal.get(0));
156 | fillHexFields(ev.data.cal.data('colorpicker').color, ev.data.cal.get(0));
157 | $(document).unbind('mouseup', upHue);
158 | $(document).unbind('mousemove', moveHue);
159 | return false;
160 | },
161 | downSelector = function (ev) {
162 | var current = {
163 | cal: $(this).parent(),
164 | pos: $(this).offset()
165 | };
166 | current.preview = current.cal.data('colorpicker').livePreview;
167 | $(document).bind('mouseup', current, upSelector);
168 | $(document).bind('mousemove', current, moveSelector);
169 | },
170 | moveSelector = function (ev) {
171 | change.apply(
172 | ev.data.cal.data('colorpicker')
173 | .fields
174 | .eq(6)
175 | .val(parseInt(100*(150 - Math.max(0,Math.min(150,(ev.pageY - ev.data.pos.top))))/150, 10))
176 | .end()
177 | .eq(5)
178 | .val(parseInt(100*(Math.max(0,Math.min(150,(ev.pageX - ev.data.pos.left))))/150, 10))
179 | .get(0),
180 | [ev.data.preview]
181 | );
182 | return false;
183 | },
184 | upSelector = function (ev) {
185 | fillRGBFields(ev.data.cal.data('colorpicker').color, ev.data.cal.get(0));
186 | fillHexFields(ev.data.cal.data('colorpicker').color, ev.data.cal.get(0));
187 | $(document).unbind('mouseup', upSelector);
188 | $(document).unbind('mousemove', moveSelector);
189 | return false;
190 | },
191 | enterSubmit = function (ev) {
192 | $(this).addClass('colorpicker_focus');
193 | },
194 | leaveSubmit = function (ev) {
195 | $(this).removeClass('colorpicker_focus');
196 | },
197 | clickSubmit = function (ev) {
198 | var cal = $(this).parent();
199 | var col = cal.data('colorpicker').color;
200 | cal.data('colorpicker').origColor = col;
201 | setCurrentColor(col, cal.get(0));
202 | cal.data('colorpicker').onSubmit(col, HSBToHex(col), HSBToRGB(col), cal.data('colorpicker').el);
203 | },
204 | show = function (ev) {
205 | var cal = $('#' + $(this).data('colorpickerId'));
206 | cal.data('colorpicker').onBeforeShow.apply(this, [cal.get(0)]);
207 | var pos = $(this).offset();
208 | var viewPort = getViewport();
209 | var top = pos.top + this.offsetHeight;
210 | var left = pos.left;
211 | if (top + 176 > viewPort.t + viewPort.h) {
212 | top -= this.offsetHeight + 176;
213 | }
214 | if (left + 356 > viewPort.l + viewPort.w) {
215 | left -= 356;
216 | }
217 | cal.css({left: left + 'px', top: top + 'px'});
218 | if (cal.data('colorpicker').onShow.apply(this, [cal.get(0)]) != false) {
219 | cal.show();
220 | }
221 | $(document).bind('mousedown', {cal: cal}, hide);
222 | return false;
223 | },
224 | hide = function (ev) {
225 | if (!isChildOf(ev.data.cal.get(0), ev.target, ev.data.cal.get(0))) {
226 | if (ev.data.cal.data('colorpicker').onHide.apply(this, [ev.data.cal.get(0)]) != false) {
227 | ev.data.cal.hide();
228 | }
229 | $(document).unbind('mousedown', hide);
230 | }
231 | },
232 | isChildOf = function(parentEl, el, container) {
233 | if (parentEl == el) {
234 | return true;
235 | }
236 | if (parentEl.contains) {
237 | return parentEl.contains(el);
238 | }
239 | if ( parentEl.compareDocumentPosition ) {
240 | return !!(parentEl.compareDocumentPosition(el) & 16);
241 | }
242 | var prEl = el.parentNode;
243 | while(prEl && prEl != container) {
244 | if (prEl == parentEl)
245 | return true;
246 | prEl = prEl.parentNode;
247 | }
248 | return false;
249 | },
250 | getViewport = function () {
251 | var m = document.compatMode == 'CSS1Compat';
252 | return {
253 | l : window.pageXOffset || (m ? document.documentElement.scrollLeft : document.body.scrollLeft),
254 | t : window.pageYOffset || (m ? document.documentElement.scrollTop : document.body.scrollTop),
255 | w : window.innerWidth || (m ? document.documentElement.clientWidth : document.body.clientWidth),
256 | h : window.innerHeight || (m ? document.documentElement.clientHeight : document.body.clientHeight)
257 | };
258 | },
259 | fixHSB = function (hsb) {
260 | return {
261 | h: Math.min(360, Math.max(0, hsb.h)),
262 | s: Math.min(100, Math.max(0, hsb.s)),
263 | b: Math.min(100, Math.max(0, hsb.b))
264 | };
265 | },
266 | fixRGB = function (rgb) {
267 | return {
268 | r: Math.min(255, Math.max(0, rgb.r)),
269 | g: Math.min(255, Math.max(0, rgb.g)),
270 | b: Math.min(255, Math.max(0, rgb.b))
271 | };
272 | },
273 | fixHex = function (hex) {
274 | var len = 6 - hex.length;
275 | if (len > 0) {
276 | var o = [];
277 | for (var i=0; i -1) ? hex.substring(1) : hex), 16);
287 | return {r: hex >> 16, g: (hex & 0x00FF00) >> 8, b: (hex & 0x0000FF)};
288 | },
289 | HexToHSB = function (hex) {
290 | return RGBToHSB(HexToRGB(hex));
291 | },
292 | RGBToHSB = function (rgb) {
293 | var hsb = {
294 | h: 0,
295 | s: 0,
296 | b: 0
297 | };
298 | var min = Math.min(rgb.r, rgb.g, rgb.b);
299 | var max = Math.max(rgb.r, rgb.g, rgb.b);
300 | var delta = max - min;
301 | hsb.b = max;
302 | if (max != 0) {
303 |
304 | }
305 | hsb.s = max != 0 ? 255 * delta / max : 0;
306 | if (hsb.s != 0) {
307 | if (rgb.r == max) {
308 | hsb.h = (rgb.g - rgb.b) / delta;
309 | } else if (rgb.g == max) {
310 | hsb.h = 2 + (rgb.b - rgb.r) / delta;
311 | } else {
312 | hsb.h = 4 + (rgb.r - rgb.g) / delta;
313 | }
314 | } else {
315 | hsb.h = -1;
316 | }
317 | hsb.h *= 60;
318 | if (hsb.h < 0) {
319 | hsb.h += 360;
320 | }
321 | hsb.s *= 100/255;
322 | hsb.b *= 100/255;
323 | return hsb;
324 | },
325 | HSBToRGB = function (hsb) {
326 | var rgb = {};
327 | var h = Math.round(hsb.h);
328 | var s = Math.round(hsb.s*255/100);
329 | var v = Math.round(hsb.b*255/100);
330 | if(s == 0) {
331 | rgb.r = rgb.g = rgb.b = v;
332 | } else {
333 | var t1 = v;
334 | var t2 = (255-s)*v/255;
335 | var t3 = (t1-t2)*(h%60)/60;
336 | if(h==360) h = 0;
337 | if(h<60) {rgb.r=t1; rgb.b=t2; rgb.g=t2+t3}
338 | else if(h<120) {rgb.g=t1; rgb.b=t2; rgb.r=t1-t3}
339 | else if(h<180) {rgb.g=t1; rgb.r=t2; rgb.b=t2+t3}
340 | else if(h<240) {rgb.b=t1; rgb.r=t2; rgb.g=t1-t3}
341 | else if(h<300) {rgb.b=t1; rgb.g=t2; rgb.r=t2+t3}
342 | else if(h<360) {rgb.r=t1; rgb.g=t2; rgb.b=t1-t3}
343 | else {rgb.r=0; rgb.g=0; rgb.b=0}
344 | }
345 | return {r:Math.round(rgb.r), g:Math.round(rgb.g), b:Math.round(rgb.b)};
346 | },
347 | RGBToHex = function (rgb) {
348 | var hex = [
349 | rgb.r.toString(16),
350 | rgb.g.toString(16),
351 | rgb.b.toString(16)
352 | ];
353 | $.each(hex, function (nr, val) {
354 | if (val.length == 1) {
355 | hex[nr] = '0' + val;
356 | }
357 | });
358 | return hex.join('');
359 | },
360 | HSBToHex = function (hsb) {
361 | return RGBToHex(HSBToRGB(hsb));
362 | },
363 | restoreOriginal = function () {
364 | var cal = $(this).parent();
365 | var col = cal.data('colorpicker').origColor;
366 | cal.data('colorpicker').color = col;
367 | fillRGBFields(col, cal.get(0));
368 | fillHexFields(col, cal.get(0));
369 | fillHSBFields(col, cal.get(0));
370 | setSelector(col, cal.get(0));
371 | setHue(col, cal.get(0));
372 | setNewColor(col, cal.get(0));
373 | };
374 | return {
375 | init: function (opt) {
376 | opt = $.extend({}, defaults, opt||{});
377 | if (typeof opt.color == 'string') {
378 | opt.color = HexToHSB(opt.color);
379 | } else if (opt.color.r != undefined && opt.color.g != undefined && opt.color.b != undefined) {
380 | opt.color = RGBToHSB(opt.color);
381 | } else if (opt.color.h != undefined && opt.color.s != undefined && opt.color.b != undefined) {
382 | opt.color = fixHSB(opt.color);
383 | } else {
384 | return this;
385 | }
386 | return this.each(function () {
387 | if (!$(this).data('colorpickerId')) {
388 | var options = $.extend({}, opt);
389 | options.origColor = opt.color;
390 | var id = 'collorpicker_' + parseInt(Math.random() * 1000);
391 | $(this).data('colorpickerId', id);
392 | var cal = $(tpl).attr('id', id);
393 | if (options.flat) {
394 | cal.appendTo(this).show();
395 | } else {
396 | cal.appendTo(document.body);
397 | }
398 | options.fields = cal
399 | .find('input')
400 | .bind('keyup', keyDown)
401 | .bind('change', change)
402 | .bind('blur', blur)
403 | .bind('focus', focus);
404 | cal
405 | .find('span').bind('mousedown', downIncrement).end()
406 | .find('>div.colorpicker_current_color').bind('click', restoreOriginal);
407 | options.selector = cal.find('div.colorpicker_color').bind('mousedown', downSelector);
408 | options.selectorIndic = options.selector.find('div div');
409 | options.el = this;
410 | options.hue = cal.find('div.colorpicker_hue div');
411 | cal.find('div.colorpicker_hue').bind('mousedown', downHue);
412 | options.newColor = cal.find('div.colorpicker_new_color');
413 | options.currentColor = cal.find('div.colorpicker_current_color');
414 | cal.data('colorpicker', options);
415 | cal.find('div.colorpicker_submit')
416 | .bind('mouseenter', enterSubmit)
417 | .bind('mouseleave', leaveSubmit)
418 | .bind('click', clickSubmit);
419 | fillRGBFields(options.color, cal.get(0));
420 | fillHSBFields(options.color, cal.get(0));
421 | fillHexFields(options.color, cal.get(0));
422 | setHue(options.color, cal.get(0));
423 | setSelector(options.color, cal.get(0));
424 | setCurrentColor(options.color, cal.get(0));
425 | setNewColor(options.color, cal.get(0));
426 | if (options.flat) {
427 | cal.css({
428 | position: 'relative',
429 | display: 'block'
430 | });
431 | } else {
432 | $(this).bind(options.eventName, show);
433 | }
434 | }
435 | });
436 | },
437 | showPicker: function() {
438 | return this.each( function () {
439 | if ($(this).data('colorpickerId')) {
440 | show.apply(this);
441 | }
442 | });
443 | },
444 | hidePicker: function() {
445 | return this.each( function () {
446 | if ($(this).data('colorpickerId')) {
447 | $('#' + $(this).data('colorpickerId')).hide();
448 | }
449 | });
450 | },
451 | setColor: function(col) {
452 | if (typeof col == 'string') {
453 | col = HexToHSB(col);
454 | } else if (col.r != undefined && col.g != undefined && col.b != undefined) {
455 | col = RGBToHSB(col);
456 | } else if (col.h != undefined && col.s != undefined && col.b != undefined) {
457 | col = fixHSB(col);
458 | } else {
459 | return this;
460 | }
461 | return this.each(function(){
462 | if ($(this).data('colorpickerId')) {
463 | var cal = $('#' + $(this).data('colorpickerId'));
464 | cal.data('colorpicker').color = col;
465 | cal.data('colorpicker').origColor = col;
466 | fillRGBFields(col, cal.get(0));
467 | fillHSBFields(col, cal.get(0));
468 | fillHexFields(col, cal.get(0));
469 | setHue(col, cal.get(0));
470 | setSelector(col, cal.get(0));
471 | setCurrentColor(col, cal.get(0));
472 | setNewColor(col, cal.get(0));
473 | }
474 | });
475 | }
476 | };
477 | }();
478 | $.fn.extend({
479 | ColorPicker: ColorPicker.init,
480 | ColorPickerHide: ColorPicker.hidePicker,
481 | ColorPickerShow: ColorPicker.showPicker,
482 | ColorPickerSetColor: ColorPicker.setColor
483 | });
484 | })(jQuery)
--------------------------------------------------------------------------------