dat.gui/elements/controller-number/controller-number.js
2014-09-07 18:27:32 -07:00

271 lines
4.7 KiB
JavaScript

/* globals Gui, Polymer */
/*
[ ] arrow keys
[ ] min() max() step() commands of yore
[x] only validate input box on blur, not on keydown
[x] enter key blurs
[x] decimals
[x] step
[x] dy to drag friction
[x] negative slider
[x] hover behavior
*/
Gui.register('controller-number', function(value) {
return typeof value == 'number';
});
Polymer('controller-number', {
value: 0,
decimals: 3,
computed: {
slider: 'min !== undefined && max !== undefined'
},
ready: function() {
var _this = this;
window.addEventListener('keydown', function(e) {
if (e.keyCode == 18) {
_this._alt = true;
}
}, false);
window.addEventListener('keyup', function(e) {
if (e.keyCode == 18) {
_this._alt = false;
}
}, false);
// this.super();
},
init: function(min, max, step) {
this.min = min;
this.max = max;
this.step = step;
},
// Observers
// -------------------------------
valueChanged: function(newValue) {
if (this.step !== undefined) {
this.value = Math.round(this.value / this.step) * this.step;
}
if (this.min !== undefined) {
this.value = Math.max(this.value, this.min);
}
if (this.max !== undefined) {
this.value = Math.min(this.value, this.max);
}
this.super();
},
minChanged: function() {
this.value = Math.max(this.value, this.min);
this.update();
},
maxChanged: function() {
this.value = Math.min(this.value, this.max);
this.update();
},
update: function() {
var ratio = this.map(this.value, this.min, this.max, 0, 1);
if (this.min < 0 && this.max > 0) {
this.$.container.classList.add('straddle-zero');
var zero = this.map(0, this.min, this.max, 0, 1);
if (this.value >= 0) {
this.$.fill.style.left = zero * 100 + '%';
this.$.fill.style.width = (ratio - zero) * 100 + '%';
this.$.fill.style.right = '';
} else {
this.$.fill.style.left = '';
this.$.fill.style.width = (zero - ratio) * 100 + '%';
this.$.fill.style.right = (1 - zero) * 100 + '%';
}
} else {
this.$.container.classList.remove('straddle-zero');
if (this.max > 0) {
this.$.fill.style.left = 0;
this.$.fill.style.width = ratio * 100 + '%';
this.$.fill.style.right = '';
} else {
this.$.fill.style.left = '';
this.$.fill.style.width = (1 - ratio) * 100 + '%';
this.$.fill.style.right = 0;
}
}
this.$.knob.style.left = ratio * 100 + '%';
this.$.container.classList.toggle('positive', this.value >= 0);
this.$.container.classList.toggle('negative', this.value < 0);
this.super();
},
// Events
// -------------------------------
click: function(e) {
this.$.input.select();
},
keydown: function(e) {
if (e.keyCode == 13) {
this.$.input.blur();
}
},
down: function(e) {
e.preventDefault();
this._rect = this.$.track.getBoundingClientRect();
if (!this._alt) { this.value = this.valueFromX(e.x); }
this.fire( 'sliderDown' );
},
up: function(e) {
// this.$.container.classList.add( 'transition');
this.fire( 'sliderUp' );
},
trackstart: function(e) {
// this.$.container.classList.remove( 'transition');
this._dragFriction = 1;
},
trackx: function(e) {
if (this.step === undefined) {
var dv = this.valueFromDX(e.ddx);
if (this._alt) { dv /= 10; }
this.value += dv * this._dragFriction;
} else {
this.value = this.valueFromX(e.pageX);
}
},
tracky: function(e) {
this._dragFriction = Math.max(0.01,
Math.min(1, this.map(e.dy, 50, 300, 1, 0.1)));
},
blur: function(e) {
var v = parseFloat(this.$.input.value);
if (v === v) {
this.value = v;
}
},
// Filters
// -------------------------------
truncate: function(v) {
if (v % 1 !== 0 && this.decimals !== undefined) {
return this.limitDecimals(v, this.decimals);
} else {
return v;
}
},
// Helpers
// -------------------------------
limitDecimals: function(v, maxDecimals) {
var str = v.toString();
var numDecimals = str.substring(str.indexOf('.') + 1).length;
str = v.toFixed(Math.min(numDecimals, this.decimals));
for (var z, i = 0, l = str.length; i < l; i++) {
if (str.charAt(i) !== '0') {
z = i;
}
}
return str.substring(0, z + 1);
},
valueFromX: function(x) {
return this.map(x, this._rect.left, this._rect.right, this.min, this.max);
},
valueFromDX: function(dx) {
return this.map(dx, 0, this._rect.width, 0, this.max - this.min);
}
});