I have a multi-value jQuery slider with a defined step (it is defined by another slider, lets pretend for example's sake that it is a step:15) and a range of say 0-600. I want users to be able to drag the two values to the left and right like usual. But if a click is performed inside of the two values, they should be able to drag the whole range left and right.
A user is forced to set values like the following:
0,600
15,120
240,255
150,150
When, I want a user to be able to set values like the following:
1,271
15,165
25,115
580,595
These numbers still follow the step:15 rule of the slider, but can't be accessed with the basics of a jQuery slider because it wants to snap values to 30 increments (0,15,30,..,585,600). The most intuitive way I can think of this to be done is letting a user drag their 'range' of values left and right. But when the slider is clicked in between the two values, jQuery sets this as a new value.
I have used the slider's start event to detect if a user is clicking within the range (instead of clicking on a handle or the un-selected portion of the slider). I then need to set some sort of slide function within the slider that constantly detects the mouse position and slides left and right like that. I am at an intermediate level of Javascript (in my opinion) and not quite sure how I would go about doing that. You can play with my JSFiddle:
http://jsfiddle.net/JhKxh/9/
*note: the only problem with my JSFiddle is if you click the slider's border, it doesn't count as the class ui-slider-range (but some CSS tweaking should be able to fix this).
your answer should be here
Drag the Range of a UI Input Range Slider
Look here:
http://docs.jquery.com/UI/API/1.8/Slider
The following code works well and is an extension of your original jsfiddle. I finally understood what you wanted and it seems to work fine now:
Live Working Code Sample
JavaScript:
$(document).ready(function () {
'use strict';
var stepSlider = $('#stepSlider');
var stepText = $('#stepText');
var rangeSlider = $('#rangeSlider');
var rangeText = $('#rangeText');
var oldStep;
stepSlider.slider({
min:0,
max:120,
slide:function (event, ui) {
stepText.text(ui.value);
var rsValues = rangeSlider.slider("option", "values");
var stepDiff = ui.value - oldStep;
var rsMax = rangeSlider.slider("option", "max");
var rsMin = rangeSlider.slider("option", "min");
if (stepDiff > 0) {
rsValues[1] += stepDiff;
if (rsValues[1] > rsMax) {
rsValues[0] = rsMax - ui.value;
rsValues[1] = rsMax;
}
} else if (stepDiff < 0) {
rsValues[1] += stepDiff;
if (rsValues[1] < rsMin) {
rsValues[0] = rsMin;
rsValues[1] = ui.value;
}
}
rangeSlider.slider("option", "values", rsValues);
rangeText.text(rsValues[0] + ' - ' + rsValues[1]);
oldStep = ui.value;
}
});
rangeSlider.slider({
min:0,
max:600,
values:[0, 0],
slide:function (event, ui) {
var step = stepSlider.slider("option", "value");
var oldValues = rangeSlider.slider("option", "values");
var rsMax = rangeSlider.slider("option", "max");
var rsMin = rangeSlider.slider("option", "min");
var diff;
if (oldValues[0] != ui.values[0]) {
diff = ui.values[0] - oldValues[0];
if (diff > 0 && diff <= step && ui.values[1] === rsMax) {
return false;
}
ui.values[1] += diff;
if (ui.values[1] > rsMax) {
ui.values[1] = rsMax;
ui.values[0] = ui.values[1] - step;
}
rangeSlider.slider("option", "values", ui.values);
rangeText.text(ui.values[0] + ' - ' + ui.values[1]);
return false;
}
if (oldValues[1] != ui.values[1]) {
diff = ui.values[1] - oldValues[1];
if (diff < 0 && diff >= -step && ui.values[0] === rsMin) {
return false;
}
ui.values[0] += diff;
if (ui.values[0] < rsMin) {
ui.values[0] = rsMin;
ui.values[1] = ui.values[0] + step;
}
rangeSlider.slider("option", "values", ui.values);
rangeText.text(ui.values[0] + ' - ' + ui.values[1]);
return false;
}
rangeText.text(ui.values[0] + ' - ' + ui.values[1]);
}
});
oldStep = stepSlider.slider("option", "value");
});
HTML:
<!DOCTYPE html>
<html>
<head>
<title>Sliders</title>
<link href="rangeSliders.css" rel="stylesheet" type="text/css"/>
<link href="http://code.jquery.com/ui/1.9.0/themes/base/jquery-ui.css" rel="stylesheet" type="text/css"/>
<script src="http://code.jquery.com/jquery-1.8.2.js"></script>
<script src="http://code.jquery.com/ui/1.9.0/jquery-ui.js"></script>
</head>
<body>
<div id="stepSlider">
<div id="stepText">0</div>
</div>
<div id="rangeSlider">
<div id="rangeText">0-600</div>
</div>
<script type="text/javascript" src="rangeSliders.js"></script>
</body>
</html>
CSS:
body {
margin: 50px;
}
#stepSlider, #rangeSlider {
width: 200px;
margin-bottom: 25px;
}
#stepText, #rangeText {
margin: -4px 0 0 225px;
width: 100%;
}
Related
I'm using a range slider with jQuery UI but when I move the slider, the background line does not show up so it's hard to tell where it is at. How do I highlight the background line only for the selected portion?
jsfiddle is below.
https://jsfiddle.net/zbmt5qrn/
/* INTEREST RATE SLIDER */
$("#interestRange").slider({
min: 0,
max: 100,
step: 1,
values: [10],
slide: function(event, ui) {
for (var i = 0; i < ui.values.length; ++i) {
$("input.interestValue[data-index=" + i + "]").val(ui.values[i]);
}
}
});
$("input.interestValue").change(function() {
var $this = $(this);
$("#interestValue").slider("values", $this.data("index"), $this.val());
});
function handleInterestChange(input) {
if (input.value < 0) input.value = 0;
if (input.value > 24) input.value = 24;
}
var items =[ '8%','24%'];
var oneBig = 100 / (items.length - 1);
$.each(items, function(key,value){
var w = oneBig;
if(key === 0 || key === items.length-1)
w = oneBig/2;
$("#interestLabel").append("<label style='width: "+w+"%'>"+value+"</laben>");
});
I am removing the code about '8%/24%' because it does not seem to be relevant to this question.
There are a couple ways to set the background. You could insert a new element inside #interestRange and change its width based on the slider value. But if you do not need to worry about supporting outdated browsers, it would be much easier to use apply a linear-gradient to the background of #interestRange.
const sliderMin = 0
const sliderMax = 100
const sliderDefaultValue = 10
function setSliderBackground(value){
const sliderRange = sliderMax - sliderMin
const sliderPercent = Math.floor(100 * (value / sliderRange))
$("#interestRange").css({
background: `linear-gradient(90deg, #0000ff ${sliderPercent}%, #ffffff ${sliderPercent}%)`
})
}
function setSliderValue(value){
$("#interestRange").slider("value", value);
}
function setInputValue(value){
$("#interestValue").val(value)
}
$(document).ready(()=>{
$("#interestRange").slider({
min: sliderMin,
max: sliderMax,
step: 1,
// Handle when the user moves the slider
slide: (event, ui)=>{
const sliderValue = ui.value
setInputValue(sliderValue)
setSliderBackground(sliderValue)
}
})
// Handle when the user types in a value
$("#interestValue").change(()=>{
const typedValue = $("#interestValue").val()
setSliderValue(typedValue)
setSliderBackground(typedValue)
})
// Stuff to do when the page loads
setSliderValue(sliderDefaultValue)
setInputValue(sliderDefaultValue)
setSliderBackground(sliderDefaultValue)
})
<link href="https://code.jquery.com/ui/1.12.0-rc.2/themes/smoothness/jquery-ui.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<p>Interest Rate:</p>
<div>
<div id="interestRange"></div>
<div id="interestLabel"></div>
</div>
<div>
<input type="number" id="interestValue" />
</div>
I am trying to set a background image rotation for a div with a image already in it, doesn't seem to change anything, thought I would check if someone could see the problem since no errors come up.
<script>
$( document ).ready(function() {
setInterval(function() {
var tips = [
"header.jpg",
"header2.jpg",
"header3.jpg",
"header4.jpg",
"header5.jpg",
];
var i = 0;
if (i == tips.length) --i;
$('.containercoloring').fadeTo('slow', 0.3, function()
{
$(this).css('background-image', 'url(' + tips[i] + ')');
}).delay(1000).fadeTo('slow', 1);
i++;
}, 5 * 1000);
});
</script>
<body>
<div class="containercoloring"> </div>
</body>
Below is the working(updated) code. I hope you are importing jquery lib separately.
<script>
$(document).ready(function() {
var i = 0;
setInterval(function() {
var tips = [
"header.jpg",
"header2.jpg",
"header3.jpg",
"header4.jpg",
"header5.jpg"
];
var imageIndex = ++i % tips.length;
$('.containercoloring').fadeTo('slow', 0.3, function() {
$(this).css('background-image', 'url(' + tips[imageIndex] + ')');
}).delay(1000).fadeTo('slow', 1);
}, 5 * 1000);
});
</script>
<body>
<div class="containercoloring" style="height: 100px;">Image Container</div>
</body>
You can test here in this jsfiddle - https://jsfiddle.net/nbq9f6bg/
Hope it helps!
So there were a couple of notes I had about your example. Please see the comments below. I used background color and removed the transitions to show it easier.
// declare variables
var tips = [
"#ff9000",
"#ff0000",
"#0099ff"
];
// counter
var i = 0;
// direction
var direction = 'forwards';
// time in between intervals
var timer = 2000;
function changeBackground() {
// Check the length minus 1 since your counter starts at 0
if (i == (tips.length - 1)) {
direction = 'backwards';
} else if(i == 0) {
// only set the direction back to forwards when the counter is 0 again
direction = 'forwards';
}
$('.containercoloring').css('background-color', tips[i]);
// add or subtract based on the direction
if(direction == 'forwards') {
i++;
} else {
i--;
}
}
$( document ).ready(function() {
// save interval to a variable so you can stop it later
var theInterval = setInterval(changeBackground, timer);
// run the function since the interval will take 2000ms to execute
changeBackground();
});
.containercoloring {
height: 100px;
width: 100px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="containercoloring"> </div>
I am using jQuery UI Slider. I have multiple hanldes with range set to false. Is there a way to color the range between two handles/sliders/markers whatever you want to call them? I have not found a solution to this yet.
This is my code/initialization that I am using.
var initialValues = [180, 435, 1080, 1320],
updateValue = function (ui) {
var hours = Math.floor(ui.value / 60);
var minutes = ui.value - (hours * 60);
if (hours.length == 1) hours = '0' + hours;
if (minutes.length == 1) minutes = '0' + minutes;
if (minutes == 0) minutes = '00';
if (hours >= 12) {
if (hours == 12) {
hours = hours;
minutes = minutes + " PM";
} else {
hours = hours - 12;
minutes = minutes + " PM";
}
} else {
hours = hours;
minutes = minutes + " AM";
}
if (hours == 0) {
hours = 12;
minutes = minutes;
}
//console.log(ui.handle)
$(ui.handle).attr('data-value', hours + ':' + minutes);
};
var timeLabels = ["12:00 a.m","1:00 a.m","2:00 a.m","3:00 a.m","4:00 a.m","5:00 a.m","6:00 a.m","7:00 a.m","8:00 a.m","9:00 a.m","10:00 a.m","11:00 a.m",
"12:00 p.m","1:00 p.m","2:00 p.m","3:00 p.m","4:00 p.m","5:00 p.m","6:00 p.m","7:00 p.m","8:00 p.m","9:00 p.m","10:00 p.m","11:00 p.m", "12:00 p.m"];
(function ($) {
$.widget('my-namespace.customSlider', $.ui.slider, {
options: {
ticks: false
},
// Called when the slider is instantiated.
_create: function() {
// Call the orginal constructor, creating the slider normally.
this._super();
// If the "ticks" option is false or the "step" option is
// less than 5, there's nothing to do.
if ( !this.options.ticks || this.options.step < 5 ) {
return;
}
// Setup some variables for rendering the tick marks below the slider.
var cnt = this.options.min,
background = this.element.css( "border-color" ),
left;
while ( cnt <= this.options.max ) {
// Compute the "left" CSS property for the next tick mark.
left = ( cnt / this.options.max * 100 ).toFixed( 2 ) + "%";
// Creates the tick div, and adds it to the element. It adds the
// "ui-slider-tick" class, which has common properties for each tick.
// It also applies the computed CSS properties, "left" and "background".
//console.log($("</div>"))
$( "<div/>" ).addClass( "ui-slider-tick" )
.appendTo( this.element )
.css( { left: left, background: background } );
cnt += this.options.step;
}
console.log(this.element[0].id)
cnt = this.options.min
var i = 0;
while (cnt <= this.options.max) {
//console.log(timeLabels[i])
$($(".pct-slider#" + this.element[0].id).find('.ui-slider-tick')[cnt]).append("<div class='tick-labels'>" + timeLabels[i] + "</div>");
cnt = cnt + 4;
i++;
}
//$(".pct-slider#" + sliders[0]).find('.ui-slider-tick').find('.tick-labels').hide()
},
addValue: function( val ) {
this.options.values.push(val);
console.log(val)
var time = convertToTime(val)
console.log(time)
this._refresh();
$($(".ui-slider-handle").last()).attr('data-value', time)
},
removeValue: function( ) {
if (this.options.values.length > 1) {
this.options.values.pop( );
this._refresh();
}
}
});
})(jQuery);
var sliders =["mondaySlider", "tuesdaySlider","wednesdaySlider","thursdaySlider","fridaySlider","saturdaySlider","sundaySlider"];
$(".pct-slider#" + sliders[0])
.customSlider({
min: 0,
max: 1440,
step: 15,
range: false,
ticks: true,
values: initialValues,
create: function (event, ui) {
$.each( initialValues, function(i, v){
updateValue({
value: v,
handle: $(".pct-slider#" + sliders[0]).find('.ui-slider-handle').eq(i)
});
});
},
slide: function (event, ui) {
var handleIndex = $('a', event.target).index(ui.handle),
curr = ui.values[handleIndex],
next = ui.values[handleIndex + 1] - 15,
prev = ui.values[handleIndex - 1] + 15;
if (curr > next || curr < prev) {
return false;
}
updateValue(ui);
//positionSelects();
}
});
I was trying to append divs onto my handles, but when I append a div it makes my handle disappear. My thought was to append a div on two handles and color the background of that div. Not working out for me though.
Heres a fiddle of what my initial slider looks like : http://jsfiddle.net/5TTm4/3095/
I want to color between the sets of handles
You can add div inside your slider and resize them when you move the handles. With proper css it'll give the effect you're describing. You may need to tweak it a little bit, but this should give you some ideas:
HTML
//You add divs inside your slider, you need four, the last region will be
/background of slider
<div class="pct-slider" id="mondaySlider">
<div class="color-region"></div>
<div class="color-region"></div>
<div class="color-region"></div>
<div class="color-region"></div>
</div>
CSS
//Make your divs relative and give them color
.color-region
{
position: relative;
height: 100%;
float: left;
}
.color-region:nth-child(1)
{
background-color: blue;
}
.color-region:nth-child(1)
{
background-color: blue;
}
.color-region:nth-child(2)
{
background-color: red;
}
.color-region:nth-child(3)
{
background-color: yellow;
}
.color-region:nth-child(4)
{
background-color: green;
}
JS
function resize_colors() {
//you start at 0
var cur_pos = 0;
$(".ui-slider-handle").each(function (i) {
//for each handle you check position and set width of corresponding color div
$('.color-region').eq(i).css('width', $(this).position().left - cur_pos)
//update cur_pos to calculate next color width
cur_pos = $(this).position().left;
})
}
You'll see it doesn't follow completely on slide event, part of this is because slide event is triggered when it moves only, so when you stop, there's a moment not updating. But maybe if you run resize color on some other event it will give a better result.
See fiddle:http://jsfiddle.net/t4veqohy/1/
I have a Javascript who works well, because yesterday i get here some very good solutions.
I want to know if i can extended this Javascript with another Query.
The query now, gives an alert when the number is bigger then 199. It works well.
But now i want to know, if i can get confirmbox inside for the same inputbox, when i write a number bigger then 100?
Here an example
I write the number 110 and i does get an confirm box with an Information(bla bla), and when i click Yes this number stays in the inputbox.
But when i write 200 or bigger then i does get the alert that this number is to big.
Here the code, what i get yesterday, whenn the number is bigger then 199:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Page</title>
<script type="text/javascript">
function minMax() {
var min = 0;
var mid = 99;
var max = 199;
var num = parseInt(document.getElementById('value_one').value);
if (num > mid && num < max) {
var r = confirm(num + ' n\'is greater than ' + mid+ '. Press Yes to retain it.');
if (r == false) document.getElementById('value_one').value = "";
return false;
}
if (min > num || max < num) {
alert(num + ' n\'is not between ' + min + ' and ' + max);
return false;
}
</script>
</head>
<body>
<form>
Value: <input type='text' id="value_one" onBlur="minMax();">
</form>
</body>
</html>
Is it possible and if somebody has an idea?
You can use confirm box for this instead of alert. Check the demo it on w3school.
Try this
<script type="text/javascript">
function minMax() {
var min = 0;
var mid = 100;
var max = 199;
var num = parseInt(document.getElementById('value_one').value);
if (num > mid && num < max) {
var r = confirm(num + ' n\'is greater than ' + mid+ '. Press Yes to retain it.');
if (r == false) document.getElementById('value_one').value = "";
return false;
}
if (min > num || max < num) {
alert(num + ' n\'is not between ' + min + ' and ' + max);
return false;
}
}
</script>
Check the demo on jsFiddle.net.
Hope this works out for you.
There is a confirm box you can control it based on the option you selected(yes or cancel).
You can also make the textbox clean when it cross the max (document.getElementById('value_one').value=0)
I'm not too experienced in JQuery beyond standard api functionality, but I have a number of scrollers on my page which all use the same code, only they each have a few of their own settings (for example, separate heights and scroll limits, and current number of times they have been scrolled). I want to be able to use the code over and over again, but with each reference receiving its own set of variables. I think that prototypes are what I'm after, but I can't quite wrap my head around the examples I've seen of this. This is my scroller code:
$(document).ready(function() {
var scrollAmt = 50; //distance in pixels;
var scrollableAmt = $('#weblinks .container').outerHeight();
var viewAmt = $('#weblinks').outerHeight();
var maxScroll = Math.ceil((scrollableAmt-viewAmt) / scrollAmt);
var currentItem = 0;
function setScrollButtons(scrollRef,scrollAmount){
}
$("#weblinks .scrollDownBtn").click(function(){
if (currentItem <= maxScroll){
$('#weblinks .container:not(:animated)').animate({'top' : '-='+ scrollAmt + ''},500,function(){
currentItem++
});
} else {
currentItem = 0;
$('#weblinks .container:not(:animated)').animate({'top' : currentItem},500);
}
});
$("#weblinks .scrollUpBtn").click(function(){
if (currentItem > 0){
$('#weblinks .container:not(:animated)').animate({'top' : '+='+ scrollAmt + ''},500,function(){
currentItem--;
});
} else {
$('#weblinks .container:not(:animated)').animate({'top' : currentItem},500);
}
});
});
So essentially what I'd want to do is create a function or class, I guess, which accomplishes all of the above code, but be able to pass it a div reference to take the place of #weblinks, and maybe pass it a scroll amount, and multiple instances of this functionality be able to exist on the same page together. Anybody have any advice about the best way to go about this?
EDIT: I've added the HTML that will always exist for each scroller.
<div id="weblinks" class="scrollbar_container">
<div class="customScrollBox">
<div class="container">
<div class="content">
</div>
</div>
<a class="scrollUpBtn" href="javascript:void(0);"></a> <a class="scrollDownBtn" href="javascript:void(0);"></a>
</div>
</div>
My Bid:
(function($){
$.fn.extend({
customScroller: function(options){
return this.each(function(i,e){
var container = $(e).find('.container'),
content = $(e).find('.content'),
scrollUpBtn = $(e).find('.scrollUpBtn'),
scrollDownBtn = $(e).find('.scrollDownBtn');
var self = $(e);
var o = $.extend({}, $.fn.customScroller.defaults, options);
o.scrollableAmt = container.outerHeight();
o.viewAmt = self.outerHeight();
o.maxScroll = Math.ceil((o.scrollableAmt - o.viewAmt) / o.scrollAmt);
scrollDownBtn.click(function(){
console.log('DOWN -- current: '+o.currentItem);
if (o.currentItem <= o.maxScroll){
container.filter(':not(:animated)').animate({
top: '-='+o.scrollAmt
},500,function(){
o.currentItem++;
});
}else{
o.currentItem = 0;
container.filter(':not(:animated)').animate({
top: o.currentItem
},500);
}
});
scrollUpBtn.click(function(){
console.log('UP -- current: '+o.currentItem);
if (o.currentItem > 0){
container.filter(':not(:animated)').animate({
top: '+='+o.scrollAmt
},500,function(){
o.currentItem--;
});
}else{
container.filter(':not(:animated)').animate({
top: o.currentItem
},500);
}
});
});
}
});
$.fn.customScroller.defaults = {
scrollAmt: 50,
scrollableAmt: 0,
viewAmt: 0,
maxScroll: 0,
currentItem: 0
};
})(jQuery);
$('#weblinks').customScroller();
To answer your question, I use extend in a couple of places: one for the options, and the other for jQuery addon ability.
$.fn.extend tells jQuery this is extending its functionality.
$.extend({},$.fn.customScroller.defaults, option); allows you to call .customScroller({ scrollAmount: 10 }) and change the behavior of the scroll.
any other questions, please just ask.
This is a good candidate for jQuery plugin you can create for yourself. Of course if you want to spend some time and learn this principle :)
How to develop a jQuery plugin for some details of what and how jQuery plugins do
You could pretty simply refactor it in the case that all div's will have a sub container class. Something like:
function scrollExample(divId) {
var scrollAmt = 50; //distance in pixels;
var scrollableAmt = $(divId + ' .container').outerHeight();
var viewAmt = $(divId).outerHeight();
var maxScroll = Math.ceil((scrollableAmt-viewAmt) / scrollAmt);
var currentItem = 0;
function setScrollButtons(scrollRef,scrollAmount){
}
$(divId + " .scrollDownBtn").click(function(){
if (currentItem <= maxScroll){
$(divId + ' .container:not(:animated)').animate({'top' : '-='+ scrollAmt + ''},500,function(){
currentItem++
});
} else {
currentItem = 0;
$(divId + ' .container:not(:animated)').animate({'top' : currentItem},500);
}
});
$(divId + " .scrollUpBtn").click(function(){
if (currentItem > 0){
$(divId + ' .container:not(:animated)').animate({'top' : '+='+ scrollAmt + ''},500,function(){
currentItem--;
});
} else {
$(divId + ' .container:not(:animated)').animate({'top' : currentItem},500);
}
});
});
Then call it with something like:
$(document).ready(function() {
scrollExample('#webLinks');
}
If you had the actual reference to the object it would be slightly different, but still follow a similar principle.