Skip to content

Instantly share code, notes, and snippets.

@tmcw
Created October 9, 2013 21:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tmcw/6909075 to your computer and use it in GitHub Desktop.
Save tmcw/6909075 to your computer and use it in GitHub Desktop.
GIF89a???????!?,DnX;
.dragdealer {
position: absolute;
height: 20px;
background: url(cr-hatch-light-gray.gif);
margin-bottom: 1em;
top:495px;
}
.dragdealer .handle {
position: absolute;
cursor: pointer;
}
.dragdealer .red-bar {
width: 120px;
height: 20px;
background: #333333;
color: #FFF;
line-height: 20px;
text-align: center;
border-radius:1px;
-moz-border-radius:3px;
-webkit-border-radius:3px;
}
.dragdealer .disabled {
background: #898989;
}
/**
* Dragdealer JS v0.9.5
* http://code.ovidiu.ch/dragdealer-js
*
* Copyright (c) 2010, Ovidiu Chereches
* MIT License
* http://legal.ovidiu.ch/licenses/MIT
*/
/* Cursor */
var Cursor =
{
x: 0, y: 0,
init: function()
{
this.setEvent('mouse');
this.setEvent('touch');
},
setEvent: function(type)
{
var moveHandler = document['on' + type + 'move'] || function(){};
document['on' + type + 'move'] = function(e)
{
moveHandler(e);
Cursor.refresh(e);
}
},
refresh: function(e)
{
if(!e)
{
e = window.event;
}
if(e.type == 'mousemove')
{
this.set(e);
}
else if(e.touches)
{
this.set(e.touches[0]);
}
},
set: function(e)
{
if(e.pageX || e.pageY)
{
this.x = e.pageX;
this.y = e.pageY;
}
else if(e.clientX || e.clientY)
{
this.x = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
this.y = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
}
}
};
Cursor.init();
/* Position */
var Position =
{
get: function(obj)
{
var curleft = curtop = 0;
if(obj.offsetParent)
{
do
{
curleft += obj.offsetLeft;
curtop += obj.offsetTop;
}
while((obj = obj.offsetParent));
}
return [curleft, curtop];
}
};
/* Dragdealer */
var Dragdealer = function(wrapper, options)
{
if(typeof(wrapper) == 'string')
{
wrapper = document.getElementById(wrapper);
}
if(!wrapper)
{
return;
}
var handle = wrapper.getElementsByTagName('div')[0];
if(!handle || handle.className.search(/(^|\s)handle(\s|$)/) == -1)
{
return;
}
this.init(wrapper, handle, options || {});
this.setup();
};
Dragdealer.prototype =
{
init: function(wrapper, handle, options)
{
this.wrapper = wrapper;
this.handle = handle;
this.options = options;
this.disabled = this.getOption('disabled', false);
this.horizontal = this.getOption('horizontal', true);
this.vertical = this.getOption('vertical', false);
this.slide = this.getOption('slide', true);
this.steps = this.getOption('steps', 0);
this.snap = this.getOption('snap', false);
this.loose = this.getOption('loose', false);
this.speed = this.getOption('speed', 10) / 100;
this.xPrecision = this.getOption('xPrecision', 0);
this.yPrecision = this.getOption('yPrecision', 0);
this.callback = options.callback || null;
this.animationCallback = options.animationCallback || null;
this.bounds = {
left: options.left || 0, right: -(options.right || 0),
top: options.top || 0, bottom: -(options.bottom || 0),
x0: 0, x1: 0, xRange: 0,
y0: 0, y1: 0, yRange: 0
};
this.value = {
prev: [-1, -1],
current: [options.x || 0, options.y || 0],
target: [options.x || 0, options.y || 0]
};
this.offset = {
wrapper: [0, 0],
mouse: [0, 0],
prev: [-999999, -999999],
current: [0, 0],
target: [0, 0]
};
this.change = [0, 0];
this.activity = false;
this.dragging = false;
this.tapping = false;
},
getOption: function(name, defaultValue)
{
return this.options[name] !== undefined ? this.options[name] : defaultValue;
},
setup: function()
{
this.setWrapperOffset();
this.setBoundsPadding();
this.setBounds();
this.setSteps();
this.addListeners();
},
setWrapperOffset: function()
{
this.offset.wrapper = Position.get(this.wrapper);
},
setBoundsPadding: function()
{
if(!this.bounds.left && !this.bounds.right)
{
this.bounds.left = Position.get(this.handle)[0] - this.offset.wrapper[0];
this.bounds.right = -this.bounds.left;
}
if(!this.bounds.top && !this.bounds.bottom)
{
this.bounds.top = Position.get(this.handle)[1] - this.offset.wrapper[1];
this.bounds.bottom = -this.bounds.top;
}
},
setBounds: function()
{
this.bounds.x0 = this.bounds.left;
this.bounds.x1 = this.wrapper.offsetWidth + this.bounds.right;
this.bounds.xRange = (this.bounds.x1 - this.bounds.x0) - this.handle.offsetWidth;
this.bounds.y0 = this.bounds.top;
this.bounds.y1 = this.wrapper.offsetHeight + this.bounds.bottom;
this.bounds.yRange = (this.bounds.y1 - this.bounds.y0) - this.handle.offsetHeight;
this.bounds.xStep = 1 / (this.xPrecision || Math.max(this.wrapper.offsetWidth, this.handle.offsetWidth));
this.bounds.yStep = 1 / (this.yPrecision || Math.max(this.wrapper.offsetHeight, this.handle.offsetHeight));
},
setSteps: function()
{
if(this.steps > 1)
{
this.stepRatios = [];
for(var i = 0; i <= this.steps - 1; i++)
{
this.stepRatios[i] = i / (this.steps - 1);
}
}
},
addListeners: function()
{
var self = this;
this.wrapper.onselectstart = function()
{
return false;
}
this.handle.onmousedown = this.handle.ontouchstart = function(e)
{
self.handleDownHandler(e);
};
this.wrapper.onmousedown = this.wrapper.ontouchstart = function(e)
{
self.wrapperDownHandler(e);
};
var mouseUpHandler = document.onmouseup || function(){};
document.onmouseup = function(e)
{
mouseUpHandler(e);
self.documentUpHandler(e);
};
var touchEndHandler = document.ontouchend || function(){};
document.ontouchend = function(e)
{
touchEndHandler(e);
self.documentUpHandler(e);
};
var resizeHandler = window.onresize || function(){};
window.onresize = function(e)
{
resizeHandler(e);
self.documentResizeHandler(e);
};
this.wrapper.onmousemove = function(e)
{
self.activity = true;
}
this.wrapper.onclick = function(e)
{
return !self.activity;
}
this.interval = setInterval(function(){ self.animate() }, 25);
self.animate(false, true);
},
handleDownHandler: function(e)
{
this.activity = false;
Cursor.refresh(e);
this.preventDefaults(e, true);
this.startDrag();
this.cancelEvent(e);
},
wrapperDownHandler: function(e)
{
Cursor.refresh(e);
this.preventDefaults(e, true);
this.startTap();
},
documentUpHandler: function(e)
{
this.stopDrag();
this.stopTap();
//this.cancelEvent(e);
},
documentResizeHandler: function(e)
{
this.setWrapperOffset();
this.setBounds();
this.update();
},
enable: function()
{
this.disabled = false;
this.handle.className = this.handle.className.replace(/\s?disabled/g, '');
},
disable: function()
{
this.disabled = true;
this.handle.className += ' disabled';
},
setStep: function(x, y, snap)
{
this.setValue(
this.steps && x > 1 ? (x - 1) / (this.steps - 1) : 0,
this.steps && y > 1 ? (y - 1) / (this.steps - 1) : 0,
snap
);
},
setValue: function(x, y, snap)
{
this.setTargetValue([x, y || 0]);
if(snap)
{
this.groupCopy(this.value.current, this.value.target);
}
},
startTap: function(target)
{
if(this.disabled)
{
return;
}
this.tapping = true;
if(target === undefined)
{
target = [
Cursor.x - this.offset.wrapper[0] - (this.handle.offsetWidth / 2),
Cursor.y - this.offset.wrapper[1] - (this.handle.offsetHeight / 2)
];
}
this.setTargetOffset(target);
},
stopTap: function()
{
if(this.disabled || !this.tapping)
{
return;
}
this.tapping = false;
this.setTargetValue(this.value.current);
this.result();
},
startDrag: function()
{
if(this.disabled)
{
return;
}
this.offset.mouse = [
Cursor.x - Position.get(this.handle)[0],
Cursor.y - Position.get(this.handle)[1]
];
this.dragging = true;
},
stopDrag: function()
{
if(this.disabled || !this.dragging)
{
return;
}
this.dragging = false;
var target = this.groupClone(this.value.current);
if(this.slide)
{
var ratioChange = this.change;
target[0] += ratioChange[0] * 4;
target[1] += ratioChange[1] * 4;
}
this.setTargetValue(target);
this.result();
},
feedback: function()
{
var value = this.value.current;
if(this.snap && this.steps > 1)
{
value = this.getClosestSteps(value);
}
if(!this.groupCompare(value, this.value.prev))
{
if(typeof(this.animationCallback) == 'function')
{
this.animationCallback(value[0], value[1]);
}
this.groupCopy(this.value.prev, value);
}
},
result: function()
{
if(typeof(this.callback) == 'function')
{
this.callback(this.value.target[0], this.value.target[1]);
}
},
animate: function(direct, first)
{
if(direct && !this.dragging)
{
return;
}
if(this.dragging)
{
var prevTarget = this.groupClone(this.value.target);
var offset = [
Cursor.x - this.offset.wrapper[0] - this.offset.mouse[0],
Cursor.y - this.offset.wrapper[1] - this.offset.mouse[1]
];
this.setTargetOffset(offset, this.loose);
this.change = [
this.value.target[0] - prevTarget[0],
this.value.target[1] - prevTarget[1]
];
}
if(this.dragging || first)
{
this.groupCopy(this.value.current, this.value.target);
}
if(this.dragging || this.glide() || first)
{
this.update();
this.feedback();
}
},
glide: function()
{
var diff = [
this.value.target[0] - this.value.current[0],
this.value.target[1] - this.value.current[1]
];
if(!diff[0] && !diff[1])
{
return false;
}
if(Math.abs(diff[0]) > this.bounds.xStep || Math.abs(diff[1]) > this.bounds.yStep)
{
this.value.current[0] += diff[0] * this.speed;
this.value.current[1] += diff[1] * this.speed;
}
else
{
this.groupCopy(this.value.current, this.value.target);
}
return true;
},
update: function()
{
if(!this.snap)
{
this.offset.current = this.getOffsetsByRatios(this.value.current);
}
else
{
this.offset.current = this.getOffsetsByRatios(
this.getClosestSteps(this.value.current)
);
}
this.show();
},
show: function()
{
if(!this.groupCompare(this.offset.current, this.offset.prev))
{
if(this.horizontal)
{
this.handle.style.left = String(this.offset.current[0]) + 'px';
}
if(this.vertical)
{
this.handle.style.top = String(this.offset.current[1]) + 'px';
}
this.groupCopy(this.offset.prev, this.offset.current);
}
},
setTargetValue: function(value, loose)
{
var target = loose ? this.getLooseValue(value) : this.getProperValue(value);
this.groupCopy(this.value.target, target);
this.offset.target = this.getOffsetsByRatios(target);
},
setTargetOffset: function(offset, loose)
{
var value = this.getRatiosByOffsets(offset);
var target = loose ? this.getLooseValue(value) : this.getProperValue(value);
this.groupCopy(this.value.target, target);
this.offset.target = this.getOffsetsByRatios(target);
},
getLooseValue: function(value)
{
var proper = this.getProperValue(value);
return [
proper[0] + ((value[0] - proper[0]) / 4),
proper[1] + ((value[1] - proper[1]) / 4)
];
},
getProperValue: function(value)
{
var proper = this.groupClone(value);
proper[0] = Math.max(proper[0], 0);
proper[1] = Math.max(proper[1], 0);
proper[0] = Math.min(proper[0], 1);
proper[1] = Math.min(proper[1], 1);
if((!this.dragging && !this.tapping) || this.snap)
{
if(this.steps > 1)
{
proper = this.getClosestSteps(proper);
}
}
return proper;
},
getRatiosByOffsets: function(group)
{
return [
this.getRatioByOffset(group[0], this.bounds.xRange, this.bounds.x0),
this.getRatioByOffset(group[1], this.bounds.yRange, this.bounds.y0)
];
},
getRatioByOffset: function(offset, range, padding)
{
return range ? (offset - padding) / range : 0;
},
getOffsetsByRatios: function(group)
{
return [
this.getOffsetByRatio(group[0], this.bounds.xRange, this.bounds.x0),
this.getOffsetByRatio(group[1], this.bounds.yRange, this.bounds.y0)
];
},
getOffsetByRatio: function(ratio, range, padding)
{
return Math.round(ratio * range) + padding;
},
getClosestSteps: function(group)
{
return [
this.getClosestStep(group[0]),
this.getClosestStep(group[1])
];
},
getClosestStep: function(value)
{
var k = 0;
var min = 1;
for(var i = 0; i <= this.steps - 1; i++)
{
if(Math.abs(this.stepRatios[i] - value) < min)
{
min = Math.abs(this.stepRatios[i] - value);
k = i;
}
}
return this.stepRatios[k];
},
groupCompare: function(a, b)
{
return a[0] == b[0] && a[1] == b[1];
},
groupCopy: function(a, b)
{
a[0] = b[0];
a[1] = b[1];
},
groupClone: function(a)
{
return [a[0], a[1]];
},
preventDefaults: function(e, selection)
{
if(!e)
{
e = window.event;
}
if(e.preventDefault)
{
e.preventDefault();
}
e.returnValue = false;
if(selection && document.selection)
{
document.selection.empty();
}
},
cancelEvent: function(e)
{
if(!e)
{
e = window.event;
}
if(e.stopPropagation)
{
e.stopPropagation();
}
e.cancelBubble = true;
}
};
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title></title>
<script src='//api.tiles.mapbox.com/mapbox.js/v1.3.1/mapbox.js'></script>
<script src='dragdealer.js'></script>
<link href='//api.tiles.mapbox.com/mapbox.js/v1.3.1/mapbox.css' rel='stylesheet' />
<link href='dragdealer.css' rel='stylesheet' />
<link href='style.css' rel='stylesheet' />
<!--[if lte IE 8]>
<link href='//api.tiles.mapbox.com/mapbox.js/v1.3.1/mapbox.ie.css' rel='stylesheet'>
<![endif]-->
<style>
body { margin:0; padding:0; }
#map {
width:650px;
height:495px;
}
</style>
</head>
<body>
<div id='map'></div>
<div id='azavea-slider' class='dragdealer' style='width:650px'>
<div id='azavea-slide-bar' class='red-bar handle'></div>
</div>
<script type='text/javascript'>
var number_years = 22,
start_year = 1990,
map = L.mapbox.map('map')
.setView([40, -100.50], 4),
years = [],
currentOverlay;
map.addControl(L.mapbox.legendControl().addLegend('<div class="overlay-legend"><div class="scale"> <ul class="labels"> <li><span style="background:#0C5D00;"></span>Over 99th percentile</li><li><span style="background:#5C8100;"></span>98th - 99th percentile</li><li><span style="background:#7E9C00;"></span>95th - 98th percentile</li><li><span style="background:#B8C300;"></span>90th - 95th percentile</li><li><span style="background:#D2CF00;"></span>70th - 95thth percentile</li><li><span style="background:#DCDA53;"></span>10th - 70th percentile</li><li><span style="background:#E6E4A6;"></span>Below 10th percentile</li></ul> </div> </div>'));
for (var y = start_year; y <= start_year + number_years; y += 2) {
var year = {
year: y,
tiles: L.mapbox.tileLayer('sunlight.pop_' + y),
grid: L.mapbox.gridLayer('sunlight.pop_' + y)
};
years.push(year);
}
currentOverlay = years[0].tiles.addTo(map);
currentGrid = years[0].grid.addTo(map);
currentGridControl = L.mapbox.gridControl(years[0].grid).addTo(map);
var timeout;
var slideBar = document.getElementById('azavea-slide-bar');
var azaveaSlider = new Dragdealer('azavea-slider', {
x: 0,
steps: 1 + number_years / 2,
snap: true,
animationCallback: onslide
});
function onslide(x, y) {
var numForward = x * ((number_years / 2)),
yearNumber = start_year + (numForward * 2);
slideBar.innerHTML = yearNumber;
if (currentGridControl) map.removeControl(currentGridControl);
currentOverlay = years[numForward].tiles.addTo(map);
currentGrid = years[numForward].grid.addTo(map);
currentGridControl = L.mapbox.gridControl(currentGrid).addTo(map);
if (timeout) window.clearTimeout(timeout);
timeout = window.setTimeout(cleanup, 100);
}
function cleanup() {
map.eachLayer(function(l) {
if (l !== currentOverlay && l !== currentGrid) {
map.removeLayer(l);
}
});
}
</script>
</body>
</html>
/* Overidden legend styles */
.wax-legend .overlay-legend {
padding-top: 1px;
min-width: 143px;
}
.wax-legend .title {
text-align: left;
margin-bottom: 1px;
font-weight: bold;
font-size: 90%;
line-height: 14px;
width: 143px;
}
.wax-legend .title2 {
text-align: left;
margin-top: 1px;
margin-bottom: 4px;
font-size: 75%;
line-height: 14px;
width: 143px;
}
.wax-legend .overlay-legend.drought .title2 {
width: 185px;
}
.wax-legend .overlay-legend.commitment .title {
width: 160px;
}
.wax-legend .scale {
clear: both;
}
.wax-legend .scale ul {
margin: 0;
padding: 0;
list-style: none !important;
-webkit-padding-start: 0 !important;
}
.wax-legend .scale ul li {
font-size: 80%;
list-style: none !important;
margin-left: 0px !important;
padding:2px 0;
}
.wax-legend ul.labels li span {
display:inline-block;
vertical-align:middle;
height: 16px;
width: 30px;
border: .5px solid #333;
margin-right: 5px;
margin-left: 0px !important;
}
.wax-legend ul li span {
display: block;
margin-left: 0px !important;
}
.wax-legend .source1 {
font-size: 70%;
color: #666;
margin-top: 1px;
clear: both;
}
.wax-legend .source2 {
font-size: 70%;
color: #666;
margin-top: 1px;
clear: both;
}
.wax-attribution a,
.wax-legend a {
color: #7F8A8C;
text-decoration: none !important;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment