jQuery UI: smooth slider with one snap (to default value)? - javascript

I'd like to make a slider that snaps to the center while retaining smooth action elsewhere. Something like a jQuery version of a real-life speaker balance slider. Is it possible?
Or should I just create my own slider with a draggable object, constricted to one axis with containing it frame, snapping to another object (or grid) positioned in the center of the frame?
Edit: I simply need a slider that allows values e.g. from -10 to -1, 0, and 1 to 10 (between -1 and 1 snap to 0) with step: 0.1

You should be able to use the jQuery slider, but restrict its motion with the slide event:
jSlider.slider({
// other options...
slide: function (event, ui) {
if (ui.value > -1 && ui.value < 1 && ui.value != 0) {
// force it to 0 between -1 and 1.
jSlider.slider('value', 0);
return false;
}
return true;
}
});

Hmmm...so this is what I'm envisioning in my head...A background that slides on a timer like a carousel (maybe these are big images), with a row of thumbnails on top that slides smooth. That what you want to build?
EDIT: Here's what you need to do:
I rarely find the need to use jQuery plugins. Here is what you need:
Mousedown (on the slider). api.jquery.com/mousedown/. There is a callback on mouse down an on release.
Track mouse position inside the slider container while you're dragging the slider docs.jquery.com/Tutorials:Mouse_Position
Use the animate function to move the slider while your mouse still hasn't been released api.jquery.com/animate/ Stop animate on release.
When your slider gets to a certain x position in it's container, force the "smooth" function - ie a different animate function.

Use the following so that your jquery slider automatically snaps to the nearest in the step. The trick is to implement your own step-interval-slider. The problem is, if your max and min are separated by a small distance (for e.g. 5-10) your slide will behave in steps because the default step=1, so you need to compute your step based on that. If your max-min values are separated by a huge distance (e.g. 1-1000 or more) you can leave the computed_step calculation and initialize it to 1.
max_limit = 30;
min_limit = 5;
stick_to_steps_of = 5;
var computed_step = max_term/100; //you can vary the denominator to make it smoother
$("#my_slider" ).slider({
animate : true,
value: max_limit,
min: min_limit,
max: max_limit,
step: computed_step,
stop: function( event, ui ) {
d = parseInt(parseInt(ui.value)/stick_to_steps_of);
rem = parseInt(ui.value)%stick_to_steps_of;
var fval = 0;
if (rem <= parseInt(stick_to_steps_of/2)) {
fval = d*stick_to_steps_of;
}else{
fval = (d+1)*stick_to_steps_of;
}
$("#my_slider").slider('option', 'value', fval);
$('#myslider_current_value').html(fval); //some placeholder to show the current value
}
});

Related

Bootstrap slider - prevent flipping the two cursors and stop slide

I would like to use Bootstrap slider to represent 3 lengths of axes whose sum doesn't change (the max value of the slider corresponds to this sum).
So I have 2 cursors on bootstrap slider and the 3 intervals represent these lengths.
Here's an example: bootstrap with two cursors
My issue is that I would like to stop dragging the second cursor (on the right) when it is equal (or nearly with a fixed step) to the first one (on the left) and inversely for the first cursor.
I saw there's an slide stop event but this doesn't seem to be the same thing.
I have surely to modify the bootstrap-slider.js source but I don't know how to do for implementing this specific functionality.
It would be like:
slider.on("slide", function(slideEvt) {
if ((cursor2.value - cursor1.value) < step)
{ this.stopSlide();}
});
Using slides events it's possible. The idea is to see which cursor is fixed, and when its value change, block the slide movement, by setting value.
Didn't find a cleaner way to block slide event...
Working code :
var slider = new Slider("#slider1");
var initPos,
fixedCursor,
fixedCursorPos;
slider.on("slideStart", function(slideEvt) {
initPos = slideEvt;
fixedCursor = null;
fixedCursorPos = null;
});
slider.on("slide", function(slideEvt) {
if (initPos[0] !== initPos[1] && (slideEvt[0] !== initPos[0] || slideEvt[1] !== initPos[1])) {
if (fixedCursor == null) {
fixedCursor = (slideEvt[0] === initPos[0] ? 0 : 1);
fixedCursorPos = slideEvt[fixedCursor];
}
if (fixedCursorPos !== slideEvt[fixedCursor]) {
slider.setValue([fixedCursorPos, fixedCursorPos], false, false);
}
}
});
Working JS Bin : http://jsbin.com/kopakiciti/1/edit?html,js,output

jQuery Knob partially read only

I have a collection of jQuery knobs on my page that represent percentages. Each knob can have a value from 0-100, however, each subsequent knob should not have a value less than the previous knob. Essentially I want to make part of the knob read only - to prevent the user from dragging the value below the previous knob's value - similar to a 'min' value.
Example
Knob 1 25%
Knob 2 50% (min value still 0, max 100, but the value has to be greater than 25)
Knob 3 75%
Knob 4 100%
I have tried binding to the 'change' event on the knob, but that is not giving me what I want. Below I'm binding to the change event to try to limit the value - this is hard coded to test the simple use case. I am probably going to want to bind to the 'draw' event to limit the values on animation but haven't got that far.
$(this).trigger('configure', {
'change': function (v) {
console.log("Updating value " + v);
if(v < 25) {
console.log("Updating value");
this.cv = 25;
}
}
});
Not sure if this is the best way to do it, but you can manipulate the angleOffset and angleArc options of the dial based on the value of the previous one. For example, if you have two dials:
HTML
<input type="text" value="75" id="dial1">
<input type="text" value="75" id="dial2">
Your javascript would be something like this:
$(function () {
$("#dial1").knob({
'change': function (v) {
$('#dial2')
.trigger(
'configure', {
'angleOffset': (v / 100 * 360),
'angleArc': ((100-v) / 100 * 360),
'min': v,
});
}
});
$("#dial2").knob();
});
As for the empty space left in the dial, you can fix that by setting the canvas background to an image of a full knob.
CSS
canvas {
background: url('http://imgur.com/aeTBhL9.png');
}
Here's a jsFiddle example.

jQuery Mobile slider snap?

I've spent the better past of 2 hours trying out random code from different sources that claim they've managed to snap the slider to particular points. I'm not sure if this is feasible with the jQuery Mobile library, since the jQuery UI version does support it, but i'm really needing to figure something out for a current project.
Essentially I have a timeline with different dates. They're not in "steps", like 10's or 20's, they're different numbers. Something like 1, 3, 10, 12, 32. I need the slider to snap at those points.
Currently, I have something that's testing the step attr only.
$('#slider-1').live( "change", function(e) {
var step = $(this).attr('step'),
val = $(this).val();
if(step % val == step || val == step){
console.log(val)
}
});
The issue i'm having with the slider, not only the snapping, is when i slide anywhere near 20 or 40 or 60 etc, i'm getting console logs. It's not logging ON 20 etc.
Figured it out after many iterations of code and reading the documentation for specific events I can bind.
So essentially I had a timeline of numbers in my array that looks something like:
-0--10--20-----70--100---150---200---250---300---350---400-----500----------------1000
I needed to snap to the nearest number depending on the position of the slider-handle. I did this by testing the current value when the slider was being moved against the closest number in the array. I would then dynamically change the sliders value and would then have to do a force refresh of the slider to see the change.
$(function() {
/*
Array of values between 0 - 1000 (can be any set of numbers you want to snap to,
but you must make sure the 'max' attribute on the input element is <= the last
value in the array)
*/
var values = [0, 10, 20, 70, 100, 150, 200, 250, 300, 350, 400, 500, 1000],
/*
A way for us to check the current and previous values of the slider so we only
call doSomething() if these are different. This way the function isn't called twice. These should NOT have the same values on init.
*/
currentVal = 0,
prevVal = null,
// Assign our slider to a variable so we're not hitting the dom repeatedly.
$slider = $("#slider-1");
/*
After each change of our input value, we assign the slider value to the nearest number
in our array for our "snap" effect
*/
$($slider).bind("change", function(){
$($slider).val(findNearest($($slider).val()))
});
/*
We must capture click events on the slider itself if the user doesn't drag the handle.
*/
$(".ui-slider[role=application]").bind("vclick",function(){
$($slider).slider('refresh');
})
/*
jQuery creates new dom elements for us, which in the case of the handle, is an anchor element.
Use mouseup method to test on the computer, otherwise touchend method for mobile devices.
*/
$("a.ui-slider-handle").touchend(function(){
// If our currentVal hasn't changed after a snap action, do nothing, otherwise call doSomething()
if(currentVal != prevVal) {
prevVal = currentVal;
doSomething();
}
// Force slider refresh for visible snap effect
$($slider).slider('refresh');
})
// Used to iterate over our array and check for nearest value to what is passed in
function findNearest(goal) {
var closest = null;
$.each(values, function(){
if (closest == null || Math.abs(this - goal) < Math.abs(closest - goal)) {
closest = this;
}
});
return currentVal = Number(closest);
}
function doSomething(){
...
}
});
And my HTML:
<label for="slider-1" id="slider_label_1">Input slider:</label>
<input type="range" name="slider-1" id="slider-1" value="0" min="0" max="1000" step="10" />

Cleaning up a SerialScroll Resize Function

Greeting's
I'am still relatively new to JavaScript and Jquery and I know there has got to be a better method than the one I'am using.
I'am working on a serialScroll implementation. There is a master scrollTo that controls the left/right movement of a number of slides. Each slide contains it's own implementation of a vertical serialScroll. I have the resize on the scrollTo working great and the resize on the vertical works but I can't figure an elegant method for ensuring that on resize the current position remains centered, My current method works but is very inefficient.
$(function(){
var $up = $('#sec1_nav a.up').hide();//up button -- each slide needs it's own unique nav buttons
var $down = $('#sec1_nav a.down');//down button -- each slide needs it's own unique nav buttons
$('#screen1').serialScroll({
target:'#section1',
items:'.item',
prev:'#sec1_nav a.up',
next:'#sec1_nav a.down',
axis:'y',
duration:1000,
force:true,
cylce: false,
onBefore:function( e, elem, $pane, $items, pos ){
$up.add($down).show();
if( pos == 0 )$up.hide();
else if( pos == $items.length -1 )
$down.hide();
// Here's where it get ugly, I'am adding a unique class for each slide to the item's
$('.item').removeClass('pos1'); //Each slides need's it's own class i.e. slide1 = pos1, slide2 = pos2 etc.
$(elem).addClass('pos1');
}
});
$(window).bind("resize", function(){
resize1(); // Same goes for the resize function, each slide need's it's own function.
});
});
function resize1() {
height = $(window).height();
width = $(window).width();
mask_height = height * $('.item').length; // sets the new mask height
// Resize Height of the area
$('.sections').css({height: height, width : width});
$('.item').css({height: height, width : width});
$('#mask').css({height : mask_height, width : width});
$('.sections').scrollTo('.pos1', 0 ); // This issue is where it all fall apart, instead of using serialScroll, i'am stuck using scrollTo to maintain the current slide position.
}

set the size of the element when using animation in javascript

I want to use some animation in my page,so I google "javascript animation",I found this wonderful tutorial:
The JavaScript animation is implemented as gradual changing of DOM element styles or canvas objects.
The whole process is split into pieces, and each piece is called by
timer. Because the timer interval is very small, the animation looks
continuous.
So it seems that the dom animation is implemented by set the size of the element step by step.
This is the The generic animation provided by the tutorial:
function animate(opts) {
var start = new Date
var id = setInterval(function() {
var timePassed = new Date - start
var progress = timePassed / opts.duration
if (progress > 1) progress = 1
var delta = opts.delta(progress)
opts.step(delta)
if (progress == 1) {
clearInterval(id)
}
}, opts.delay || 10)
}
However I found that if an element in the page does not have the "width or height" property in its "style" property. How can we use them??
Now,suppose I have an element in the page with id "tip_info" who does not show at first,when I click an button,I want it opend with the animation.
<div id="wrapper" sytle="display:none">the content</div>
<input type="button" onclick="animate()" value="open"/>
Now,I try to use the generic animation:
var ele=document.getElementById('wrapper');
animate({
delay: 10,
duration: duration || 1000, // 1 sec by default
delta: delta,
step: function(delta) {
ele.style.width= The_Final_Width*delta + "px";
ele.style.height= The_Final_Height*delta + "px"
}
});
But how can I know the "The_Final_Width" and "The_Final_Height" value???
Its width and height should be changed according to the content inner the element.
Even when the animation complete,normally,the element does not need the "width" and "height" attrubutes,it just need the "display='block'".
So does it mean that an element want to be animated must have the explict size?
I would do it in three steps:
Use a jQuery function or a custom function to quickly display:block the div, get its size (width/height), and display:none again. It would be so fast that a human eye can't see it.
Animate with the width/height I got previously
At the end of the animation, I would set width/height to auto or initial. So if you add some content in it, it will increase its size automatically.

Categories

Resources