Skip to content

Commit

Permalink
renovations
Browse files Browse the repository at this point in the history
  • Loading branch information
iliakan committed Feb 21, 2015
1 parent a62682e commit 35081a7
Show file tree
Hide file tree
Showing 115 changed files with 439 additions and 325 deletions.
Binary file removed 1-js/2-first-steps/17-function-basics/style.png
Binary file not shown.
Binary file removed 1-js/5-functions-closures/2-closures/1.png
Binary file not shown.
Binary file removed 1-js/5-functions-closures/2-closures/1@2x.png
Binary file not shown.
Binary file removed 1-js/5-functions-closures/2-closures/2.png
Binary file not shown.
Binary file removed 1-js/5-functions-closures/2-closures/2@2x.png
Binary file not shown.
Binary file removed 1-js/5-functions-closures/2-closures/3.png
Binary file not shown.
Binary file removed 1-js/5-functions-closures/2-closures/3@2x.png
Binary file not shown.
Binary file removed 1-js/5-functions-closures/2-closures/4.png
Binary file not shown.
Binary file removed 1-js/5-functions-closures/2-closures/4@2x.png
Binary file not shown.
Binary file removed 1-js/5-functions-closures/2-closures/5.png
Binary file not shown.
Binary file removed 1-js/5-functions-closures/2-closures/5@2x.png
Binary file not shown.
Binary file removed 1-js/5-functions-closures/2-closures/6.png
Binary file not shown.
Binary file removed 2-ui/1-document/15-metrics/clientWidthNoPadding.png
Binary file not shown.
File renamed without changes
@@ -1,4 +1,6 @@

Для решения этой задачи достаточно создать две функции: `valueToPosition` будет получать по значению положение бегунка, а `positionToValue` -- наоборот, транслировать текущую координату бегунка в значение.

Как сопоставить позицию слайдера и значение?

Для этого посмотрим крайние значения слайдера. Допустим, размер бегунка `10px`.
Expand All @@ -17,10 +19,16 @@ pixelsPerValue = (sliderElem.clientWidth-thumbElem.clientWidth) / max;

Используя `pixelsPerValue` мы сможем переводить позицию бегунка в значение и обратно.

Крайнее левое значение `thumbElem.style.left` равно нулю, крайнее правой -- как раз ширине доступной области `sliderElem.clientWidth - thumbElem.clientWidth`. Поэтому можно получив значение, поделив его на `pixelsPerValue`:
Крайнее левое значение `thumbElem.style.left` равно нулю, крайнее правой -- как раз ширине доступной области `sliderElem.clientWidth - thumbElem.clientWidth`. Поэтому можно получить значение слайдера, поделив его на `pixelsPerValue`:

```js
value = Math.round( newLeft / pixelsPerValue);
function positionToValue(left) {
return Math.round( left / pixelsPerValue);
}

function valueToPosition(value) {
return pixelsPerValue * value;
}
```


@@ -0,0 +1,44 @@
<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8">
<script src="https://cdn.polyfill.io/v1/polyfill.js?features=CustomEvents,Element.prototype.closest"></script>
<link rel="stylesheet" href="slider.css">
<script src="slider.js"></script>
</head>

<body>
<div id="slider" class="slider">
<div class="thumb"></div>
</div>


Slide:<span id="slide">&nbsp;</span>
Change:<span id="change">&nbsp;</span>

<button onclick="slider.setValue(50)">slider.setValue(50)</button>

<script>

var sliderElem = document.getElementById('slider');

var slider = new Slider({
elem: sliderElem,
max: 100
});

sliderElem.addEventListener('slide', function(event) {
document.getElementById('slide').innerHTML = event.detail;
});

sliderElem.addEventListener('change', function(event) {
document.getElementById('change').innerHTML = event.detail;
});

</script>


</body>

</html>
@@ -0,0 +1,19 @@
.slider {
margin: 5px;
width: 310px;
height: 15px;
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);
}
.thumb {
position: relative;
top: -5px;
width: 10px;
height: 25px;
border-radius: 3px;
background: blue;
cursor: pointer;
}
@@ -0,0 +1,88 @@
function Slider(options) {
var elem = options.elem;

var thumbElem = elem.querySelector('.thumb');

var max = options.max || 100;
var sliderCoords, thumbCoords, shiftX, shiftY;

// [<*>----------------]
// |...............|
// first last
var pixelsPerValue = (elem.clientWidth - thumbElem.clientWidth) / max;

elem.ondragstart = function() {
return false;
};

elem.onmousedown = function(event) {
if (event.target.closest('.thumb')) {
startDrag(event.clientX, event.clientY);
return false; // disable selection start (cursor change)
}
}

function startDrag(startClientX, startClientY) {
thumbCoords = thumbElem.getBoundingClientRect();
shiftX = startClientX - thumbCoords.left;
shiftY = startClientY - thumbCoords.top;

sliderCoords = elem.getBoundingClientRect();

document.addEventListener('mousemove', onDocumentMouseMove);
document.addEventListener('mouseup', onDocumentMouseUp);
}

function moveTo(clientX) {
// вычесть координату родителя, т.к. position: relative
var newLeft = clientX - shiftX - sliderCoords.left;

// курсор ушёл вне слайдера
if(newLeft < 0) {
newLeft = 0;
}
var rightEdge = elem.offsetWidth - thumbElem.offsetWidth;
if(newLeft > rightEdge) {
newLeft = rightEdge;
}

thumbElem.style.left = newLeft + 'px';

elem.dispatchEvent(new CustomEvent('slide', {
bubbles: true,
detail: positionToValue(newLeft)
}));
}

function valueToPosition(value) {
return pixelsPerValue * value;
}

function positionToValue(left) {
return Math.round( left / pixelsPerValue);
}

function onDocumentMouseMove(e) {
moveTo(e.clientX);
}

function onDocumentMouseUp() {
endDrag();
}

function endDrag() {
document.removeEventListener('mousemove', onDocumentMouseMove);
document.removeEventListener('mouseup', onDocumentMouseUp);

elem.dispatchEvent(new CustomEvent('change', {
bubbles: true,
detail: positionToValue(parseInt(thumbElem.style.left))
}));
}

function setValue(value) {
thumbElem.style.left = valueToPosition(value) + 'px';
}

this.setValue = setValue;
}
46 changes: 46 additions & 0 deletions 2-ui/5-widgets/5-custom-events/4-slider-events/task.md
@@ -0,0 +1,46 @@
# Слайдер с событиями

[importance 5]

На основе слайдера из задачи [](/task/slider-widget) создайте графический компонент, который умеет возвращать/получать значение.

Синтаксис:

```js
var slider = new Slider({
elem: document.getElementById('slider'),
max: 100 // слайдер на самой правой позиции соответствует 100
});
```

Метод `setValue` устанавливает значение:

```js
slider.setValue(50);
```

У слайдера должно быть два события: `slide` при каждом передвижении и `change` при отпускании мыши (установке значения).

Пример использования:

```js
var sliderElem = document.getElementById('slider');

sliderElem.addEventListener('slide', function(event) {
document.getElementById('slide').innerHTML = event.detail;
});

sliderElem.addEventListener('change', function(event) {
document.getElementById('change').innerHTML = event.detail;
});
```

В действии:
[iframe src="solution" height="80"]

<ul>
<li>Ширина/высота слайдера может быть любой, JS-код это должен учитывать.</li>
<li>Центр бегунка должен располагаться в точности над выбранным значением. Например, он должен быть в центре для 50 при `max=100`.</li>
</ul>

Исходный документ -- возьмите решение задачи [](/task/slider-widget).
32 changes: 32 additions & 0 deletions 2-ui/5-widgets/6-what-next/article.md
@@ -0,0 +1,32 @@
# Что изучать дальше

Если вы прочитали весь учебник и сделали задачи, то на текущий момент вы обладаете важнейшими фундаментальными знаниями и навыками JavaScript.

[cut]

В этом разделе мы изучали основы создания компонентов на JavaScript. Если проект большой и сложный, то понадобятся дополнительные инструменты для связывания компонент между собой, для привязки к ним данных и так далее.

Сейчас существует много фреймворков. Всё активно развивается, меняется, кипит и булькает, может быть из этого получится "общепринятая" архитектура, а может и нет. Сейчас явного победителя нет, выбор фреймворка зависит от проекта и личных предпочтений разработчиков.

Примеры удачных фреймворков, которые можно изучить:

<ul>
<li>[Angular.JS](http://angularjs.org)</li>
<li>[React.JS](http://facebook.github.io/react/) + [Flux](http://facebook.github.io/flux/)</li>
<li>[Backbone.JS](http://backbonejs.org/) + [Marionette](http://marionettejs.com/)</li>
</ul>

Также для работы с браузерами понадобятся различные [API](https://ru.wikipedia.org/wiki/%D0%98%D0%BD%D1%82%D0%B5%D1%80%D1%84%D0%B5%D0%B9%D1%81_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_%D0%BF%D1%80%D0%B8%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B9), в частности:

<ul>
<li>Работу с окнами и фреймами.</li>
<li>Регулярные выражения, класс `RegExp`.</li>
<li>Объекты `XMLHttpRequest` и `WebSocket` для работы с сервером.</li>
<li>Другие возможности современных браузеров.</li>
</ul>

В дополнительных разделах учебника мы обязательно разберём что-то из этого.

...И, конечно, понадобится система сборки проектов, например [WebPack](http://webpack.github.io/).

Успехов вам!

0 comments on commit 35081a7

Please sign in to comment.