├── .gitignore ├── LICENSE ├── README.md ├── bower.json ├── dist ├── RangeSlider-all.min.css ├── RangeSlider-all.min.js ├── RangeSlider-minimal.min.css ├── RangeSlider-minimal.min.js ├── RangeSlider-solo.min.css └── RangeSlider-solo.min.js ├── gulpfile.js ├── package.json ├── src ├── RangeSlider-core.css └── RangeSlider-core.js └── test └── test-1.html /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # Compiled binary addons (http://nodejs.org/api/addons.html) 20 | build/Release 21 | 22 | # Dependency directory 23 | # Commenting this out is preferred by some people, see 24 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 25 | node_modules 26 | 27 | # Users Environment Variables 28 | .lock-wscript 29 | /bower_components 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Shane Gadsby 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 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Chart.JS-RangeSlider 2 | A range slider plugin for Chart.JS, that enables you to select a specific data scales. 3 | 4 | ## Demo 5 | JSFiddle: https://jsfiddle.net/schme16/xfyvvup8/195/ 6 | 7 | ## Installation: 8 | `bower install chart.js-rangeslider --save` 9 | `npm install chart.js-rangeslider --save` 10 | or straight from the source: 11 | - As a zip: https://github.com/schme16/Chart.js-RangeSlider/archive/master.zip) 12 | - via git: `git clone https://github.com/schme16/Chart.js-RangeSlider.git` 13 | 14 | ## Dependencies 15 | - jQuery (_for now_) 16 | - Chart.js 17 | - noUISlider 18 | 19 | ## Which one should I use? 20 | - Include the version that suits you best; the library comes in three flavours: 21 | - Solo: Only the plugin is included. 22 | - Minimal: The plugin and the slider library [noUISlider](https://github.com/leongersen/noUiSlider) is included 23 | - All: This one is batteries included, as such it come with jQuery, Chart.js noUISlider and the plugin all bundled together. 24 | 25 | ## Usage 26 | ```javascript 27 | new RangeSliderChart({ 28 | 29 | chartData: chartJSDatasets, //The same data you give to Chart.js 30 | chartOpts: chartJSOptions, //Your Chart.js options 31 | chartType: 'Line', //Which Chart.js chart you want (eg. Lie, Bar, Pie, etc.) 32 | chartCTX: ctx, //your canvas context 33 | 34 | class: 'my-chart-ranger', //Specifies a custom class you want applied to your sliders 35 | 36 | initial: [3, 10] //Which data points to start the sliders on 37 | }) 38 | ``` 39 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "chart.js-rangeslider", 3 | "version": "1.2.5", 4 | "homepage": "https://github.com/schme16/Chart.js-RangeSlider", 5 | "repo": "https://github.com/schme16/Chart.js-RangeSlider", 6 | "authors": [ 7 | "Shane Gadsby " 8 | ], 9 | "description": "This adds the option of having a range slider to your charts, to allow you to select a specific data scale — Edit", 10 | "main": "Chart.JS-RangeSlider.min.js", 11 | "keywords": [ 12 | "Chart.js", 13 | "plugin", 14 | "range", 15 | "slider", 16 | "RangeSlider" 17 | ], 18 | "license": "MIT", 19 | "ignore": [ 20 | "**/.*", 21 | "node_modules", 22 | "gulpfile.js", 23 | "bower_components", 24 | "test", 25 | "tests" 26 | ], 27 | "dependencies": { 28 | "Chart.js": "^2.2.2", 29 | "nouislider": "^8.5.1", 30 | "jquery": "2" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /dist/RangeSlider-all.min.css: -------------------------------------------------------------------------------- 1 | /*! nouislider - 8.5.1 - 2016-04-24 16:00:30 */ 2 | 3 | 4 | .noUi-target,.noUi-target *{-webkit-touch-callout:none;-webkit-user-select:none;-ms-touch-action:none;touch-action:none;-ms-user-select:none;-moz-user-select:none;-webkit-user-select:none;user-select:none;box-sizing:border-box}.noUi-target{position:relative;direction:ltr}.noUi-base{width:100%;height:100%;position:relative;z-index:1}.noUi-origin{position:absolute;right:0;top:0;left:0;bottom:0}.noUi-handle{position:relative;z-index:1}.noUi-stacking .noUi-handle{z-index:10}.noUi-state-tap .noUi-origin{-webkit-transition:left .3s,top .3s;transition:left .3s,top .3s}.noUi-state-drag *{cursor:inherit!important}.noUi-base,.noUi-handle{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.noUi-horizontal{height:18px}.noUi-horizontal .noUi-handle{width:34px;height:28px;left:-17px;top:-6px}.noUi-vertical{width:18px}.noUi-vertical .noUi-handle{width:28px;height:34px;left:-6px;top:-17px}.noUi-background{background:#FAFAFA;box-shadow:inset 0 1px 1px #f0f0f0}.noUi-connect{background:#3FB8AF;box-shadow:inset 0 0 3px rgba(51,51,51,.45);-webkit-transition:background 450ms;transition:background 450ms}.noUi-origin{border-radius:2px}.noUi-target{border-radius:4px;border:1px solid #D3D3D3;box-shadow:inset 0 1px 1px #F0F0F0,0 3px 6px -5px #BBB}.noUi-target.noUi-connect{box-shadow:inset 0 0 3px rgba(51,51,51,.45),0 3px 6px -5px #BBB}.noUi-draggable{cursor:w-resize}.noUi-vertical .noUi-draggable{cursor:n-resize}.noUi-handle{border:1px solid #D9D9D9;border-radius:3px;background:#FFF;cursor:default;box-shadow:inset 0 0 1px #FFF,inset 0 1px 7px #EBEBEB,0 3px 6px -3px #BBB}.noUi-active{box-shadow:inset 0 0 1px #FFF,inset 0 1px 7px #DDD,0 3px 6px -3px #BBB}.noUi-handle:after,.noUi-handle:before{content:"";display:block;position:absolute;height:14px;width:1px;background:#E8E7E6;left:14px;top:6px}.noUi-handle:after{left:17px}.noUi-vertical .noUi-handle:after,.noUi-vertical .noUi-handle:before{width:14px;height:1px;left:6px;top:14px}.noUi-vertical .noUi-handle:after{top:17px}[disabled] .noUi-connect,[disabled].noUi-connect{background:#B8B8B8}[disabled] .noUi-handle,[disabled].noUi-origin{cursor:not-allowed}.noUi-pips,.noUi-pips *{box-sizing:border-box}.noUi-pips{position:absolute;color:#999}.noUi-value{position:absolute;text-align:center}.noUi-value-sub{color:#ccc;font-size:10px}.noUi-marker{position:absolute;background:#CCC}.noUi-marker-large,.noUi-marker-sub{background:#AAA}.noUi-pips-horizontal{padding:10px 0;height:80px;top:100%;left:0;width:100%}.noUi-value-horizontal{-webkit-transform:translate3d(-50%,50%,0);transform:translate3d(-50%,50%,0)}.noUi-marker-horizontal.noUi-marker{margin-left:-1px;width:2px;height:5px}.noUi-marker-horizontal.noUi-marker-sub{height:10px}.noUi-marker-horizontal.noUi-marker-large{height:15px}.noUi-pips-vertical{padding:0 10px;height:100%;top:0;left:100%}.noUi-value-vertical{-webkit-transform:translate3d(0,-50%,0);transform:translate3d(0,-50%,0);padding-left:25px}.noUi-marker-vertical.noUi-marker{width:5px;height:2px;margin-top:-1px}.noUi-marker-vertical.noUi-marker-sub{width:10px}.noUi-marker-vertical.noUi-marker-large{width:15px}.noUi-tooltip{display:block;position:absolute;border:1px solid #D9D9D9;border-radius:3px;background:#fff;padding:5px;text-align:center}.noUi-horizontal .noUi-handle-lower .noUi-tooltip{top:-32px}.noUi-horizontal .noUi-handle-upper .noUi-tooltip{bottom:-32px}.noUi-vertical .noUi-handle-lower .noUi-tooltip{left:120%}.noUi-vertical .noUi-handle-upper .noUi-tooltip{right:120%} 5 | .range-slider { 6 | margin: auto; 7 | margin-top:15px; 8 | height: 10px; 9 | } 10 | 11 | .noUi-horizontal .noUi-handle { 12 | width: 34px; 13 | height: 28px; 14 | left: -17px; 15 | top: -10px; 16 | } -------------------------------------------------------------------------------- /dist/RangeSlider-minimal.min.css: -------------------------------------------------------------------------------- 1 | /*! nouislider - 8.5.1 - 2016-04-24 16:00:30 */ 2 | 3 | 4 | .noUi-target,.noUi-target *{-webkit-touch-callout:none;-webkit-user-select:none;-ms-touch-action:none;touch-action:none;-ms-user-select:none;-moz-user-select:none;-webkit-user-select:none;user-select:none;box-sizing:border-box}.noUi-target{position:relative;direction:ltr}.noUi-base{width:100%;height:100%;position:relative;z-index:1}.noUi-origin{position:absolute;right:0;top:0;left:0;bottom:0}.noUi-handle{position:relative;z-index:1}.noUi-stacking .noUi-handle{z-index:10}.noUi-state-tap .noUi-origin{-webkit-transition:left .3s,top .3s;transition:left .3s,top .3s}.noUi-state-drag *{cursor:inherit!important}.noUi-base,.noUi-handle{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.noUi-horizontal{height:18px}.noUi-horizontal .noUi-handle{width:34px;height:28px;left:-17px;top:-6px}.noUi-vertical{width:18px}.noUi-vertical .noUi-handle{width:28px;height:34px;left:-6px;top:-17px}.noUi-background{background:#FAFAFA;box-shadow:inset 0 1px 1px #f0f0f0}.noUi-connect{background:#3FB8AF;box-shadow:inset 0 0 3px rgba(51,51,51,.45);-webkit-transition:background 450ms;transition:background 450ms}.noUi-origin{border-radius:2px}.noUi-target{border-radius:4px;border:1px solid #D3D3D3;box-shadow:inset 0 1px 1px #F0F0F0,0 3px 6px -5px #BBB}.noUi-target.noUi-connect{box-shadow:inset 0 0 3px rgba(51,51,51,.45),0 3px 6px -5px #BBB}.noUi-draggable{cursor:w-resize}.noUi-vertical .noUi-draggable{cursor:n-resize}.noUi-handle{border:1px solid #D9D9D9;border-radius:3px;background:#FFF;cursor:default;box-shadow:inset 0 0 1px #FFF,inset 0 1px 7px #EBEBEB,0 3px 6px -3px #BBB}.noUi-active{box-shadow:inset 0 0 1px #FFF,inset 0 1px 7px #DDD,0 3px 6px -3px #BBB}.noUi-handle:after,.noUi-handle:before{content:"";display:block;position:absolute;height:14px;width:1px;background:#E8E7E6;left:14px;top:6px}.noUi-handle:after{left:17px}.noUi-vertical .noUi-handle:after,.noUi-vertical .noUi-handle:before{width:14px;height:1px;left:6px;top:14px}.noUi-vertical .noUi-handle:after{top:17px}[disabled] .noUi-connect,[disabled].noUi-connect{background:#B8B8B8}[disabled] .noUi-handle,[disabled].noUi-origin{cursor:not-allowed}.noUi-pips,.noUi-pips *{box-sizing:border-box}.noUi-pips{position:absolute;color:#999}.noUi-value{position:absolute;text-align:center}.noUi-value-sub{color:#ccc;font-size:10px}.noUi-marker{position:absolute;background:#CCC}.noUi-marker-large,.noUi-marker-sub{background:#AAA}.noUi-pips-horizontal{padding:10px 0;height:80px;top:100%;left:0;width:100%}.noUi-value-horizontal{-webkit-transform:translate3d(-50%,50%,0);transform:translate3d(-50%,50%,0)}.noUi-marker-horizontal.noUi-marker{margin-left:-1px;width:2px;height:5px}.noUi-marker-horizontal.noUi-marker-sub{height:10px}.noUi-marker-horizontal.noUi-marker-large{height:15px}.noUi-pips-vertical{padding:0 10px;height:100%;top:0;left:100%}.noUi-value-vertical{-webkit-transform:translate3d(0,-50%,0);transform:translate3d(0,-50%,0);padding-left:25px}.noUi-marker-vertical.noUi-marker{width:5px;height:2px;margin-top:-1px}.noUi-marker-vertical.noUi-marker-sub{width:10px}.noUi-marker-vertical.noUi-marker-large{width:15px}.noUi-tooltip{display:block;position:absolute;border:1px solid #D9D9D9;border-radius:3px;background:#fff;padding:5px;text-align:center}.noUi-horizontal .noUi-handle-lower .noUi-tooltip{top:-32px}.noUi-horizontal .noUi-handle-upper .noUi-tooltip{bottom:-32px}.noUi-vertical .noUi-handle-lower .noUi-tooltip{left:120%}.noUi-vertical .noUi-handle-upper .noUi-tooltip{right:120%} 5 | .range-slider { 6 | margin: auto; 7 | margin-top:15px; 8 | height: 10px; 9 | } 10 | 11 | .noUi-horizontal .noUi-handle { 12 | width: 34px; 13 | height: 28px; 14 | left: -17px; 15 | top: -10px; 16 | } -------------------------------------------------------------------------------- /dist/RangeSlider-minimal.min.js: -------------------------------------------------------------------------------- 1 | /*! nouislider - 8.5.1 - 2016-04-24 16:00:29 */ 2 | 3 | !function(a){"function"==typeof define&&define.amd?define([],a):"object"==typeof exports?module.exports=a():window.noUiSlider=a()}(function(){"use strict";function a(a){return a.filter(function(a){return this[a]?!1:this[a]=!0},{})}function b(a,b){return Math.round(a/b)*b}function c(a){var b=a.getBoundingClientRect(),c=a.ownerDocument,d=c.documentElement,e=l();return/webkit.*Chrome.*Mobile/i.test(navigator.userAgent)&&(e.x=0),{top:b.top+e.y-d.clientTop,left:b.left+e.x-d.clientLeft}}function d(a){return"number"==typeof a&&!isNaN(a)&&isFinite(a)}function e(a,b,c){i(a,b),setTimeout(function(){j(a,b)},c)}function f(a){return Math.max(Math.min(a,100),0)}function g(a){return Array.isArray(a)?a:[a]}function h(a){var b=a.split(".");return b.length>1?b[1].length:0}function i(a,b){a.classList?a.classList.add(b):a.className+=" "+b}function j(a,b){a.classList?a.classList.remove(b):a.className=a.className.replace(new RegExp("(^|\\b)"+b.split(" ").join("|")+"(\\b|$)","gi")," ")}function k(a,b){return a.classList?a.classList.contains(b):new RegExp("\\b"+b+"\\b").test(a.className)}function l(){var a=void 0!==window.pageXOffset,b="CSS1Compat"===(document.compatMode||""),c=a?window.pageXOffset:b?document.documentElement.scrollLeft:document.body.scrollLeft,d=a?window.pageYOffset:b?document.documentElement.scrollTop:document.body.scrollTop;return{x:c,y:d}}function m(){return window.navigator.pointerEnabled?{start:"pointerdown",move:"pointermove",end:"pointerup"}:window.navigator.msPointerEnabled?{start:"MSPointerDown",move:"MSPointerMove",end:"MSPointerUp"}:{start:"mousedown touchstart",move:"mousemove touchmove",end:"mouseup touchend"}}function n(a,b){return 100/(b-a)}function o(a,b){return 100*b/(a[1]-a[0])}function p(a,b){return o(a,a[0]<0?b+Math.abs(a[0]):b-a[0])}function q(a,b){return b*(a[1]-a[0])/100+a[0]}function r(a,b){for(var c=1;a>=b[c];)c+=1;return c}function s(a,b,c){if(c>=a.slice(-1)[0])return 100;var d,e,f,g,h=r(c,a);return d=a[h-1],e=a[h],f=b[h-1],g=b[h],f+p([d,e],c)/n(f,g)}function t(a,b,c){if(c>=100)return a.slice(-1)[0];var d,e,f,g,h=r(c,b);return d=a[h-1],e=a[h],f=b[h-1],g=b[h],q([d,e],(c-f)*n(f,g))}function u(a,c,d,e){if(100===e)return e;var f,g,h=r(e,a);return d?(f=a[h-1],g=a[h],e-f>(g-f)/2?g:f):c[h-1]?a[h-1]+b(e-a[h-1],c[h-1]):e}function v(a,b,c){var e;if("number"==typeof b&&(b=[b]),"[object Array]"!==Object.prototype.toString.call(b))throw new Error("noUiSlider: 'range' contains invalid value.");if(e="min"===a?0:"max"===a?100:parseFloat(a),!d(e)||!d(b[0]))throw new Error("noUiSlider: 'range' value isn't numeric.");c.xPct.push(e),c.xVal.push(b[0]),e?c.xSteps.push(isNaN(b[1])?!1:b[1]):isNaN(b[1])||(c.xSteps[0]=b[1])}function w(a,b,c){return b?void(c.xSteps[a]=o([c.xVal[a],c.xVal[a+1]],b)/n(c.xPct[a],c.xPct[a+1])):!0}function x(a,b,c,d){this.xPct=[],this.xVal=[],this.xSteps=[d||!1],this.xNumSteps=[!1],this.snap=b,this.direction=c;var e,f=[];for(e in a)a.hasOwnProperty(e)&&f.push([a[e],e]);for(f.length&&"object"==typeof f[0][0]?f.sort(function(a,b){return a[0][0]-b[0][0]}):f.sort(function(a,b){return a[0]-b[0]}),e=0;e2)throw new Error("noUiSlider: 'start' option is incorrect.");a.handles=b.length,a.start=b}function B(a,b){if(a.snap=b,"boolean"!=typeof b)throw new Error("noUiSlider: 'snap' option must be a boolean.")}function C(a,b){if(a.animate=b,"boolean"!=typeof b)throw new Error("noUiSlider: 'animate' option must be a boolean.")}function D(a,b){if(a.animationDuration=b,"number"!=typeof b)throw new Error("noUiSlider: 'animationDuration' option must be a number.")}function E(a,b){if("lower"===b&&1===a.handles)a.connect=1;else if("upper"===b&&1===a.handles)a.connect=2;else if(b===!0&&2===a.handles)a.connect=3;else{if(b!==!1)throw new Error("noUiSlider: 'connect' option doesn't match handle count.");a.connect=0}}function F(a,b){switch(b){case"horizontal":a.ort=0;break;case"vertical":a.ort=1;break;default:throw new Error("noUiSlider: 'orientation' option is invalid.")}}function G(a,b){if(!d(b))throw new Error("noUiSlider: 'margin' option must be numeric.");if(0!==b&&(a.margin=a.spectrum.getMargin(b),!a.margin))throw new Error("noUiSlider: 'margin' option is only supported on linear sliders.")}function H(a,b){if(!d(b))throw new Error("noUiSlider: 'limit' option must be numeric.");if(a.limit=a.spectrum.getMargin(b),!a.limit)throw new Error("noUiSlider: 'limit' option is only supported on linear sliders.")}function I(a,b){switch(b){case"ltr":a.dir=0;break;case"rtl":a.dir=1,a.connect=[0,2,1,3][a.connect];break;default:throw new Error("noUiSlider: 'direction' option was not recognized.")}}function J(a,b){if("string"!=typeof b)throw new Error("noUiSlider: 'behaviour' must be a string containing options.");var c=b.indexOf("tap")>=0,d=b.indexOf("drag")>=0,e=b.indexOf("fixed")>=0,f=b.indexOf("snap")>=0,g=b.indexOf("hover")>=0;if(d&&!a.connect)throw new Error("noUiSlider: 'drag' behaviour must be used with 'connect': true.");a.events={tap:c||f,drag:d,fixed:e,snap:f,hover:g}}function K(a,b){var c;if(b!==!1)if(b===!0)for(a.tooltips=[],c=0;cd&&(e+=Math.abs(d)),e>100&&(d-=e-100),[f(d),f(e)]):[d,e]}function p(a,b){a.preventDefault();var c,d,e=0===a.type.indexOf("touch"),f=0===a.type.indexOf("mouse"),g=0===a.type.indexOf("pointer"),h=a;return 0===a.type.indexOf("MSPointer")&&(g=!0),e&&(c=a.changedTouches[0].pageX,d=a.changedTouches[0].pageY),b=b||l(),(f||g)&&(c=a.clientX+b.x,d=a.clientY+b.y),h.pageOffset=b,h.points=[c,d],h.cursor=f||g,h}function q(a,b){var c=document.createElement("div"),e=document.createElement("div"),f=[d.cssClasses.handleLower,d.cssClasses.handleUpper];return a&&f.reverse(),i(e,d.cssClasses.handle),i(e,f[b]),i(c,d.cssClasses.origin),c.appendChild(e),c}function r(a,b,c){switch(a){case 1:i(b,d.cssClasses.connect),i(c[0],d.cssClasses.background);break;case 3:i(c[1],d.cssClasses.background);case 2:i(c[0],d.cssClasses.connect);case 0:i(b,d.cssClasses.background)}}function s(a,b,c){var d,e=[];for(d=0;a>d;d+=1)e.push(c.appendChild(q(b,d)));return e}function t(a,b,c){i(c,d.cssClasses.target),0===a?i(c,d.cssClasses.ltr):i(c,d.cssClasses.rtl),0===b?i(c,d.cssClasses.horizontal):i(c,d.cssClasses.vertical);var e=document.createElement("div");return i(e,d.cssClasses.base),c.appendChild(e),e}function u(a,b){if(!d.tooltips[b])return!1;var c=document.createElement("div");return c.className=d.cssClasses.tooltip,a.firstChild.appendChild(c)}function v(){d.dir&&d.tooltips.reverse();var a=W.map(u);d.dir&&(a.reverse(),d.tooltips.reverse()),S("update",function(b,c,e){a[c]&&(a[c].innerHTML=d.tooltips[c]===!0?b[c]:d.tooltips[c].to(e[c]))})}function w(a,b,c){if("range"===a||"steps"===a)return _.xVal;if("count"===a){var d,e=100/(b-1),f=0;for(b=[];(d=f++*e)<=100;)b.push(d);a="positions"}return"positions"===a?b.map(function(a){return _.fromStepping(c?_.getStep(a):a)}):"values"===a?c?b.map(function(a){return _.fromStepping(_.getStep(_.toStepping(a)))}):b:void 0}function x(b,c,d){function e(a,b){return(a+b).toFixed(7)/1}var f=_.direction,g={},h=_.xVal[0],i=_.xVal[_.xVal.length-1],j=!1,k=!1,l=0;return _.direction=0,d=a(d.slice().sort(function(a,b){return a-b})),d[0]!==h&&(d.unshift(h),j=!0),d[d.length-1]!==i&&(d.push(i),k=!0),d.forEach(function(a,f){var h,i,m,n,o,p,q,r,s,t,u=a,v=d[f+1];if("steps"===c&&(h=_.xNumSteps[f]),h||(h=v-u),u!==!1&&void 0!==v)for(i=u;v>=i;i=e(i,h)){for(n=_.toStepping(i),o=n-l,r=o/b,s=Math.round(r),t=o/s,m=1;s>=m;m+=1)p=l+m*t,g[p.toFixed(5)]=["x",0];q=d.indexOf(i)>-1?1:"steps"===c?2:0,!f&&j&&(q=0),i===v&&k||(g[n.toFixed(5)]=[i,q]),l=n}}),_.direction=f,g}function y(a,b,c){function e(a,b){var c=b===d.cssClasses.value,e=c?m:n,f=c?k:l;return b+" "+e[d.ort]+" "+f[a]}function f(a,b,c){return'class="'+e(c[1],b)+'" style="'+d.style+": "+a+'%"'}function g(a,e){_.direction&&(a=100-a),e[1]=e[1]&&b?b(e[0],e[1]):e[1],j+="
",e[1]&&(j+="
"+c.to(e[0])+"
")}var h=document.createElement("div"),j="",k=[d.cssClasses.valueNormal,d.cssClasses.valueLarge,d.cssClasses.valueSub],l=[d.cssClasses.markerNormal,d.cssClasses.markerLarge,d.cssClasses.markerSub],m=[d.cssClasses.valueHorizontal,d.cssClasses.valueVertical],n=[d.cssClasses.markerHorizontal,d.cssClasses.markerVertical];return i(h,d.cssClasses.pips),i(h,0===d.ort?d.cssClasses.pipsHorizontal:d.cssClasses.pipsVertical),Object.keys(a).forEach(function(b){g(b,a[b])}),h.innerHTML=j,h}function z(a){var b=a.mode,c=a.density||1,d=a.filter||!1,e=a.values||!1,f=a.stepped||!1,g=w(b,e,f),h=x(c,b,g),i=a.format||{to:Math.round};return Z.appendChild(y(h,d,i))}function A(){var a=V.getBoundingClientRect(),b="offset"+["Width","Height"][d.ort];return 0===d.ort?a.width||V[b]:a.height||V[b]}function B(a,b,c){var e;for(e=0;e1?!1:e.hover&&b.buttons?!1:(b.calcPoint=b.points[d.ort],void c(b,e)))},g=[];return a.split(" ").forEach(function(a){b.addEventListener(a,f,!1),g.push([a,f])}),g}function E(a,b){if(-1===navigator.appVersion.indexOf("MSIE 9")&&0===a.buttons&&0!==b.buttonsProperty)return F(a,b);var c,d,e=b.handles||W,f=!1,g=100*(a.calcPoint-b.start)/b.baseSize,h=e[0]===W[0]?0:1;if(c=o(g,b.positions,e.length>1),f=L(e[0],c[h],1===e.length),e.length>1){if(f=L(e[1],c[h?0:1],!1)||f)for(d=0;d1&&i(Z,d.cssClasses.drag);var h=function(){return!1};document.body.noUiListener=h,document.body.addEventListener("selectstart",h,!1)}void 0!==b.handleNumber&&B("start",b.handleNumber)}function I(a){var b,f,g=a.calcPoint,h=0;return a.stopPropagation(),W.forEach(function(a){h+=c(a)[d.style]}),b=h/2>g||1===W.length?0:1,W[b].hasAttribute("disabled")&&(b=b?0:1),g-=c(V)[d.style],f=100*g/A(),d.events.snap||e(Z,d.cssClasses.tap,d.animationDuration),W[b].hasAttribute("disabled")?!1:(L(W[b],f),B("slide",b,!0),B("set",b,!0),B("change",b,!0),void(d.events.snap&&H(a,{handles:[W[b]]})))}function J(a){var b=a.calcPoint-c(V)[d.style],e=_.getStep(100*b/A()),f=_.fromStepping(e);Object.keys(ba).forEach(function(a){"hover"===a.split(".")[0]&&ba[a].forEach(function(a){a.call(X,f)})})}function K(a){if(a.fixed||W.forEach(function(a,b){D(Y.start,a.children[0],H,{handles:[a],handleNumber:b})}),a.tap&&D(Y.start,V,I,{handles:W}),a.hover&&D(Y.move,V,J,{hover:!0}),a.drag){var b=[V.querySelector("."+d.cssClasses.connect)];i(b[0],d.cssClasses.draggable),a.fixed&&b.push(W[b[0]===W[0]?1:0].children[0]),b.forEach(function(a){D(Y.start,a,H,{handles:W})})}}function L(a,b,c){var e=a!==W[0]?1:0,g=$[0]+d.margin,h=$[1]-d.margin,k=$[0]+d.limit,l=$[1]-d.limit;return W.length>1&&(b=e?Math.max(b,g):Math.min(b,h)),c!==!1&&d.limit&&W.length>1&&(b=e?Math.min(b,k):Math.max(b,l)),b=_.getStep(b),b=f(b),b===$[e]?!1:(window.requestAnimationFrame?window.requestAnimationFrame(function(){a.style[d.style]=b+"%"}):a.style[d.style]=b+"%",a.previousSibling||(j(a,d.cssClasses.stacking),b>50&&i(a,d.cssClasses.stacking)),$[e]=b,aa[e]=_.fromStepping(b),B("update",e),!0)}function M(a,b){var c,e,f;for(d.limit&&(a+=1),c=0;a>c;c+=1)e=c%2,f=b[e],null!==f&&f!==!1&&("number"==typeof f&&(f=String(f)),f=d.format.from(f),(f===!1||isNaN(f)||L(W[e],_.toStepping(f),c===3-d.dir)===!1)&&B("update",e))}function N(a,b){var c,f,h=g(a);for(b=void 0===b?!0:!!b,d.dir&&d.handles>1&&h.reverse(),d.animate&&-1!==$[0]&&e(Z,d.cssClasses.tap,d.animationDuration),c=W.length>1?3:1,1===h.length&&(c=1),M(c,h),f=0;f=c[1]?c[2]:c[0]||!1;return[i,f]});return C(a)}function S(a,b){ba[a]=ba[a]||[],ba[a].push(b),"update"===a.split(".")[0]&&W.forEach(function(a,b){B("update",b)})}function T(a){var b=a&&a.split(".")[0],c=b&&a.substring(b.length);Object.keys(ba).forEach(function(a){var d=a.split(".")[0],e=a.substring(d.length);b&&b!==d||c&&c!==e||delete ba[a]})}function U(a,b){var c=P(),e=O({start:[0,0],margin:a.margin,limit:a.limit,step:void 0===a.step?d.singleStep:a.step,range:a.range,animate:a.animate,snap:void 0===a.snap?d.snap:a.snap});["margin","limit","range","animate"].forEach(function(b){void 0!==a[b]&&(d[b]=a[b])}),e.spectrum.direction=_.direction,_=e.spectrum,$=[-1,-1],N(a.start||c,b)}var V,W,X,Y=m(),Z=b,$=[-1,-1],_=d.spectrum,aa=[],ba={};if(Z.noUiSlider)throw new Error("Slider was already initialized.");return V=t(d.dir,d.ort,Z),W=s(d.handles,d.dir,V),r(d.connect,Z,W),d.pips&&z(d.pips),d.tooltips&&v(),X={destroy:Q,steps:R,on:S,off:T,get:P,set:N,updateOptions:U,options:n,target:Z,pips:z},K(d.events),X}function Q(a,b){if(!a.nodeName)throw new Error("noUiSlider.create requires a single element.");var c=O(b,a),d=P(a,c,b);return d.set(c.start),a.noUiSlider=d,d}x.prototype.getMargin=function(a){return 2===this.xPct.length?o(this.xVal,a):!1},x.prototype.toStepping=function(a){return a=s(this.xVal,this.xPct,a),this.direction&&(a=100-a),a},x.prototype.fromStepping=function(a){return this.direction&&(a=100-a),t(this.xVal,this.xPct,a)},x.prototype.getStep=function(a){return this.direction&&(a=100-a),a=u(this.xPct,this.xSteps,this.snap,a),this.direction&&(a=100-a),a},x.prototype.getApplicableStep=function(a){var b=r(a,this.xPct),c=100===a?2:1;return[this.xNumSteps[b-2],this.xVal[b-c],this.xNumSteps[b-c]]},x.prototype.convert=function(a){return this.getStep(this.toStepping(a))};var R={to:function(a){return void 0!==a&&a.toFixed(2)},from:Number};return{create:Q}}); 4 | function RangeSliderChart(opts){var ranger={chartProto:new Chart(opts.chartCTX),datasets:opts.chartData,chartOpts:opts.chartOpts||{},options:opts,sliderElement:$("
"),_getData:function(min,max){var d={},Datasets=JSON.parse(JSON.stringify(ranger.datasets));d.labels=Datasets.labels.splice(min,max-min||1),d.datasets=[];for(var i in Datasets.datasets){var nD=Datasets.datasets[i];nD.data=nD.data.splice(min,max-min||1),nD.pointBackgroundColor=nD.pointBackgroundColor.splice(min,max-min||1),nD.pointBorderColor=nD.pointBorderColor.splice(min,max-min||1),d.datasets.push(nD)}return d},_draw:function(ctx,data,options,opts){ranger.chart?(ranger.chart.data.datasets=data.datasets,ranger.chart.data.labels=data.labels,ranger.chart.update()):ranger.chart=new Chart(ctx,{type:opts.chartType||options.type||"line",data:data,options:options})},_create:function(){noUiSlider.create(ranger.sliderElement[0],{start:ranger.options.initial,step:1,connect:!0,range:{min:0,max:ranger.datasets.datasets[0].data.length-1}}),ranger.sliderElement[0].noUiSlider.on("slide",function(b){ranger._min=parseInt(b[0]),ranger._max=parseInt(b[1])+1,console.log(ranger._min,ranger._max)}),ranger.sliderElement[0].noUiSlider.on("change",function(b){ranger.chart&&ranger._draw(opts.chartCTX,ranger._getData(ranger._min,ranger._max),ranger.chartOpts,ranger.opts)}),ranger.sliderElement.insertAfter(opts.chartCTX.canvas),ranger._draw(opts.chartCTX,ranger._getData(ranger.options.initial[0],ranger.options.initial[1]),ranger.chartOpts,ranger.options)}};return ranger.sliderElement.addClass("range-slider").css({width:opts.chartCTX.canvas.width-50}),$(window).on("resize",function(){ranger.sliderElement.css({width:opts.chartCTX.canvas.width-50})}),ranger._create(),ranger} -------------------------------------------------------------------------------- /dist/RangeSlider-solo.min.css: -------------------------------------------------------------------------------- 1 | .range-slider { 2 | margin: auto; 3 | margin-top:15px; 4 | height: 10px; 5 | } 6 | 7 | .noUi-horizontal .noUi-handle { 8 | width: 34px; 9 | height: 28px; 10 | left: -17px; 11 | top: -10px; 12 | } -------------------------------------------------------------------------------- /dist/RangeSlider-solo.min.js: -------------------------------------------------------------------------------- 1 | function RangeSliderChart(opts){var ranger={chartProto:new Chart(opts.chartCTX),datasets:opts.chartData,chartOpts:opts.chartOpts||{},options:opts,sliderElement:$("
"),_getData:function(min,max){var d={},Datasets=JSON.parse(JSON.stringify(ranger.datasets));d.labels=Datasets.labels.splice(min,max-min||1),d.datasets=[];for(var i in Datasets.datasets){var nD=Datasets.datasets[i];nD.data=nD.data.splice(min,max-min||1),nD.pointBackgroundColor=nD.pointBackgroundColor.splice(min,max-min||1),nD.pointBorderColor=nD.pointBorderColor.splice(min,max-min||1),d.datasets.push(nD)}return d},_draw:function(ctx,data,options,opts){ranger.chart?(ranger.chart.data.datasets=data.datasets,ranger.chart.data.labels=data.labels,ranger.chart.update()):ranger.chart=new Chart(ctx,{type:opts.chartType||options.type||"line",data:data,options:options})},_create:function(){noUiSlider.create(ranger.sliderElement[0],{start:ranger.options.initial,step:1,connect:!0,range:{min:0,max:ranger.datasets.datasets[0].data.length-1}}),ranger.sliderElement[0].noUiSlider.on("slide",function(b){ranger._min=parseInt(b[0]),ranger._max=parseInt(b[1])+1,console.log(ranger._min,ranger._max)}),ranger.sliderElement[0].noUiSlider.on("change",function(b){ranger.chart&&ranger._draw(opts.chartCTX,ranger._getData(ranger._min,ranger._max),ranger.chartOpts,ranger.opts)}),ranger.sliderElement.insertAfter(opts.chartCTX.canvas),ranger._draw(opts.chartCTX,ranger._getData(ranger.options.initial[0],ranger.options.initial[1]),ranger.chartOpts,ranger.options)}};return ranger.sliderElement.addClass("range-slider").css({width:opts.chartCTX.canvas.width-50}),$(window).on("resize",function(){ranger.sliderElement.css({width:opts.chartCTX.canvas.width-50})}),ranger._create(),ranger} -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | gulp = require('gulp'); 2 | plugins = require('gulp-load-plugins')(); 3 | fs = require('fs'); 4 | del = require('del'); 5 | path = require('path'); 6 | 7 | 8 | var staticJS = { 9 | jquery: 'bower_components/jquery/dist/jquery.min.js', 10 | chartjs: 'bower_components/Chart.js/dist/Chart.bundle.js', 11 | nouislider: 'bower_components/nouislider/distribute/nouislider.min.js', 12 | }, 13 | 14 | staticCss = { 15 | nouislider: 'bower_components/nouislider/distribute/nouislider.min.css', 16 | }, 17 | 18 | srcJS = [ 19 | 'src/RangeSlider-core.js' 20 | ], 21 | 22 | srcCSS = [ 23 | 'src/RangeSlider-core.css' 24 | ] 25 | 26 | outputDir = 'dist', 27 | 28 | /* buildChains = { 29 | solo: { 30 | js: src, 31 | chain: ['Build Source', 'Concat'] 32 | } 33 | 34 | all: { 35 | chain: ['Build Source'] 36 | js: [ 37 | staticJS.jquery, 38 | staticJS.chartjs, 39 | staticJS.nouislider, 40 | src 41 | ], 42 | css: [ 43 | staticCss.nouislider 44 | ] 45 | } 46 | } 47 | */ 48 | 49 | 50 | 51 | gulp.task('Start', function () { 52 | del.sync([outputDir], {force: true}) 53 | return gulp 54 | }); 55 | 56 | gulp.task('Finish', ['Start', 'Build All'], function () { 57 | return gulp 58 | }); 59 | 60 | gulp.task('default', ['Finish', 'Watch']); 61 | 62 | gulp.task('Watch', function () { 63 | gulp.watch('src/*', ['Finish']) 64 | }); 65 | 66 | gulp.task('Build CSS', function () { 67 | return gulp.src(srcCSS) 68 | .pipe(plugins.autoprefixer()) 69 | //.pipe(plugins.minifyCSS()) 70 | .pipe(plugins.concat('RangeSlider-solo.min.css')) 71 | .pipe(gulp.dest(outputDir)); 72 | }); 73 | 74 | gulp.task('Build Minimal CSS', ['Build CSS'], function () { 75 | return gulp.src([ 76 | staticCss.nouislider, 77 | outputDir + '/RangeSlider-solo.min.css' 78 | ]) 79 | .pipe(plugins.autoprefixer()) 80 | //.pipe(plugins.minifyCSS()) 81 | .pipe(plugins.concat('RangeSlider-minimal.min.css')) 82 | .pipe(gulp.dest(outputDir)); 83 | }); 84 | 85 | gulp.task('Build All CSS', ['Build Minimal CSS'], function () { 86 | return gulp.src([ 87 | staticCss.nouislider, 88 | outputDir + '/RangeSlider-solo.min.css' 89 | ]) 90 | .pipe(plugins.autoprefixer()) 91 | //.pipe(plugins.minifyCSS()) 92 | .pipe(plugins.concat('RangeSlider-all.min.css')) 93 | .pipe(gulp.dest(outputDir)); 94 | }); 95 | 96 | 97 | 98 | gulp.task('Build Source', ['Build All CSS'], function () { 99 | return gulp.src(srcJS) 100 | .pipe(plugins.uglify({mangle:false})) 101 | .pipe(plugins.concat('RangeSlider-solo.min.js')) 102 | .pipe(gulp.dest(outputDir)); 103 | }); 104 | 105 | gulp.task('Build Minimal', ['Build Source'], function () { 106 | return gulp.src([ 107 | staticJS.nouislider, 108 | outputDir + '/RangeSlider-solo.min.js' 109 | ]) 110 | .pipe(plugins.concat('RangeSlider-minimal.min.js')) 111 | .pipe(gulp.dest(outputDir)); 112 | }); 113 | 114 | gulp.task('Build All', ['Build Minimal'], function () { 115 | return gulp.src([ 116 | staticJS.jquery, 117 | staticJS.chartjs, 118 | outputDir + '//RangeSlider-minimal.min.js' 119 | ]) 120 | .pipe(plugins.concat('RangeSlider-all.min.js')) 121 | .pipe(gulp.dest(outputDir)); 122 | }); 123 | 124 | 125 | 126 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "chart.js-rangeslider", 3 | "version": "1.2.5", 4 | "description": "This adds the option of having a range slider to your charts, to allow you to select a specific data scale", 5 | "main": "Chart.JS-RangeSlider.min.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://schme16@github.com/schme16/Chart.js-RangeSlider" 12 | }, 13 | "keywords": [ 14 | "Chart.js", 15 | "plugin", 16 | "rage", 17 | "slider", 18 | "RangeSlider" 19 | ], 20 | "ignore": [ 21 | "**/.*", 22 | "node_modules", 23 | "gulpfile.js", 24 | "bower_components", 25 | "test", 26 | "tests" 27 | ], 28 | "author": "Shane Gadsby ", 29 | "license": "MIT", 30 | "bugs": { 31 | "url": "https://github.com/schme16/Chart.js-RangeSlider/issues" 32 | }, 33 | "homepage": "https://github.com/schme16/Chart.js-RangeSlider", 34 | "devDependencies": { 35 | "del": "^1.1.1", 36 | "gulp": "^3.8.11", 37 | "gulp-autoprefixer": "^2.1.0", 38 | "gulp-concat": "^2.5.2", 39 | "gulp-load-plugins": "^0.8.1", 40 | "gulp-minify-css": "^1.0.0", 41 | "gulp-uglify": "^1.1.0" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/RangeSlider-core.css: -------------------------------------------------------------------------------- 1 | .range-slider { 2 | margin: auto; 3 | margin-top:15px; 4 | height: 10px; 5 | } 6 | 7 | .noUi-horizontal .noUi-handle { 8 | width: 34px; 9 | height: 28px; 10 | left: -17px; 11 | top: -10px; 12 | } -------------------------------------------------------------------------------- /src/RangeSlider-core.js: -------------------------------------------------------------------------------- 1 | function RangeSliderChart (opts) { 2 | var ranger = { 3 | chartProto: new Chart(opts.chartCTX), 4 | datasets: opts.chartData, 5 | chartOpts: opts.chartOpts || {}, 6 | options: opts, 7 | sliderElement: $('
'), 8 | 9 | _getData: function (min, max) { 10 | 11 | var d = {}, 12 | Datasets = JSON.parse(JSON.stringify(ranger.datasets)) 13 | d.labels = Datasets.labels.splice(min, (max-min || 1)) 14 | d.datasets = [] 15 | for (var i in Datasets.datasets) { 16 | var nD = Datasets.datasets[i] 17 | nD.data = nD.data.splice(min, (max-min || 1)) 18 | nD.pointBackgroundColor = nD.pointBackgroundColor.splice(min, max - min || 1) 19 | nD.pointBorderColor = nD.pointBorderColor.splice(min, max - min || 1) 20 | d.datasets.push(nD) 21 | } 22 | 23 | return d 24 | }, 25 | 26 | _draw: function (ctx, data, options, opts) { 27 | if (!ranger.chart) { 28 | 29 | ranger.chart = new Chart(ctx, { 30 | type: opts.chartType || options.type || 'line', 31 | data: data, 32 | options: options 33 | }) 34 | } 35 | else { 36 | ranger.chart.data.datasets = data.datasets 37 | ranger.chart.data.labels = data.labels 38 | ranger.chart.update() 39 | } 40 | }, 41 | 42 | _create: function () { 43 | 44 | noUiSlider.create(ranger.sliderElement[0], { 45 | start: ranger.options.initial, 46 | step: 1, 47 | connect: true, 48 | range: { 49 | 'min': 0, 50 | 'max': ranger.datasets.datasets[0].data.length -1 51 | } 52 | }) 53 | 54 | ranger.sliderElement[0].noUiSlider.on('slide', function (b) { 55 | ranger._min = parseInt(b[0]) 56 | ranger._max = parseInt(b[1]) + 1 57 | console.log(ranger._min, ranger._max) 58 | }) 59 | 60 | ranger.sliderElement[0].noUiSlider.on('change', function (b) { 61 | if (ranger.chart) { 62 | ranger._draw(opts.chartCTX, ranger._getData( ranger._min, ranger._max ), ranger.chartOpts, ranger.opts) 63 | } 64 | }) 65 | 66 | 67 | ranger.sliderElement.insertAfter(opts.chartCTX.canvas) 68 | 69 | ranger._draw(opts.chartCTX, ranger._getData( ranger.options.initial[0], ranger.options.initial[1] ), ranger.chartOpts, ranger.options) 70 | } 71 | 72 | } 73 | 74 | 75 | 76 | ranger.sliderElement 77 | .addClass('range-slider') 78 | .css({ 79 | width: opts.chartCTX.canvas.width - 50 80 | }) 81 | 82 | //TODO: add rangeslider width adjustment 83 | $(window).on('resize', function () { 84 | ranger.sliderElement.css({ 85 | width: opts.chartCTX.canvas.width - 50 86 | }) 87 | }) 88 | 89 | ranger._create() 90 | return ranger 91 | } 92 | -------------------------------------------------------------------------------- /test/test-1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Chart.js demo 6 | 7 | 8 | 9 | 10 | 11 | 12 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 156 | 157 | --------------------------------------------------------------------------------