implementing a slider with proportional-width thumb using jquery-ui draggable, and with fixes to handle fractional pixels and too-small thumb
attempt to fix problems with too-thin thumb and with fractional pixels. idea: 1. min thumb width = 5px 2. round up thumb width to integer pixels 3. in left half of track, use left edge to set start time (and set end by calculation) 4. in right half of track, use right edge of thumb to set end time (and calculate start from it)
by hrabinowitz
HTML
<h3>implementing a slider with proportional-width thumb using jquery-ui draggable</h3>
<h3>within another DOM element:</h3>
<table>
<tr>
<td>
a rather very very long label
</td>
<td>
<div id="track" class="track">
<div id="thumb" class="thumb draggable ui-widget-content">
<p>ui.position.left=<span id="offsetX"></span></p>
<div id="startDisplay">
xx
</div>
<div id="endDisplay">
yy
</div>
<div id="startTimeDisplay">
xx:00
</div>
<div id="endTimeDisplay">
yy:00
</div>
</div>
</div>
</td>
</tr>
</table>
<br><br><br><br><br><br>
<h4>
Choose a range within the dataRange. Thumb is approximately proportional to the ratio of range to dataRange.
</h4>
<label for="rangeMillis" id="rangeLabel">Range: </label>
<select name="rangeMillis" id="rangeMillis">
<option value="86400000">1 day</option>
<option value="604800000" selected>1 week</option>
<option value="2592000000">30 days</option>
<option value="15768000000">half year</option>
<option value="31536000000">1 year</option>
</select>
CSS
.draggable {
position: absolute;
width: 100px;
height: 90px;
/*padding: 0.5em; */
float: left;
/*margin: 0 10px 10px 0;*/
margin: 0 0 0 0;
padding: 0;
background: yellow;
border: .5px solid orange;
cursor: ew-resize;
}
#startDisplay {
margin-top: 50px;
}
#endDisplay {
/*margin-top: 50px;*/
float: right;
}
#startTimeDisplay {
margin-top: 12px;
width: 250px;
text-align: left;
}
#endTimeDisplay {
float: right;
text-align: right;
width: 250px;
}
.track {
position: relative;
width: 500px;
height: 90px;
border: 0px solid #ccc;
padding: 0px;
background: lightGray;
margin: 0 0 0 0;
}
#metaSlider {
width: 600px;
}
#rangeLabel {
font-weight: bold;
}
JavaScript
// my code ===============
"use strict";
/**
* timeRangeSlider is a slider whose thumb is proportional
* to a given timeRange within a dataRange, and whose slide
* events pick a start and end time.
* When initializing, pass in options that include
* dataRange (object with start, end)
* $track (a jquery selection of the track div)
* $thumb (a jquery selection of the thumb div)
*/
var TimeRangeSlider = function(options) {
"use strict";
this.dataRange = options.dataRange;
this.dataDiff = dataRange.end - dataRange.start;
this.$track = options.$track;
this.trackWidth = options.$track.width();
this.$thumb = options.$thumb;
this.$rangeMillis = options.$rangeMillis;
this.$startDisplay = options.$startDisplay;
this.$endDisplay = options.$endDisplay;
this.$startTimeDisplay = options.$startTimeDisplay;
this.$endTimeDisplay = options.$endTimeDisplay;
var that = this;
this.trackOffset = this.$track.position().left;
this.containment = [this.trackOffset, 0, this.trackOffset + this.trackWidth - this.$thumb.width(), 90];
console.log("dataDiff=", this.dataDiff, "trackWidth=", this.trackWidth, "thumbWidth=" + this.$thumb.width());
TimeRangeSlider.prototype.getStartDate = function(left) {
var startEpoch = this.dataRange.start + left/this.trackWidth*this.dataDiff;
return startEpoch;
}
TimeRangeSlider.prototype.getEndDate = function(left) {
var endEpoch = this.getStartDate(left) + this.$thumb.width()/this.trackWidth * this.dataDiff;
return endEpoch;
}
TimeRangeSlider.prototype.onDrag = function(e, ui) {
if (ui instanceof HTMLElement) {
var left = +$(ui).position().left;
} else {
var left = +ui.position.left;
}
$('#offsetX').text(left);
var startEpoch = that.getStartDate(/*ui*/left);
var endEpoch = that.getEndDate(/*ui*/left);
that.$startDisplay.text(startEpoch);
that.$endDisplay.text(endEpoch);
var startDate = new Date(startEpoch);
var endDate = new...