This commit is contained in:
Ilya Kantor 2014-10-26 22:10:13 +03:00
parent 06f61d8ce8
commit f301cb744d
2271 changed files with 103162 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View file

@ -0,0 +1,29 @@
# Сопоставление значения и слайдера
Как сопоставить позицию слайдера и значение?
Для этого посмотрим крайние значения слайдера. Допустим, размер бегунка `10px`.
Раз центр соответствует значению, то крайнее левое значение будет соответствовать центру на `5px`, а крайнее правой -- центру на `5px` от правой границы:
<img src="slider.png">
Соответственно, ширина области изменения будет `sliderElem.clientWidth - thumbElem.clientWidth`. Далее её можно уже поделить на части, количество пикселей на значение будет:
```js
pixelsPerValue = (sliderElem.clientWidth-thumbElem.clientWidth) / max;
```
Может получиться так, что это значение будет дробным, меньше единицы. Например, если `max = 1000`, а ширина слайдера `110` (пробег 100), то будет `0.1` пикселя на значение.
Используя `pixelsPerValue` мы сможем переводить позицию бегунка в значение и обратно.
Крайнее левое значение `thumbElem.style.left` равно нулю, крайнее правой -- как раз ширине доступной области `sliderElem.clientWidth - thumbElem.clientWidth`. Поэтому можно получив значение, поделив его на `pixelsPerValue`:
```js
value = Math.round( newLeft / pixelsPerValue);
```
# Полное решение
[edit src="solution"/]

View file

@ -0,0 +1 @@
{"name":"slider-events","plunk":"fDSnstP28seNXtvYZAcb"}

View file

@ -0,0 +1,183 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="http://code.jquery.com/jquery.min.js"></script>
<style>
.slider {
width: 310px;
height: 15px;
margin: 5px;
border-radius: 5px;
background: #E0E0E0;
background: -moz-linear-gradient(left top , #E0E0E0, #EEEEEE) repeat scroll 0 0 transparent;
background: -webkit-gradient(linear, left top, right bottom, from(#E0E0E0), to(#EEEEEE));
background: linear-gradient(left top, #E0E0E0, #EEEEEE);
}
.slider-thumb {
position: relative;
width: 10px;
height: 25px;
left: 10px;
top: -5px;
border-radius: 3px;
background: blue;
cursor: pointer;
}
.sliding .slider-thumb {
cursor: move;
}
</style>
</head>
<body>
<div id="slider" class="slider">
<div class="slider-thumb"></div>
</div>
Slide:<span id="slide">&nbsp;</span>
Change:<span id="change">&nbsp;</span>
<script>
function Slider(options) {
var self = this;
var elem = options.elem;
var thumbElem = elem.find('.slider-thumb');
// [<*>----------------]
// |...............|
// first last
var pixelsPerValue = (elem.width() - thumbElem.width()) / options.max;
var value = options.value || 0;
// при начале переноса фиксируются
var thumbCursorShift; // сдвиг курсора относительно бегунка
var sliderCoords; // и координаты слайдера
thumbElem.on('mousedown', onThumbMouseDown)
.on('selectstart dragstart', false);
setSlidingValue(value, true);
function onThumbMouseDown(e) {
startSlide(e.pageX, e.pageY);
return false;
}
function onDocumentMouseMove(e) {
// вычесть координату родителя, т.к. position: relative
var newLeft = e.pageX - thumbCursorShift.x - sliderCoords.left;
// курсор ушёл вне слайдера
if (newLeft < 0) {
newLeft = 0;
}
var rightEdge = elem.outerWidth() - thumbElem.outerWidth();
if (newLeft > rightEdge) {
newLeft = rightEdge;
}
setSlidingValue( Math.round( newLeft / pixelsPerValue) );
}
function onDocumentMouseUp() {
endSlide();
}
function endSlide() {
$(document).off('.slider');
$(self).triggerHandler({
type: "change",
value: value
});
elem.removeClass('sliding');
}
function startSlide(downPageX, downPageY) {
var thumbCoords = thumbElem.offset();
thumbCursorShift = {
x: downPageX - thumbCoords.left,
y: downPageY - thumbCoords.top
};
sliderCoords = elem.offset();
$(document).on({
'mousemove.slider': onDocumentMouseMove,
'mouseup.slider': onDocumentMouseUp
});
elem.addClass('sliding');
}
/**
* Установить промежуточное значение
* quiet -- означает "не генерировать событие"
*/
function setSlidingValue(newValue, quiet) {
value = newValue;
thumbElem.css('left', value * pixelsPerValue ^ 0);
if (!quiet) {
$(self).triggerHandler({
type: "slide",
value: value
});
}
}
/**
* Установить окончательное значение
* @param {number} newValue новое значение
* @param {boolean} quiet если установлен, то без события
*/
this.setValue = function(newValue, quiet) {
// установить значение БЕЗ генерации события slide
// т.е. slide в любом случае нет
setSlidingValue(newValue, true);
// ..а change будет, если не указан quiet
if (!quiet) {
$(self).triggerHandler({
type: "change",
value: value
});
}
}
}
var slider = new Slider({
elem: $('#slider'),
max: 100,
value: 10
});
$(slider).on({
slide: function(e) {
$('#slide').html(e.value);
},
change: function(e) {
$('#change').html(e.value);
}
});
slider.setValue(50);
</script>
</body>
</html>

View file

@ -0,0 +1 @@
{"name":"slider-events","plunk":"fDSnstP28seNXtvYZAcb"}

View file

@ -0,0 +1,183 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="http://code.jquery.com/jquery.min.js"></script>
<style>
.slider {
width: 310px;
height: 15px;
margin: 5px;
border-radius: 5px;
background: #E0E0E0;
background: -moz-linear-gradient(left top , #E0E0E0, #EEEEEE) repeat scroll 0 0 transparent;
background: -webkit-gradient(linear, left top, right bottom, from(#E0E0E0), to(#EEEEEE));
background: linear-gradient(left top, #E0E0E0, #EEEEEE);
}
.slider-thumb {
position: relative;
width: 10px;
height: 25px;
left: 10px;
top: -5px;
border-radius: 3px;
background: blue;
cursor: pointer;
}
.sliding .slider-thumb {
cursor: move;
}
</style>
</head>
<body>
<div id="slider" class="slider">
<div class="slider-thumb"></div>
</div>
Slide:<span id="slide">&nbsp;</span>
Change:<span id="change">&nbsp;</span>
<script>
function Slider(options) {
var self = this;
var elem = options.elem;
var thumbElem = elem.find('.slider-thumb');
// [<*>----------------]
// |...............|
// first last
var pixelsPerValue = (elem.width() - thumbElem.width()) / options.max;
var value = options.value || 0;
// при начале переноса фиксируются
var thumbCursorShift; // сдвиг курсора относительно бегунка
var sliderCoords; // и координаты слайдера
thumbElem.on('mousedown', onThumbMouseDown)
.on('selectstart dragstart', false);
setSlidingValue(value, true);
function onThumbMouseDown(e) {
startSlide(e.pageX, e.pageY);
return false;
}
function onDocumentMouseMove(e) {
// вычесть координату родителя, т.к. position: relative
var newLeft = e.pageX - thumbCursorShift.x - sliderCoords.left;
// курсор ушёл вне слайдера
if (newLeft < 0) {
newLeft = 0;
}
var rightEdge = elem.outerWidth() - thumbElem.outerWidth();
if (newLeft > rightEdge) {
newLeft = rightEdge;
}
setSlidingValue( Math.round( newLeft / pixelsPerValue) );
}
function onDocumentMouseUp() {
endSlide();
}
function endSlide() {
$(document).off('.slider');
$(self).triggerHandler({
type: "change",
value: value
});
elem.removeClass('sliding');
}
function startSlide(downPageX, downPageY) {
var thumbCoords = thumbElem.offset();
thumbCursorShift = {
x: downPageX - thumbCoords.left,
y: downPageY - thumbCoords.top
};
sliderCoords = elem.offset();
$(document).on({
'mousemove.slider': onDocumentMouseMove,
'mouseup.slider': onDocumentMouseUp
});
elem.addClass('sliding');
}
/**
* Установить промежуточное значение
* quiet -- означает "не генерировать событие"
*/
function setSlidingValue(newValue, quiet) {
value = newValue;
thumbElem.css('left', value * pixelsPerValue ^ 0);
if (!quiet) {
$(self).triggerHandler({
type: "slide",
value: value
});
}
}
/**
* Установить окончательное значение
* @param {number} newValue новое значение
* @param {boolean} quiet если установлен, то без события
*/
this.setValue = function(newValue, quiet) {
// установить значение БЕЗ генерации события slide
// т.е. slide в любом случае нет
setSlidingValue(newValue, true);
// ..а change будет, если не указан quiet
if (!quiet) {
$(self).triggerHandler({
type: "change",
value: value
});
}
}
}
var slider = new Slider({
elem: $('#slider'),
max: 100,
value: 10
});
$(slider).on({
slide: function(e) {
$('#slide').html(e.value);
},
change: function(e) {
$('#change').html(e.value);
}
});
slider.setValue(50);
</script>
</body>
</html>

View file

@ -0,0 +1,45 @@
# Слайдер с событиями
[importance 5]
На основе слайдера из задачи [](/task/slider) создайте графический компонент, который умеет возвращать/получать значение.
Синтаксис:
```js
var slider = new Slider({
elem: $('#slider'),
max: 100 // слайдер на самой правой позиции соответствует 100
});
```
Метод `setValue` устанавливает значение:
```js
slider.setValue(50);
```
У слайдера должно быть два события: `slide` при каждом передвижении и `change` при отпускании мыши (установке значения).
Пример использования:
```js
$(slider).on({
slide: function(value) {
$('#slide').html(value);
},
change: function(value) {
$('#change').html(value);
}
});
```
В действии:
[iframe src="solution" height="60"]
<ul>
<li>Дизайн слайдера, ширина/высота элементов должна быть изменяемой через CSS, без необходимости трогать JS-код.</li>
<li>Центр бегунка должен располагаться над значением. Например, он должен быть в центре для 50 при максимуме 100.</li>
</ul>
Исходный документ -- возьмите решение из задачи [](/task/slider).