Получить дочерний элемент по координатам клика.
Суть такая, есть блок (контейнер), внутри него есть n блоков, так вот, по клику на контейнер в любом месте, нужно получить подходящий элемент.
структура примерно такая: --------------------------- | 0 | | 1 | | 2 | | 3 | --------------------------- Решил я это такм способом.
[].filter.call(this.children, function(item) {
return item.getBoundingClientRect().left <= event.clientX;
}).pop();
Собственно, код работает, но, что-то мне подсказывает, что хоть способ и рабочий, фильтровать массив и вытаскивать с него последний элемент не лучший способ.. Есть у кого-то идеи? Вот полный код.
<style>
div {
display: flex;
justify-content: space-between;
padding: 30px;
background-color: #fff;
border: 1px solid #999;
cursor: pointer;
}
span {
width: 100px;
height: 100px;
background-color: tomato;
color: #fff;
text-align: center;
font-size: 80px;
-moz-user-select: none; /* fucking double click :D */
}
</style>
<div>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
</div>
<script>
'use strict';
const div = document.querySelector('div');
div.addEventListener('click', handleClick);
function getPos(item) {
return item.getBoundingClientRect().left;
}
function handleClick(e) {
const items = Array.from(this.children);
const filtredItems = items.filter(item =>
item.getBoundingClientRect().left <= e.clientX
);
const item = filtredItems.pop() || items[0];
// clear items
items.forEach(item => {
item.innerHTML = '';
});
// active item
item.innerHTML = '+';
}
</script>
|
Lemme,
решение http://javascript.ru/forum/misc/6102...tml#post405988 ... чуть добавить фильтр |
рони, спасибо, интересно=)
|
Через offsetLeft никак? А потом через array.some найти нужный. Будет работать быстрее, т.к. не придется по всем элементам массива бегать.
var x = e.clientX;
var span = document.querySelectorAll('span');
var temp = span[0];
[].some.call(span, function (elem) {
if (elem.offsetLeft > x) {
return true;
}
temp = elem;
})
|
Ближайший элемент от места клика
Lemme,
<!DOCTYPE HTML>
<html>
<head>
<title>Untitled</title>
<meta charset="utf-8">
<style>
div {
display: flex;
justify-content: space-between;
padding: 30px;
background-color: #fff;
border: 1px solid #999;
cursor: pointer;
}
span {
width: 100px;
height: 100px;
background-color: tomato;
color: #fff;
text-align: center;
font-size: 80px;
-moz-user-select: none; /* fucking double click :D */
}
</style>
</head>
<body>
<div>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
</div>
<script>
window.addEventListener("DOMContentLoaded", function() {
var b = document.querySelector("div"),
d = b.querySelectorAll("span"),
c;
b.addEventListener("click", function(b) {
c = [].map.call(d, function(a) {
var e = a.getBoundingClientRect(),
c = e.left + a.offsetWidth / 2 - b.clientX;
a = e.top + a.offsetHeight / 2 - b.clientY;
return Math.sqrt(c * c + a * a)
});
var f = Math.min.apply(null, c);
[].forEach.call(d, function(a, b) {
a.innerHTML = c[b] > f ? "" : "+"
})
})
});
</script>
</body>
</html>
|
<style>
div {
display: flex;
justify-content: space-between;
padding: 30px;
background-color: #fff;
border: 1px solid #999;
cursor: pointer;
}
span {
width: 100px;
height: 100px;
background-color: tomato;
color: #fff;
text-align: center;
font-size: 80px;
-moz-user-select: none; /* fucking double click :D */
}
</style>
<div>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
</div>
<script>
var div = document.querySelector('div');
div.addEventListener('click', function (e) {
var x = e.clientX;
var span = document.querySelectorAll('span');
var temp = span[0];
[].some.call(span, function (elem, i) {
if (elem.offsetLeft > x) {
return true;
}
temp = elem;
});
[].forEach.call(span,function(elem){
(elem == temp) ? elem.innerHTML = '+' : elem.innerHTML = '';
})
})
</script>
|
Lemme,
вопрос только - можно кликнуть так что минимальное растояние будет одинаковое для нескольких элементов, тогда как? |
destus,
не работает если брать минимальное растояние -- ваш вариант для ближайшего слева |
Цитата:
|
Цитата:
|
:) Окей. Для горизонтали.
<style>
div {
display: flex;
justify-content: space-between;
padding: 30px;
background-color: #fff;
border: 1px solid #999;
cursor: pointer;
}
span {
width: 100px;
height: 100px;
background-color: tomato;
color: #fff;
text-align: center;
font-size: 80px;
-moz-user-select: none; /* fucking double click :D */
}
</style>
<div>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
</div>
<script>
var div = document.querySelector('div');
div.addEventListener('click', function (e) {
var x = e.clientX;
var span = document.querySelectorAll('span');
var temp = span[0];
[].some.call(span, function (elem) {
if (elem.offsetLeft > x) {
var rightCoordBlock = temp.offsetLeft + temp.offsetWidth;
var lenBetweenBlock = elem.offsetLeft - (rightCoordBlock);
if ((rightCoordBlock + parseInt(lenBetweenBlock / 2)) < x) temp = elem;
return true;
}
temp = elem;
});
[].forEach.call(span,function(elem){
(elem == temp) ? elem.innerHTML = '+' : elem.innerHTML = '';
})
})
</script>
|
Оптимальнее будет вычислять растояния от центра каждого блока до точки (e.clientX, e.clientY). Минимальное расстояние из всех прямых и будет ответом в задаче.
Или, например, так как все блоки имеют одинаковую ширину и отступы между, то можно вычислить ширину, которую занимает такой элемент на странице (ширина блока + правый отступ). Далее целочисленно делим e.clientX на эту ширину и получаем сколько блоков нам нужно пропустить, чтобы получить нужный. Вариантов вагон :D |
Цитата:
|
Цитата:
|
Цитата:
|
Даже 5 пост можно немного оптимизировать. Не записывать всё в новый массив и находить минимум, а использовать Array.reduce.
|
Цитата:
Разная может быть ширина блоков и высота контейнера.
<style>
.container {
padding: 50px 0;
display: flex;
background-color: #fff;
border: 1px solid #999;
}
.block {
height: 50px;
background-color: tomato;
border: 1px solid #333;
}
</style>
<div class="container">
<div class="block" style="width: 35%"></div>
<div class="block" style="width: 45%"></div>
<div class="block" style="width: 20%"></div>
</div>
|
Lemme, ближайший блок к клику дубль 2
<!DOCTYPE HTML>
<html>
<head>
<title>Untitled</title>
<meta charset="utf-8">
</head>
<body>
<style>
.container {
padding: 50px 0;
display: flex;
background-color: #fff;
border: 1px solid #999;
}
.block {
height: 50px;
background-color: tomato;
border: 1px solid #333;
}
</style>
<div class="container">
<div class="block" style="width: 35%"></div>
<div class="block" style="width: 45%"></div>
<div class="block" style="width: 20%"></div>
</div>
<script>
window.addEventListener("DOMContentLoaded", function() {
var d = document.querySelector(".container"),
e = d.querySelectorAll(".block"),
c;
d.addEventListener("click", function(b) {
c = [].map.call(e, function(a) {
a = a.getBoundingClientRect();
c = a.left > b.clientX ? a.left : a.right < b.clientX ? a.right : b.clientX;
c -= b.clientX;
a = a.top > b.clientY ? a.top : a.bottom < b.clientY ? a.bottom : b.clientY;
a -= b.clientY;
return Math.sqrt(c * c + a * a)
});
var d = Math.min.apply(null, c);
[].forEach.call(e, function(a, b) {
a.innerHTML = c[b] > d ? "" : "+"
})
})
});
</script>
</body>
</html>
|
рони, круто, универсально, но, ад =)))
p.s может какие-то книжки с подобнымыми манипуляциями кто-то всречал?=) |
Цитата:
|
рони,круто,спасибо=)
Блин, зачем эти лимиты на плюсы ставить=) |
Визуализация работы скрипта ближайший от клика
Lemme,
кликая можно увидеть какой блок скрипт выбрал ближайшим и какое место на этом блоке ближе всего к точке клика :)
<!DOCTYPE HTML>
<html>
<head>
<title>Untitled</title>
<meta charset="utf-8">
</head>
<body>
<style>
.container {
display: flex;
justify-content: space-between;
padding: 120px;
background-color: #FF8C00;
border: 1px solid #999;
cursor: pointer;
}
span {
cursor: default;
padding: 0;
width: 100px;
height: 100px;
background-color: #32CD32;
color: #fff;
text-align: center;
font-size: 80px;
-webkit-user-select: none;
user-select: none;
-moz-user-select: none; /* fucking double click :D */
}
.arrow {
-webkit-transform-origin: 0;
-moz-transform-origin: 0;
-o-transform-origin: 0;
transform-origin: 0;
position: absolute;
}
.arrow:before,
.arrow:after {
content: "";
display: block;
position: absolute;
width: 0;
height: 0;
border: 40px solid transparent;
border-right: 0;
}
.arrow {
width: 0px;
height: 2px;
background: #0000CD;
}
.arrow:after {
top: -5px;
right: 0px;
border-left-color: #0000CD;
border-width: 6px 0 6px 30px;
}
.arrow.replay:before,
.arrow.replay:after {
display: none;
}
.arrow.replay {
border-radius: 50%;
border: 2px solid #F0FFF0;
width: 30px;
height: 30px;
margin-left: -15px;
margin-top: -15px;
background-color: transparent ;
-webkit-animation: ripple 2s ease-in-out infinite;
-moz-animation: ripple 2s ease-in-out infinite;
-o-animation: ripple 2s ease-in-out infinite;
animation: ripple 2s ease-in-out infinite;
}
@keyframes ripple {
0% {
opacity: 0;
-webkit-transform: scale(0);
-ms-transform: scale(0);
-o-transform: scale(0);
-moz-transform: scale(0);
transform: scale(0);
margin-left: 0px;
}
100% {
margin-left: -15px;
opacity: 1;
-webkit-transform: scale(1);
-ms-transform: scale(1);
-o-transform: scale(1);
-moz-transform: scale(1);
transform: scale(1);
}
}
@-webkit-keyframes ripple {
0% {
opacity: 0;
-webkit-transform: scale(0);
-ms-transform: scale(0);
-o-transform: scale(0);
-moz-transform: scale(0);
transform: scale(0);
}
100% {
opacity: 1;
-webkit-transform: scale(1);
-ms-transform: scale(1);
-o-transform: scale(1);
-moz-transform: scale(1);
transform: scale(1);
}
}</style>
<div class="container">
<span></span>
<span></span>
<span></span>
</div>
<div class="arrow"></div>
<script>
window.addEventListener("DOMContentLoaded", function() {
var e = document.querySelector(".container"),
h = e.querySelectorAll("span"),
d = document.querySelector(".arrow"),
c;
e.addEventListener("click", function(b) {
var g = [];
c = [].map.call(h, function(a) {
a = a.getBoundingClientRect();
c = a.left > b.clientX ? a.left : a.right < b.clientX ? a.right : b.clientX;
c -= b.clientX;
a = a.top > b.clientY ? a.top : a.bottom < b.clientY ? a.bottom : b.clientY;
a -= b.clientY;
g.push(360 - 180 / Math.PI * Math.atan2(a, c));
return Math.sqrt(c * c + a * a)
});
var f = Math.min.apply(null,c),
e = c.indexOf(f);
d.style.left = b.clientX + "px";
d.style.top = b.clientY + "px";
d.style.width = (f ? f : 30) + "px";
f ? (d.classList.remove("replay"),
d.style.transform = "rotate(-" + g[e] + "deg)",
d.style.webkitTransform = "rotate(-" + g[e] + "deg)") : d.classList.add("replay")
})
});
</script>
</body>
</html>
|
рони, это великолепно, карл!! =)
Пост в закладки!! =) p.s нужно учить математику=))) Пошел снова тыкать плюсик в оффтопик=))). |
| Часовой пояс GMT +3, время: 15:53. |