javascript/jquery selecting last element in row - javascript

I'm using "float: left" to place blocks in container. Like this on large screen:
on small scree:
can i select last element on row when user clicks on any element?

If the elements are all inline or floating then there wont be a concept of a "last element on row".
I suggest you calculate the element using known values:
$('.box').on('click', function (e) {
// calculate how many boxes will be in a "row"
var windowWidth = $('ul').width();
var boxWidth = $('.box').outerWidth();
var boxesPerRow = ~~(windowWidth / boxWidth);
// get the index of the clicked element
var index = $(e.currentTarget).index();
// get the column of the clicked element
var col = (index % boxesPerRow) + 1;
// calculate how far it is to the end of this row,
// and select that element
var $endOfRow = $('.box').eq(index + boxesPerRow - col);
if (!$endOfRow.length) $endOfRow = $('.box').last();
});
Updated my answer with one that works. Here's the fiddle: http://jsfiddle.net/gvbw9Lkz/4/

As an alternative you can dynamically work out which elements are in the same row by comparing their position() values:
$(function() {
// cache the collection of all the blocks
var blocks = $('.block');
blocks.on('click', function() {
blocks.removeClass('highlight');
var $this = $(this);
// get the y coordinate of the clicked block
var y = $this.position().top;
// store the blocks in the row
var rowBlocks = $this;
// search backwards until we find a different y coordinate or reach 0
for (var i = $this.index() - 1; i >= 0; i--) {
var block = blocks.eq(i);
if (block.position().top == y) {
// add the element to the rowBlocks selector
rowBlocks = rowBlocks.add(block);
} else {
// different coordinate, stop searching
break;
}
}
// search forwards until we find a different y coordinate or reach the end
for (var i = $this.index() + 1; i < blocks.length; i++) {
var block = blocks.eq(i);
if (block.position().top == y) {
// add the element to the rowBlocks selector
rowBlocks = rowBlocks.add(block);
} else {
// different coordinate, stop searching
break;
}
}
// hightlight the row
rowBlocks.addClass('highlight');
});
});
.container {
width: 300px;
}
.block {
background-color: #000;
width: 50px;
height: 50px;
margin: 10px;
float: left;
}
.block.highlight {
background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="container">
<div class="block">1</div>
<div class="block">2</div>
<div class="block">3</div>
<div class="block">4</div>
<div class="block">5</div>
<div class="block">6</div>
<div class="block">7</div>
<div class="block">8</div>
<div class="block">9</div>
<div class="block">10</div>
<div class="block">11</div>
<div class="block">12</div>
<div class="block">13</div>
<div class="block">14</div>
<div class="block">15</div>
<div class="block">16</div>
<div class="block">17</div>
<div class="block">18</div>
<div class="block">19</div>
<div class="block">20</div>
</div>

Related

How to listen for events even when the object has been replaced in JavaScript

I am creating a scrabble game with JavaScript and I have an issue. I have this function that creates scrabble tiles inside a tile rack div. I also have an event listener that listens for when the tile divs are clicked. When a section on the board is clicked, and then the tile div is clicked it places the tile on the board and then it would be removed from the the parent div(tile rack). How this works is this: I create an array which has those tile divs inside and then when I remove the div from inside the array, I would override the parent div(tile rack) with the new array. all this happens very well but the issue now is that when the old tiles overrides the new tiles in the parent div, the event listener does not work again.
here is my code and a link to my entire code explaining this:
let bag = ["A|1","A|1","A|1","A|1","A|1","A|1","A|1","A|1","A|1","B|3","B|3","C|3","C|3","D|2","D|2","D|2","D|2","E|1","E|1","E|1","E|1","E|1","E|1","E|1","E|1","E|1","E|1","E|1","E|1","F|4","F|4","G|2","G|2","G|2","H|4","H|4","I|1","I|1","I|1","I|1","I|1","I|1","I|1","I|1","I|1","J|8","K|5","L|1","L|1","L|1","L|1","M|3","M|3","N|1","N|1","N|1","N|1","N|1","N|1","O|1","O|1","O|1","O|1","O|1","O|1","O|1","O|1","P|3","P|3","Q|10","R|1","R|1","R|1","R|1","R|1","R|1","S|1","S|1","S|1","S|1","T|1","T|1","T|1","T|1","T|1","T|1","U|1","U|1","U|1","U|1","V|4","V|4","W|4","W|4","X|8","Y|4","Y|4","Z|10","|","|"];
// to fill the plate or stick with tiles from the bag array
let player1 = [];
let player2 = [];
let player1plate = document.getElementById("plate1");
let player2plate = document.getElementById("plate2");
// var tile = bag[Math.floor(Math.random() * bag.length)];
// FILL THE PLATE OR STICK WITH TILES
function fillStick(player, numberOfTilesNeeded, playerplate, id) {
let insert = "";
for (let i = 0; i < numberOfTilesNeeded; i++) {
randomIndex = Math.floor(Math.random() * bag.length);
player.push(bag[randomIndex]);
bag.splice(randomIndex, 1);
}
for (let j = 0; j < player.length; j++) {
insert += `
<div class="tile" id="${id}${j}">
<h2> ${player[j].split("|")[0]}</h2>
<p>${player[j].split("|")[1]}</p>
</div>`;
}
playerplate.innerHTML = insert;
// console.log(bag);
console.log(player1);
}
fillStick(player1, 7, player1plate, "tile");
fillStick(player2, 7, player2plate, "rile");
function removeTile(player, playerplate, id) {
let insert = "";
for (let j = 0; j < player.length; j++) {
insert += `
<div class="tile" id="${id}${j}">
<h2> ${player[j].split("|")[0]}</h2>
<p>${player[j].split("|")[1]}</p>
</div>`;
}
playerplate.insertAdjacentHTML("beforeend",insert);
console.log(playerplate);
}
// for the tiles on the rack/plate to click and be placed on the board
let tileClicked = 0;
let allTiles = document.querySelectorAll(".tile");
allTiles.forEach((e) => {
e.addEventListener("click", () => {
for (let i = 0; i < allTiles.length; i++) {
allTiles[i].setAttribute("class", "tile");
}
if (tileClicked == e.id) {
e.setAttribute("class", "tile");
tileClicked = 0;
} else {
e.setAttribute("class", "tile active");
tileClicked = e.id;
if (clicked != 0) {
document
.getElementById(clicked)
.setAttribute(
"style",
"background: #dfb15b; flex-direction: column;"
);
document.getElementById(clicked).setAttribute("class", "tilesections");
document.getElementById(clicked).innerHTML = e.innerHTML;
if (tileClicked.split("e")[0] == "til") {
player1.splice(tileClicked.split("e")[1], 1);
removeTile(player1, player1plate, "tile")
} else {
player2.splice(tileClicked.split("e")[1], 1);
removeTile(player2, player2plate, "rile")// where i stopped
console.log(player2);
}
clicked = 0;
tileClicked = 0;
e.setAttribute("class", "tile");
}
}
// console.log(e.id);
// console.log(player1);
});
});
to understand the problem better to can check the full code with this link
https://codepen.io/crentsil/pen/WNpeoKo
I think you should approach this question a little bit differently. Instead of adding an even listener on every single tile, you should add one on the container of the tiles. When you click an inner tile the event will "bubble" upwards. When it reaches the container div, you can catch it and get the originally clicked tile with the event.target attribute of the event parameter.
HTML:
<div id="board">
<div id="1"> 1 </div>
<div id="2"> 2 </div>
<div id="3"> 3 </div>
</div>
CSS
#board > div
{
width: 50px;
height: 50px;
background-color: gray;
margin: 10px;
}
JS
document.getElementById('board').addEventListener('click', (e) =>
{
let t = e.target
alert(`${t.id} clicked`)
})

Show overlay id using mousemove

Thanks to a really helpful user on this website (whose name I do not know, but I wish to thank and credit him!), I got the following tip on how to store area elements in an array so that when I mouse over a coordinate, I could display all of the overlay id's of the area elements that existed at that coordinate (even if the area elements were not at the same z-level):
I'm just stuck on one thing- once I have gathered all the elements that exist at the coordinate in the hoveredElements array, how do I show their overlay ids?
EDIT:
Here is an example of the full code (the overlay still does not display when I mouse over)
The file test.txt contains:
cscCSL1A15 700 359 905 318
cscCSL1A14 794 400 905 318
I use the maphilight plugin available online, and blanketaphi.png is the plot I use as a background.
<!DOCTYPE html>
<html>
<head>
<title>Detector Elements</title>
<script type="text/javascript"
src="Demo_imagemap_highlight_files/jquery-1.js"></script>
<!-- add maphilight plugin -->
<script type="text/javascript"
src="Demo_imagemap_highlight_files/jquery_002.js"></script>
</head>
<body>
<div class="content">
<div class="map"
style='display: block; background: transparent
url("Demo_imagemap_highlight_files/blanketaphi.png")
repeat scroll 0% 0%; position: relative; padding: 0px; width: 1037px;
height: 557px;'>
<canvas width="1037" height="557" style="width: 1037px; height: 557px;
position: absolute; left: 0px; top: 0px; padding: 0px; border: 0px none;
opacity: 1;"></canvas>
<img style="opacity: 0; position: absolute; left: 0px; top: 0px; padding: 0px;
border: 0px none;" src="Demo_imagemap_highlight_files/blanketaphi.png"
alt="foo" class="map maphilighted" usemap="#demo" height="557" width="1037"
border="0" />
</div>
</div>
<map name="demo" id="demo"></map>
</body>
</html>
<script type="text/javascript">
window.onload = function(){
var f = (function(){
var xhr = [];
var files = [ "test.txt"];
for (i = 0; i < 1; i++) {
(function (i){
xhr[i] = new XMLHttpRequest();
xhr[i].open("GET", files[i], true);
xhr[i].onreadystatechange = function () {
if (xhr[i].readyState == 4 && xhr[i].status == 200) {
// get text contents
j=20000*i + 50000;
var coords = xhr[i].responseText.split("\n");
coords = coords.filter(Boolean) //prevents extra rect with 0 coords
coords.forEach(function(coord) {
var area = document.createElement("area");
var att = document.createAttribute("data-maphilight");
if (i == 0) { //green
att.value = '{"strokeColor":"000000","strokeWidth":2,' +
'"fillColor":"009900","fillOpacity":0.5}';
}
area.setAttributeNode(att);
area.id = "r"+j;
area.shape = "rect";
area.coords = coord.substring(10,coord.length).trim()
.replace(/ +/g,","); // replaces spaces in txt file with commas
area.href = "#";
area.alt = "r"+j;
// create overlay with first term in string
var div = document.createElement("div");
div.id ="overlayr"+j;
div.innerHTML = coord.substring(0,10);
div.style.display = "none";
//increase j
j++;
// get map element
document.getElementById("demo").appendChild(area);
document.getElementById("demo").appendChild(div);
});
$('.map').maphilight();
//display overlay ids by mousing over
var elementPositions = [];
var hoveredElements = [];
if($('#demo')) {
$('#demo area').each(function() {
var offset = $(this).offset();
var top = offset.top;
var left = offset.left;
var bottom = $(window).height() - top - $(this).height();
var right = $(window).width() - left - $(this).width();
elementPositions.push({
element: $(this),
top: top,
bottom: bottom,
left: left,
right: right
});
//alert(top + "," + left + "," + right + "," + bottom);
});
$("body").mousemove(function(e) {
hoveredElements = [];
var yPosition = e.pageX;
var xPosition = e.pageY;
for (var i = 0; i < elementPositions.length; i++) {
if (xPosition >= elementPositions[i].left &&
xPosition <= elementPositions[i].right &&
yPosition >= elementPositions[i].top &&
yPosition <= elementPositions[i].bottom) {
// The mouse is within the element's boundaries
$("#hovers").append(elementPositions[i].element);
}
}
for (var i = 0; i < hoveredElements.length; i++) {
// The element as a jQuery object
var elem = hoveredElements[i];
var id = hoveredElements[i].attr('id');
$('#overlay'+id).show();
}
});
};
}
};
xhr[i].send();
})(i);
}
})();
};
</script>
Why not just something like this:
var elementPositions = [];
var hoveredElements = [];
if($('#demo')) {
$('#demo area').each(function() {
var offset = $(this).offset();
var top = offset.top;
var left = offset.left;
var bottom = $(window).height() - top - $(this).height();
var right = $(window).width() - left - $(this).width();
elementPositions.push({ element: $(this), top: top, bottom: bottom, left: left, right: right });
//alert(top + "," + left + "," + right + "," + bottom);
});
$("body").mousemove(function(e) {
hoveredElements = [];
var yPosition = e.pageX;
var xPosition = e.pageY;
for (var i = 0; i < elementPositions.length; i++) {
if (xPosition >= elementPositions[i].left &&
xPosition <= elementPositions[i].right &&
yPosition >= elementPositions[i].top &&
yPosition <= elementPositions[i].bottom) {
// The mouse is within the element's boundaries
hoveredElements.push(elementPositions[i].element);
$("#hovers").append(elementPositions[i].element);
}
} //end of for loop over all elements
console.log(hoveredElements);
for (var i = 0; hoveredElements.length; i++)
{ //for loop over all hovered elements
// The element as a jQuery object
var elem = hoveredElements[i];
var id = hoveredElements[i].attr('id');
console.log(id);
$('#overlay'+id).show();
// Do stuff to that jQuery element:
//??? something like elem.show();
}
You've got a lot of stuff here that doesn't make sense to me but here's what I can gather so far.
Your areas need to be in a container called demo area. Not sure how the space in the ID works so in my case I switched it to demoarea. Also somewhere in the page, there has to be another element called demo for anything to even happen.
Once that's done, the script loads demoarea into the elementPositions array. Judging from your description that's not what you want to do, you probably want to load all the elements inside demoareainto the array. So the first change is
$('#demo area').each(function() {
Becomes
$('#demoarea').children().each(function() {
Now what becomes confusing to me is that this script for whatever reason decides that you need to have another element called hover so it can move the element out of demoarea into hover when you mouse over it. If that is what you want, then you can do your show trick with some simple CSS.
<div style="display:none" id="overlayr6064"> Example Overlay ID name </div>
Becomes
<div id="overlayr6064"> Example Overlay ID name </div>
And then you add:
<style>
#demoarea div {
display: none;
}
#hover div {
display: block;
}
</style>
Assuming that is not what you wanted, what #liamEgan did to add the elements to the hoveredElements array is good, but you have an infinite loop here
for (var i = 0; hoveredElements.length; i++)
it should be
for (var i = 0; i < hoveredElements.length; i++)
Then the rest works... except one last thing, you want to load these listeners to your script when the page loads in a document ready method.
So in all it looks a bit like:
//display overlay ids by mousing over (my map is called 'demo')
var elementPositions = [];
var hoveredElements = [];
if($('#demo')) {
$('#demoarea').children().each(function() {
var offset = $(this).offset();
var top = offset.top;
var left = offset.left;
var bottom = $(window).height() - top - $(this).height();
var right = $(window).width() - left - $(this).width();
elementPositions.push({ element: $(this), top: top, bottom: bottom, left: left, right: right });
});
console.log('After Scanning demoarea elementPositions looks like:')
console.log(elementPositions);
$(document).ready(function () {
$("body").mousemove(function(e) {
hoveredElements = [];
var yPosition = e.pageX;
var xPosition = e.pageY;
for (var i = 0; i < elementPositions.length; i++) {
if (xPosition >= elementPositions[i].left &&
xPosition <= elementPositions[i].right &&
yPosition >= elementPositions[i].top &&
yPosition <= elementPositions[i].bottom) {
// The mouse is within the element's boundaries
if (typeof elementPositions[i].element != "undefined") {
hoveredElements.push(elementPositions[i].element);
$("#hovers").append(elementPositions[i].element);
}
}
} //end of for loop over all elements
for (var i = 0; i < hoveredElements.length; i++) { //for loop over all hovered elements
// The element as a jQuery object
console.log(hoveredElements[i]);
if (typeof hoveredElements[i] != "undefined") {
var elem = hoveredElements[i];
var id = elem.attr('id');
$('#overlay'+id).show();
}
// Do stuff to that jQuery element:
//??? something like elem.show();
}
});
});
}
#demoarea {
border: 2px blue dotted;
}
/* Border added so I can see where to mouse over */
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="demo">
<div id="demoarea">
<area shape="rect" coords="431,499,458,491" href="#" id="r6064" alt="r6064">
<div style="display:none" id="overlayr6064"> Example Overlay ID name </div>
</div>
<div id="hovers">
</div>
</div>
Edit: sorry I added the undefined tests while fixing this because of the infinite loop but I think they're not really needed. Still nice to have though. Also since the area also gets moved into the hover area this script does try to show an element called overlayoverlayr6064r6064 which fortunately doesn't exist. But ya, again, probably not what you had in mind.

Selecting next div with Button and changing the value

I have a 4 div elements each with their own value, for example 0. I have a button with a plus and minus that changes the value in each box. I also have a set next button so you can do the same thing to the next box.
The problem I'm facing is how to select the next div and change the value with the same plus and minus buttons and then selecting the next div and doing the same until you're at the end. It then has to return to the first div. Here is my code:
<div class="code_div">
<div class="code_area">
<p id="number1">00</p>
</div>
<div class="code_area2">
<p id="number2">00</p>
</div>
<div class="code_area3">
<p id="number3">00</p>
</div>
<div class="code_area4">
<p id="number4">00</p>
</div>
var value = 0;
var plus = false;
var minus = false;
$(document).ready(function() {
$('#set_next').click(function() {
});
$('#minus').click(function() {
minus = false;
plus = true;
if (plus == true) {
value -= 5;
}
displayValue()
});
$('#plus').click(function() {
minus = true;
plus = false;
if (minus == true) {
value += 5;
}
displayValue()
});
});
function displayValue() {
document.getElementById("number1").innerHTML = value;
}
Can anyone help me?
Keep it simple. You have a list of divs, so use a list instead. Even if you want to keep your original markup, this should give an idea on how to implement this.
var $items = $('ul li'),
qtItems = $items.length,
activeItem = 0;
$('#setnext').click(function () {
$items.removeClass('active').eq(++activeItem % qtItems).addClass('active');
});
$('#plus, #minus').click(function () {
var currvalue = $items.eq(activeItem % qtItems).text();
this.id === 'plus' ? currvalue++ : currvalue--;
$items.eq(activeItem % qtItems).text(currvalue);
});
ul {
list-style: none;
}
ul li {
display: inline-block;
margin: 0 1em;
padding: 1em;
background-color: green;
opacity: .5;
}
li.active {
opacity: 1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li class="active">0</li>
<li>0</li>
<li>0</li>
<li>0</li>
</ul>
<button id="setnext">set next</button>
<button id="plus">plus</button>
<button id="minus">minus</button>
But, if you cannot simplify your markup, here is another simple solution using your original html.
As you can see, you don't need all of those classes and ids.
var value = 0;
var plus = false;
var minus = false;
var index=1;
$( document ).ready(function() {
$('#set_next').click(function() {
index++;
//update
$("#number"+index).css("color","blue");
if(index==5){
index=1;
}
});
$('#minus').click(function() {
minus = false;
plus = true;
if (plus == true){
value -= 5;
}
displayValue()
});
$('#plus').click(function() {
minus = true;
plus = false;
if (minus == true){
value += 5;
}
displayValue()
});
});
function displayValue(){
document.getElementById("number"+index).innerHTML = value;
}
Although your code needs a lot of polishing (i can give you a cleaner approach if you want)
https://jsfiddle.net/cbw4zc55/
something along these lines?
html code:
<div class="code_div">
<div class="code_area">
<p id="number1">00</p>
</div>
<div class="code_area2">
<p id="number2">00</p>
</div>
<div class="code_area3">
<p id="number3">00</p>
</div>
<div class="code_area4">
<p id="number4">00</p>
</div>
<button id="set_next">set next</button>
<button id="minus">minus</button>
<button id="plus">plus</button>
javascript:
var current = 1;
var max = 4;
var value = 0;
var plus = false;
var minus = false;
$( document ).ready(function() {
$('#set_next').click(function() {
if( current < max )
{
current+=1;
}
else
{
current = 1;
}
value = parseInt($("#number"+current).text());
});
$('#minus').click(function() {
minus = false;
plus = true;
if (plus == true){
value -= 5;
}
displayValue()
});
$('#plus').click(function() {
minus = true;
plus = false;
if (minus == true){
value += 5;
}
displayValue()
});
});
function displayValue(){
document.getElementById("number"+current).innerHTML = value;
}
EDIT:
Note that you would need to recalculate the current element value each time you change your focus to a new one (aside from that the selected answer is just perfect as well)

How to increment margin value (or any style value) for each element using javascript?

I want left margin of every element in a class to have 70px left margin more than the last one. i.e. marginLeft += 70px;
Here's what I have tried:
function MarginLeftFunc()
{
var elements = document.getElementsByClassName('divClass');
var i;
for(i=0; i<elements.length; i++)
{
elements[i].style.marginLeft += 70 + "px";
console.log(elements[i].style.marginLeft);
}
}
window.addEventListener('load', MarginLeftFunc, false);
<body>
<div class="container">
<div class="divClass">Div1</div>
<div class="divClass">Div2</div>
<div class="divClass">Div3</div>
</div>
</body>
Now the console logs exactly 3 elements, which is good, but its not incrementing value of left margin. It set all the element's left Margins to 70px.
It just logs 70px 3 times. I have tried fiddling with variable 'i', inserting multiple loops, but have not found a solution yet. What do i have to do to increment value for each element? And no JQuery.
You can try use method getComputedStyle,
The Window.getComputedStyle() method gives the values of all the CSS
properties of an element after applying the active stylesheets and
resolving any basic computation those values may contain.
because element.style.marginLeft does not show styles that come from CSS rules.
function MarginLeftFunc() {
var elements = document.getElementsByClassName('divClass');
var i, marginLeft = 70;
for (i = 0; i < elements.length; i++) {
marginLeft += parseInt(window.getComputedStyle(elements[i]).marginLeft, 10) + 70;
elements[i].style.marginLeft = marginLeft + 'px';
}
}
window.addEventListener('load', MarginLeftFunc, false);
.divClass {
margin-left: 10px;
}
<div class="container">
<div class="divClass">Div1</div>
<div class="divClass">Div2</div>
<div class="divClass">Div3</div>
</div>
I think this is what you are looking for
function MarginLeftFunc()
{
var i;
var elements = document.getElementsByClassName('divClass');
var elementStyle = window.getComputedStyle(elements[0]);//gives the style of first element
var margleft =elementStyle.marginLeft;//get margin left value
margleft = margleft.replace("px", " ");//remove px
margleft = parseInt(margleft);//convert string to integer
for(i=0; i<elements.length; i++)
{
margleft+=70;
elements[i].style.marginLeft = margleft + "px";
console.log(elements[i].style.marginLeft);
}
}
window.addEventListener('load', MarginLeftFunc, false);
.divClass {
margin-left: 10px;
}
<div class="container">
<div class="divClass">Div1</div>
<div class="divClass">Div2</div>
<div class="divClass">Div3</div>
</div>

Javascript Drag and drop

I'm looking for someone to explain how to drag and drop in javascript, I want a horizontal line with some customizable images in it.
I've had a look at the online tutorials for these but find them very hard to use.
I would recommend that you look into one of the Javascript Frameworks out there. We use prototype with scriptaculous.
You can look at a demo for Drag and Drop in Scriptaculous here. And you can run through a tutorial here.
Or look into any of the other frameworks such as JQuery or Dojo.
Here is my code as it is...I have used this page to get this far..
It currently moves everything into column one, I think it's something to do with the mouse.
print("<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Page</title>
<--
<style type="text/css">
<!--
.DragContainer, .OverDragContainer {
float: left;
margin: 3px;
width: 100px;
border: #669999 2px solid;
padding: 5px;
}
.DragBox, .OverDragBox, .DragDragBox, .miniDragBox {
border: #000 1px solid;
padding: 2px;
font-size: 10px;
margin-bottom: 5px;
width: 94px;
cursor: pointer;
font-family: verdana, tahoma, arial;
background-color: #eee;
}
.OverDragContainer {
background-color: #eee;
}
.OverDragBox, .DragDragBox {
background-color: #ffff99;
}
.DragDragBox {
filter: alpha(opacity=50);
background-color: #ff99cc;
}
legend {
font-weight: bold;
font-size: 12px;
color: #666699;
font-family: verdana, tahoma, arial;
}
fieldset {
padding: 3px;
}
.History {
font-size: 10px;
overflow: auto;
width: 100%;
font-family: verdana, tahoma, arial;
height: 82px;
}
#DragContainer8 {
border: #669999 1px solid;
padding: 5px 0 0 5px
width: 110px;
height: 40px;
}
.miniDragBox {
float: left;
margin: 0 5px 5px 0;
width: 20px;
height: 20px;
}
-->
</style>
<--script type="text/javascript">
// iMouseDown represents the current mouse button state: up or down
/*
lMouseState represents the previous mouse button state so that we can
check for button clicks and button releases:
if(iMouseDown && !lMouseState) // button just clicked!
if(!iMouseDown && lMouseState) // button just released!
*/
var mouseOffset = null;
var iMouseDown = false;
var lMouseState = false;
var dragObject = null;
// Demo 0 variables
var DragDrops = [];
var curTarget = null;
var lastTarget = null;
var dragHelper = null;
var tempDiv = null;
var rootParent = null;
var rootSibling = null;
Number.prototype.NaN0=function(){return isNaN(this)?0:this;}
function CreateDragContainer(){
/*
Create a new "Container Instance" so that items from one "Set" can not
be dragged into items from another "Set"
*/
var cDrag = DragDrops.length;
DragDrops[cDrag] = [];
/*
Each item passed to this function should be a "container". Store each
of these items in our current container
*/
for(var i=0; i<arguments.length; i++){
var cObj = arguments[i];
DragDrops[cDrag].push(cObj);
cObj.setAttribute('DropObj', cDrag);
/*
Every top level item in these containers should be draggable. Do this
by setting the DragObj attribute on each item and then later checking
this attribute in the mouseMove function
*/
for(var j=0; j<cObj.childNodes.length; j++){
// Firefox puts in lots of #text nodes...skip these
if(cObj.childNodes[j].nodeName=='#text') continue;
cObj.childNodes[j].setAttribute('DragObj', cDrag);
}
}
}
function getMouseOffset(target, ev){
ev = ev || window.event;
var docPos = getPosition(target);
var mousePos = mouseCoords(ev);
return {x:mousePos.x - docPos.x, y:mousePos.y - docPos.y};
}
function getPosition(e){
var left = 0;
var top = 0;
while (e.offsetParent){
left += e.offsetLeft;
top += e.offsetTop;
e = e.offsetParent;
}
left += e.offsetLeft;
top += e.offsetTop;
return {x:left, y:top};
}
function makeDraggable(item){
if(!item) return;
item.onmousedown = function(ev){
dragObject = this;
mouseOffset = getMouseOffset(this, ev);
return false;
}
}
function makeClickable(object){
object.onmousedown = function(){
dragObject = this;
}
}
function mouseCoords(ev){
if(ev.pageX || ev.pageY){
return {x:ev.pageX, y:ev.pageY};
}
return {
x:ev.clientX + document.body.scrollLeft - document.body.clientLeft,
y:ev.clientY + document.body.scrollTop - document.body.clientTop
};
}
function mouseMove(ev){
ev = ev || window.event;
/*
We are setting target to whatever item the mouse is currently on
Firefox uses event.target here, MSIE uses event.srcElement
*/
var target = ev.target || ev.srcElement;
var mousePos = mouseCoords(ev);
// mouseOut event - fires if the item the mouse is on has changed
if(lastTarget && (target!==lastTarget)){
// reset the classname for the target element
var origClass = lastTarget.getAttribute('origClass');
if(origClass) lastTarget.className = origClass;
}
/*
dragObj is the grouping our item is in (set from the createDragContainer function).
if the item is not in a grouping we ignore it since it can't be dragged with this
script.
*/
var dragObj = target.getAttribute('DragObj');
// if the mouse was moved over an element that is draggable
if(dragObj!=null){
// mouseOver event - Change the item's class if necessary
if(target!=lastTarget){
var oClass = target.getAttribute('overClass');
if(oClass){
target.setAttribute('origClass', target.className);
target.className = oClass;
}
}
// if the user is just starting to drag the element
if(iMouseDown && !lMouseState){
// mouseDown target
curTarget = target;
// Record the mouse x and y offset for the element
rootParent = curTarget.parentNode;
rootSibling = curTarget.nextSibling;
mouseOffset = getMouseOffset(target, ev);
// We remove anything that is in our dragHelper DIV so we can put a new item in it.
for(var i=0; i<dragHelper.childNodes.length; i++) dragHelper.removeChild(dragHelper.childNodes[i]);
// Make a copy of the current item and put it in our drag helper.
dragHelper.appendChild(curTarget.cloneNode(true));
dragHelper.style.display = 'block';
// set the class on our helper DIV if necessary
var dragClass = curTarget.getAttribute('dragClass');
if(dragClass){
dragHelper.firstChild.className = dragClass;
}
// disable dragging from our helper DIV (it's already being dragged)
dragHelper.firstChild.removeAttribute('DragObj');
/*
Record the current position of all drag/drop targets related
to the element. We do this here so that we do not have to do
it on the general mouse move event which fires when the mouse
moves even 1 pixel. If we don't do this here the script
would run much slower.
*/
var dragConts = DragDrops[dragObj];
/*
first record the width/height of our drag item. Then hide it since
it is going to (potentially) be moved out of its parent.
*/
curTarget.setAttribute('startWidth', parseInt(curTarget.offsetWidth));
curTarget.setAttribute('startHeight', parseInt(curTarget.offsetHeight));
curTarget.style.display = 'none';
// loop through each possible drop container
for(var i=0; i<dragConts.length; i++){
with(dragConts[i]){
var pos = getPosition(dragConts[i]);
/*
save the width, height and position of each container.
Even though we are saving the width and height of each
container back to the container this is much faster because
we are saving the number and do not have to run through
any calculations again. Also, offsetHeight and offsetWidth
are both fairly slow. You would never normally notice any
performance hit from these two functions but our code is
going to be running hundreds of times each second so every
little bit helps!
Note that the biggest performance gain here, by far, comes
from not having to run through the getPosition function
hundreds of times.
*/
setAttribute('startWidth', parseInt(offsetWidth));
setAttribute('startHeight', parseInt(offsetHeight));
setAttribute('startLeft', pos.x);
setAttribute('startTop', pos.y);
}
// loop through each child element of each container
for(var j=0; j<dragConts[i].childNodes.length; j++){
with(dragConts[i].childNodes[j]){
if((nodeName=='#text') || (dragConts[i].childNodes[j]==curTarget)) continue;
var pos = getPosition(dragConts[i].childNodes[j]);
// save the width, height and position of each element
setAttribute('startWidth', parseInt(offsetWidth));
setAttribute('startHeight', parseInt(offsetHeight));
setAttribute('startLeft', pos.x);
setAttribute('startTop', pos.y);
}
}
}
}
}
// If we get in here we are dragging something
if(curTarget){
// move our helper div to wherever the mouse is (adjusted by mouseOffset)
dragHelper.style.top = mousePos.y - mouseOffset.y;
dragHelper.style.left = mousePos.x - mouseOffset.x;
var dragConts = DragDrops[curTarget.getAttribute('DragObj')];
var activeCont = null;
var xPos = mousePos.x - mouseOffset.x + (parseInt(curTarget.getAttribute('startWidth')) /2);
var yPos = mousePos.y - mouseOffset.y + (parseInt(curTarget.getAttribute('startHeight'))/2);
// check each drop container to see if our target object is "inside" the container
for(var i=0; i<dragConts.length; i++){
with(dragConts[i]){
if(((getAttribute('startLeft')) < xPos) &&
((getAttribute('startTop')) < yPos) &&
((getAttribute('startLeft') + getAttribute('startWidth')) > xPos) &&
((getAttribute('startTop') + getAttribute('startHeight')) > yPos)){
/*
our target is inside of our container so save the container into
the activeCont variable and then exit the loop since we no longer
need to check the rest of the containers
*/
activeCont = dragConts[i];
// exit the for loop
break;
}
}
}
// Our target object is in one of our containers. Check to see where our div belongs
if(activeCont){
// beforeNode will hold the first node AFTER where our div belongs
var beforeNode = null;
// loop through each child node (skipping text nodes).
for(var i=activeCont.childNodes.length-1; i>=0; i--){
with(activeCont.childNodes[i]){
if(nodeName=='#text') continue;
// if the current item is "After" the item being dragged
if(
curTarget != activeCont.childNodes[i] &&
((getAttribute('startLeft') + getAttribute('startWidth')) > xPos) &&
((getAttribute('startTop') + getAttribute('startHeight')) > yPos)){
beforeNode = activeCont.childNodes[i];
}
}
}
// the item being dragged belongs before another item
if(beforeNode){
if(beforeNode!=curTarget.nextSibling){
activeCont.insertBefore(curTarget, beforeNode);
}
// the item being dragged belongs at the end of the current container
} else {
if((curTarget.nextSibling) || (curTarget.parentNode!=activeCont)){
activeCont.appendChild(curTarget);
}
}
// make our drag item visible
if(curTarget.style.display!=''){
curTarget.style.display = '';
}
} else {
// our drag item is not in a container, so hide it.
if(curTarget.style.display!='none'){
curTarget.style.display = 'none';
}
}
}
// track the current mouse state so we can compare against it next time
lMouseState = iMouseDown;
// mouseMove target
lastTarget = target;
// track the current mouse state so we can compare against it next time
lMouseState = iMouseDown;
// this helps prevent items on the page from being highlighted while dragging
return false;
}
function mouseUp(ev){
if(curTarget){
// hide our helper object - it is no longer needed
dragHelper.style.display = 'none';
// if the drag item is invisible put it back where it was before moving it
if(curTarget.style.display == 'none'){
if(rootSibling){
rootParent.insertBefore(curTarget, rootSibling);
} else {
rootParent.appendChild(curTarget);
}
}
// make sure the drag item is visible
curTarget.style.display = '';
}
curTarget = null;
iMouseDown = false;
}
function mouseDown(){
iMouseDown = true;
if(lastTarget){
return false;
}
}
document.onmousemove = mouseMove;
document.onmousedown = mouseDown;
document.onmouseup = mouseUp;
window.onload = function(){
// Create our helper object that will show the item while dragging
dragHelper = document.createElement('DIV');
dragHelper.style.cssText = 'position:absolute;display:none;';
CreateDragContainer(
document.getElementById('DragContainer1'),
document.getElementById('DragContainer2'),
document.getElementById('DragContainer3')
);
document.body.appendChild(dragHelper);
}
</script><!--the mouse over and dragging class are defined on each item-->
</head>
<body>
<br/>
<div class="DragContainer" id="DragContainer1">
<div class="DragBox" id="Item1" overClass="OverDragBox" dragClass="DragDragBox">Item #1</div>
<div class="DragBox" id="Item2" overClass="OverDragBox" dragClass="DragDragBox">Item #2</div>
<div class="DragBox" id="Item3" overClass="OverDragBox" dragClass="DragDragBox">Item #3</div>
<div class="DragBox" id="Item4" overClass="OverDragBox" dragClass="DragDragBox">Item #4</div>
</div>
<div class="DragContainer" id="DragContainer2">
<div class="DragBox" id="Item5" overClass="OverDragBox" dragClass="DragDragBox">Item #5</div>
<div class="DragBox" id="Item6" overClass="OverDragBox" dragClass="DragDragBox">Item #6</div>
<div class="DragBox" id="Item7" overClass="OverDragBox" dragClass="DragDragBox">Item #7</div>
<div class="DragBox" id="Item8" overClass="OverDragBox" dragClass="DragDragBox">Item #8</div>
</div>
<div class="DragContainer" id="DragContainer3">
<div class="DragBox" id="Item9" overClass="OverDragBox" dragClass="DragDragBox">Item #9</div>
<div class="DragBox" id="Item10" overClass="OverDragBox" dragClass="DragDragBox">Item #10</div>
<div class="DragBox" id="Item11" overClass="OverDragBox" dragClass="DragDragBox">Item #11</div>
<div class="DragBox" id="Item12" overClass="OverDragBox" dragClass="DragDragBox">Item #12</div>
</div>
<br/>
</body>
</html>
");
Find 2x of:
dragHelper.style.top = mousePos.y - mouseOffset.y;
dragHelper.style.left = mousePos.x - mouseOffset.x;
change to:
dragHelper.style.top = mousePos.y - mouseOffset.y + 'px';
dragHelper.style.left = mousePos.x - mouseOffset.x + 'px';
Works on FF. 3.6
the answer is here jQuery drag-and-drop DIV selection with images and text
<script type="text/javascript" src="http://www.dynamicdrive.com/dynamicindex11/domdrag/dom-drag.js"></script>
<script type="text/javascript">
Drag.init(document.getElementById("exampleid")); //sets the id to look for to make object draggable
</script>

Categories

Resources