JavaScript: произвольно расставляем объекты на картинке
Ну уж вот этот код должен легко решать задачу произвольной расстановки-перетаскивания объектов-картинок на фоновой картинке, не обмена содержимым между контейнерами, как здесь, а именно свободного размещения.
Порядок персонажей определяется порядком описания их разделов в разметке, то есть, #hero1
изначально находится "за спиной" у #hero2
и т.д., но последний перетаскиваемый персонаж должен оказаться впереди остальных, если их спрайты накладываются. Также в коде простым образом учтены мобильные устройства с их сенсорными экранами и отличными от классических событиями яваскрипта.
Код реализуется на разделах div
, потому что у картинок img
имеется собственная обработка событий drag-and-drop браузерами, надо её отдельно отключать и т.п.
Вообще говоря, все картинки должны быть одного размера и с прозрачным фоном, чтобы не было неожиданных эффектов.
Удобно, если персонажей можно разместить на одной картинке, как и сделано здесь, а потом "нарезать" отображаемые части с помощью CSS (см. .hero
и #hero1
... #hero5
в стиле).
Вот содержательная задача для демонстрации кода в работе. С помощью перетаскивания мышкой или пальцем расставь марионеток на теле России... автору лучшей композиции - скидка в полтора года от срока с перспективой УДО!
Код этого примера с точностью до адресов картинок field.png
и heroes.png
(документ HTML без обрамления, кодировка Юникода UTF-8). В старом Internet Explorer это не должно работать, в остальных браузерах, в том числе, в MS Edge - вполне себе.
<style> /* Игровое поле */ #field { background: url(field.png); width: 875px; height: 449px; float: left; margin: 0; padding: 0; } /* Герои (переносимые элементы) */ .hero { background: url(heroes.png); width: 175px; height: 310px; float: left; margin: 0; padding: 0; } /* Сдвиг по X и Y каждого героя с картинки heroes.png */ #hero1 { background-position: 0 0; } #hero2 { background-position: -175px 0; } #hero3 { background-position: -350px 0; } #hero4 { background-position: -525px 0; } #hero5 { background-position: -700px 0; } .draggable { cursor: pointer; } </style> <div id="field"></div> <div style="clear:both"></div> <div class="hero draggable" id="hero1"></div> <div class="hero draggable" id="hero2"></div> <div class="hero draggable" id="hero3"></div> <div class="hero draggable" id="hero4"></div> <div class="hero draggable" id="hero5"></div> <div style="clear:both"></div> <script> let mobile = /android|blackberry|ios|ipad|ipod|iphone|mobile|webos/i.test(navigator.userAgent); function draggableHeroes (e) { let draggable = e.target; if (!draggable.classList.contains('draggable')) return; draggable.ondragstart = () => false; if (mobile) document.body.style.overflow = "hidden" e.preventDefault(); let dragWidth = draggable.offsetWidth; let dragHeight = draggable.offsetHeight; let shiftX = (e.clientX || e.touches[0].clientX) - draggable.getBoundingClientRect().left; let shiftY = (e.clientY || e.touches[0].clientY) - draggable.getBoundingClientRect().top; draggable.style.position = 'absolute'; draggable.style.zIndex = 99; document.body.append (draggable); function setPosition (x, y) { let top = document.documentElement.scrollTop; let maxX = document.documentElement.clientWidth; let maxY = document.documentElement.clientHeight + top; let shiftPlus = mobile ? 24 : 12; let posX = x - shiftX; let posY = y - shiftY + top; if (posX + dragWidth > maxX) posX = maxX - dragWidth; if (posY + dragHeight > maxY) { posY = maxY - dragHeight; window.scrollBy (0, shiftPlus); } if (posX < 0) posX = 0; if (posY < top) { posY = top; window.scrollBy(0, -shiftPlus) } draggable.style.left = posX+'px'; draggable.style.top = posY+'px'; } let x = mobile ? e.touches[0].clientX : e.clientX; let y = mobile ? e.touches[0].clientY : e.clientY; setPosition(x, y); function moveAt (e) { let x = mobile ? e.touches[0].clientX : e.clientX; let y = mobile ? e.touches[0].clientY : e.clientY; setPosition(x, y); } function drop () { if (mobile) { document.removeEventListener('touchmove', moveAt); document.removeEventListener('touchend', drop); document.body.style.overflow = ''; } else { document.removeEventListener('mousemove', moveAt); document.removeEventListener('mouseup', drop); } } if (mobile) { document.addEventListener('touchmove', moveAt); document.addEventListener('touchend', drop); } else { document.addEventListener('mousemove', moveAt); document.addEventListener('mouseup', drop) } } if (mobile) document.addEventListener('touchstart', draggableHeroes); else document.addEventListener('mousedown', draggableHeroes); </script> <noscript> <p>Требуется JavaScript для работы приложения</p> </noscript>

картинка field.png

картинка heroes.png
Для фона использована картина И.С. Глазунова "Вечная Россия", "пиксель-артные" персонажи, которых, надеюсь, вы всех узнаёте, лежат вот в этом файле Photoshop во вдвое большем масштабе, чем в приложении.
Архив .zip с файлом .psd персонажей (442 Кб)
P.S. Вот и первая расстановка, по-моему, изрядно.

расстановка

ещё одна расстановка, тоже не на фоне картины, скрипт это позволяет
21.06.2020, 17:34 [1444 просмотра]