├── .browserslistrc ├── .eslintrc.js ├── .gitignore ├── .npmignore ├── .prettierrc ├── CHANGELOG.md ├── LICENSE ├── README.md ├── babel.config.js ├── package.json ├── postcss.config.js ├── public └── index.html ├── resources ├── data.json ├── header.png └── histogram-slider-demo.gif ├── src ├── App.vue ├── lib │ ├── HistogramSlider.vue │ ├── props.js │ └── range-slider.js └── main.js ├── vue.config.js └── yarn.lock /.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true 5 | }, 6 | extends: ['plugin:vue/essential', '@vue/prettier'], 7 | rules: { 8 | 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off', 9 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off' 10 | }, 11 | parserOptions: { 12 | parser: 'babel-eslint' 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw? -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | resources 2 | public 3 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "tabWidth": 2, 4 | "useTabs": false, 5 | "semi": false, 6 | "singleQuote": true, 7 | "trailingComma": "none", 8 | "bracketSpacing": true, 9 | "jsxBracketSameLine": false, 10 | "fluid": false 11 | } 12 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # ChangeLog 2 | 3 | ## v0.3.5 4 | 5 | ### New Features 6 | - Added handle size prop 7 | 8 | ## v0.3.3 9 | 10 | ### Bug Fix 11 | - Fixed hist color issue 12 | 13 | ## v0.3.2 14 | 15 | ### Bug Fix 16 | - Performance improvements 17 | 18 | ## v0.3.1 19 | 20 | ### Bug Fix 21 | - Histogram clip issue fixed 22 | 23 | ## v0.3.0 24 | 25 | ### New Features 26 | - Add histogram clip 27 | 28 | ## v0.2.1 29 | 30 | ### Bug Fix 31 | - First and lash histogram bar color not change problem fixed 32 | 33 | ## v0.2.0 34 | 35 | ### New Features 36 | - `min`, `max` props are not required 37 | - `type` 'single' option is completed 38 | 39 | ## v0.1.0 -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Oguzhan Inan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 |

5 | Range slider with histogram for Vue 6 |

7 |

8 | 9 | npm 10 | GitHub issues 11 | npm 12 |

13 |
14 | 15 | ## 🚀 Quick Start 16 | If you are a try and learn developer, you can start trying the vue-histogram-slider now using codesandbox.io. 17 | 18 | 19 | Edit Vue Histogram Slider 20 | 21 | 22 | 23 |

24 | 25 |

26 | 27 | ## 📦 Installation 28 | ### yarn 29 | `yarn add vue-histogram-slider` 30 | 31 | ### npm 32 | `npm i vue-histogram-slider` 33 | 34 | ## 🔧 Usage 35 | ```js 36 | import Vue from 'vue'; 37 | import HistogramSlider from 'vue-histogram-slider'; 38 | import 'vue-histogram-slider/dist/histogram-slider.css'; 39 | 40 | Vue.component(HistogramSlider.name, HistogramSlider); 41 | ``` 42 | 43 | ```xml 44 | 49 | ``` 50 | 51 | ## 📋 Props 52 | 53 | Property |Type|Default|Description 54 | ---|:---:|:---:|--- 55 | min|number|1|Set slider minimum value 56 | max|number|100|Set slider maximum value 57 | data|array| - |Data for histogram 58 | block|boolean|false|Locks slider and makes it inactive 59 | grid|boolean|true|Enables grid of values. 60 | gridNum|number|4|Number of grid units. 61 | step|number|1|Set sliders step. Always > 0. Could be fractional. 62 | hideMinMax|boolean|true|Hides min and max labels 63 | hideFromTo|boolean|false|Hides from and to labels 64 | toFixed|boolean|false|Fix position of right handle. 65 | fromFixed|boolean|false|Fix position of left (or single) handle. 66 | forceEdges|boolean|false|Slider will be always inside it's container. 67 | dragInterval|boolean|false|Allow user to drag whole range. Only in double type 68 | keyboard|boolean|true|Activates keyboard controls. Move left: ←, ↓, A, S. Move right: →, ↑, W, D. 69 | type|string|double|Choose slider type, could be single - for one handle, or double for two handles 70 | width|number|600|width of dialog 71 | barHeight|number|100|Set max histogram bar height 72 | barWidth|number|6|Set histogram bar width 73 | barGap|number|5|Set histogram bar gap 74 | barRadius|number|4|Set histogram bar radius 75 | prettify|function|null|Set up your own prettify function. Can be anything. For example, you can set up unix time as slider values and than transform them to cool looking dates. 76 | lineHeight|number|6|Set slider line height 77 | transitionDuration|number|100|Set duration to histogram bars 78 | primaryColor|string|#0091ff|Primary color 79 | labelColor|string|#0091ff|Label color 80 | holderColor|string|#dee4ec|Holder color 81 | handleColor|string|#ffffff|Slider handle color 82 | gridTextColor|string|silver|Primary color 83 | fontFamily|string|'Arial, sans-serif'|Set text font family 84 | fontSize|number|12|Set text font size 85 | handleSize|number|26|Slider handle size 86 | histSliderGap|number|6|Set gap between slider and histogram 87 | updateColorOnChange|boolean|true|Update histogram bar color on change **(recommended false for performance)** 88 | 89 | ## 🔧 Event 90 | Name|Description 91 | ---|--- 92 | start |Triggers when slider start. 93 | change|Triggers when each values change. 94 | update|Triggers when slider is modified by external methods update or reset. 95 | finish|Triggers when user releases handle. 96 | 97 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['@vue/app'] 3 | } 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-histogram-slider", 3 | "description": "Range slider with histogram for vue.js", 4 | "version": "0.3.8", 5 | "main": "dist/histogram-slider.umd.min.js", 6 | "license": "MIT", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/oguzhaninan/vue-histogram-slider.git" 10 | }, 11 | "keywords": [ 12 | "vue", 13 | "vuejs", 14 | "slider", 15 | "range-slider", 16 | "histogram", 17 | "histogram-slider" 18 | ], 19 | "scripts": { 20 | "serve": "vue-cli-service serve", 21 | "prepare": "yarn build", 22 | "build": "vue-cli-service build --name histogram-slider --entry ./src/lib/HistogramSlider.vue --target lib", 23 | "prepublishOnly": "yarn lint && yarn build", 24 | "lint": "vue-cli-service lint" 25 | }, 26 | "dependencies": { 27 | "d3-array": "^2.3.2", 28 | "d3-brush": "^1.1.3", 29 | "d3-scale": "^3.1.0", 30 | "d3-selection": "^1.4.0", 31 | "d3-transition": "^1.2.0", 32 | "jquery": "3.5", 33 | "vue": "^2.6.10" 34 | }, 35 | "devDependencies": { 36 | "@vue/cli-plugin-babel": "^3.11.0", 37 | "@vue/cli-plugin-eslint": "^3.11.0", 38 | "@vue/cli-service": "^3.11.0", 39 | "@vue/eslint-config-prettier": "^5.0.0", 40 | "babel-eslint": "^10.0.1", 41 | "eslint": "^5.16.0", 42 | "eslint-plugin-prettier": "^3.1.0", 43 | "eslint-plugin-vue": "^5.0.0", 44 | "lint-staged": "^8.1.5", 45 | "prettier": "^1.18.2", 46 | "vue-template-compiler": "^2.6.10" 47 | }, 48 | "gitHooks": { 49 | "pre-commit": "lint-staged" 50 | }, 51 | "lint-staged": { 52 | "*.{js,vue}": [ 53 | "vue-cli-service lint", 54 | "git add" 55 | ] 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | autoprefixer: {} 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | vue-histogram-slider 8 | 9 | 10 | 13 |
14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /resources/data.json: -------------------------------------------------------------------------------- 1 | ["2004-11-23T22:00:00.000Z", "2005-02-28T22:00:00.000Z", "2005-03-09T22:00:00.000Z", "2005-03-21T22:00:00.000Z", "2005-05-06T21:00:00.000Z", "2005-06-01T21:00:00.000Z", "2005-06-13T21:00:00.000Z", "2005-06-30T21:00:00.000Z", "2005-07-03T21:00:00.000Z", "2005-07-14T21:00:00.000Z", "2005-07-30T21:00:00.000Z", "2005-08-30T21:00:00.000Z", "2005-08-31T21:00:00.000Z", "2005-09-30T21:00:00.000Z", "2005-11-13T22:00:00.000Z", "2005-11-30T22:00:00.000Z", "2005-12-08T22:00:00.000Z", "2005-12-14T22:00:00.000Z", "2005-12-18T22:00:00.000Z", "2005-12-28T22:00:00.000Z", "2006-02-06T22:00:00.000Z", "2006-02-13T22:00:00.000Z", "2006-02-14T22:00:00.000Z", "2006-02-14T22:00:00.000Z", "2006-03-14T22:00:00.000Z", "2006-03-16T22:00:00.000Z", "2006-03-31T21:00:00.000Z", "2006-04-04T21:00:00.000Z", "2006-04-05T21:00:00.000Z", "2006-04-11T21:00:00.000Z", "2006-04-23T21:00:00.000Z", "2006-04-30T21:00:00.000Z", "2006-05-09T21:00:00.000Z", "2006-05-11T21:00:00.000Z", "2006-05-11T21:00:00.000Z", "2006-05-25T21:00:00.000Z", "2006-05-29T21:00:00.000Z", "2006-06-01T21:00:00.000Z", "2006-06-06T21:00:00.000Z", "2006-06-07T21:00:00.000Z", "2006-06-08T21:00:00.000Z", "2006-06-13T21:00:00.000Z", "2006-06-15T21:00:00.000Z", "2006-06-20T21:00:00.000Z", "2006-06-25T21:00:00.000Z", "2006-06-27T21:00:00.000Z", "2006-07-04T21:00:00.000Z", "2006-07-04T21:00:00.000Z", "2006-07-06T21:00:00.000Z", "2006-07-31T21:00:00.000Z", "2006-08-02T21:00:00.000Z", "2006-08-20T21:00:00.000Z", "2006-08-22T21:00:00.000Z", "2006-09-13T21:00:00.000Z", "2006-09-27T21:00:00.000Z", "2006-09-30T21:00:00.000Z", "2006-09-30T21:00:00.000Z", "2006-10-05T21:00:00.000Z", "2006-10-17T21:00:00.000Z", "2006-10-19T21:00:00.000Z", "2006-10-24T21:00:00.000Z", "2006-11-06T22:00:00.000Z", "2006-11-09T22:00:00.000Z", "2006-11-10T22:00:00.000Z", "2006-11-19T22:00:00.000Z", "2006-11-21T22:00:00.000Z", "2006-11-30T22:00:00.000Z", "2006-12-11T22:00:00.000Z", "2006-12-17T22:00:00.000Z", "2006-12-18T22:00:00.000Z", "2006-12-18T22:00:00.000Z", "2006-12-19T22:00:00.000Z", "2006-12-20T22:00:00.000Z", "2006-12-23T22:00:00.000Z", "2006-12-25T22:00:00.000Z", "2006-12-26T22:00:00.000Z", "2006-12-27T22:00:00.000Z", "2006-12-28T22:00:00.000Z", "2007-01-22T22:00:00.000Z", "2007-01-29T22:00:00.000Z", "2007-01-30T22:00:00.000Z", "2007-01-31T22:00:00.000Z", "2007-02-24T22:00:00.000Z", "2007-02-24T22:00:00.000Z", "2007-03-04T22:00:00.000Z", "2007-03-10T22:00:00.000Z", "2007-03-11T22:00:00.000Z", "2007-03-12T22:00:00.000Z", "2007-03-13T22:00:00.000Z", "2007-03-15T22:00:00.000Z", "2007-03-25T21:00:00.000Z", "2007-04-01T21:00:00.000Z", "2007-04-02T21:00:00.000Z", "2007-04-07T21:00:00.000Z", "2007-04-08T21:00:00.000Z", "2007-04-12T21:00:00.000Z", "2007-04-22T21:00:00.000Z", "2007-04-23T21:00:00.000Z", "2007-04-23T21:00:00.000Z", "2007-04-25T21:00:00.000Z", "2007-04-29T21:00:00.000Z", "2007-05-04T21:00:00.000Z", "2007-05-14T21:00:00.000Z", "2007-05-15T21:00:00.000Z", "2007-05-17T21:00:00.000Z", "2007-05-23T21:00:00.000Z", "2007-05-24T21:00:00.000Z", "2007-06-12T21:00:00.000Z", "2007-06-15T21:00:00.000Z", "2007-06-24T21:00:00.000Z", "2007-06-26T21:00:00.000Z", "2007-07-05T21:00:00.000Z", "2007-07-18T21:00:00.000Z", "2007-07-22T21:00:00.000Z", "2007-08-01T21:00:00.000Z", "2007-08-03T21:00:00.000Z", "2007-08-12T21:00:00.000Z", "2007-08-31T21:00:00.000Z", "2007-08-31T21:00:00.000Z", "2007-09-05T21:00:00.000Z", "2007-09-11T21:00:00.000Z", "2007-09-13T21:00:00.000Z", "2007-09-16T21:00:00.000Z", "2007-09-24T21:00:00.000Z", "2007-09-27T21:00:00.000Z", "2007-10-07T21:00:00.000Z", "2007-10-10T21:00:00.000Z", "2007-10-18T21:00:00.000Z", "2007-10-21T21:00:00.000Z", "2007-10-23T21:00:00.000Z", "2007-10-29T22:00:00.000Z", "2007-10-31T22:00:00.000Z", "2007-10-31T22:00:00.000Z", "2007-11-01T22:00:00.000Z", "2007-11-04T22:00:00.000Z", "2007-11-05T22:00:00.000Z", "2007-11-08T22:00:00.000Z", "2007-11-10T22:00:00.000Z", "2007-11-11T22:00:00.000Z", "2007-11-13T22:00:00.000Z", "2007-11-19T22:00:00.000Z", "2007-11-21T22:00:00.000Z", "2007-11-24T22:00:00.000Z", "2007-11-25T22:00:00.000Z", "2007-12-04T22:00:00.000Z", "2007-12-10T22:00:00.000Z", "2007-12-10T22:00:00.000Z", "2007-12-27T22:00:00.000Z", "2007-12-31T22:00:00.000Z", "2008-02-05T22:00:00.000Z", "2008-02-27T22:00:00.000Z", "2008-02-29T22:00:00.000Z", "2008-02-29T22:00:00.000Z", "2008-02-29T22:00:00.000Z", "2008-03-04T22:00:00.000Z", "2008-03-05T22:00:00.000Z", "2008-03-08T22:00:00.000Z", "2008-03-10T22:00:00.000Z", "2008-03-17T22:00:00.000Z", "2008-03-31T21:00:00.000Z", "2008-03-31T21:00:00.000Z", "2008-04-24T21:00:00.000Z", "2008-04-27T21:00:00.000Z", "2008-04-27T21:00:00.000Z", "2008-04-27T21:00:00.000Z", "2008-04-28T21:00:00.000Z", "2008-04-28T21:00:00.000Z", "2008-04-28T21:00:00.000Z", "2008-04-28T21:00:00.000Z", "2008-04-30T21:00:00.000Z", "2008-04-30T21:00:00.000Z", "2008-05-03T21:00:00.000Z", "2008-05-05T21:00:00.000Z", "2008-06-02T21:00:00.000Z", "2008-06-13T21:00:00.000Z", "2008-06-14T21:00:00.000Z", "2008-06-16T21:00:00.000Z", "2008-06-22T21:00:00.000Z", "2008-06-30T21:00:00.000Z", "2008-07-02T21:00:00.000Z", "2008-07-17T21:00:00.000Z", "2008-08-19T21:00:00.000Z", "2008-08-27T21:00:00.000Z", "2008-08-31T21:00:00.000Z", "2008-08-31T21:00:00.000Z", "2008-09-17T21:00:00.000Z", "2008-09-18T21:00:00.000Z", "2008-09-21T21:00:00.000Z", "2008-09-30T21:00:00.000Z", "2008-10-07T21:00:00.000Z", "2008-10-07T21:00:00.000Z", "2008-10-29T22:00:00.000Z", "2008-11-02T22:00:00.000Z", "2008-11-11T22:00:00.000Z", "2008-11-12T22:00:00.000Z", "2008-11-18T22:00:00.000Z", "2008-11-25T22:00:00.000Z", "2008-11-27T22:00:00.000Z", "2008-12-04T22:00:00.000Z", "2008-12-17T22:00:00.000Z", "2008-12-31T22:00:00.000Z", "2008-12-31T22:00:00.000Z", "2009-01-19T22:00:00.000Z", "2009-01-31T22:00:00.000Z", "2009-02-12T22:00:00.000Z", "2009-02-16T22:00:00.000Z", "2009-02-21T22:00:00.000Z", "2009-02-22T22:00:00.000Z", "2009-02-24T22:00:00.000Z", "2009-02-25T22:00:00.000Z", "2009-02-27T22:00:00.000Z", "2009-03-19T22:00:00.000Z", "2009-03-31T21:00:00.000Z", "2009-03-31T21:00:00.000Z", "2009-04-03T21:00:00.000Z", "2009-04-08T21:00:00.000Z", "2009-04-09T21:00:00.000Z", "2009-04-12T21:00:00.000Z", "2009-04-15T21:00:00.000Z", "2009-04-30T21:00:00.000Z", "2009-05-04T21:00:00.000Z", "2009-05-18T21:00:00.000Z", "2009-05-26T21:00:00.000Z", "2009-05-29T21:00:00.000Z", "2009-06-04T21:00:00.000Z", "2009-06-14T21:00:00.000Z", "2009-07-02T21:00:00.000Z", "2009-07-19T21:00:00.000Z", "2009-07-22T21:00:00.000Z", "2009-07-29T21:00:00.000Z", "2009-08-06T21:00:00.000Z", "2009-08-09T21:00:00.000Z", "2009-08-16T21:00:00.000Z", "2009-08-16T21:00:00.000Z", "2009-08-26T21:00:00.000Z", "2009-08-27T21:00:00.000Z", "2009-08-31T21:00:00.000Z", "2009-09-07T21:00:00.000Z", "2009-09-14T21:00:00.000Z", "2009-10-02T21:00:00.000Z", "2009-10-18T21:00:00.000Z", "2009-10-20T21:00:00.000Z", "2009-10-29T22:00:00.000Z", "2009-10-30T22:00:00.000Z", "2009-11-01T22:00:00.000Z", "2009-11-04T22:00:00.000Z", "2009-11-05T22:00:00.000Z", "2009-11-05T22:00:00.000Z", "2009-11-05T22:00:00.000Z", "2009-11-09T22:00:00.000Z", "2009-11-22T22:00:00.000Z", "2009-11-29T22:00:00.000Z", "2009-11-30T22:00:00.000Z", "2009-12-16T22:00:00.000Z", "2010-02-07T22:00:00.000Z", "2010-02-09T22:00:00.000Z", "2010-02-15T22:00:00.000Z", "2010-02-28T22:00:00.000Z", "2010-03-13T22:00:00.000Z", "2010-03-22T22:00:00.000Z", "2010-03-22T22:00:00.000Z", "2010-03-22T22:00:00.000Z", "2010-03-28T21:00:00.000Z", "2010-03-31T21:00:00.000Z", "2010-04-08T21:00:00.000Z", "2010-04-13T21:00:00.000Z", "2010-04-20T21:00:00.000Z", "2010-04-25T21:00:00.000Z", "2010-04-28T21:00:00.000Z", "2010-04-29T21:00:00.000Z", "2010-05-04T21:00:00.000Z", "2010-05-04T21:00:00.000Z", "2010-05-04T21:00:00.000Z", "2010-05-11T21:00:00.000Z", "2010-05-18T21:00:00.000Z", "2010-05-18T21:00:00.000Z", "2010-05-18T21:00:00.000Z", "2010-05-26T21:00:00.000Z", "2010-06-07T21:00:00.000Z", "2010-06-18T21:00:00.000Z", "2010-06-19T21:00:00.000Z", "2010-06-21T21:00:00.000Z", "2010-06-30T21:00:00.000Z", "2010-08-23T21:00:00.000Z", "2010-08-31T21:00:00.000Z", "2010-08-31T21:00:00.000Z", "2010-08-31T21:00:00.000Z", "2010-09-30T21:00:00.000Z", "2010-09-30T21:00:00.000Z", "2010-09-30T21:00:00.000Z", "2010-10-18T21:00:00.000Z", "2010-10-18T21:00:00.000Z", "2010-10-21T21:00:00.000Z", "2010-10-22T21:00:00.000Z", "2010-10-26T21:00:00.000Z", "2010-11-05T22:00:00.000Z", "2010-11-07T22:00:00.000Z", "2010-11-10T22:00:00.000Z", "2010-11-18T22:00:00.000Z", "2010-11-25T22:00:00.000Z", "2010-12-09T22:00:00.000Z", "2010-12-09T22:00:00.000Z", "2010-12-09T22:00:00.000Z", "2010-12-26T22:00:00.000Z", "2010-12-31T22:00:00.000Z", "2011-01-17T22:00:00.000Z", "2011-01-27T22:00:00.000Z", "2011-02-21T22:00:00.000Z", "2011-03-10T22:00:00.000Z", "2011-03-22T22:00:00.000Z", "2011-03-22T22:00:00.000Z", "2011-03-23T22:00:00.000Z", "2011-03-28T21:00:00.000Z", "2011-04-05T21:00:00.000Z", "2011-04-06T21:00:00.000Z", "2011-04-06T21:00:00.000Z", "2011-04-08T21:00:00.000Z", "2011-04-25T21:00:00.000Z", "2011-05-10T21:00:00.000Z", "2011-05-15T21:00:00.000Z", "2011-05-18T21:00:00.000Z", "2011-05-19T21:00:00.000Z", "2011-05-24T21:00:00.000Z", "2011-07-13T21:00:00.000Z", "2011-07-26T21:00:00.000Z", "2011-08-31T21:00:00.000Z", "2011-09-02T21:00:00.000Z", "2011-09-18T21:00:00.000Z", "2011-09-27T21:00:00.000Z", "2011-09-30T21:00:00.000Z", "2011-10-31T22:00:00.000Z", "2011-11-03T22:00:00.000Z", "2011-11-06T22:00:00.000Z", "2011-11-08T22:00:00.000Z", "2011-11-15T22:00:00.000Z", "2011-11-23T22:00:00.000Z", "2011-11-25T22:00:00.000Z", "2011-11-27T22:00:00.000Z", "2011-12-27T22:00:00.000Z", "2012-02-16T22:00:00.000Z", "2012-02-19T22:00:00.000Z", "2012-03-19T22:00:00.000Z", "2012-03-27T21:00:00.000Z", "2012-04-15T21:00:00.000Z", "2012-04-15T21:00:00.000Z", "2012-04-16T21:00:00.000Z", "2012-04-18T21:00:00.000Z", "2012-04-24T21:00:00.000Z", "2012-05-03T21:00:00.000Z", "2012-05-13T21:00:00.000Z", "2012-06-15T21:00:00.000Z", "2012-06-17T21:00:00.000Z", "2012-07-17T21:00:00.000Z", "2012-07-18T21:00:00.000Z", "2012-07-30T21:00:00.000Z", "2012-08-09T21:00:00.000Z", "2012-08-31T21:00:00.000Z", "2012-09-05T21:00:00.000Z", "2012-09-05T21:00:00.000Z", "2012-09-15T21:00:00.000Z", "2012-09-19T21:00:00.000Z", "2012-09-20T21:00:00.000Z", "2012-10-09T21:00:00.000Z", "2012-10-10T21:00:00.000Z", "2012-10-16T21:00:00.000Z", "2012-10-19T21:00:00.000Z", "2012-10-20T21:00:00.000Z", "2012-10-30T22:00:00.000Z", "2012-11-01T22:00:00.000Z", "2012-11-08T22:00:00.000Z", "2012-11-14T22:00:00.000Z", "2012-12-02T22:00:00.000Z", "2013-01-14T22:00:00.000Z", "2013-01-23T22:00:00.000Z", "2013-02-06T22:00:00.000Z", "2013-02-28T22:00:00.000Z", "2013-03-18T22:00:00.000Z", "2013-03-23T22:00:00.000Z", "2013-04-02T21:00:00.000Z", "2013-04-09T21:00:00.000Z", "2013-04-10T21:00:00.000Z", "2013-04-11T21:00:00.000Z", "2013-04-16T21:00:00.000Z", "2013-04-17T21:00:00.000Z", "2013-04-18T21:00:00.000Z", "2013-04-24T21:00:00.000Z", "2013-04-25T21:00:00.000Z", "2013-04-27T21:00:00.000Z", "2013-04-30T21:00:00.000Z", "2013-04-30T21:00:00.000Z", "2013-05-06T21:00:00.000Z", "2013-05-12T21:00:00.000Z", "2013-05-19T21:00:00.000Z", "2013-05-21T21:00:00.000Z", "2013-06-04T21:00:00.000Z", "2013-06-06T21:00:00.000Z", "2013-07-02T21:00:00.000Z", "2013-08-22T21:00:00.000Z", "2013-08-29T21:00:00.000Z", "2013-09-05T21:00:00.000Z", "2013-09-21T21:00:00.000Z", "2013-09-22T21:00:00.000Z", "2013-09-26T21:00:00.000Z", "2013-10-08T21:00:00.000Z", "2013-10-16T21:00:00.000Z", "2013-10-19T21:00:00.000Z", "2013-10-22T21:00:00.000Z", "2013-11-04T22:00:00.000Z", "2013-11-13T22:00:00.000Z", "2013-11-25T22:00:00.000Z", "2013-11-28T22:00:00.000Z", "2013-11-28T22:00:00.000Z", "2013-12-05T22:00:00.000Z", "2014-02-03T22:00:00.000Z", "2014-02-19T22:00:00.000Z", "2014-04-14T21:00:00.000Z", "2014-06-05T21:00:00.000Z", "2014-06-10T21:00:00.000Z", "2014-06-11T21:00:00.000Z", "2014-07-02T21:00:00.000Z", "2014-07-03T21:00:00.000Z", "2014-07-06T21:00:00.000Z", "2014-07-16T21:00:00.000Z", "2014-07-16T21:00:00.000Z", "2014-08-04T21:00:00.000Z", "2014-08-26T21:00:00.000Z", "2014-09-01T21:00:00.000Z", "2014-09-01T21:00:00.000Z", "2014-09-18T21:00:00.000Z", "2014-09-20T21:00:00.000Z", "2014-09-23T21:00:00.000Z", "2014-10-23T21:00:00.000Z", "2014-10-27T22:00:00.000Z", "2014-10-30T22:00:00.000Z", "2014-11-04T22:00:00.000Z", "2014-12-06T22:00:00.000Z", "2014-12-18T22:00:00.000Z", "2015-02-05T22:00:00.000Z", "2015-02-28T22:00:00.000Z", "2015-04-09T21:00:00.000Z", "2015-05-17T21:00:00.000Z", "2015-05-21T21:00:00.000Z", "2015-05-31T21:00:00.000Z", "2015-06-28T21:00:00.000Z", "2015-08-19T21:00:00.000Z", "2015-09-01T21:00:00.000Z", "2015-09-09T21:00:00.000Z", "2015-09-18T21:00:00.000Z", "2015-09-20T21:00:00.000Z", "2015-09-30T21:00:00.000Z", "2015-11-10T22:00:00.000Z", "2015-11-25T22:00:00.000Z", "2016-06-23T21:00:00.000Z", "2016-08-31T21:00:00.000Z", "2016-10-05T21:00:00.000Z", "2016-10-21T21:00:00.000Z", "2016-12-12T21:00:00.000Z", "2016-12-25T21:00:00.000Z", "2017-02-15T21:00:00.000Z", "2017-03-23T21:00:00.000Z"] -------------------------------------------------------------------------------- /resources/header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oguzhaninan/vue-histogram-slider/fe8f143095a548ffb956b340a1fe528bab8b4dc2/resources/header.png -------------------------------------------------------------------------------- /resources/histogram-slider-demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oguzhaninan/vue-histogram-slider/fe8f143095a548ffb956b340a1fe528bab8b4dc2/resources/histogram-slider-demo.gif -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 36 | 37 | 70 | -------------------------------------------------------------------------------- /src/lib/HistogramSlider.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 235 | 236 | 510 | -------------------------------------------------------------------------------- /src/lib/props.js: -------------------------------------------------------------------------------- 1 | export default { 2 | data: { 3 | type: Array, 4 | required: true 5 | }, 6 | min: { 7 | type: Number 8 | }, 9 | max: { 10 | type: Number 11 | }, 12 | clip: { 13 | type: Boolean, 14 | default: true 15 | }, 16 | block: { 17 | type: Boolean, 18 | default: false 19 | }, 20 | grid: { 21 | type: Boolean, 22 | default: true 23 | }, 24 | gridNum: { 25 | type: Number, 26 | default: 4 27 | }, 28 | step: { 29 | type: Number, 30 | default: 1 31 | }, 32 | hideMinMax: { 33 | type: Boolean, 34 | default: true 35 | }, 36 | hideFromTo: { 37 | type: Boolean, 38 | default: false 39 | }, 40 | toFixed: { 41 | type: Boolean, 42 | default: false 43 | }, 44 | fromFixed: { 45 | type: Boolean, 46 | default: false 47 | }, 48 | forceEdges: { 49 | type: Boolean, 50 | default: false 51 | }, 52 | dragInterval: { 53 | type: Boolean, 54 | default: false 55 | }, 56 | keyboard: { 57 | type: Boolean, 58 | default: true 59 | }, 60 | type: { 61 | type: String, 62 | default: 'double', 63 | validator: function(value) { 64 | return ['double', 'single'].indexOf(value) !== -1 65 | } 66 | }, 67 | width: { 68 | type: Number, 69 | default: 650 70 | }, 71 | barHeight: { 72 | type: Number, 73 | default: 100 74 | }, 75 | barWidth: { 76 | type: Number, 77 | default: 6 78 | }, 79 | barGap: { 80 | type: Number, 81 | default: 5 82 | }, 83 | barRadius: { 84 | type: Number, 85 | default: 4 86 | }, 87 | prettify: Function, 88 | labelColor: { 89 | type: String, 90 | default: '#0091ff' 91 | }, 92 | primaryColor: { 93 | type: String, 94 | default: '#0091ff' 95 | }, 96 | holderColor: { 97 | type: String, 98 | default: '#dee4ec' 99 | }, 100 | handleColor: { 101 | type: String, 102 | default: '#ffffff' 103 | }, 104 | gridTextColor: { 105 | type: String, 106 | default: 'silver' 107 | }, 108 | lineHeight: { 109 | type: Number, 110 | default: 6 111 | }, 112 | transitionDuration: { 113 | type: Number, 114 | default: 80 115 | }, 116 | fontFamily: { 117 | type: String, 118 | default: 'Arial, sans-serif' 119 | }, 120 | fontSize: { 121 | type: Number, 122 | default: 12 123 | }, 124 | histSliderGap: { 125 | type: Number, 126 | default: 6 127 | }, 128 | colors: { 129 | type: Array 130 | }, 131 | updateColorOnChange: { 132 | type: Boolean, 133 | default: true 134 | }, 135 | handleSize: { 136 | type: Number, 137 | default: 26 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/lib/range-slider.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | // Ion.RangeSlider 3 | // version 2.3.1 Build: 382 4 | // © Denis Ineshin, 2019 5 | // https://github.com/IonDen 6 | // 7 | // Project page: http://ionden.com/a/plugins/ion.rangeSlider/en.html 8 | // GitHub page: https://github.com/IonDen/ion.rangeSlider 9 | // 10 | // Released under MIT licence: 11 | // http://ionden.com/a/plugins/licence-en.html 12 | // ===================================================================================================================== 13 | 14 | var jQuery = require('jquery') 15 | 16 | ;(function(factory) { 17 | if ((typeof jQuery === 'undefined' || !jQuery) && typeof define === 'function' && define.amd) { 18 | define(['jquery'], function(jQuery) { 19 | return factory(jQuery, document, window, navigator) 20 | }) 21 | } else if ((typeof jQuery === 'undefined' || !jQuery) && typeof exports === 'object') { 22 | factory(require('jquery'), document, window, navigator) 23 | } else { 24 | factory(jQuery, document, window, navigator) 25 | } 26 | })(function($, document, window, navigator, undefined) { 27 | 'use strict' 28 | 29 | // ================================================================================================================= 30 | // Service 31 | 32 | var plugin_count = 0 33 | 34 | // IE8 fix 35 | var is_old_ie = (function() { 36 | var n = navigator.userAgent, 37 | r = /msie\s\d+/i, 38 | v 39 | if (n.search(r) > 0) { 40 | v = r.exec(n).toString() 41 | v = v.split(' ')[1] 42 | if (v < 9) { 43 | $('html').addClass('lt-ie9') 44 | return true 45 | } 46 | } 47 | return false 48 | })() 49 | if (!Function.prototype.bind) { 50 | Function.prototype.bind = function bind(that) { 51 | var target = this 52 | var slice = [].slice 53 | 54 | if (typeof target != 'function') { 55 | throw new TypeError() 56 | } 57 | 58 | var args = slice.call(arguments, 1), 59 | bound = function() { 60 | if (this instanceof bound) { 61 | var F = function() {} 62 | F.prototype = target.prototype 63 | var self = new F() 64 | 65 | var result = target.apply(self, args.concat(slice.call(arguments))) 66 | if (Object(result) === result) { 67 | return result 68 | } 69 | return self 70 | } else { 71 | return target.apply(that, args.concat(slice.call(arguments))) 72 | } 73 | } 74 | 75 | return bound 76 | } 77 | } 78 | if (!Array.prototype.indexOf) { 79 | Array.prototype.indexOf = function(searchElement, fromIndex) { 80 | var k 81 | if (this == null) { 82 | throw new TypeError('"this" is null or not defined') 83 | } 84 | var O = Object(this) 85 | var len = O.length >>> 0 86 | if (len === 0) { 87 | return -1 88 | } 89 | var n = +fromIndex || 0 90 | if (Math.abs(n) === Infinity) { 91 | n = 0 92 | } 93 | if (n >= len) { 94 | return -1 95 | } 96 | k = Math.max(n >= 0 ? n : len - Math.abs(n), 0) 97 | while (k < len) { 98 | if (k in O && O[k] === searchElement) { 99 | return k 100 | } 101 | k++ 102 | } 103 | return -1 104 | } 105 | } 106 | 107 | // ================================================================================================================= 108 | // Template 109 | 110 | var base_html = 111 | '' + 112 | '' + 113 | '01' + 114 | '000' + 115 | '' + 116 | '' 117 | 118 | var single_html = 119 | '' + 120 | '' + 121 | '' 122 | 123 | var double_html = 124 | '' + 125 | '' + 126 | '' + 127 | '' + 128 | '' 129 | 130 | var disable_html = '' 131 | 132 | // ================================================================================================================= 133 | // Core 134 | 135 | /** 136 | * Main plugin constructor 137 | * 138 | * @param input {Object} link to base input element 139 | * @param options {Object} slider config 140 | * @param plugin_count {Number} 141 | * @constructor 142 | */ 143 | var IonRangeSlider = function(input, options, plugin_count) { 144 | this.VERSION = '2.3.1' 145 | this.input = input 146 | this.plugin_count = plugin_count 147 | this.current_plugin = 0 148 | this.calc_count = 0 149 | this.update_tm = 0 150 | this.old_from = 0 151 | this.old_to = 0 152 | this.old_min_interval = null 153 | this.raf_id = null 154 | this.dragging = false 155 | this.force_redraw = false 156 | this.no_diapason = false 157 | this.has_tab_index = true 158 | this.is_key = false 159 | this.is_update = false 160 | this.is_start = true 161 | this.is_finish = false 162 | this.is_active = false 163 | this.is_resize = false 164 | this.is_click = false 165 | 166 | options = options || {} 167 | 168 | // cache for links to all DOM elements 169 | this.$cache = { 170 | win: $(window), 171 | body: $(document.body), 172 | input: $(input), 173 | cont: null, 174 | rs: null, 175 | min: null, 176 | max: null, 177 | from: null, 178 | to: null, 179 | single: null, 180 | bar: null, 181 | line: null, 182 | s_single: null, 183 | s_from: null, 184 | s_to: null, 185 | shad_single: null, 186 | shad_from: null, 187 | shad_to: null, 188 | edge: null, 189 | grid: null, 190 | grid_labels: [] 191 | } 192 | 193 | // storage for measure variables 194 | this.coords = { 195 | // left 196 | x_gap: 0, 197 | x_pointer: 0, 198 | 199 | // width 200 | w_rs: 0, 201 | w_rs_old: 0, 202 | w_handle: 0, 203 | 204 | // percents 205 | p_gap: 0, 206 | p_gap_left: 0, 207 | p_gap_right: 0, 208 | p_step: 0, 209 | p_pointer: 0, 210 | p_handle: 0, 211 | p_single_fake: 0, 212 | p_single_real: 0, 213 | p_from_fake: 0, 214 | p_from_real: 0, 215 | p_to_fake: 0, 216 | p_to_real: 0, 217 | p_bar_x: 0, 218 | p_bar_w: 0, 219 | 220 | // grid 221 | grid_gap: 0, 222 | big_num: 0, 223 | big: [], 224 | big_w: [], 225 | big_p: [], 226 | big_x: [] 227 | } 228 | 229 | // storage for labels measure variables 230 | this.labels = { 231 | // width 232 | w_min: 0, 233 | w_max: 0, 234 | w_from: 0, 235 | w_to: 0, 236 | w_single: 0, 237 | 238 | // percents 239 | p_min: 0, 240 | p_max: 0, 241 | p_from_fake: 0, 242 | p_from_left: 0, 243 | p_to_fake: 0, 244 | p_to_left: 0, 245 | p_single_fake: 0, 246 | p_single_left: 0 247 | } 248 | 249 | /** 250 | * get and validate config 251 | */ 252 | var $inp = this.$cache.input, 253 | val = $inp.prop('value'), 254 | config, 255 | config_from_data, 256 | prop 257 | 258 | // default config 259 | config = { 260 | skin: 'flat', 261 | type: 'single', 262 | 263 | min: 10, 264 | max: 100, 265 | from: null, 266 | to: null, 267 | step: 1, 268 | 269 | min_interval: 0, 270 | max_interval: 0, 271 | drag_interval: false, 272 | 273 | values: [], 274 | p_values: [], 275 | 276 | from_fixed: false, 277 | from_min: null, 278 | from_max: null, 279 | from_shadow: false, 280 | 281 | to_fixed: false, 282 | to_min: null, 283 | to_max: null, 284 | to_shadow: false, 285 | 286 | prettify_enabled: true, 287 | prettify_separator: ' ', 288 | prettify: null, 289 | 290 | force_edges: false, 291 | 292 | keyboard: true, 293 | 294 | grid: false, 295 | grid_margin: true, 296 | grid_num: 4, 297 | grid_snap: false, 298 | 299 | hide_min_max: false, 300 | hide_from_to: false, 301 | 302 | prefix: '', 303 | postfix: '', 304 | max_postfix: '', 305 | decorate_both: true, 306 | values_separator: ' — ', 307 | 308 | input_values_separator: ';', 309 | 310 | disable: false, 311 | block: false, 312 | 313 | extra_classes: '', 314 | 315 | scope: null, 316 | onStart: null, 317 | onChange: null, 318 | onFinish: null, 319 | onUpdate: null 320 | } 321 | 322 | // check if base element is input 323 | if ($inp[0].nodeName !== 'INPUT') { 324 | console && console.warn && console.warn('Base element should be !', $inp[0]) 325 | } 326 | 327 | // config from data-attributes extends js config 328 | config_from_data = { 329 | skin: $inp.data('skin'), 330 | type: $inp.data('type'), 331 | 332 | min: $inp.data('min'), 333 | max: $inp.data('max'), 334 | from: $inp.data('from'), 335 | to: $inp.data('to'), 336 | step: $inp.data('step'), 337 | 338 | min_interval: $inp.data('minInterval'), 339 | max_interval: $inp.data('maxInterval'), 340 | drag_interval: $inp.data('dragInterval'), 341 | 342 | values: $inp.data('values'), 343 | 344 | from_fixed: $inp.data('fromFixed'), 345 | from_min: $inp.data('fromMin'), 346 | from_max: $inp.data('fromMax'), 347 | from_shadow: $inp.data('fromShadow'), 348 | 349 | to_fixed: $inp.data('toFixed'), 350 | to_min: $inp.data('toMin'), 351 | to_max: $inp.data('toMax'), 352 | to_shadow: $inp.data('toShadow'), 353 | 354 | prettify_enabled: $inp.data('prettifyEnabled'), 355 | prettify_separator: $inp.data('prettifySeparator'), 356 | 357 | force_edges: $inp.data('forceEdges'), 358 | 359 | keyboard: $inp.data('keyboard'), 360 | 361 | grid: $inp.data('grid'), 362 | grid_margin: $inp.data('gridMargin'), 363 | grid_num: $inp.data('gridNum'), 364 | grid_snap: $inp.data('gridSnap'), 365 | 366 | hide_min_max: $inp.data('hideMinMax'), 367 | hide_from_to: $inp.data('hideFromTo'), 368 | 369 | prefix: $inp.data('prefix'), 370 | postfix: $inp.data('postfix'), 371 | max_postfix: $inp.data('maxPostfix'), 372 | decorate_both: $inp.data('decorateBoth'), 373 | values_separator: $inp.data('valuesSeparator'), 374 | 375 | input_values_separator: $inp.data('inputValuesSeparator'), 376 | 377 | disable: $inp.data('disable'), 378 | block: $inp.data('block'), 379 | 380 | extra_classes: $inp.data('extraClasses') 381 | } 382 | config_from_data.values = config_from_data.values && config_from_data.values.split(',') 383 | 384 | for (prop in config_from_data) { 385 | if (config_from_data.hasOwnProperty(prop)) { 386 | if (config_from_data[prop] === undefined || config_from_data[prop] === '') { 387 | delete config_from_data[prop] 388 | } 389 | } 390 | } 391 | 392 | // input value extends default config 393 | if (val !== undefined && val !== '') { 394 | val = val.split( 395 | config_from_data.input_values_separator || options.input_values_separator || ';' 396 | ) 397 | 398 | if (val[0] && val[0] == +val[0]) { 399 | val[0] = +val[0] 400 | } 401 | if (val[1] && val[1] == +val[1]) { 402 | val[1] = +val[1] 403 | } 404 | 405 | if (options && options.values && options.values.length) { 406 | config.from = val[0] && options.values.indexOf(val[0]) 407 | config.to = val[1] && options.values.indexOf(val[1]) 408 | } else { 409 | config.from = val[0] && +val[0] 410 | config.to = val[1] && +val[1] 411 | } 412 | } 413 | 414 | // js config extends default config 415 | $.extend(config, options) 416 | 417 | // data config extends config 418 | $.extend(config, config_from_data) 419 | this.options = config 420 | 421 | // validate config, to be sure that all data types are correct 422 | this.update_check = {} 423 | this.validate() 424 | 425 | // default result object, returned to callbacks 426 | this.result = { 427 | input: this.$cache.input, 428 | slider: null, 429 | 430 | min: this.options.min, 431 | max: this.options.max, 432 | 433 | from: this.options.from, 434 | from_percent: 0, 435 | from_value: null, 436 | 437 | to: this.options.to, 438 | to_percent: 0, 439 | to_value: null 440 | } 441 | 442 | this.init() 443 | } 444 | 445 | IonRangeSlider.prototype = { 446 | /** 447 | * Starts or updates the plugin instance 448 | * 449 | * @param [is_update] {boolean} 450 | */ 451 | init: function(is_update) { 452 | this.no_diapason = false 453 | this.coords.p_step = this.convertToPercent(this.options.step, true) 454 | 455 | this.target = 'base' 456 | 457 | this.toggleInput() 458 | this.append() 459 | this.setMinMax() 460 | 461 | if (is_update) { 462 | this.force_redraw = true 463 | this.calc(true) 464 | 465 | // callbacks called 466 | this.callOnUpdate() 467 | } else { 468 | this.force_redraw = true 469 | this.calc(true) 470 | 471 | // callbacks called 472 | this.callOnStart() 473 | } 474 | 475 | this.updateScene() 476 | }, 477 | 478 | /** 479 | * Appends slider template to a DOM 480 | */ 481 | append: function() { 482 | var container_html = 483 | '' 490 | this.$cache.input.before(container_html) 491 | this.$cache.input.prop('readonly', true) 492 | this.$cache.cont = this.$cache.input.prev() 493 | this.result.slider = this.$cache.cont 494 | 495 | this.$cache.cont.html(base_html) 496 | this.$cache.rs = this.$cache.cont.find('.irs') 497 | this.$cache.min = this.$cache.cont.find('.irs-min') 498 | this.$cache.max = this.$cache.cont.find('.irs-max') 499 | this.$cache.from = this.$cache.cont.find('.irs-from') 500 | this.$cache.to = this.$cache.cont.find('.irs-to') 501 | this.$cache.single = this.$cache.cont.find('.irs-single') 502 | this.$cache.line = this.$cache.cont.find('.irs-line') 503 | this.$cache.grid = this.$cache.cont.find('.irs-grid') 504 | 505 | if (this.options.type === 'single') { 506 | this.$cache.cont.append(single_html) 507 | this.$cache.bar = this.$cache.cont.find('.irs-bar') 508 | this.$cache.edge = this.$cache.cont.find('.irs-bar-edge') 509 | this.$cache.s_single = this.$cache.cont.find('.single') 510 | this.$cache.from[0].style.visibility = 'hidden' 511 | this.$cache.to[0].style.visibility = 'hidden' 512 | this.$cache.shad_single = this.$cache.cont.find('.shadow-single') 513 | } else { 514 | this.$cache.cont.append(double_html) 515 | this.$cache.bar = this.$cache.cont.find('.irs-bar') 516 | this.$cache.s_from = this.$cache.cont.find('.from') 517 | this.$cache.s_to = this.$cache.cont.find('.to') 518 | this.$cache.shad_from = this.$cache.cont.find('.shadow-from') 519 | this.$cache.shad_to = this.$cache.cont.find('.shadow-to') 520 | 521 | this.setTopHandler() 522 | } 523 | 524 | if (this.options.hide_from_to) { 525 | this.$cache.from[0].style.display = 'none' 526 | this.$cache.to[0].style.display = 'none' 527 | this.$cache.single[0].style.display = 'none' 528 | } 529 | 530 | this.appendGrid() 531 | 532 | if (this.options.disable) { 533 | this.appendDisableMask() 534 | this.$cache.input[0].disabled = true 535 | } else { 536 | this.$cache.input[0].disabled = false 537 | this.removeDisableMask() 538 | this.bindEvents() 539 | } 540 | 541 | // block only if not disabled 542 | if (!this.options.disable) { 543 | if (this.options.block) { 544 | this.appendDisableMask() 545 | } else { 546 | this.removeDisableMask() 547 | } 548 | } 549 | 550 | if (this.options.drag_interval) { 551 | this.$cache.bar[0].style.cursor = 'ew-resize' 552 | } 553 | }, 554 | 555 | /** 556 | * Determine which handler has a priority 557 | * works only for double slider type 558 | */ 559 | setTopHandler: function() { 560 | var min = this.options.min, 561 | max = this.options.max, 562 | from = this.options.from, 563 | to = this.options.to 564 | 565 | if (from > min && to === max) { 566 | this.$cache.s_from.addClass('type_last') 567 | } else if (to < max) { 568 | this.$cache.s_to.addClass('type_last') 569 | } 570 | }, 571 | 572 | /** 573 | * Determine which handles was clicked last 574 | * and which handler should have hover effect 575 | * 576 | * @param target {String} 577 | */ 578 | changeLevel: function(target) { 579 | switch (target) { 580 | case 'single': 581 | this.coords.p_gap = this.toFixed(this.coords.p_pointer - this.coords.p_single_fake) 582 | this.$cache.s_single.addClass('state_hover') 583 | break 584 | case 'from': 585 | this.coords.p_gap = this.toFixed(this.coords.p_pointer - this.coords.p_from_fake) 586 | this.$cache.s_from.addClass('state_hover') 587 | this.$cache.s_from.addClass('type_last') 588 | this.$cache.s_to.removeClass('type_last') 589 | break 590 | case 'to': 591 | this.coords.p_gap = this.toFixed(this.coords.p_pointer - this.coords.p_to_fake) 592 | this.$cache.s_to.addClass('state_hover') 593 | this.$cache.s_to.addClass('type_last') 594 | this.$cache.s_from.removeClass('type_last') 595 | break 596 | case 'both': 597 | this.coords.p_gap_left = this.toFixed(this.coords.p_pointer - this.coords.p_from_fake) 598 | this.coords.p_gap_right = this.toFixed(this.coords.p_to_fake - this.coords.p_pointer) 599 | this.$cache.s_to.removeClass('type_last') 600 | this.$cache.s_from.removeClass('type_last') 601 | break 602 | } 603 | }, 604 | 605 | /** 606 | * Then slider is disabled 607 | * appends extra layer with opacity 608 | */ 609 | appendDisableMask: function() { 610 | this.$cache.cont.append(disable_html) 611 | this.$cache.cont.addClass('irs-disabled') 612 | }, 613 | 614 | /** 615 | * Then slider is not disabled 616 | * remove disable mask 617 | */ 618 | removeDisableMask: function() { 619 | this.$cache.cont.remove('.irs-disable-mask') 620 | this.$cache.cont.removeClass('irs-disabled') 621 | }, 622 | 623 | /** 624 | * Remove slider instance 625 | * and unbind all events 626 | */ 627 | remove: function() { 628 | this.$cache.cont.remove() 629 | this.$cache.cont = null 630 | 631 | this.$cache.line.off('keydown.irs_' + this.plugin_count) 632 | 633 | this.$cache.body.off('touchmove.irs_' + this.plugin_count) 634 | this.$cache.body.off('mousemove.irs_' + this.plugin_count) 635 | 636 | this.$cache.win.off('touchend.irs_' + this.plugin_count) 637 | this.$cache.win.off('mouseup.irs_' + this.plugin_count) 638 | 639 | if (is_old_ie) { 640 | this.$cache.body.off('mouseup.irs_' + this.plugin_count) 641 | this.$cache.body.off('mouseleave.irs_' + this.plugin_count) 642 | } 643 | 644 | this.$cache.grid_labels = [] 645 | this.coords.big = [] 646 | this.coords.big_w = [] 647 | this.coords.big_p = [] 648 | this.coords.big_x = [] 649 | 650 | cancelAnimationFrame(this.raf_id) 651 | }, 652 | 653 | /** 654 | * bind all slider events 655 | */ 656 | bindEvents: function() { 657 | if (this.no_diapason) { 658 | return 659 | } 660 | 661 | this.$cache.body.on('touchmove.irs_' + this.plugin_count, this.pointerMove.bind(this)) 662 | this.$cache.body.on('mousemove.irs_' + this.plugin_count, this.pointerMove.bind(this)) 663 | 664 | this.$cache.win.on('touchend.irs_' + this.plugin_count, this.pointerUp.bind(this)) 665 | this.$cache.win.on('mouseup.irs_' + this.plugin_count, this.pointerUp.bind(this)) 666 | 667 | this.$cache.line.on( 668 | 'touchstart.irs_' + this.plugin_count, 669 | this.pointerClick.bind(this, 'click') 670 | ) 671 | this.$cache.line.on( 672 | 'mousedown.irs_' + this.plugin_count, 673 | this.pointerClick.bind(this, 'click') 674 | ) 675 | 676 | this.$cache.line.on('focus.irs_' + this.plugin_count, this.pointerFocus.bind(this)) 677 | 678 | if (this.options.drag_interval && this.options.type === 'double') { 679 | this.$cache.bar.on( 680 | 'touchstart.irs_' + this.plugin_count, 681 | this.pointerDown.bind(this, 'both') 682 | ) 683 | this.$cache.bar.on( 684 | 'mousedown.irs_' + this.plugin_count, 685 | this.pointerDown.bind(this, 'both') 686 | ) 687 | } else { 688 | this.$cache.bar.on( 689 | 'touchstart.irs_' + this.plugin_count, 690 | this.pointerClick.bind(this, 'click') 691 | ) 692 | this.$cache.bar.on( 693 | 'mousedown.irs_' + this.plugin_count, 694 | this.pointerClick.bind(this, 'click') 695 | ) 696 | } 697 | 698 | if (this.options.type === 'single') { 699 | this.$cache.single.on( 700 | 'touchstart.irs_' + this.plugin_count, 701 | this.pointerDown.bind(this, 'single') 702 | ) 703 | this.$cache.s_single.on( 704 | 'touchstart.irs_' + this.plugin_count, 705 | this.pointerDown.bind(this, 'single') 706 | ) 707 | this.$cache.shad_single.on( 708 | 'touchstart.irs_' + this.plugin_count, 709 | this.pointerClick.bind(this, 'click') 710 | ) 711 | 712 | this.$cache.single.on( 713 | 'mousedown.irs_' + this.plugin_count, 714 | this.pointerDown.bind(this, 'single') 715 | ) 716 | this.$cache.s_single.on( 717 | 'mousedown.irs_' + this.plugin_count, 718 | this.pointerDown.bind(this, 'single') 719 | ) 720 | this.$cache.edge.on( 721 | 'mousedown.irs_' + this.plugin_count, 722 | this.pointerClick.bind(this, 'click') 723 | ) 724 | this.$cache.shad_single.on( 725 | 'mousedown.irs_' + this.plugin_count, 726 | this.pointerClick.bind(this, 'click') 727 | ) 728 | } else { 729 | this.$cache.single.on( 730 | 'touchstart.irs_' + this.plugin_count, 731 | this.pointerDown.bind(this, null) 732 | ) 733 | this.$cache.single.on( 734 | 'mousedown.irs_' + this.plugin_count, 735 | this.pointerDown.bind(this, null) 736 | ) 737 | 738 | this.$cache.from.on( 739 | 'touchstart.irs_' + this.plugin_count, 740 | this.pointerDown.bind(this, 'from') 741 | ) 742 | this.$cache.s_from.on( 743 | 'touchstart.irs_' + this.plugin_count, 744 | this.pointerDown.bind(this, 'from') 745 | ) 746 | this.$cache.to.on('touchstart.irs_' + this.plugin_count, this.pointerDown.bind(this, 'to')) 747 | this.$cache.s_to.on( 748 | 'touchstart.irs_' + this.plugin_count, 749 | this.pointerDown.bind(this, 'to') 750 | ) 751 | this.$cache.shad_from.on( 752 | 'touchstart.irs_' + this.plugin_count, 753 | this.pointerClick.bind(this, 'click') 754 | ) 755 | this.$cache.shad_to.on( 756 | 'touchstart.irs_' + this.plugin_count, 757 | this.pointerClick.bind(this, 'click') 758 | ) 759 | 760 | this.$cache.from.on( 761 | 'mousedown.irs_' + this.plugin_count, 762 | this.pointerDown.bind(this, 'from') 763 | ) 764 | this.$cache.s_from.on( 765 | 'mousedown.irs_' + this.plugin_count, 766 | this.pointerDown.bind(this, 'from') 767 | ) 768 | this.$cache.to.on('mousedown.irs_' + this.plugin_count, this.pointerDown.bind(this, 'to')) 769 | this.$cache.s_to.on('mousedown.irs_' + this.plugin_count, this.pointerDown.bind(this, 'to')) 770 | this.$cache.shad_from.on( 771 | 'mousedown.irs_' + this.plugin_count, 772 | this.pointerClick.bind(this, 'click') 773 | ) 774 | this.$cache.shad_to.on( 775 | 'mousedown.irs_' + this.plugin_count, 776 | this.pointerClick.bind(this, 'click') 777 | ) 778 | } 779 | 780 | if (this.options.keyboard) { 781 | this.$cache.line.on('keydown.irs_' + this.plugin_count, this.key.bind(this, 'keyboard')) 782 | } 783 | 784 | if (is_old_ie) { 785 | this.$cache.body.on('mouseup.irs_' + this.plugin_count, this.pointerUp.bind(this)) 786 | this.$cache.body.on('mouseleave.irs_' + this.plugin_count, this.pointerUp.bind(this)) 787 | } 788 | }, 789 | 790 | /** 791 | * Focus with tabIndex 792 | * 793 | * @param e {Object} event object 794 | */ 795 | pointerFocus: function(e) { 796 | if (!this.target) { 797 | var x 798 | var $handle 799 | 800 | if (this.options.type === 'single') { 801 | $handle = this.$cache.single 802 | } else { 803 | $handle = this.$cache.from 804 | } 805 | 806 | x = $handle.offset().left 807 | x += $handle.width() / 2 - 1 808 | 809 | this.pointerClick('single', { preventDefault: function() {}, pageX: x }) 810 | } 811 | }, 812 | 813 | /** 814 | * Mousemove or touchmove 815 | * only for handlers 816 | * 817 | * @param e {Object} event object 818 | */ 819 | pointerMove: function(e) { 820 | if (!this.dragging) { 821 | return 822 | } 823 | 824 | var x = e.pageX || (e.originalEvent.touches && e.originalEvent.touches[0].pageX) 825 | this.coords.x_pointer = x - this.coords.x_gap 826 | 827 | this.calc() 828 | }, 829 | 830 | /** 831 | * Mouseup or touchend 832 | * only for handlers 833 | * 834 | * @param e {Object} event object 835 | */ 836 | pointerUp: function(e) { 837 | if (this.current_plugin !== this.plugin_count) { 838 | return 839 | } 840 | 841 | if (this.is_active) { 842 | this.is_active = false 843 | } else { 844 | return 845 | } 846 | 847 | this.$cache.cont.find('.state_hover').removeClass('state_hover') 848 | 849 | this.force_redraw = true 850 | 851 | if (is_old_ie) { 852 | $('*').prop('unselectable', false) 853 | } 854 | 855 | this.updateScene() 856 | this.restoreOriginalMinInterval() 857 | 858 | // callbacks call 859 | if ($.contains(this.$cache.cont[0], e.target) || this.dragging) { 860 | this.callOnFinish() 861 | } 862 | 863 | this.dragging = false 864 | }, 865 | 866 | /** 867 | * Mousedown or touchstart 868 | * only for handlers 869 | * 870 | * @param target {String|null} 871 | * @param e {Object} event object 872 | */ 873 | pointerDown: function(target, e) { 874 | e.preventDefault() 875 | var x = e.pageX || (e.originalEvent.touches && e.originalEvent.touches[0].pageX) 876 | if (e.button === 2) { 877 | return 878 | } 879 | 880 | if (target === 'both') { 881 | this.setTempMinInterval() 882 | } 883 | 884 | if (!target) { 885 | target = this.target || 'from' 886 | } 887 | 888 | this.current_plugin = this.plugin_count 889 | this.target = target 890 | 891 | this.is_active = true 892 | this.dragging = true 893 | 894 | this.coords.x_gap = this.$cache.rs.offset().left 895 | this.coords.x_pointer = x - this.coords.x_gap 896 | 897 | this.calcPointerPercent() 898 | this.changeLevel(target) 899 | 900 | if (is_old_ie) { 901 | $('*').prop('unselectable', true) 902 | } 903 | 904 | this.$cache.line.trigger('focus') 905 | 906 | this.updateScene() 907 | }, 908 | 909 | /** 910 | * Mousedown or touchstart 911 | * for other slider elements, like diapason line 912 | * 913 | * @param target {String} 914 | * @param e {Object} event object 915 | */ 916 | pointerClick: function(target, e) { 917 | e.preventDefault() 918 | var x = e.pageX || (e.originalEvent.touches && e.originalEvent.touches[0].pageX) 919 | if (e.button === 2) { 920 | return 921 | } 922 | 923 | this.current_plugin = this.plugin_count 924 | this.target = target 925 | 926 | this.is_click = true 927 | this.coords.x_gap = this.$cache.rs.offset().left 928 | this.coords.x_pointer = +(x - this.coords.x_gap).toFixed() 929 | 930 | this.force_redraw = true 931 | this.calc() 932 | 933 | this.$cache.line.trigger('focus') 934 | }, 935 | 936 | /** 937 | * Keyborard controls for focused slider 938 | * 939 | * @param target {String} 940 | * @param e {Object} event object 941 | * @returns {boolean|undefined} 942 | */ 943 | key: function(target, e) { 944 | if ( 945 | this.current_plugin !== this.plugin_count || 946 | e.altKey || 947 | e.ctrlKey || 948 | e.shiftKey || 949 | e.metaKey 950 | ) { 951 | return 952 | } 953 | 954 | switch (e.which) { 955 | case 83: // W 956 | case 65: // A 957 | case 40: // DOWN 958 | case 37: // LEFT 959 | e.preventDefault() 960 | this.moveByKey(false) 961 | break 962 | 963 | case 87: // S 964 | case 68: // D 965 | case 38: // UP 966 | case 39: // RIGHT 967 | e.preventDefault() 968 | this.moveByKey(true) 969 | break 970 | } 971 | 972 | return true 973 | }, 974 | 975 | /** 976 | * Move by key 977 | * 978 | * @param right {boolean} direction to move 979 | */ 980 | moveByKey: function(right) { 981 | var p = this.coords.p_pointer 982 | var p_step = (this.options.max - this.options.min) / 100 983 | p_step = this.options.step / p_step 984 | 985 | if (right) { 986 | p += p_step 987 | } else { 988 | p -= p_step 989 | } 990 | 991 | this.coords.x_pointer = this.toFixed((this.coords.w_rs / 100) * p) 992 | this.is_key = true 993 | this.calc() 994 | }, 995 | 996 | /** 997 | * Set visibility and content 998 | * of Min and Max labels 999 | */ 1000 | setMinMax: function() { 1001 | if (!this.options) { 1002 | return 1003 | } 1004 | 1005 | if (this.options.hide_min_max) { 1006 | this.$cache.min[0].style.display = 'none' 1007 | this.$cache.max[0].style.display = 'none' 1008 | return 1009 | } 1010 | 1011 | if (this.options.values.length) { 1012 | this.$cache.min.html(this.decorate(this.options.p_values[this.options.min])) 1013 | this.$cache.max.html(this.decorate(this.options.p_values[this.options.max])) 1014 | } else { 1015 | var min_pretty = this._prettify(this.options.min) 1016 | var max_pretty = this._prettify(this.options.max) 1017 | 1018 | this.result.min_pretty = min_pretty 1019 | this.result.max_pretty = max_pretty 1020 | 1021 | this.$cache.min.html(this.decorate(min_pretty, this.options.min)) 1022 | this.$cache.max.html(this.decorate(max_pretty, this.options.max)) 1023 | } 1024 | 1025 | this.labels.w_min = this.$cache.min.outerWidth(false) 1026 | this.labels.w_max = this.$cache.max.outerWidth(false) 1027 | }, 1028 | 1029 | /** 1030 | * Then dragging interval, prevent interval collapsing 1031 | * using min_interval option 1032 | */ 1033 | setTempMinInterval: function() { 1034 | var interval = this.result.to - this.result.from 1035 | 1036 | if (this.old_min_interval === null) { 1037 | this.old_min_interval = this.options.min_interval 1038 | } 1039 | 1040 | this.options.min_interval = interval 1041 | }, 1042 | 1043 | /** 1044 | * Restore min_interval option to original 1045 | */ 1046 | restoreOriginalMinInterval: function() { 1047 | if (this.old_min_interval !== null) { 1048 | this.options.min_interval = this.old_min_interval 1049 | this.old_min_interval = null 1050 | } 1051 | }, 1052 | 1053 | // ============================================================================================================= 1054 | // Calculations 1055 | 1056 | /** 1057 | * All calculations and measures start here 1058 | * 1059 | * @param update {boolean=} 1060 | */ 1061 | calc: function(update) { 1062 | if (!this.options) { 1063 | return 1064 | } 1065 | 1066 | this.calc_count++ 1067 | 1068 | if (this.calc_count === 10 || update) { 1069 | this.calc_count = 0 1070 | this.coords.w_rs = this.$cache.rs.outerWidth(false) 1071 | 1072 | this.calcHandlePercent() 1073 | } 1074 | 1075 | if (!this.coords.w_rs) { 1076 | return 1077 | } 1078 | 1079 | this.calcPointerPercent() 1080 | var handle_x = this.getHandleX() 1081 | 1082 | if (this.target === 'both') { 1083 | this.coords.p_gap = 0 1084 | handle_x = this.getHandleX() 1085 | } 1086 | 1087 | if (this.target === 'click') { 1088 | this.coords.p_gap = this.coords.p_handle / 2 1089 | handle_x = this.getHandleX() 1090 | 1091 | if (this.options.drag_interval) { 1092 | this.target = 'both_one' 1093 | } else { 1094 | this.target = this.chooseHandle(handle_x) 1095 | } 1096 | } 1097 | 1098 | switch (this.target) { 1099 | case 'base': 1100 | var w = (this.options.max - this.options.min) / 100, 1101 | f = (this.result.from - this.options.min) / w, 1102 | t = (this.result.to - this.options.min) / w 1103 | 1104 | this.coords.p_single_real = this.toFixed(f) 1105 | this.coords.p_from_real = this.toFixed(f) 1106 | this.coords.p_to_real = this.toFixed(t) 1107 | 1108 | this.coords.p_single_real = this.checkDiapason( 1109 | this.coords.p_single_real, 1110 | this.options.from_min, 1111 | this.options.from_max 1112 | ) 1113 | this.coords.p_from_real = this.checkDiapason( 1114 | this.coords.p_from_real, 1115 | this.options.from_min, 1116 | this.options.from_max 1117 | ) 1118 | this.coords.p_to_real = this.checkDiapason( 1119 | this.coords.p_to_real, 1120 | this.options.to_min, 1121 | this.options.to_max 1122 | ) 1123 | 1124 | this.coords.p_single_fake = this.convertToFakePercent(this.coords.p_single_real) 1125 | this.coords.p_from_fake = this.convertToFakePercent(this.coords.p_from_real) 1126 | this.coords.p_to_fake = this.convertToFakePercent(this.coords.p_to_real) 1127 | 1128 | this.target = null 1129 | 1130 | break 1131 | 1132 | case 'single': 1133 | if (this.options.from_fixed) { 1134 | break 1135 | } 1136 | 1137 | this.coords.p_single_real = this.convertToRealPercent(handle_x) 1138 | this.coords.p_single_real = this.calcWithStep(this.coords.p_single_real) 1139 | this.coords.p_single_real = this.checkDiapason( 1140 | this.coords.p_single_real, 1141 | this.options.from_min, 1142 | this.options.from_max 1143 | ) 1144 | 1145 | this.coords.p_single_fake = this.convertToFakePercent(this.coords.p_single_real) 1146 | 1147 | break 1148 | 1149 | case 'from': 1150 | if (this.options.from_fixed) { 1151 | break 1152 | } 1153 | 1154 | this.coords.p_from_real = this.convertToRealPercent(handle_x) 1155 | this.coords.p_from_real = this.calcWithStep(this.coords.p_from_real) 1156 | if (this.coords.p_from_real > this.coords.p_to_real) { 1157 | this.coords.p_from_real = this.coords.p_to_real 1158 | } 1159 | this.coords.p_from_real = this.checkDiapason( 1160 | this.coords.p_from_real, 1161 | this.options.from_min, 1162 | this.options.from_max 1163 | ) 1164 | this.coords.p_from_real = this.checkMinInterval( 1165 | this.coords.p_from_real, 1166 | this.coords.p_to_real, 1167 | 'from' 1168 | ) 1169 | this.coords.p_from_real = this.checkMaxInterval( 1170 | this.coords.p_from_real, 1171 | this.coords.p_to_real, 1172 | 'from' 1173 | ) 1174 | 1175 | this.coords.p_from_fake = this.convertToFakePercent(this.coords.p_from_real) 1176 | 1177 | break 1178 | 1179 | case 'to': 1180 | if (this.options.to_fixed) { 1181 | break 1182 | } 1183 | 1184 | this.coords.p_to_real = this.convertToRealPercent(handle_x) 1185 | this.coords.p_to_real = this.calcWithStep(this.coords.p_to_real) 1186 | if (this.coords.p_to_real < this.coords.p_from_real) { 1187 | this.coords.p_to_real = this.coords.p_from_real 1188 | } 1189 | this.coords.p_to_real = this.checkDiapason( 1190 | this.coords.p_to_real, 1191 | this.options.to_min, 1192 | this.options.to_max 1193 | ) 1194 | this.coords.p_to_real = this.checkMinInterval( 1195 | this.coords.p_to_real, 1196 | this.coords.p_from_real, 1197 | 'to' 1198 | ) 1199 | this.coords.p_to_real = this.checkMaxInterval( 1200 | this.coords.p_to_real, 1201 | this.coords.p_from_real, 1202 | 'to' 1203 | ) 1204 | 1205 | this.coords.p_to_fake = this.convertToFakePercent(this.coords.p_to_real) 1206 | 1207 | break 1208 | 1209 | case 'both': 1210 | if (this.options.from_fixed || this.options.to_fixed) { 1211 | break 1212 | } 1213 | 1214 | handle_x = this.toFixed(handle_x + this.coords.p_handle * 0.001) 1215 | 1216 | this.coords.p_from_real = this.convertToRealPercent(handle_x) - this.coords.p_gap_left 1217 | this.coords.p_from_real = this.calcWithStep(this.coords.p_from_real) 1218 | this.coords.p_from_real = this.checkDiapason( 1219 | this.coords.p_from_real, 1220 | this.options.from_min, 1221 | this.options.from_max 1222 | ) 1223 | this.coords.p_from_real = this.checkMinInterval( 1224 | this.coords.p_from_real, 1225 | this.coords.p_to_real, 1226 | 'from' 1227 | ) 1228 | this.coords.p_from_fake = this.convertToFakePercent(this.coords.p_from_real) 1229 | 1230 | this.coords.p_to_real = this.convertToRealPercent(handle_x) + this.coords.p_gap_right 1231 | this.coords.p_to_real = this.calcWithStep(this.coords.p_to_real) 1232 | this.coords.p_to_real = this.checkDiapason( 1233 | this.coords.p_to_real, 1234 | this.options.to_min, 1235 | this.options.to_max 1236 | ) 1237 | this.coords.p_to_real = this.checkMinInterval( 1238 | this.coords.p_to_real, 1239 | this.coords.p_from_real, 1240 | 'to' 1241 | ) 1242 | this.coords.p_to_fake = this.convertToFakePercent(this.coords.p_to_real) 1243 | 1244 | break 1245 | 1246 | case 'both_one': 1247 | if (this.options.from_fixed || this.options.to_fixed) { 1248 | break 1249 | } 1250 | 1251 | var real_x = this.convertToRealPercent(handle_x), 1252 | from = this.result.from_percent, 1253 | to = this.result.to_percent, 1254 | full = to - from, 1255 | half = full / 2, 1256 | new_from = real_x - half, 1257 | new_to = real_x + half 1258 | 1259 | if (new_from < 0) { 1260 | new_from = 0 1261 | new_to = new_from + full 1262 | } 1263 | 1264 | if (new_to > 100) { 1265 | new_to = 100 1266 | new_from = new_to - full 1267 | } 1268 | 1269 | this.coords.p_from_real = this.calcWithStep(new_from) 1270 | this.coords.p_from_real = this.checkDiapason( 1271 | this.coords.p_from_real, 1272 | this.options.from_min, 1273 | this.options.from_max 1274 | ) 1275 | this.coords.p_from_fake = this.convertToFakePercent(this.coords.p_from_real) 1276 | 1277 | this.coords.p_to_real = this.calcWithStep(new_to) 1278 | this.coords.p_to_real = this.checkDiapason( 1279 | this.coords.p_to_real, 1280 | this.options.to_min, 1281 | this.options.to_max 1282 | ) 1283 | this.coords.p_to_fake = this.convertToFakePercent(this.coords.p_to_real) 1284 | 1285 | break 1286 | } 1287 | 1288 | if (this.options.type === 'single') { 1289 | this.coords.p_bar_x = this.coords.p_handle / 2 1290 | this.coords.p_bar_w = this.coords.p_single_fake 1291 | 1292 | this.result.from_percent = this.coords.p_single_real 1293 | this.result.from = this.convertToValue(this.coords.p_single_real) 1294 | this.result.from_pretty = this._prettify(this.result.from) 1295 | 1296 | if (this.options.values.length) { 1297 | this.result.from_value = this.options.values[this.result.from] 1298 | } 1299 | } else { 1300 | this.coords.p_bar_x = this.toFixed(this.coords.p_from_fake + this.coords.p_handle / 2) 1301 | this.coords.p_bar_w = this.toFixed(this.coords.p_to_fake - this.coords.p_from_fake) 1302 | 1303 | this.result.from_percent = this.coords.p_from_real 1304 | this.result.from = this.convertToValue(this.coords.p_from_real) 1305 | this.result.from_pretty = this._prettify(this.result.from) 1306 | this.result.to_percent = this.coords.p_to_real 1307 | this.result.to = this.convertToValue(this.coords.p_to_real) 1308 | this.result.to_pretty = this._prettify(this.result.to) 1309 | 1310 | if (this.options.values.length) { 1311 | this.result.from_value = this.options.values[this.result.from] 1312 | this.result.to_value = this.options.values[this.result.to] 1313 | } 1314 | } 1315 | 1316 | this.calcMinMax() 1317 | this.calcLabels() 1318 | }, 1319 | 1320 | /** 1321 | * calculates pointer X in percent 1322 | */ 1323 | calcPointerPercent: function() { 1324 | if (!this.coords.w_rs) { 1325 | this.coords.p_pointer = 0 1326 | return 1327 | } 1328 | 1329 | if (this.coords.x_pointer < 0 || isNaN(this.coords.x_pointer)) { 1330 | this.coords.x_pointer = 0 1331 | } else if (this.coords.x_pointer > this.coords.w_rs) { 1332 | this.coords.x_pointer = this.coords.w_rs 1333 | } 1334 | 1335 | this.coords.p_pointer = this.toFixed((this.coords.x_pointer / this.coords.w_rs) * 100) 1336 | }, 1337 | 1338 | convertToRealPercent: function(fake) { 1339 | var full = 100 - this.coords.p_handle 1340 | return (fake / full) * 100 1341 | }, 1342 | 1343 | convertToFakePercent: function(real) { 1344 | var full = 100 - this.coords.p_handle 1345 | return (real / 100) * full 1346 | }, 1347 | 1348 | getHandleX: function() { 1349 | var max = 100 - this.coords.p_handle, 1350 | x = this.toFixed(this.coords.p_pointer - this.coords.p_gap) 1351 | 1352 | if (x < 0) { 1353 | x = 0 1354 | } else if (x > max) { 1355 | x = max 1356 | } 1357 | 1358 | return x 1359 | }, 1360 | 1361 | calcHandlePercent: function() { 1362 | if (this.options.type === 'single') { 1363 | this.coords.w_handle = this.$cache.s_single.outerWidth(false) 1364 | } else { 1365 | this.coords.w_handle = this.$cache.s_from.outerWidth(false) 1366 | } 1367 | 1368 | this.coords.p_handle = this.toFixed((this.coords.w_handle / this.coords.w_rs) * 100) 1369 | }, 1370 | 1371 | /** 1372 | * Find closest handle to pointer click 1373 | * 1374 | * @param real_x {Number} 1375 | * @returns {String} 1376 | */ 1377 | chooseHandle: function(real_x) { 1378 | if (this.options.type === 'single') { 1379 | return 'single' 1380 | } else { 1381 | var m_point = 1382 | this.coords.p_from_real + (this.coords.p_to_real - this.coords.p_from_real) / 2 1383 | if (real_x >= m_point) { 1384 | return this.options.to_fixed ? 'from' : 'to' 1385 | } else { 1386 | return this.options.from_fixed ? 'to' : 'from' 1387 | } 1388 | } 1389 | }, 1390 | 1391 | /** 1392 | * Measure Min and Max labels width in percent 1393 | */ 1394 | calcMinMax: function() { 1395 | if (!this.coords.w_rs) { 1396 | return 1397 | } 1398 | 1399 | this.labels.p_min = (this.labels.w_min / this.coords.w_rs) * 100 1400 | this.labels.p_max = (this.labels.w_max / this.coords.w_rs) * 100 1401 | }, 1402 | 1403 | /** 1404 | * Measure labels width and X in percent 1405 | */ 1406 | calcLabels: function() { 1407 | if (!this.coords.w_rs || this.options.hide_from_to) { 1408 | return 1409 | } 1410 | 1411 | if (this.options.type === 'single') { 1412 | this.labels.w_single = this.$cache.single.outerWidth(false) 1413 | this.labels.p_single_fake = (this.labels.w_single / this.coords.w_rs) * 100 1414 | this.labels.p_single_left = 1415 | this.coords.p_single_fake + this.coords.p_handle / 2 - this.labels.p_single_fake / 2 1416 | this.labels.p_single_left = this.checkEdges( 1417 | this.labels.p_single_left, 1418 | this.labels.p_single_fake 1419 | ) 1420 | } else { 1421 | this.labels.w_from = this.$cache.from.outerWidth(false) 1422 | this.labels.p_from_fake = (this.labels.w_from / this.coords.w_rs) * 100 1423 | this.labels.p_from_left = 1424 | this.coords.p_from_fake + this.coords.p_handle / 2 - this.labels.p_from_fake / 2 1425 | this.labels.p_from_left = this.toFixed(this.labels.p_from_left) 1426 | this.labels.p_from_left = this.checkEdges(this.labels.p_from_left, this.labels.p_from_fake) 1427 | 1428 | this.labels.w_to = this.$cache.to.outerWidth(false) 1429 | this.labels.p_to_fake = (this.labels.w_to / this.coords.w_rs) * 100 1430 | this.labels.p_to_left = 1431 | this.coords.p_to_fake + this.coords.p_handle / 2 - this.labels.p_to_fake / 2 1432 | this.labels.p_to_left = this.toFixed(this.labels.p_to_left) 1433 | this.labels.p_to_left = this.checkEdges(this.labels.p_to_left, this.labels.p_to_fake) 1434 | 1435 | this.labels.w_single = this.$cache.single.outerWidth(false) 1436 | this.labels.p_single_fake = (this.labels.w_single / this.coords.w_rs) * 100 1437 | this.labels.p_single_left = 1438 | (this.labels.p_from_left + this.labels.p_to_left + this.labels.p_to_fake) / 2 - 1439 | this.labels.p_single_fake / 2 1440 | this.labels.p_single_left = this.toFixed(this.labels.p_single_left) 1441 | this.labels.p_single_left = this.checkEdges( 1442 | this.labels.p_single_left, 1443 | this.labels.p_single_fake 1444 | ) 1445 | } 1446 | }, 1447 | 1448 | // ============================================================================================================= 1449 | // Drawings 1450 | 1451 | /** 1452 | * Main function called in request animation frame 1453 | * to update everything 1454 | */ 1455 | updateScene: function() { 1456 | if (this.raf_id) { 1457 | cancelAnimationFrame(this.raf_id) 1458 | this.raf_id = null 1459 | } 1460 | 1461 | clearTimeout(this.update_tm) 1462 | this.update_tm = null 1463 | 1464 | if (!this.options) { 1465 | return 1466 | } 1467 | 1468 | this.drawHandles() 1469 | 1470 | if (this.is_active) { 1471 | this.raf_id = requestAnimationFrame(this.updateScene.bind(this)) 1472 | } else { 1473 | this.update_tm = setTimeout(this.updateScene.bind(this), 300) 1474 | } 1475 | }, 1476 | 1477 | /** 1478 | * Draw handles 1479 | */ 1480 | drawHandles: function() { 1481 | this.coords.w_rs = this.$cache.rs.outerWidth(false) 1482 | 1483 | if (!this.coords.w_rs) { 1484 | return 1485 | } 1486 | 1487 | if (this.coords.w_rs !== this.coords.w_rs_old) { 1488 | this.target = 'base' 1489 | this.is_resize = true 1490 | } 1491 | 1492 | if (this.coords.w_rs !== this.coords.w_rs_old || this.force_redraw) { 1493 | this.setMinMax() 1494 | this.calc(true) 1495 | this.drawLabels() 1496 | if (this.options.grid) { 1497 | this.calcGridMargin() 1498 | this.calcGridLabels() 1499 | } 1500 | this.force_redraw = true 1501 | this.coords.w_rs_old = this.coords.w_rs 1502 | this.drawShadow() 1503 | } 1504 | 1505 | if (!this.coords.w_rs) { 1506 | return 1507 | } 1508 | 1509 | if (!this.dragging && !this.force_redraw && !this.is_key) { 1510 | return 1511 | } 1512 | 1513 | if ( 1514 | this.old_from !== this.result.from || 1515 | this.old_to !== this.result.to || 1516 | this.force_redraw || 1517 | this.is_key 1518 | ) { 1519 | this.drawLabels() 1520 | 1521 | this.$cache.bar[0].style.left = this.coords.p_bar_x + '%' 1522 | this.$cache.bar[0].style.width = this.coords.p_bar_w + '%' 1523 | 1524 | if (this.options.type === 'single') { 1525 | this.$cache.bar[0].style.left = 0 1526 | this.$cache.bar[0].style.width = this.coords.p_bar_w + this.coords.p_bar_x + '%' 1527 | 1528 | this.$cache.s_single[0].style.left = this.coords.p_single_fake + '%' 1529 | 1530 | this.$cache.single[0].style.left = this.labels.p_single_left + '%' 1531 | } else { 1532 | this.$cache.s_from[0].style.left = this.coords.p_from_fake + '%' 1533 | this.$cache.s_to[0].style.left = this.coords.p_to_fake + '%' 1534 | 1535 | if (this.old_from !== this.result.from || this.force_redraw) { 1536 | this.$cache.from[0].style.left = this.labels.p_from_left + '%' 1537 | } 1538 | if (this.old_to !== this.result.to || this.force_redraw) { 1539 | this.$cache.to[0].style.left = this.labels.p_to_left + '%' 1540 | } 1541 | 1542 | this.$cache.single[0].style.left = this.labels.p_single_left + '%' 1543 | } 1544 | 1545 | this.writeToInput() 1546 | 1547 | if ( 1548 | (this.old_from !== this.result.from || this.old_to !== this.result.to) && 1549 | !this.is_start 1550 | ) { 1551 | this.$cache.input.trigger('change') 1552 | this.$cache.input.trigger('input') 1553 | } 1554 | 1555 | this.old_from = this.result.from 1556 | this.old_to = this.result.to 1557 | 1558 | // callbacks call 1559 | if (!this.is_resize && !this.is_update && !this.is_start && !this.is_finish) { 1560 | this.callOnChange() 1561 | } 1562 | if (this.is_key || this.is_click) { 1563 | this.is_key = false 1564 | this.is_click = false 1565 | this.callOnFinish() 1566 | } 1567 | 1568 | this.is_update = false 1569 | this.is_resize = false 1570 | this.is_finish = false 1571 | } 1572 | 1573 | this.is_start = false 1574 | this.is_key = false 1575 | this.is_click = false 1576 | this.force_redraw = false 1577 | }, 1578 | 1579 | /** 1580 | * Draw labels 1581 | * measure labels collisions 1582 | * collapse close labels 1583 | */ 1584 | drawLabels: function() { 1585 | if (!this.options) { 1586 | return 1587 | } 1588 | 1589 | var values_num = this.options.values.length 1590 | var p_values = this.options.p_values 1591 | var text_single 1592 | var text_from 1593 | var text_to 1594 | var from_pretty 1595 | var to_pretty 1596 | 1597 | if (this.options.hide_from_to) { 1598 | return 1599 | } 1600 | 1601 | if (this.options.type === 'single') { 1602 | if (values_num) { 1603 | text_single = this.decorate(p_values[this.result.from]) 1604 | this.$cache.single.html(text_single) 1605 | } else { 1606 | from_pretty = this._prettify(this.result.from) 1607 | 1608 | text_single = this.decorate(from_pretty, this.result.from) 1609 | this.$cache.single.html(text_single) 1610 | } 1611 | 1612 | this.calcLabels() 1613 | 1614 | if (this.labels.p_single_left < this.labels.p_min + 1) { 1615 | this.$cache.min[0].style.visibility = 'hidden' 1616 | } else { 1617 | this.$cache.min[0].style.visibility = 'visible' 1618 | } 1619 | 1620 | if (this.labels.p_single_left + this.labels.p_single_fake > 100 - this.labels.p_max - 1) { 1621 | this.$cache.max[0].style.visibility = 'hidden' 1622 | } else { 1623 | this.$cache.max[0].style.visibility = 'visible' 1624 | } 1625 | } else { 1626 | if (values_num) { 1627 | if (this.options.decorate_both) { 1628 | text_single = this.decorate(p_values[this.result.from]) 1629 | text_single += this.options.values_separator 1630 | text_single += this.decorate(p_values[this.result.to]) 1631 | } else { 1632 | text_single = this.decorate( 1633 | p_values[this.result.from] + this.options.values_separator + p_values[this.result.to] 1634 | ) 1635 | } 1636 | text_from = this.decorate(p_values[this.result.from]) 1637 | text_to = this.decorate(p_values[this.result.to]) 1638 | 1639 | this.$cache.single.html(text_single) 1640 | this.$cache.from.html(text_from) 1641 | this.$cache.to.html(text_to) 1642 | } else { 1643 | from_pretty = this._prettify(this.result.from) 1644 | to_pretty = this._prettify(this.result.to) 1645 | 1646 | if (this.options.decorate_both) { 1647 | text_single = this.decorate(from_pretty, this.result.from) 1648 | text_single += this.options.values_separator 1649 | text_single += this.decorate(to_pretty, this.result.to) 1650 | } else { 1651 | text_single = this.decorate( 1652 | from_pretty + this.options.values_separator + to_pretty, 1653 | this.result.to 1654 | ) 1655 | } 1656 | text_from = this.decorate(from_pretty, this.result.from) 1657 | text_to = this.decorate(to_pretty, this.result.to) 1658 | 1659 | this.$cache.single.html(text_single) 1660 | this.$cache.from.html(text_from) 1661 | this.$cache.to.html(text_to) 1662 | } 1663 | 1664 | this.calcLabels() 1665 | 1666 | var min = Math.min(this.labels.p_single_left, this.labels.p_from_left), 1667 | single_left = this.labels.p_single_left + this.labels.p_single_fake, 1668 | to_left = this.labels.p_to_left + this.labels.p_to_fake, 1669 | max = Math.max(single_left, to_left) 1670 | 1671 | if (this.labels.p_from_left + this.labels.p_from_fake >= this.labels.p_to_left) { 1672 | this.$cache.from[0].style.visibility = 'hidden' 1673 | this.$cache.to[0].style.visibility = 'hidden' 1674 | this.$cache.single[0].style.visibility = 'visible' 1675 | 1676 | if (this.result.from === this.result.to) { 1677 | if (this.target === 'from') { 1678 | this.$cache.from[0].style.visibility = 'visible' 1679 | } else if (this.target === 'to') { 1680 | this.$cache.to[0].style.visibility = 'visible' 1681 | } else if (!this.target) { 1682 | this.$cache.from[0].style.visibility = 'visible' 1683 | } 1684 | this.$cache.single[0].style.visibility = 'hidden' 1685 | max = to_left 1686 | } else { 1687 | this.$cache.from[0].style.visibility = 'hidden' 1688 | this.$cache.to[0].style.visibility = 'hidden' 1689 | this.$cache.single[0].style.visibility = 'visible' 1690 | max = Math.max(single_left, to_left) 1691 | } 1692 | } else { 1693 | this.$cache.from[0].style.visibility = 'visible' 1694 | this.$cache.to[0].style.visibility = 'visible' 1695 | this.$cache.single[0].style.visibility = 'hidden' 1696 | } 1697 | 1698 | if (min < this.labels.p_min + 1) { 1699 | this.$cache.min[0].style.visibility = 'hidden' 1700 | } else { 1701 | this.$cache.min[0].style.visibility = 'visible' 1702 | } 1703 | 1704 | if (max > 100 - this.labels.p_max - 1) { 1705 | this.$cache.max[0].style.visibility = 'hidden' 1706 | } else { 1707 | this.$cache.max[0].style.visibility = 'visible' 1708 | } 1709 | } 1710 | }, 1711 | 1712 | /** 1713 | * Draw shadow intervals 1714 | */ 1715 | drawShadow: function() { 1716 | var o = this.options, 1717 | c = this.$cache, 1718 | is_from_min = typeof o.from_min === 'number' && !isNaN(o.from_min), 1719 | is_from_max = typeof o.from_max === 'number' && !isNaN(o.from_max), 1720 | is_to_min = typeof o.to_min === 'number' && !isNaN(o.to_min), 1721 | is_to_max = typeof o.to_max === 'number' && !isNaN(o.to_max), 1722 | from_min, 1723 | from_max, 1724 | to_min, 1725 | to_max 1726 | 1727 | if (o.type === 'single') { 1728 | if (o.from_shadow && (is_from_min || is_from_max)) { 1729 | from_min = this.convertToPercent(is_from_min ? o.from_min : o.min) 1730 | from_max = this.convertToPercent(is_from_max ? o.from_max : o.max) - from_min 1731 | from_min = this.toFixed(from_min - (this.coords.p_handle / 100) * from_min) 1732 | from_max = this.toFixed(from_max - (this.coords.p_handle / 100) * from_max) 1733 | from_min = from_min + this.coords.p_handle / 2 1734 | 1735 | c.shad_single[0].style.display = 'block' 1736 | c.shad_single[0].style.left = from_min + '%' 1737 | c.shad_single[0].style.width = from_max + '%' 1738 | } else { 1739 | c.shad_single[0].style.display = 'none' 1740 | } 1741 | } else { 1742 | if (o.from_shadow && (is_from_min || is_from_max)) { 1743 | from_min = this.convertToPercent(is_from_min ? o.from_min : o.min) 1744 | from_max = this.convertToPercent(is_from_max ? o.from_max : o.max) - from_min 1745 | from_min = this.toFixed(from_min - (this.coords.p_handle / 100) * from_min) 1746 | from_max = this.toFixed(from_max - (this.coords.p_handle / 100) * from_max) 1747 | from_min = from_min + this.coords.p_handle / 2 1748 | 1749 | c.shad_from[0].style.display = 'block' 1750 | c.shad_from[0].style.left = from_min + '%' 1751 | c.shad_from[0].style.width = from_max + '%' 1752 | } else { 1753 | c.shad_from[0].style.display = 'none' 1754 | } 1755 | 1756 | if (o.to_shadow && (is_to_min || is_to_max)) { 1757 | to_min = this.convertToPercent(is_to_min ? o.to_min : o.min) 1758 | to_max = this.convertToPercent(is_to_max ? o.to_max : o.max) - to_min 1759 | to_min = this.toFixed(to_min - (this.coords.p_handle / 100) * to_min) 1760 | to_max = this.toFixed(to_max - (this.coords.p_handle / 100) * to_max) 1761 | to_min = to_min + this.coords.p_handle / 2 1762 | 1763 | c.shad_to[0].style.display = 'block' 1764 | c.shad_to[0].style.left = to_min + '%' 1765 | c.shad_to[0].style.width = to_max + '%' 1766 | } else { 1767 | c.shad_to[0].style.display = 'none' 1768 | } 1769 | } 1770 | }, 1771 | 1772 | /** 1773 | * Write values to input element 1774 | */ 1775 | writeToInput: function() { 1776 | if (this.options.type === 'single') { 1777 | if (this.options.values.length) { 1778 | this.$cache.input.prop('value', this.result.from_value) 1779 | } else { 1780 | this.$cache.input.prop('value', this.result.from) 1781 | } 1782 | this.$cache.input.data('from', this.result.from) 1783 | } else { 1784 | if (this.options.values.length) { 1785 | this.$cache.input.prop( 1786 | 'value', 1787 | this.result.from_value + this.options.input_values_separator + this.result.to_value 1788 | ) 1789 | } else { 1790 | this.$cache.input.prop( 1791 | 'value', 1792 | this.result.from + this.options.input_values_separator + this.result.to 1793 | ) 1794 | } 1795 | this.$cache.input.data('from', this.result.from) 1796 | this.$cache.input.data('to', this.result.to) 1797 | } 1798 | }, 1799 | 1800 | // ============================================================================================================= 1801 | // Callbacks 1802 | 1803 | callOnStart: function() { 1804 | this.writeToInput() 1805 | 1806 | if (this.options.onStart && typeof this.options.onStart === 'function') { 1807 | if (this.options.scope) { 1808 | this.options.onStart.call(this.options.scope, this.result) 1809 | } else { 1810 | this.options.onStart(this.result) 1811 | } 1812 | } 1813 | }, 1814 | callOnChange: function() { 1815 | this.writeToInput() 1816 | 1817 | if (this.options.onChange && typeof this.options.onChange === 'function') { 1818 | if (this.options.scope) { 1819 | this.options.onChange.call(this.options.scope, this.result) 1820 | } else { 1821 | this.options.onChange(this.result) 1822 | } 1823 | } 1824 | }, 1825 | callOnFinish: function() { 1826 | this.writeToInput() 1827 | 1828 | if (this.options.onFinish && typeof this.options.onFinish === 'function') { 1829 | if (this.options.scope) { 1830 | this.options.onFinish.call(this.options.scope, this.result) 1831 | } else { 1832 | this.options.onFinish(this.result) 1833 | } 1834 | } 1835 | }, 1836 | callOnUpdate: function() { 1837 | this.writeToInput() 1838 | 1839 | if (this.options.onUpdate && typeof this.options.onUpdate === 'function') { 1840 | if (this.options.scope) { 1841 | this.options.onUpdate.call(this.options.scope, this.result) 1842 | } else { 1843 | this.options.onUpdate(this.result) 1844 | } 1845 | } 1846 | }, 1847 | 1848 | // ============================================================================================================= 1849 | // Service methods 1850 | 1851 | toggleInput: function() { 1852 | this.$cache.input.toggleClass('irs-hidden-input') 1853 | 1854 | if (this.has_tab_index) { 1855 | this.$cache.input.prop('tabindex', -1) 1856 | } else { 1857 | this.$cache.input.removeProp('tabindex') 1858 | } 1859 | 1860 | this.has_tab_index = !this.has_tab_index 1861 | }, 1862 | 1863 | /** 1864 | * Convert real value to percent 1865 | * 1866 | * @param value {Number} X in real 1867 | * @param no_min {boolean=} don't use min value 1868 | * @returns {Number} X in percent 1869 | */ 1870 | convertToPercent: function(value, no_min) { 1871 | var diapason = this.options.max - this.options.min, 1872 | one_percent = diapason / 100, 1873 | val, 1874 | percent 1875 | 1876 | if (!diapason) { 1877 | this.no_diapason = true 1878 | return 0 1879 | } 1880 | 1881 | if (no_min) { 1882 | val = value 1883 | } else { 1884 | val = value - this.options.min 1885 | } 1886 | 1887 | percent = val / one_percent 1888 | 1889 | return this.toFixed(percent) 1890 | }, 1891 | 1892 | /** 1893 | * Convert percent to real values 1894 | * 1895 | * @param percent {Number} X in percent 1896 | * @returns {Number} X in real 1897 | */ 1898 | convertToValue: function(percent) { 1899 | var min = this.options.min, 1900 | max = this.options.max, 1901 | min_decimals = min.toString().split('.')[1], 1902 | max_decimals = max.toString().split('.')[1], 1903 | min_length, 1904 | max_length, 1905 | avg_decimals = 0, 1906 | abs = 0 1907 | 1908 | if (percent === 0) { 1909 | return this.options.min 1910 | } 1911 | if (percent === 100) { 1912 | return this.options.max 1913 | } 1914 | 1915 | if (min_decimals) { 1916 | min_length = min_decimals.length 1917 | avg_decimals = min_length 1918 | } 1919 | if (max_decimals) { 1920 | max_length = max_decimals.length 1921 | avg_decimals = max_length 1922 | } 1923 | if (min_length && max_length) { 1924 | avg_decimals = min_length >= max_length ? min_length : max_length 1925 | } 1926 | 1927 | if (min < 0) { 1928 | abs = Math.abs(min) 1929 | min = +(min + abs).toFixed(avg_decimals) 1930 | max = +(max + abs).toFixed(avg_decimals) 1931 | } 1932 | 1933 | var number = ((max - min) / 100) * percent + min, 1934 | string = this.options.step.toString().split('.')[1], 1935 | result 1936 | 1937 | if (string) { 1938 | number = +number.toFixed(string.length) 1939 | } else { 1940 | number = number / this.options.step 1941 | number = number * this.options.step 1942 | 1943 | number = +number.toFixed(0) 1944 | } 1945 | 1946 | if (abs) { 1947 | number -= abs 1948 | } 1949 | 1950 | if (string) { 1951 | result = +number.toFixed(string.length) 1952 | } else { 1953 | result = this.toFixed(number) 1954 | } 1955 | 1956 | if (result < this.options.min) { 1957 | result = this.options.min 1958 | } else if (result > this.options.max) { 1959 | result = this.options.max 1960 | } 1961 | 1962 | return result 1963 | }, 1964 | 1965 | /** 1966 | * Round percent value with step 1967 | * 1968 | * @param percent {Number} 1969 | * @returns percent {Number} rounded 1970 | */ 1971 | calcWithStep: function(percent) { 1972 | var rounded = Math.round(percent / this.coords.p_step) * this.coords.p_step 1973 | 1974 | if (rounded > 100) { 1975 | rounded = 100 1976 | } 1977 | if (percent === 100) { 1978 | rounded = 100 1979 | } 1980 | 1981 | return this.toFixed(rounded) 1982 | }, 1983 | 1984 | checkMinInterval: function(p_current, p_next, type) { 1985 | var o = this.options, 1986 | current, 1987 | next 1988 | 1989 | if (!o.min_interval) { 1990 | return p_current 1991 | } 1992 | 1993 | current = this.convertToValue(p_current) 1994 | next = this.convertToValue(p_next) 1995 | 1996 | if (type === 'from') { 1997 | if (next - current < o.min_interval) { 1998 | current = next - o.min_interval 1999 | } 2000 | } else { 2001 | if (current - next < o.min_interval) { 2002 | current = next + o.min_interval 2003 | } 2004 | } 2005 | 2006 | return this.convertToPercent(current) 2007 | }, 2008 | 2009 | checkMaxInterval: function(p_current, p_next, type) { 2010 | var o = this.options, 2011 | current, 2012 | next 2013 | 2014 | if (!o.max_interval) { 2015 | return p_current 2016 | } 2017 | 2018 | current = this.convertToValue(p_current) 2019 | next = this.convertToValue(p_next) 2020 | 2021 | if (type === 'from') { 2022 | if (next - current > o.max_interval) { 2023 | current = next - o.max_interval 2024 | } 2025 | } else { 2026 | if (current - next > o.max_interval) { 2027 | current = next + o.max_interval 2028 | } 2029 | } 2030 | 2031 | return this.convertToPercent(current) 2032 | }, 2033 | 2034 | checkDiapason: function(p_num, min, max) { 2035 | var num = this.convertToValue(p_num), 2036 | o = this.options 2037 | 2038 | if (typeof min !== 'number') { 2039 | min = o.min 2040 | } 2041 | 2042 | if (typeof max !== 'number') { 2043 | max = o.max 2044 | } 2045 | 2046 | if (num < min) { 2047 | num = min 2048 | } 2049 | 2050 | if (num > max) { 2051 | num = max 2052 | } 2053 | 2054 | return this.convertToPercent(num) 2055 | }, 2056 | 2057 | toFixed: function(num) { 2058 | num = num.toFixed(20) 2059 | return +num 2060 | }, 2061 | 2062 | _prettify: function(num) { 2063 | if (!this.options.prettify_enabled) { 2064 | return num 2065 | } 2066 | 2067 | if (this.options.prettify && typeof this.options.prettify === 'function') { 2068 | return this.options.prettify(num) 2069 | } else { 2070 | return this.prettify(num) 2071 | } 2072 | }, 2073 | 2074 | prettify: function(num) { 2075 | var n = num.toString() 2076 | return n.replace(/(\d{1,3}(?=(?:\d\d\d)+(?!\d)))/g, '$1' + this.options.prettify_separator) 2077 | }, 2078 | 2079 | checkEdges: function(left, width) { 2080 | if (!this.options.force_edges) { 2081 | return this.toFixed(left) 2082 | } 2083 | 2084 | if (left < 0) { 2085 | left = 0 2086 | } else if (left > 100 - width) { 2087 | left = 100 - width 2088 | } 2089 | 2090 | return this.toFixed(left) 2091 | }, 2092 | 2093 | validate: function() { 2094 | var o = this.options, 2095 | r = this.result, 2096 | v = o.values, 2097 | vl = v.length, 2098 | value, 2099 | i 2100 | 2101 | if (typeof o.min === 'string') o.min = +o.min 2102 | if (typeof o.max === 'string') o.max = +o.max 2103 | if (typeof o.from === 'string') o.from = +o.from 2104 | if (typeof o.to === 'string') o.to = +o.to 2105 | if (typeof o.step === 'string') o.step = +o.step 2106 | 2107 | if (typeof o.from_min === 'string') o.from_min = +o.from_min 2108 | if (typeof o.from_max === 'string') o.from_max = +o.from_max 2109 | if (typeof o.to_min === 'string') o.to_min = +o.to_min 2110 | if (typeof o.to_max === 'string') o.to_max = +o.to_max 2111 | 2112 | if (typeof o.grid_num === 'string') o.grid_num = +o.grid_num 2113 | 2114 | if (o.max < o.min) { 2115 | o.max = o.min 2116 | } 2117 | 2118 | if (vl) { 2119 | o.p_values = [] 2120 | o.min = 0 2121 | o.max = vl - 1 2122 | o.step = 1 2123 | o.grid_num = o.max 2124 | o.grid_snap = true 2125 | 2126 | for (i = 0; i < vl; i++) { 2127 | value = +v[i] 2128 | 2129 | if (!isNaN(value)) { 2130 | v[i] = value 2131 | value = this._prettify(value) 2132 | } else { 2133 | value = v[i] 2134 | } 2135 | 2136 | o.p_values.push(value) 2137 | } 2138 | } 2139 | 2140 | if (typeof o.from !== 'number' || isNaN(o.from)) { 2141 | o.from = o.min 2142 | } 2143 | 2144 | if (typeof o.to !== 'number' || isNaN(o.to)) { 2145 | o.to = o.max 2146 | } 2147 | 2148 | if (o.type === 'single') { 2149 | if (o.from < o.min) o.from = o.min 2150 | if (o.from > o.max) o.from = o.max 2151 | } else { 2152 | if (o.from < o.min) o.from = o.min 2153 | if (o.from > o.max) o.from = o.max 2154 | 2155 | if (o.to < o.min) o.to = o.min 2156 | if (o.to > o.max) o.to = o.max 2157 | 2158 | if (this.update_check.from) { 2159 | if (this.update_check.from !== o.from) { 2160 | if (o.from > o.to) o.from = o.to 2161 | } 2162 | if (this.update_check.to !== o.to) { 2163 | if (o.to < o.from) o.to = o.from 2164 | } 2165 | } 2166 | 2167 | if (o.from > o.to) o.from = o.to 2168 | if (o.to < o.from) o.to = o.from 2169 | } 2170 | 2171 | if (typeof o.step !== 'number' || isNaN(o.step) || !o.step || o.step < 0) { 2172 | o.step = 1 2173 | } 2174 | 2175 | if (typeof o.from_min === 'number' && o.from < o.from_min) { 2176 | o.from = o.from_min 2177 | } 2178 | 2179 | if (typeof o.from_max === 'number' && o.from > o.from_max) { 2180 | o.from = o.from_max 2181 | } 2182 | 2183 | if (typeof o.to_min === 'number' && o.to < o.to_min) { 2184 | o.to = o.to_min 2185 | } 2186 | 2187 | if (typeof o.to_max === 'number' && o.from > o.to_max) { 2188 | o.to = o.to_max 2189 | } 2190 | 2191 | if (r) { 2192 | if (r.min !== o.min) { 2193 | r.min = o.min 2194 | } 2195 | 2196 | if (r.max !== o.max) { 2197 | r.max = o.max 2198 | } 2199 | 2200 | if (r.from < r.min || r.from > r.max) { 2201 | r.from = o.from 2202 | } 2203 | 2204 | if (r.to < r.min || r.to > r.max) { 2205 | r.to = o.to 2206 | } 2207 | } 2208 | 2209 | if ( 2210 | typeof o.min_interval !== 'number' || 2211 | isNaN(o.min_interval) || 2212 | !o.min_interval || 2213 | o.min_interval < 0 2214 | ) { 2215 | o.min_interval = 0 2216 | } 2217 | 2218 | if ( 2219 | typeof o.max_interval !== 'number' || 2220 | isNaN(o.max_interval) || 2221 | !o.max_interval || 2222 | o.max_interval < 0 2223 | ) { 2224 | o.max_interval = 0 2225 | } 2226 | 2227 | if (o.min_interval && o.min_interval > o.max - o.min) { 2228 | o.min_interval = o.max - o.min 2229 | } 2230 | 2231 | if (o.max_interval && o.max_interval > o.max - o.min) { 2232 | o.max_interval = o.max - o.min 2233 | } 2234 | }, 2235 | 2236 | decorate: function(num, original) { 2237 | var decorated = '', 2238 | o = this.options 2239 | 2240 | if (o.prefix) { 2241 | decorated += o.prefix 2242 | } 2243 | 2244 | decorated += num 2245 | 2246 | if (o.max_postfix) { 2247 | if (o.values.length && num === o.p_values[o.max]) { 2248 | decorated += o.max_postfix 2249 | if (o.postfix) { 2250 | decorated += ' ' 2251 | } 2252 | } else if (original === o.max) { 2253 | decorated += o.max_postfix 2254 | if (o.postfix) { 2255 | decorated += ' ' 2256 | } 2257 | } 2258 | } 2259 | 2260 | if (o.postfix) { 2261 | decorated += o.postfix 2262 | } 2263 | 2264 | return decorated 2265 | }, 2266 | 2267 | updateFrom: function() { 2268 | this.result.from = this.options.from 2269 | this.result.from_percent = this.convertToPercent(this.result.from) 2270 | this.result.from_pretty = this._prettify(this.result.from) 2271 | if (this.options.values) { 2272 | this.result.from_value = this.options.values[this.result.from] 2273 | } 2274 | }, 2275 | 2276 | updateTo: function() { 2277 | this.result.to = this.options.to 2278 | this.result.to_percent = this.convertToPercent(this.result.to) 2279 | this.result.to_pretty = this._prettify(this.result.to) 2280 | if (this.options.values) { 2281 | this.result.to_value = this.options.values[this.result.to] 2282 | } 2283 | }, 2284 | 2285 | updateResult: function() { 2286 | this.result.min = this.options.min 2287 | this.result.max = this.options.max 2288 | this.updateFrom() 2289 | this.updateTo() 2290 | }, 2291 | 2292 | // ============================================================================================================= 2293 | // Grid 2294 | 2295 | appendGrid: function() { 2296 | if (!this.options.grid) { 2297 | return 2298 | } 2299 | 2300 | var o = this.options, 2301 | i, 2302 | z, 2303 | total = o.max - o.min, 2304 | big_num = o.grid_num, 2305 | big_p = 0, 2306 | big_w = 0, 2307 | small_max = 4, 2308 | local_small_max, 2309 | small_p, 2310 | small_w = 0, 2311 | result, 2312 | html = '' 2313 | 2314 | this.calcGridMargin() 2315 | 2316 | if (o.grid_snap) { 2317 | big_num = total / o.step 2318 | } 2319 | 2320 | if (big_num > 50) big_num = 50 2321 | big_p = this.toFixed(100 / big_num) 2322 | 2323 | if (big_num > 4) { 2324 | small_max = 3 2325 | } 2326 | if (big_num > 7) { 2327 | small_max = 2 2328 | } 2329 | if (big_num > 14) { 2330 | small_max = 1 2331 | } 2332 | if (big_num > 28) { 2333 | small_max = 0 2334 | } 2335 | 2336 | for (i = 0; i < big_num + 1; i++) { 2337 | local_small_max = small_max 2338 | 2339 | big_w = this.toFixed(big_p * i) 2340 | 2341 | if (big_w > 100) { 2342 | big_w = 100 2343 | } 2344 | this.coords.big[i] = big_w 2345 | 2346 | small_p = (big_w - big_p * (i - 1)) / (local_small_max + 1) 2347 | 2348 | for (z = 1; z <= local_small_max; z++) { 2349 | if (big_w === 0) { 2350 | break 2351 | } 2352 | 2353 | small_w = this.toFixed(big_w - small_p * z) 2354 | 2355 | html += '' 2356 | } 2357 | 2358 | html += '' 2359 | 2360 | result = this.convertToValue(big_w) 2361 | if (o.values.length) { 2362 | result = o.p_values[result] 2363 | } else { 2364 | result = this._prettify(result) 2365 | } 2366 | 2367 | html += 2368 | '' + 2373 | result + 2374 | '' 2375 | } 2376 | this.coords.big_num = Math.ceil(big_num + 1) 2377 | 2378 | this.$cache.cont.addClass('irs-with-grid') 2379 | this.$cache.grid.html(html) 2380 | this.cacheGridLabels() 2381 | }, 2382 | 2383 | cacheGridLabels: function() { 2384 | var $label, 2385 | i, 2386 | num = this.coords.big_num 2387 | 2388 | for (i = 0; i < num; i++) { 2389 | $label = this.$cache.grid.find('.js-grid-text-' + i) 2390 | this.$cache.grid_labels.push($label) 2391 | } 2392 | 2393 | this.calcGridLabels() 2394 | }, 2395 | 2396 | calcGridLabels: function() { 2397 | var i, 2398 | label, 2399 | start = [], 2400 | finish = [], 2401 | num = this.coords.big_num 2402 | 2403 | for (i = 0; i < num; i++) { 2404 | this.coords.big_w[i] = this.$cache.grid_labels[i].outerWidth(false) 2405 | this.coords.big_p[i] = this.toFixed((this.coords.big_w[i] / this.coords.w_rs) * 100) 2406 | this.coords.big_x[i] = this.toFixed(this.coords.big_p[i] / 2) 2407 | 2408 | start[i] = this.toFixed(this.coords.big[i] - this.coords.big_x[i]) 2409 | finish[i] = this.toFixed(start[i] + this.coords.big_p[i]) 2410 | } 2411 | 2412 | if (this.options.force_edges) { 2413 | if (start[0] < -this.coords.grid_gap) { 2414 | start[0] = -this.coords.grid_gap 2415 | finish[0] = this.toFixed(start[0] + this.coords.big_p[0]) 2416 | 2417 | this.coords.big_x[0] = this.coords.grid_gap 2418 | } 2419 | 2420 | if (finish[num - 1] > 100 + this.coords.grid_gap) { 2421 | finish[num - 1] = 100 + this.coords.grid_gap 2422 | start[num - 1] = this.toFixed(finish[num - 1] - this.coords.big_p[num - 1]) 2423 | 2424 | this.coords.big_x[num - 1] = this.toFixed( 2425 | this.coords.big_p[num - 1] - this.coords.grid_gap 2426 | ) 2427 | } 2428 | } 2429 | 2430 | this.calcGridCollision(2, start, finish) 2431 | this.calcGridCollision(4, start, finish) 2432 | 2433 | for (i = 0; i < num; i++) { 2434 | label = this.$cache.grid_labels[i][0] 2435 | 2436 | if (this.coords.big_x[i] !== Number.POSITIVE_INFINITY) { 2437 | label.style.marginLeft = -this.coords.big_x[i] + '%' 2438 | } 2439 | } 2440 | }, 2441 | 2442 | // Collisions Calc Beta 2443 | // TODO: Refactor then have plenty of time 2444 | calcGridCollision: function(step, start, finish) { 2445 | var i, 2446 | next_i, 2447 | label, 2448 | num = this.coords.big_num 2449 | 2450 | for (i = 0; i < num; i += step) { 2451 | next_i = i + step / 2 2452 | if (next_i >= num) { 2453 | break 2454 | } 2455 | 2456 | label = this.$cache.grid_labels[next_i][0] 2457 | 2458 | if (finish[i] <= start[next_i]) { 2459 | label.style.visibility = 'visible' 2460 | } else { 2461 | label.style.visibility = 'hidden' 2462 | } 2463 | } 2464 | }, 2465 | 2466 | calcGridMargin: function() { 2467 | if (!this.options.grid_margin) { 2468 | return 2469 | } 2470 | 2471 | this.coords.w_rs = this.$cache.rs.outerWidth(false) 2472 | if (!this.coords.w_rs) { 2473 | return 2474 | } 2475 | 2476 | if (this.options.type === 'single') { 2477 | this.coords.w_handle = this.$cache.s_single.outerWidth(false) 2478 | } else { 2479 | this.coords.w_handle = this.$cache.s_from.outerWidth(false) 2480 | } 2481 | this.coords.p_handle = this.toFixed((this.coords.w_handle / this.coords.w_rs) * 100) 2482 | this.coords.grid_gap = this.toFixed(this.coords.p_handle / 2 - 0.1) 2483 | 2484 | this.$cache.grid[0].style.width = this.toFixed(100 - this.coords.p_handle) + '%' 2485 | this.$cache.grid[0].style.left = this.coords.grid_gap + '%' 2486 | }, 2487 | 2488 | // ============================================================================================================= 2489 | // Public methods 2490 | 2491 | update: function(options) { 2492 | if (!this.input) { 2493 | return 2494 | } 2495 | 2496 | this.is_update = true 2497 | 2498 | this.options.from = this.result.from 2499 | this.options.to = this.result.to 2500 | this.update_check.from = this.result.from 2501 | this.update_check.to = this.result.to 2502 | 2503 | this.options = $.extend(this.options, options) 2504 | this.validate() 2505 | this.updateResult(options) 2506 | 2507 | this.toggleInput() 2508 | this.remove() 2509 | this.init(true) 2510 | }, 2511 | 2512 | reset: function() { 2513 | if (!this.input) { 2514 | return 2515 | } 2516 | 2517 | this.updateResult() 2518 | this.update() 2519 | }, 2520 | 2521 | destroy: function() { 2522 | if (!this.input) { 2523 | return 2524 | } 2525 | 2526 | this.toggleInput() 2527 | this.$cache.input.prop('readonly', false) 2528 | $.data(this.input, 'ionRangeSlider', null) 2529 | 2530 | this.remove() 2531 | this.input = null 2532 | this.options = null 2533 | } 2534 | } 2535 | 2536 | $.fn.ionRangeSlider = function(options) { 2537 | return this.each(function() { 2538 | if (!$.data(this, 'ionRangeSlider')) { 2539 | $.data(this, 'ionRangeSlider', new IonRangeSlider(this, options, plugin_count++)) 2540 | } 2541 | }) 2542 | } 2543 | 2544 | // ================================================================================================================= 2545 | // http://paulirish.com/2011/requestanimationframe-for-smart-animating/ 2546 | // http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating 2547 | 2548 | // requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel 2549 | 2550 | // MIT license 2551 | 2552 | ;(function() { 2553 | var lastTime = 0 2554 | var vendors = ['ms', 'moz', 'webkit', 'o'] 2555 | for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { 2556 | window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'] 2557 | window.cancelAnimationFrame = 2558 | window[vendors[x] + 'CancelAnimationFrame'] || 2559 | window[vendors[x] + 'CancelRequestAnimationFrame'] 2560 | } 2561 | 2562 | if (!window.requestAnimationFrame) 2563 | window.requestAnimationFrame = function(callback, element) { 2564 | var currTime = new Date().getTime() 2565 | var timeToCall = Math.max(0, 16 - (currTime - lastTime)) 2566 | var id = window.setTimeout(function() { 2567 | callback(currTime + timeToCall) 2568 | }, timeToCall) 2569 | lastTime = currTime + timeToCall 2570 | return id 2571 | } 2572 | 2573 | if (!window.cancelAnimationFrame) 2574 | window.cancelAnimationFrame = function(id) { 2575 | clearTimeout(id) 2576 | } 2577 | })() 2578 | }) 2579 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | 4 | Vue.config.productionTip = false 5 | 6 | new Vue({ 7 | render: h => h(App) 8 | }).$mount('#app') 9 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | devServer: { 3 | port: 8000 4 | } 5 | } 6 | --------------------------------------------------------------------------------