Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xbeat/aa6e91846887679b07a16f6f92be6db7 to your computer and use it in GitHub Desktop.
Save xbeat/aa6e91846887679b07a16f6f92be6db7 to your computer and use it in GitHub Desktop.
Drag & Drop Player w/ collision detection

Drag & Drop Player w/ collision detection

This is a tiny script which allows anything with the class of ".draggable" to be dragged and dropped.

A Pen by Giuseppe Canale on CodePen.

License.

<div id="field-containerV" class="fieldContainerV">
<div class="pitch">
<div class="playerContainerV" id="playerContainerV"></div>
<div class="inner-pitch">
<div class="line"></div>
<div class="half"></div>
<div class="penalty top"></div>
<div class="penalty bottom"></div>
<div class="p-spot top"></div>
<div class="p-spot bottom"></div>
<div class="center"></div>
<div class="p-place top"></div>
<div class="p-place bottom"></div>
</div>
</div>
</div>
<div id="field-containerH" class="fieldContainerH">
<div id="pitch" class="pitch">
<div class="playerContainerH" id="playerContainerH"></div>
<div class="inner-pitch">
<div class="line"></div>
<div class="half"></div>
<div class="penalty left"></div>
<div class="penalty right"></div>
<div class="p-spot left"></div>
<div class="p-spot right"></div>
<div class="center"></div>
<div class="p-place left"></div>
<div class="p-place right"></div>
</div>
</div>
</div>
<!--
<div class="controlPanel">
<div class="slider">
<input id="rangevalue" type="range" min="0" max="100" value="50" step="1" />
</div>
</div>
<div class="stage">
<div class="player active">
<div class="player__placeholder"></div>
<div class="player__card"></div>
</div>
</div>
-->
var formation = [
[5, 4, 1],
[4, 5, 1],
[4, 4, 2],
[4, 4, 1, 1],
[4, 3, 3],
[4, 3, 2],
[4, 2, 3, 1],
[4, 2, 2, 2],
[4, 2, 1, 3],
[4, 2, 4, 1],
[4, 1, 3, 2],
[4, 1, 2, 3],
[3, 5, 2, 2],
[3, 5, 1, 1],
[3, 4, 1, 2],
[3, 4, 3],
[3, 4, 2, 1]
];
playerContainerV = document.getElementById("playerContainerV");
playerContainerH = document.getElementById("playerContainerH");
var formationIndex = 2;
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
(function playerV() {
var formationText = "",
formationPicked = [],
posTop = 30;
formationPicked[0] = formation[getRandomInt(0, formation.length - 1)];
formationPicked[1] = formation[getRandomInt(0, formation.length - 1)].reverse();
var heightInterval = 520 / (formationPicked[0].length + formationPicked[1].length);
for (formations = 0; formations < 2; formations++) {
var counter = 1;
for (j = 0; j < formationPicked[formations].length; j++) {
playersByRow = formationPicked[formations][j];
var widthOffset = (340 / playersByRow);
formationText = formationText + " " + playersByRow;
for (i = 0; i < playersByRow; i++) {
var draggable = document.createElement("div");
draggable.classList.add("draggableV");
draggable.innerText = counter++;
draggable.id = counter;
draggable.setAttribute("team", formations);
draggable.style.top = posTop + "px";
draggable.style.left = ((widthOffset * i) + (widthOffset / 2)) + "px";
playerContainerV.appendChild(draggable);
formations % 2 ? draggable.style.backgroundColor = "#f00" : draggable.style.backgroundColor = "#f0f";
}
posTop += heightInterval;
}
}
})();
(function playerH() {
var formationText = "",
formationPicked = [],
posLeft = 30;
formationPicked[0] = formation[getRandomInt(0, formation.length - 1)];
formationPicked[1] = formation[getRandomInt(0, formation.length - 1)].reverse();
var widthInterval = 1100 / (formationPicked[0].length + formationPicked[1].length);
for (formations = 0; formations < 2; formations++) {
var counter = 1;
for (j = 0; j < formationPicked[formations].length; j++) {
playersByRow = formationPicked[formations][j];
var heightOffset = (650 / playersByRow);
formationText = formationText + " " + playersByRow;
for (i = 0; i < playersByRow; i++) {
var draggable = document.createElement("div");
draggable.classList.add("draggableH");
draggable.innerText = counter++;
draggable.id = counter;
draggable.setAttribute("team", formations);
draggable.style.top = ((heightOffset * i) + (heightOffset / 2)) + "px";
draggable.style.left = posLeft + "px";
playerContainerH.appendChild(draggable);
formations % 2 ? draggable.style.backgroundColor = "#f00" : draggable.style.backgroundColor = "#f0f";
}
posLeft += widthInterval;
}
}
})();
function drag(elementToDrag, event, direction) {
var scroll = getScrollOffsets();
var startX = event.clientX + scroll.x;
var startY = event.clientY + scroll.y;
var origX = elementToDrag.offsetLeft;
var origY = elementToDrag.offsetTop;
var deltaX = startX - origX;
var deltaY = startY - origY;
document.addEventListener("mousemove", moveHandler, true);
document.addEventListener("touchmove", moveHandler, true);
document.addEventListener("mouseup", upHandler, true);
document.addEventListener("touchend", upHandler, true);
event.stopPropagation();
event.preventDefault();
function moveHandler(e) {
var scroll = getScrollOffsets(),
leftPos = e.clientX + scroll.x - deltaX,
topPos = e.clientY + scroll.y - deltaY;
elementToDrag.style.left = leftPos + "px";
elementToDrag.style.top = topPos + "px";
var collObj = false;
if (direction == "V") {
//-- erase
[].forEach.call(document.getElementsByClassName("draggableV"), function(el) {
el.classList.remove("hit")
});
//-- check objDragged
[].forEach.call(document.getElementsByClassName("draggableV"), function(el) {
if (el.getAttribute("team") != elementToDrag.getAttribute("team")) {
var r1 = 15,
r2 = 15,
coll = collision(leftPos, topPos, r1, parseInt(el.style.left), parseInt(el.style.top), r2);
coll ? (el.classList.add("hit"), collObj = true) : null;
}
})
collObj ? elementToDrag.classList.add("hit") : elementToDrag.classList.remove("hit");
//-- check other
[].forEach.call(document.getElementsByClassName("draggableV"), function(el) {
var objColl = el;
[].forEach.call(document.getElementsByClassName("draggableV"), function(el) {
if (objColl.getAttribute("team") != el.getAttribute("team")) {
var r1 = 15,
r2 = 15,
coll = collision(parseInt(objColl.style.left), parseInt(objColl.style.top), r1, parseInt(el.style.left), parseInt(el.style.top), r2);
coll ? (el.classList.add("hit"), objColl.classList.add("hit")) : null;
}
});
});
} else {
//-- erase
[].forEach.call(document.getElementsByClassName("draggableH"), function(el) {
el.classList.remove("hit")
});
//-- check objDragged
[].forEach.call(document.getElementsByClassName("draggableH"), function(el) {
if (el.getAttribute("team") != elementToDrag.getAttribute("team")) {
var r1 = 30,
r2 = 30,
coll = collision(leftPos, topPos, r1, parseInt(el.style.left), parseInt(el.style.top), r2);
coll ? (el.classList.add("hit"), collObj = true) : null;
}
})
collObj ? elementToDrag.classList.add("hit") : elementToDrag.classList.remove("hit");
//-- check other
[].forEach.call(document.getElementsByClassName("draggableH"), function(el) {
var objColl = el;
[].forEach.call(document.getElementsByClassName("draggableH"), function(el) {
if (objColl.getAttribute("team") != el.getAttribute("team")) {
var r1 = 30,
r2 = 30,
coll = collision(parseInt(objColl.style.left), parseInt(objColl.style.top), r1, parseInt(el.style.left), parseInt(el.style.top), r2);
coll ? (el.classList.add("hit"), objColl.classList.add("hit")) : null;
}
});
});
}
e.stopPropagation();
}
function upHandler(e) {
document.removeEventListener("mouseup", upHandler, true);
document.removeEventListener("touchend", upHandler, true);
document.removeEventListener("mousemove", moveHandler, true);
document.removeEventListener("touchmove", moveHandler, true);
e.stopPropagation();
}
function getScrollOffsets() {
var offset = {};
offset.y = document.documentElement.scrollTop;
offset.x = document.documentElement.scrollLeft;
return offset;
}
function collision(p1x, p1y, r1, p2x, p2y, r2) {
//console.log(p1x + "," + p1y + "," + r1 + "," + p2x + "," + p2y + "," + r2);
var a;
var x;
var y;
a = r1 + r2;
x = p1x - p2x;
y = p1y - p2y;
if (a > Math.sqrt((x * x) + (y * y))) {
return true;
} else {
return false;
}
}
}
[].forEach.call(document.getElementsByClassName("draggableV"), function(el) {
el.addEventListener("touchstart", function(ev) {
drag(el, ev, "V");
}, true);
el.addEventListener("mousedown", function(ev) {
drag(el, ev, "V");
}, true);
});
[].forEach.call(document.getElementsByClassName("draggableH"), function(el) {
el.addEventListener("touchstart", function(ev) {
drag(el, ev, "H");
}, true);
el.addEventListener("mousedown", function(ev) {
drag(el, ev, "H");
}, true);
});
/* Use for parameters */
"use strict";
//var volumeSlider = document.getElementById('volume');
//var scrubberSlider = document.getElementById('scrubber');
//var sliders = [volumeSlider];
function Slider(slider) {
this.slider = slider;
slider.addEventListener('input', function() {
this.updateSliderOutput();
this.updateSliderLevel();
}.bind(this), false);
this.level = function() {
var level = this.slider.querySelector('.slider-input');
return level.value;
}
this.levelString = function() {
return parseInt(this.level());
}
this.remaining = function() {
return 99.5 - this.level();
}
this.remainingString = function() {
return parseInt(this.remaining());
}
this.updateSliderOutput = function() {
var output = this.slider.querySelector('.slider-output');
var remaining = this.slider.querySelector('.slider-remaining');
var thumb = this.slider.querySelector('.slider-thumb');
output.value = this.levelString();
output.style.left = this.levelString() + '%';
thumb.style.left = this.levelString() + '%';
if (remaining) {
remaining.style.width = this.remainingString() + '%';
}
}
this.updateSlider = function(num) {
var input = this.slider.querySelector('.slider-input');
input.value = num;
}
this.updateSliderLevel = function() {
var level = this.slider.querySelector('.slider-level');
level.style.width = this.levelString() + '%';
}
}
/*
sliders.forEach(function(slider) {
new Slider(slider);
});
*/
body {
background-color: #010101;
font-family: sans-serif;
font-size: 12px;
}
.draggableV {
display: flex;
justify-content: center;
align-items: center;
width: 20px;
height: 20px;
background: #dd0000;
border: 3px solid #fff;
border-radius: 50%;
color: #fff;
cursor: pointer;
z-index: 300;
position: absolute;
/* must be absolute */
}
.draggableH {
display: flex;
justify-content: center;
align-items: center;
width: 50px;
height: 50px;
background: #dd0000;
border: 5px solid #fff;
border-radius: 50%;
color: #fff;
cursor: pointer;
z-index: 300;
position: absolute;
/* must be absolute */
}
.hit {
background-color: gold !important;
}
/* ------- Vertical Field ------- */
.fieldContainerV {
/* the fieldContainerV */
height: 560px;
width: 379px;
position: absolute;
margin: 0 auto;
top: 10px;
left: 1150px;
}
.playerfieldContainerH {
/* the player fieldContainerH */
position: absolute;
z-index: 250;
}
.fieldContainerV .pitch {
/* the field fieldContainerV */
height: 539px;
width: 359px;
border: 10px solid #539A46;
background-color: #539A46;
position: relative;
}
.fieldContainerV .inner-pitch {
/* the border line */
height: 535px;
width: 355px;
border: 4px solid #fff;
position: relative;
}
.fieldContainerV .line {
/* the field */
height: 535px;
width: 355px;
position: absolute;
background-image: url("https://res.cloudinary.com/dj1qm0th5/image/upload/v1485701094/Pitch-TileHoriz_abar3a.jpg");
}
.fieldContainerV .half {
/* half line */
height: 265px;
width: 355px;
position: absolute;
border-bottom: 3px solid #fff;
z-index: 20;
}
.fieldContainerV .penalty {
/* penalty */
height: 65px;
width: 130px;
border: 3px solid #fff;
position: absolute;
z-index: 22;
left: 109px;
}
.fieldContainerV .penalty.top {
/* penalty top */
border-top-width: 0px;
}
.fieldContainerV .penalty.top:before {
/* small area */
border: 3px solid #fff;
border-top-width: 0px;
content: "";
left: 21px;
position: absolute;
width: 83px;
top: 0px;
height: 36px;
}
.fieldContainerV .penalty.top:after {
/* the door */
border: 3px solid #fff;
border-top-width: 0px;
bottom: 45px;
content: "";
left: 49px;
position: absolute;
width: 33px;
top: 0px;
height: 6px;
}
.fieldContainerV .penalty.bottom {
/* penalty bottom*/
bottom: 0px;
border-bottom-width: 0px;
}
.fieldContainerV .penalty.bottom:before {
/* small area */
border: 3px solid #fff;
border-bottom-width: 0px;
content: "";
left: 21px;
position: absolute;
width: 83px;
bottom: 0px;
height: 36px;
}
.fieldContainerV .penalty.bottom:after {
/* the door */
border: 3px solid #fff;
border-bottom-width: 0px;
bottom: 45px;
content: "";
left: 49px;
position: absolute;
width: 33px;
bottom: 0px;
height: 6px;
}
.fieldContainerV .p-spot.top:after {
/* penalty */
content: "\2022";
position: absolute;
color: #fff;
font-size: 20px;
top: 40px;
left: 175px;
z-index: 30;
}
.fieldContainerV .p-spot.bottom:after {
/* penalty */
content: "\2022";
position: absolute;
color: #fff;
font-size: 20px;
bottom: 40px;
left: 175px;
z-index: 30;
}
.fieldContainerV .center {
/* center circle field */
position: absolute;
width: 65px;
height: 65px;
border: 3px solid #ffffff;
top: 232px;
left: 143px;
border-radius: 50%;
}
.fieldContainerV .center::after {
/* center field disk */
background-color: #fff;
border: 5px solid #fff;
content: "";
left: 27px;
position: absolute;
top: 27px;
border-radius: 50%;
z-index: 100;
}
.fieldContainerV .p-place {
/* half circle */
border-radius: 50%;
width: 90px;
position: absolute;
height: 78px;
z-index: 210;
border: 3px solid transparent;
left: 130px;
}
.fieldContainerV .p-place.top {
/* half circle top */
border-left-color: #fff;
border-right-color: #fff;
border-bottom-color: #fff;
clip: rect(65px, 200px, 200px, 10px);
}
.fieldContainerV .p-place.bottom {
/* half circle bottom */
border-right-color: #fff;
border-left-color: #fff;
border-top-color: #fff;
bottom: 0px;
clip: rect(0px, 220px, 17px, 10px);
}
/* ------- Horizontal Field ------- */
.fieldContainerH {
/* the fieldContainerH */
width: 1120px;
height: 758px;
position: absolute;
top: 10px;
left: 10px;
background-position: top right;
transition-duration: .3s;
perspective-origin: bottom left;
transition-timing-function: ease;
}
.fieldContainerH .pitch {
/* the field fieldContainerH */
width: 1078px;
height: 718px;
border: 20px solid #539A46;
background-color: #539A46;
position: relative;
}
.fieldContainerH .inner-pitch {
/* the border line */
width: 1070px;
height: 710px;
border: 4px solid #fff;
position: relative;
}
.fieldContainerH .line {
/* the field */
width: 1070px;
height: 710px;
position: absolute;
background-image: url("https://res.cloudinary.com/dj1qm0th5/image/upload/v1485701092/Pitch-TileVert_qotjiy.jpg");
}
.fieldContainerH .half {
/* half line */
width: 535px;
height: 710px;
position: absolute;
border-right: 3px solid #fff;
z-index: 20;
}
.fieldContainerH .penalty {
/* penalty */
width: 132px;
height: 264px;
border: 3px solid #fff;
position: absolute;
z-index: 22;
}
.fieldContainerH .penalty.left {
/* penalty left */
top: 198px;
border-left-width: 0px;
}
.fieldContainerH .penalty.left:before {
/* small area */
border: 3px solid #fff;
border-left-width: 0px;
bottom: 95px;
content: "";
left: 0px;
position: absolute;
right: 115px;
top: 95px;
}
.fieldContainerH .penalty.left:after {
/* the door */
border: 3px solid #fff;
border-left-width: 0px;
bottom: 45px;
content: "";
left: 0px;
position: absolute;
right: 55px;
top: 45px;
}
.fieldContainerH .penalty.right {
/* penalty right*/
right: 0px;
top: 198px;
border-right-width: 0px;
}
.fieldContainerH .penalty.right:before {
/* small area */
border: 3px solid #fff;
border-right-width: 0px;
bottom: 95px;
content: "";
left: 115px;
position: absolute;
right: 0px;
top: 95px;
}
.fieldContainerH .penalty.right:after {
/* the door */
border: 3px solid #fff;
border-right-width: 0px;
bottom: 45px;
content: "";
left: 55px;
position: absolute;
right: 0px;
top: 45px;
}
.fieldContainerH .p-spot.left:after {
/* penalty */
content: "\2022";
position: absolute;
color: #fff;
font-size: 35px;
top: 313px;
left: 96px;
z-index: 30;
}
.fieldContainerH .p-spot.right:after {
/* penalty */
content: "\2022";
position: absolute;
color: #fff;
font-size: 35px;
top: 313px;
right: 96px;
z-index: 30;
}
.fieldContainerH .center {
/* center circle field */
position: absolute;
width: 130px;
height: 130px;
border: 3px solid #ffffff;
left: 470px;
top: 265px;
border-radius: 50%;
}
.fieldContainerH .center:after {
/* center field disk */
background-color: #fff;
border: 3px solid #fff;
bottom: 55px;
content: "";
left: 54px;
position: absolute;
right: 56px;
top: 55px;
border-radius: 50%;
}
.fieldContainerH .p-place {
/* half circle */
border-radius: 50%;
height: 156px;
position: absolute;
width: 180px;
z-index: 210;
border: 3px solid transparent;
top: 252px;
}
.fieldContainerH .p-place.left {
/* half circle left */
border-bottom-color: #fff;
border-right-color: #fff;
border-top-color: #fff;
clip: rect(0px, 200px, 160px, 132px);
}
.fieldContainerH .p-place.right {
/* half circle right */
border-bottom-color: #fff;
border-left-color: #fff;
border-top-color: #fff;
right: 0px;
clip: rect(0px, 52px, 160px, 0px);
}
/* ---- Control Panel ----*/
.controlPanel {
position: absolute;
top: 10px;
left: 1600px;
}
/* Slider */
slider {
width: 200px;
margin: 40px auto;
}
input[type="range"] {
-webkit-appearance: none;
-webkit-tap-highlight-color: rgba(255, 255, 255, 0);
cursor: pointer;
width: 100%;
height: 20px;
margin: 0;
border: none;
padding: 1px 2px;
border-radius: 14px;
background: #333;
box-shadow: inset 0 1px 0 0 #0d0e0f, inset 0 -1px 0 0 #3a3d42;
outline: none; /* no focus outline */
}
input[type="range"]::-moz-range-track {
border: inherit;
background: transparent;
}
input[type="range"]::-ms-track {
border: inherit;
color: transparent; /* don't drawn vertical reference line */
background: transparent;
}
input[type="range"]::-ms-fill-lower,
input[type="range"]::-ms-fill-upper {
background: transparent;
}
input[type="range"]::-ms-tooltip {
display: none;
}
/* thumb */
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
width: 40px;
height: 18px;
border: none;
border-radius: 12px;
background-image: linear-gradient(to bottom, #529de1 0, #245e8f 100%); /* W3C */
}
input[type="range"]::-moz-range-thumb {
width: 40px;
height: 18px;
border: none;
border-radius: 12px;
background-image: linear-gradient(to bottom, #529de1 0, #245e8f 100%); /* W3C */
}
input[type="range"]::-ms-thumb {
width: 40px;
height: 18px;
border-radius: 12px;
border: 0;
background-image: linear-gradient(to bottom, #529de1 0, #245e8f 100%); /* W3C */
}
.stage {
position: absolute;
width: 100%;
height: 100%;
top: 0;
perspective-origin: 50% -200px;
perspective: 1100px;
}
.player {
position: absolute;
height: 88px;
width: 65px;
left: 50%;
margin-left: -32.5px;
bottom: 50%;
cursor: pointer;
}
.player__placeholder {
position: absolute;
transform: rotateX(90deg);
height: 30px;
width: 30px;
bottom: -10px;
left: 0;
right: 0;
margin: auto;
border-radius: 50%;
background-color: rgba(0, 0, 0, 0.2);
}
.player__card {
position: absolute;
bottom: 26px;
left: -82.5px;
height: 260px;
background-color: #f7f7f7;
width: 230px;
padding: 0;
color: #333;
border-radius: 4px;
}
.player__card:after {
position: absolute;
content: '';
height: 1px;
width: 1px;
border: solid 10px transparent;
border-top: solid 10px #eee;
bottom: -20px;
left: 0;
right: 0;
margin: auto;
}
/* ------------ */
.wrapperFormationCarousel {
position: relative;
top:50px;
display: flex;
justify-content: center;
height: 80px;
}
.wrapperFormation {
position: relative;
display: flex;
height: 100px;
justify-content: center;
align-items: center;
overflow: hidden;
width: 555px;
flex-direction: column;
}
.formationSliding {
position: absolute;
display: flex;
justify-content: space-between;
align-items: center;
margin-left: auto;
margin-right: auto;
min-width:550px;
min-height:70px;
top:0px;
}
.formationSliding:first-of-type {
left: 0%;
}
.formationSliding:last-of-type {
left: -100%;
}
button {
width: 45px;
height: 70px;
border: none;
cursor: pointer;
background-color: rgba(0, 0, 0, 0);
}
.chevronFormationLeft:before {
border-style: solid;
border-width: 2px 2px 0 0;
content: '';
display: flex;
height: 25px;
width: 25px;
transform: rotate(225deg);
border-color: #38B87C;
position: relative;
left: 15px;
}
.chevronFormationRight:before {
border-style: solid;
border-width: 2px 2px 0 0;
content: '';
display: flex;
height: 25px;
width: 25px;
transform: rotate(45deg);
border-color: #38B87C;
position: relative;
left: -10px;
}
.formationBlock {
display: flex;
flex-direction:column;
box-sizing: border-box;
min-width:65px;
min-height:65px;
align-items: center;
margin: 2px 2px 4px;
border-radius: 5px;
border: 1px solid transparent;
cursor: pointer;
justify-content: flex-start;
}
.formationRow {
display: flex;
flex-direction:row;
}
.formationTextSmall{
font-size: 10px;
font-family: 'Open Sans', Arial, Helvetica, Sans-serif;
}
.formationPlayerSmall{
width:7px;
height:7px;
background-color:#fff;
border-radius: 50%;
margin:3px 2px;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment