PDA

View Full Version : [solved] Range Sliders



smithloganj
28 Jun 2010, 8:23 AM
Hello,
I am working on a project that involves polygons on a map that have start and end times. Below the map is a time display area with a slider to change the "current" time and then beneath this we want editable bars that represent the various polygons and their time duration. All of the logic to make the polygons appear and disappear and have these start and end times is there, all I am looking for is a way to make these bars.

I am using ext sliders with 2 values, one for the start and one for the end time. I imagine removing the track behind the sliders should be no problem with some CSS, but what I am wondering is how I can make the area between the two handles fill in with a rectangular color bar.
When looking at the screenshot, I want the bottom three sliders to have a color fill in between the two handles.
Can anyone help with how this could be done?

Thank you so much!

Animal
28 Jun 2010, 9:36 AM
I could imagine a plugin doing it. You would have to do some absolute positioning of a styles div to sit between the sliders. It's quite possible, just a little fiddly.

mankz
28 Jun 2010, 12:49 PM
Couldn't resist the temptation, here's a crude example showing one simple way of doing it. Drop it into the examples folder of Ext 3.2. Not well tested :)

JS:


Ext.ns('Ext.ux.slider');

Ext.ux.slider.Highlight = Ext.extend(Object, {

init: function(slider) {
this.slider = slider;
var that = this;

// Overwrite moveThumb method to update element after animated slide
if (slider.vertical) {
slider.moveThumb = function(index, v, animate) {
var thumb = this.thumbs[index],
el = thumb.el;

if (!animate || this.animate === false) {
el.setBottom(v);
} else {
el.shift({bottom: v, stopFx: true, duration:.35, callback : that.syncElementSize, scope : that});
}
}
} else {
slider.moveThumb = function(index, v, animate){
var thumb = this.thumbs[index].el;

if(!animate || this.animate === false){
thumb.setLeft(v);
}else{
thumb.shift({left: v, stopFx: true, duration:.35, callback : that.syncElementSize, scope : that});
}
};
}

slider.on({
scope : this,
afterrender : this.onAfterRender,
drag : this.syncElementSize,
dragend : this.syncElementSize,
changecomplete : this.syncElementSize,
destroy : this.destroy
});
},

onAfterRender : function(s) {
this.el = s.innerEl.createChild({
cls : 'ext-ux-slider-highlight'
});
this.syncElementSize();
},

syncElementSize : function() {
var s = this.slider;

if (s.vertical) {
var thumb1Bottom = s.thumbs[0].el.getBottom(true),
thumb2Bottom = s.thumbs[1].el.getBottom(true),
thumb1Top = s.thumbs[0].el.getTop(true),
thumb2Top = s.thumbs[1].el.getTop(true),
highlightTop = Math.min(thumb1Bottom, thumb2Bottom);

this.el.setTop(highlightTop);
this.el.setHeight(Math.max(thumb1Top, thumb2Top) - highlightTop);
} else {
var thumb1Right = s.thumbs[0].el.getRight(true),
thumb2Right = s.thumbs[1].el.getRight(true),
thumb1Left = s.thumbs[0].el.getLeft(true),
thumb2Left = s.thumbs[1].el.getLeft(true),
highlightLeft = Math.min(thumb1Right, thumb2Right);

this.el.setLeft(highlightLeft);
this.el.setWidth(Math.max(thumb1Left, thumb2Left) - highlightLeft);
}
},

destroy : function() {
this.slider.un({
scope : this,
afterrender : this.onRender,
drag : this.syncElementSize,
dragend : this.syncElementSize,
changecomplete : this.syncElementSize,
destroy : this.destroy
});
this.el.destroy();
}
});




CSS:


.ext-ux-slider-highlight {
position: absolute;
background : yellow;
overflow:hidden;
}

.x-slider-vert .ext-ux-slider-highlight {
width:6px;
left:8px;
}

.x-slider-horz .ext-ux-slider-highlight {
height:6px;
top:8px;
}

smithloganj
29 Jun 2010, 7:22 AM
Wow thank you so much mankz! That code worked incredibly well.
I managed to override the css to make the track underneath disappear.
Is there a way to make the color changeable through some kind of setColor function rather than hard coded in the CSS? I'd eventually like the colors to match the color of the polygon it represents. One possibility would be to make a bunch of different styles and then change between them, but it seems like there should be a better way.
I'm soo grateful for all the help I've already received - I'm still fairly new at this so adding plugins/overrides and such is still quite confusing but I'll get there :).
Thank you so much!

mankz
29 Jun 2010, 9:41 AM
Glad you liked it! Would you need to modify it dynamically, after the slider has been rendered? Or would it be enough to pass a color config to the plugin at construction time?

smithloganj
29 Jun 2010, 10:17 AM
Unfortunately it will need to be dynamically modifiable since users will have the ability to change the polygon's attributes. But I hate to take up more of your time so if it's quite complicated don't worry.
Thanks!!

mankz
29 Jun 2010, 10:44 AM
Not complicated at all, just trying to understand your use case better. So perhaps adding a setColor method on the plugin would be the best option.



setColor : function(color) {
this.el.setStyle('background-color', color);
}

smithloganj
29 Jun 2010, 11:13 AM
Oh that worked perfectly - so simple.... Hopefully I've learned enough that next time I'll be able to figure some of this out on my own! :)

I can't thank you enough! Ideally someone else will be able to use this as well.

mankz
29 Jun 2010, 11:31 AM
You're most welcome, I've created a new thread in the user extensions for this plugin. Maybe someone else will contribute to it too :)

http://www.sencha.com/forum/showthread.php?102858-3.2-Ext.ux.slider.Highlight-A-slider-background-color-plugin&p=482387#post482387

smithloganj
6 Jul 2010, 10:05 AM
Hi again,

I noticed one small issue -- I've been using the .setValue method as well as the .setMaxValue and .setMinValue on the sliders and have found that the color only follows the thumbs if the thumb moves and is animated. To fix this, I've set the thumbs to jump forward and then back into place when the min/max values are changed, but is there a better way to do this? It looks a bit funny.
Definitely not a critical problem, but if there's an easy fix that would be great.

mankz
6 Jul 2010, 10:30 AM
Hmm, try this (just did some brief testing). Using createSequence to sync el size after thumbs are synced:



init: function(slider) {
this.slider = slider;
var that = this;

// Overwrite moveThumb method to update element after animated slide
if (slider.vertical) {
slider.moveThumb = function(index, v, animate) {
var thumb = this.thumbs[index],
el = thumb.el;

if (!animate || this.animate === false) {
el.setBottom(v);
} else {
el.shift({bottom: v, stopFx: true, duration:.35, callback : that.syncElementSize, scope : that});
}
};
} else {
slider.moveThumb = function(index, v, animate){
var thumb = this.thumbs[index].el;

if(!animate || this.animate === false){
thumb.setLeft(v);
}else{
thumb.shift({left: v, stopFx: true, duration:.35, callback : that.syncElementSize, scope : that});
}
};
}

slider.on({
scope : this,
afterrender : this.onAfterRender,
change : this.syncElementSize,
destroy : this.destroy
});

},

onAfterRender : function(s) {
this.el = s.innerEl.createChild({
cls : 'ext-ux-slider-highlight'
});
this.syncElementSize();
this.slider.syncThumb = this.slider.syncThumb.createSequence(this.syncElementSize, this);
},

smithloganj
6 Jul 2010, 10:48 AM
I replaced the old block with that one and got this error on firebug:
"this.el is undefined

this.el.setLeft(highlightLeft);"

Thanks so much for helping.

mankz
6 Jul 2010, 10:52 AM
Hmm, weird. I don't get that here. Add a simple if-check in the top of syncElementSize.



if (!this.el) return;

smithloganj
6 Jul 2010, 10:54 AM
Nevermind! I just replaced the onAfterRender function with the new one instead of the whole block you posted above and it works perfectly.

Thanks again! You've been amazingly helpful.

mankz
6 Jul 2010, 10:55 AM
Good to hear it works :)

azc-scarface
6 Jul 2010, 3:14 PM
Hello,

I am using a multiple slider which uses dates as values. I am able to create the slider with the two thumbs though the Tip of each thumb shows a sort of key which I believe represents the time that is assigned to that position of the thumb instead of showing the actual date of the current position of the thumb.

I can construct my slider with




var ts = new Ext.Slider({
x: 280,
y: 110,
id: 'timeslider',
width : 700,
minValue: oldd,
maxValue: newd,
values : [oldd,newd],
plugins : new Ext.slider.Tip()//tip
});



the vars oldd and newd represent two distinct dates created with new Date(xx/xx/xxxx). My question is, is there a way to make the thumb represent the actual date of the value it represents? if yes, how can I do it?

Great plugin by the way.

Thanks in advance

azc-scarface
6 Jul 2010, 3:26 PM
Hmmm I got it right after posting the thread. Custumized the tooltip by using the following:


var tip = new Ext.slider.Tip({
getText: function(thumb){

return String.format('<b>{0}</b>', new Date(thumb.value).dateFormat('m/d/Y'));
}
});


I had tried this before though now I tried to create the Date using the thumb value and it worked.