Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Объединение нескольких clientRect (https://javascript.ru/forum/misc/30861-obedinenie-neskolkikh-clientrect.html)

Aetae 18.08.2012 12:18

Объединение нескольких clientRect
 
Собсно надо объединить clientRect'ы нескольких элементов.
Сейчас делаю так:
arr //массив элементов
i  //arr.length
var result = {'top':[],'bottom':[],'left':[],'right':[]}, position;
while(i--) {
	position = arr[i].getBoundingClientRect();
	for(var j in result) result[j].push( position[j] );
}
position = {
	'top'	: Math.min.apply(0,result.top),
	'left'	: Math.min.apply(0,result.left),
	'bottom': Math.max.apply(0,result.bottom),
	'right'	: Math.max.apply(0,result.right)
}

Но как-то оно неэстетично смотрится. И чувство возникает, что можно сделать как-то красивее, без лишних телодвижений.(делаю для себя поэтому могу потратить часок другой на эстетические изыски :) )
Нужен только ff, так что можно использовать всё вплоть до js1.8.)

Aetae 18.08.2012 14:07

Цитата:

Сообщение от Дзен-трансгуманист (Сообщение 198479)
А зачем эстетика? Мсье - гурман? :)

Жуткий. Могу пару строк неделю вылизывать если никто не торопит.) (хотя если торопят то говнокожу\дю без зазрения совести:) )

А ваша версия кода ещё более некрасива, имхо. Да и производительность(на глаз) должна быть меньше(или нет).

melky 18.08.2012 14:14

Цитата:

Сообщение от Aetae (Сообщение 198476)
Собсно надо объединить clientRect'ы нескольких элементов.
Сейчас делаю так:
arr //массив элементов
i  //arr.length
var result = {'top':[],'bottom':[],'left':[],'right':[]}, position;
while(i--) {
	position = arr[i].getBoundingClientRect();
	for(var j in result) result[j].push( position[j] );
}
position = {
	'top'	: Math.min.apply(0,result.top),
	'left'	: Math.min.apply(0,result.left),
	'bottom': Math.max.apply(0,result.bottom),
	'right'	: Math.max.apply(0,result.right)
}

Но как-то оно неэстетично смотрится. И чувство возникает, что можно сделать как-то красивее, без лишних телодвижений.(делаю для себя поэтому могу потратить часок другой на эстетические изыски :) )
Нужен только ff, так что можно использовать всё вплоть до js1.8.)

как же я жалею. о том, что не проникся к генераторам :(

наверное, как-то уродливо :) но нерасширяемо, это уж точно - условие просто ппц ... а так красиво
var arr = document.querySelectorAll("b");

var result = [].reduce.call(arr, function (prev, curr) {
  curr = curr.getBoundingClientRect();
  
  for (var prop in curr) if (prev[prop] === null ||  ( (prop === "top" || prop === "left") ? (prev[prop] >= curr[prop]):(prev[prop] <= curr[prop])) ) {
      prev[prop] = curr[prop];
  }
  
  return prev;
}, { top: null, left: null, right: null, bottom: null });


<body>
  <b>LOL</b>
  
  <br><br>
  <b>LOL</b>
  
  <b>LOL</b>
  <br>
  <b>LOL</b>
</body>

<script>
var arr = document.querySelectorAll("b");

var result = [].reduce.call(arr, function (prev, curr) {
  curr = curr.getBoundingClientRect();
  
  for (var prop in curr) if (prev[prop] === null ||
        ( (prop === "top" || prop === "left") ? (prev[prop] >= curr[prop]):(prev[prop] <= curr[prop])) ) {
      prev[prop] = curr[prop];
  }
  
  return prev;
}, { top: null, left: null, right: null, bottom: null });

var a = document.createElement("div");
a.style.cssText = "position: absolute;border: 1px green solid;";
document.body.appendChild(a);
a.style.top = result.top + 'px';
a.style.left = result.left + 'px';
a.style.height = result.bottom + 'px';
a.style.width = result.right + 'px';
</script>

Aetae 18.08.2012 16:03

Да твой быстрее моего на ~30% в общей сложности,
вариант melky - почти в 2.5 раза медленней твоего.)

Aetae 18.08.2012 16:24

Пока тогда остановлюсь на таком:
var result = { 'left': Infinity, 'top': Infinity, 'right': -Infinity, 'bottom': -Infinity };
 
while (i--) {
  r = arr[i].getBoundingClientRect();
  if (result.left > r.left) result.left = r.left;
  if (result.top > r.top) result.top = r.top;
  if (result.right < r.right) result.right = r.right;
  if (result.bottom < r.bottom) result.bottom = r.bottom;
}

Смотрится чуток эстетичнее изначально варианта от Дзен-трансгуманист, разницы в скорости нет.

Но другие предложения приветствуются.)

melky 18.08.2012 16:28

Цитата:

Сообщение от Aetae (Сообщение 198546)
Да твой быстрее моего на ~30% в общей сложности,
вариант melky - почти в 2.5 раза медленней твоего.)

все новые итераторы массивов медленней обычных циклов на такой же коэффициент.

Aetae 18.08.2012 16:45

Цитата:

Сообщение от melky (Сообщение 198556)
все новые итераторы массивов медленней обычных циклов на такой же коэффициент.

Сомнительно что-то. На кой чёрт они тогда нужны?)

melky 18.08.2012 16:48

Цитата:

Сообщение от Aetae (Сообщение 198567)
Сомнительно что-то. На кой чёрт они тогда нужны?)

для удобства. а все любители скорости и малого объёма будут до конца жизни использовать += вместо ++, && вместо if(){}, и тому подобное.

Aetae 18.08.2012 16:57

Цитата:

Сообщение от melky (Сообщение 198571)
для удобства. а все любители скорости и малого объёма будут до конца жизни использовать += вместо ++, && вместо if(){}, и тому подобное.

Да, потеснил, так оно и есть, даже ср*ный .some() . Обыдно. Этож native код, должно быть быстрее. =(

Эх, как красиво с новомодным фичами выглядела проверка текста:
function isNaT( text ) { //not a text
	return [
		/^[_a-z0-9-\.]+@[\.a-z0-9-]+\.[a-z]+$/i, //email
		/^[a-z]+:\/\/[^\s]+$/i, //url;
		/^[0-9\.,!@#\$%\^\&*\(\)`~_\-=\+|\\{}\[\]\s:;<>\?\/]+$/i //symbol
	].some( function(pattern) pattern.test( text ) )
}

Но оно аж в 3 раза медленней чем простое:
function isNaT(text){
	var pattern = [
		/^[_a-z0-9-\.]+@[\.a-z0-9-]+\.[a-z]+$/i, //email
		/^[a-z]+:\/\/[^\s]+$/i, //url;
		/^[0-9\.,!@#\$%\^\&*\(\)`~_\-=\+|\\{}\[\]\s:;<>\?\/]+$/i //symbol
	], i = pattern.length;
	while(i--) if(pattern[i].test( text )) return true;
	return false
}

а скорость, увы, всегда важна.

P.S. Это абсурд: самодельная функция some работает быстрее нативной. *facepalm*

melky 18.08.2012 17:09

Цитата:

Сообщение от Aetae
Этож native код

ну, как говорится, код нативный, а коллбек - джяваскрыптовый. :thanks:

Aetae 18.08.2012 17:19

Цитата:

Сообщение от Aetae (Сообщение 198575)
P.S. Это абсурд: самодельная функция some работает быстрее нативной. *facepalm*

Хотя нет, это не точная реализация.(с моим любимым обратным итератором);
Точная реализация, работает с точно такой же скоростью.
Фф сам написан на js большей частью, и есть подозрение, что афффтары не парились, а просто включили готовые реализации методов на js.=)

Цитата:

Сообщение от melky (Сообщение 198581)
ну, как говорится, код нативный, а коллбек - джяваскрыптовый. :thanks:

Думаю если постараться - то можно сделать как надо.

melky 18.08.2012 17:20

Цитата:

Сообщение от Aetae (Сообщение 198585)
Фф сам написан на js большей частью, и есть подозрение, что афффтары не парились, а просто включили готовые реализации методов на js.=)

:lol: или наоборот, выложили на MDN часть "исходных кодов".

melky 18.08.2012 18:38

"однобуквенные переменные" !== "лаконичность"

melky 18.08.2012 18:49

Цитата:

Сообщение от Дзен-трансгуманист
Спорное утверждение. Обычно люди ищут по возможности стремятся к адекватному компромиссу между скоростью, читабельностью и реюзабилити.

я имел в виду любителей реактивных скоростей в коде :) людей, занимающихся муравьиной оптимизацией.

Цитата:

Сообщение от Дзен-трансгуманист
А количество операторов что, уже не в счет?

простите, но я в упор не вижу разницы между этим
var result = { 'left': Infinity, 'top': Infinity, 'right': -Infinity, 'bottom': -Infinity };
 
while (i--) {
  r = arr[i].getBoundingClientRect();
  if (result.left > r.left) result.left = r.left;
  if (result.top > r.top) result.top = r.top;
  if (result.right < r.right) result.right = r.right;
  if (result.bottom < r.bottom) result.bottom = r.bottom;
}
var i = arr.length, rc, l = Infinity, t = l, r = -Infinity, b = r;

while (i--) {
  rc = arr[i].getBoundingClientRect();
  if (l > rc.left) l = rc.left;
  if (t > rc.top) t = rc.top;
  if (r < rc.right) r = rc.right;
  if (b < rc.bottom) b = rc.bottom;
}

return { 'left': l, 'top': t, 'right': r, 'bottom': b };

единственное - res ушёл в конец, и его начальные величины вылезли в переменные.

ну, да. код стал меньше :) но не сильно.

и, да. насчёт однобуквенных переменных.
я не буду устраивать холивар. (т.е. не собираюсь)
Вам приятно будет читать такой код ?

знаю, что Ваши r,l,t,b говорят сами за себя, но всё равно они не бросаются в глаза, как left, right, top, bottom

Aetae 18.08.2012 19:43

Разницы в скорости нет. А лишние переменные имхо - не гуд.

nerv_ 18.08.2012 20:23

кто хочет скорости, пусть пишет на ассемблере.
По мне так последний вариант Aetae читается лучше, так же как и первый вариант Дзен-трансгуманиста.
А по поводу первого варианта все верно Aetae зачем формировать массив там, где он не нужен. Недавно код лопатил (чужой), который производит нечеткое сравнение строк (по достаточно простому алгоритму) и выбирает из массива наилучшее совпадение. Там та же фигня была: формировался массив (непонятно зачем) и затем из этого массива выбирался элемент.

Aetae 18.08.2012 22:31

Ну идея была в том, что нативный Math.max\min будет быстрее.)


Часовой пояс GMT +3, время: 14:08.