Расставить абсолютные координаты картинкам

Доброго времени суток!
Подскажите, как правильно расставить абсолютные координаты картинкам, исходя из их html-кода. У меня они расставлены буквально для каждой, если картинок будет гораздо больше, код получается нерациональный.
Вот часть кода:

<body style='min-height: 100vh'>
<img src='1.png'>
<img src='2.png' width=100>
<img src='3.png' width=150>
<img src='4.png' style='padding-left: 50px'>

<script>
"use strict";
window.addEventListener('load', posElem, false);

function posElem(eo) {
  eo = eo || window.event;
  let elems = document.querySelectorAll('img');
  for (var i = elems.length - 1; i >= 0; i--) {
  let elem = elems[i];   

  elems[0].style.left = "8px";
  elems[0].style.top = "64px";

  elems[1].style.left = "162px";
  elems[1].style.top = "164px";
  
  elems[2].style.left = "266px";
  elems[2].style.top = "97px";
  
  elems[3].style.left = "420px";
  elems[3].style.top = "8px";
     
  elem.style.position = 'absolute';       
 } 
}
</script>

Тебе нужно сделать такую модель из доступных в JS элементов с помощью которой ты могла бы установить соответствие картинки координатам.

Например. Пусть координаты описываются массивом [x, y]. А координаты описываются последовательно для каждой картинки как она появляется в коду arr = [[x1, y1], [x2, y2], [x3, y3]]. Тогда установление координат каждой картинке будет по сути циклом с индексом i, и i-ой картинке img[i] будешь присваивать i-е значение X координаты (пусть она будет первой) arr[i][0] и Y координате, второй, arr[i][1] из этого массива координат.

И, как это часто бывает, можно сделать равноценную модель, но другой формы. Например связать класс (который нужно будет навесить картинке) с координатой. Тогда мы будем описывать это соотношение картинки и координат объектом:
{ className: 'kokoko', x: 10, y: 20 }. А все соответствия будут массивом, по которому будем снова бежать с индексом i, и для каждого элемента находить дом узлы с классом arr[i].className x координату arr[i].x и y координату arr[i].y.

Думаю, что в значениях координат не надо вставлять px, описывать координаты цифрами, а px добавлять в момент присвоения .top и .left.

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

UPD напиши если словестное описание не наталкивает на решение.

Спасибо, буду пробовать

Каким образом выбираются координаты размещения картинок?
Если цель - наиболее оптимально расположить картинки на странице, то это становится математической задачей. Если координаты известны заранее, то самый простой подход - разместить их в массиве.

Картинки должны располагаться на одной линии по горизонтали друг за другом в том же порядке. Математики здесь не надо использовать.

 for (var i = elems.length - 1; i >= 0; i--) {
    let elem = elems[i];  

    let maxHeight = 0;
     
    elems.forEach((elem) => {
        let elemHeight = elem.clientHeight;
        if (elemHeight > maxHeight) {
            maxHeight = elemHeight;
        }
    });
    elems.forEach((elem) => {
        let elemHeight = elem.clientHeight;
        elem.style.top = `${maxHeight - elemHeight}px`;
        elem.style.left = elem.offsetLeft + 'px';
     
    });
    elems.forEach((elem) => {
        elem.style.position = 'absolute';
    });

Вот такой математический способ не годится, нужно прочитать фактические координаты картинок (offsetLeft, offsetTop) и туда ставить абсолютные координаты картинок. Я получается буквально вставила эти координаты, но возник другой вопрос: а если картинок будет больше.

Обязательно ли по условиям задачи использовать стили для абсолютных координат? Спрашиваю потому что расположение картинок в линию одна за другой это больше про стили чем js.

А еще лучше дай постановку задачи максимально близко к тому как она дана тебе на вход.

Дана html-страница с 4 картинками, расположенными в один ряд в одну горизонтальную линию. Реализовать на JS возможность перетаскивания мышью по веб-странице этих картинок. Использовать именно абсолютное позиционирование. Код не должен зависеть от количества картинок и не должен зависеть от того, как именно свёрстаны картинки — какие атрибуты и стилевые свойства им заданы. Вёрстку страницы никак не менять, вся работа — только внутри тега скрипт.
Это мой код:

 <body style='min-height: 100vh'>
<img src='1.png'>
<img src='2.png' width=100>
<img src='3.png' width=150>
<img src='4.png' style='padding-left: 50px'>

<script>
"use strict";

window.addEventListener('load', posElem, false);

function posElem(eo) {
  eo = eo || window.event;
  let elems = document.querySelectorAll('img');

  for (var i = elems.length - 1; i >= 0; i--) {
    let elem = elems[i];  

    let maxHeight = 0;
     
    elems.forEach((elem) => {
        let elemHeight = elem.clientHeight;
        if (elemHeight > maxHeight) {
            maxHeight = elemHeight;
        }
    });
    elems.forEach((elem) => {
        let elemHeight = elem.clientHeight;
        elem.style.top = `${maxHeight - elemHeight}px`;
        elem.style.left = elem.offsetLeft + 'px';
     
    });
    elems.forEach((elem) => {
        elem.style.position = 'absolute';
    });

    elem.onmousedown = MouseDown;
    elem.onmouseup = MouseUp;      
   
} 
 
  function MouseDown(eo) {
    eo = eo || window.event;
    eo.preventDefault();
    
    let ShiftX = eo.pageX - eo.target.offsetLeft;
    let ShiftY = eo.pageY - eo.target.offsetTop;
 
    let pict = eo.target;
    document.body.appendChild(pict); 
  
   window.onmousemove = MouseMove; 

    function MouseMove(eo) {
      eo = eo || window.event;
      eo.preventDefault();
      pict.style.cursor = 'pointer';
      pict.style.zIndex = 10;
    
      pict.style.left = (eo.pageX - ShiftX) + 'px';
      pict.style.top = (eo.pageY - ShiftY) + 'px';
     }
  }
 
  function MouseUp(eo) {
    eo.preventDefault();  
    window.onmousemove = null;    
   }  
}

</script>

Использовала maxHeight именно для того, чтобы все картинки лежали на одной линии. Но, как оказалось, нужно решить эту задачу без математических расчетов. Нужно прочитать факт координаты картинок (offsetLeft, offsetTop) и вставить туда абсолютные координаты картинок. Как это можно реализовать, чтобы код не зависел от кол-ва картинок на странице?

Не-не, это какая-то колбаса. Такое невозможно реализовать без математических рассчетов. Эта задача чисто про математические рассчеты, координаты и позиционирования. Тот код который ты делаешь - в верном направлении.

Я бы делал через глобальный обработчик и из event бы находил произошел ли mouseDown по картинке и по какой. Именно этот код может ломаться (такое видел много раз) когда мышка отпускается за пределами картинки просто потому что браузер не успел отрисовать картинку на mouseMove.

getImage(event) - пройдется по всем parentNode и найдет хотя бы один из них кто есть картинка.

Еще бы сделал общий хелпер чтобы использовать его как в расстановке так и в драг-н-дропе картинки. Чтобы он возвращал все интересующие меня значения по картинке в объекте (ширина, высота, левая позиция, правая позиция).
getImageData(img). Потом ее будет удобно использовать для вычисления новых координат картинки при движении мыши, а так же чтобы запоминать начальное положение картинки при mousedown.

Вот это совсем не надо. Может даже портить всю ту хорошую логику которая написана.


У тебя все элементы на месте. Чуток не хватает чтобы было то что надо. Направление верное.

Я напишу свою структуру. В ней ты узнаешь элементы которые у тебя есть. И поймешь чего не хватает:

  • сделай обработчик mouseDown (можно на каждую картинку, но лучше глобально на документ и потом определять с помощью event.target был ли mouseDown по картинке)
    • если mouseDown был по картинке
      • то запомни в переменную ссылку на DOM элемент картинки, а также запомни текущий imgData этого узла
      • запомни координаты mouseDown
      • добавь обработчик onMouseMove: в нем на каждое движение мышки
        • получай значение на сколько мышка сдвинулась относительно mouseDown (у тебя будут в объекте события новые координаты), считай новую позицию картинки через getNewPos и присваивай это значение.
      • добавь обработчик на onMouseUp на который убирается обработчик mouseDown
    • если mouseDown был не по картинке, то ничего не делай.

В целом будет получаться структура типа такой. Тут важно чтобы и функции были именованные (тогда их можно будет использовать для убирания с обработчиков событий) и чтобы эти функции имели доступ к переменным, созданным в момент mouseDown.

// Характеристики картинки. Может нужно будет не top, left а x, y, или еще другой доступный/удобный параметр
getImgData(img) {
	width: 10,
	height: 20,
	top: 30,
	left: 40,
}

// Математика вычисления новых координат картинки из координат при mouseDown, mouseMove и imgData
getNewPos(mouseDown, mouseMoved, imgData) {
	return {
		top: 0,
		left: 0
	}
}


document.addEventListener('mousedown', (event) => {
	const img = getImageFromEvent(event)
        // запомнить координаты мыши откуда началось движение
        const mouseDownX = ... ///
        const mouseDownY = ... /// 
	let imgData
	function mouseMove(event) {
		// координаты мыши
		// высчитать новые значения положения картинки
		// присвоить значения в img
	}
	function mouseUp(event) {
		document.removeEventListener('mousemove', mouseMove)
		document.removeEventListener('mouseup', mouseUp)
	}
	if (img) {
		imgData = getImgData(img)
		document.addEventListener('mousemove', mouseMove)
		document.addEventListener('mouseup', mouseUp)
	}
})
1 лайк

Я поняла, спасибо большое за помощь!

Забыл очень важную вещь. Рисуй. Такие задачи нужно прорисовывать. Где какие координаты, где какие ширины. Кстати, подобная задача, это же по сути школьная начальна геометрия.

Пример как бы я отрисовывал движение картинки чтобы понять какие значения участвуют в вычислении целевого положения (время выше и слова ниже это от другого контекста)


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

1 лайк