I'm uploading a text file into my homepage and it's currently loading into a text area.
The issue is I want to drag and drop individual words into a different html element which I don't think is possible from text area elements in html?
Is there a way around this with html or JavaScript?
I would suggest you to create draggable elements for each of the words once you upload the file:
<span class="word" draggable="true">word</span>
So then you could apply the standard HTML5 drag and drop behavior on these span elements. Check out the example below:
const words = 'words from file';
const container = document.getElementById('container');
let dragged;
container.innerHTML = words.split(' ').map(w => `<span class="word" draggable="true">${w}</span>`).join('');
function onDragOver(event) {
// Prevent default to allow drop
event.preventDefault();
}
function onDragLeave(event) {
event.target.style.background = '';
}
function onDragEnter(event) {
const target = event.target;
if (target && dragged && target.classList.contains('drop-zone')) {
event.preventDefault();
// Set the dropEffect to move
event.dataTransfer.dropEffect = 'move'
target.style.background = '#1f904e';
}
}
function onDrop(event) {
const target = event.target;
if (target && dragged && target.classList.contains('drop-zone')) {
target.style.backgroundColor = '';
event.preventDefault();
// Get the id of the target and add the moved element to the target's DOM
dragged.parentNode.removeChild(dragged);
dragged.style.opacity = '';
target.appendChild(dragged);
}
}
function onDragStart(event) {
dragged = event.target;
event.dataTransfer.setData('text', event.target.id);
event.dataTransfer.dropEffect = 'move';
// Make it half transparent
event.target.style.opacity = .3;
}
function onDragEnd(event) {
// Reset the transparency
event.target.style.opacity = ''; // reset opacity when drag ends
dragged = null;
}
for (word of document.getElementsByClassName('word')) {
word.addEventListener('dragstart', onDragStart);
word.addEventListener('dragend', onDragEnd);
}
for (dropZone of document.getElementsByClassName('drop-zone')) {
dropZone.addEventListener('drop', onDrop);
dropZone.addEventListener('dragenter', onDragEnter);
dropZone.addEventListener('dragleave', onDragLeave);
dropZone.addEventListener('dragover', onDragOver);
}
.drop-zone {
position: relative;
width: 100px;
height: 30px;
overflow: hidden;
background: #878787;
color: white;
display: flex;
align-items: center;
justify-content: center;
margin: 5px 0;
}
.word {
margin: 0 2px;
}
<div id=container></div>
<div class='drop-zone'></div>
<div class='drop-zone'></div>
<div class='drop-zone'></div>
Related
Im trying to create a 2 rows 3 columns puzzle using CSS and JavaScript. The idea is that the pieces of the puzzle will be all black cut in different shapes. The users has to drag the pieces to board to complete it.I wrote a javascript that creates the board and pieces. Made them draggable too but unable to proceed from here. Need help in changing the shape of pieces from square to other shapes.
var rows = 5;
var columns = 5;
var currTile;
var otherTile;
var turns = 0;
window.onload = function() {
//initialize the 5x5 board
for (let r = 0; r < rows; r++) {
for (let c = 0; c < columns; c++) {
//<img>
let tile = document.createElement("img");
tile.src = "blank.png";
//DRAG FUNCTIONALITY
tile.addEventListener("dragstart", dragStart); //click on image to drag
tile.addEventListener("dragover", dragOver); //drag an image
tile.addEventListener("dragenter", dragEnter); //dragging an image into another one
tile.addEventListener("dragleave", dragLeave); //dragging an image away from another one
tile.addEventListener("drop", dragDrop); //drop an image onto another one
tile.addEventListener("dragend", dragEnd); //after you completed dragDrop
document.getElementById("board").append(tile);
}
}
//pieces
let pieces = [];
for (let i = 1; i <= rows * columns; i++) {
pieces.push(i.toString()); //put "1" to "25" into the array (puzzle images names)
}
pieces.reverse();
for (let i = 0; i < pieces.length; i++) {
let j = Math.floor(Math.random() * pieces.length);
//swap
let tmp = pieces[i];
pieces[i] = pieces[j];
pieces[j] = tmp;
}
for (let i = 0; i < pieces.length; i++) {
let tile = document.createElement("img");
tile.src = "blank2.png";
//DRAG FUNCTIONALITY
tile.addEventListener("dragstart", dragStart); //click on image to drag
tile.addEventListener("dragover", dragOver); //drag an image
tile.addEventListener("dragenter", dragEnter); //dragging an image into another one
tile.addEventListener("dragleave", dragLeave); //dragging an image away from another one
tile.addEventListener("drop", dragDrop); //drop an image onto another one
tile.addEventListener("dragend", dragEnd); //after you completed dragDrop
document.getElementById("pieces").append(tile);
}
}
//DRAG TILES
function dragStart() {
currTile = this; //this refers to image that was clicked on for dragging
}
function dragOver(e) {
e.preventDefault();
}
function dragEnter(e) {
e.preventDefault();
}
function dragLeave() {
}
function dragDrop() {
otherTile = this; //this refers to image that is being dropped on
}
function dragEnd() {
if (currTile.src.includes("blank")) {
return;
}
let currImg = currTile.src;
let otherImg = otherTile.src;
currTile.src = otherImg;
otherTile.src = currImg;
turns += 1;
document.getElementById("turns").innerText = turns;
}
body {
font-family: Arial, Helvetica, sans-serif;
text-align: center;
}
#board {
width: 400px;
height: 400px;
border: 2px solid purple;
margin: 0 auto;
display: flex;
flex-wrap: wrap;
}
#board img {
width: 79px;
height: 79px;
border: 0.5px solid lightblue;
}
#pieces {
width: 1040px;
height: 160px;
border: 2px solid purple;
margin: 0 auto;
display: flex;
flex-wrap: wrap;
}
#pieces img {
width: 79px;
height: 79px;
border: 0.5px solid lightblue;
}
<body>
<br>
<div id="board"></div>
<div id="pieces">
</div>
</body>
now, you can add event lister to the puzzle to handle dragover event with preventDefault() method to allow the drop to occur.
Then, in the event handler, you can retrieve the ID of the puzzle piece being dropped using getdata() method of the datatransfer object with following code:
boardElement.addEventListener("drop", e => {
// Get the ID of the puzzle piece being dropped
const id = e.dataTransfer.getData("text/plain");
// Find the puzzle piece
const piece = puzzlePieces.find(piece => piece.id === id);
// Update the color of the puzzle piece
piece.color = "black";
// Render the puzzle board
render();
});
Then, you can add event dragenter in drag-over class in boardelemennt and dragleave to release the drag.
I'm trying to come up with a cross-device code that handles pointer events.
I'm running this code successfully on Chrome/Android (using USB debugging), but the Chrome desktop just acts up and keeps firing pointermove after the mouse has been released.
(Another problem is that the moves are not as smooth as on the mobile)
Playable demo
These SO posts don't solve my problem:
event-listener-with-pointerup-not-firing-when-activated-from-touchscreen
pointerup-event-does-not-fire-for-mouse-actions-on-a-link-when-pointermove-has-b
The "pointerup" Event is assigned to the #canvas, but such event will never occur because the mouse is actually above the generated DIV circle.
Since your circles are just visual helpers, set in CSS
.dot {
/* ... */
pointer-events: none;
}
Also, make sure to use Event.preventDefault() on "pointerdown".
Regarding the other strategies for a seamless experience, both on desktop and on mobile (touch):
assign only the "pointerdown" Event to a desired Element (canvas in your case)
use the window object for all the other events
Edited example:
const canvas = document.getElementById('canvas');
function startTouch(ev) {
ev.preventDefault();
const dot = document.createElement('div');
dot.classList.add('dot');
dot.id = ev.pointerId;
dot.style.left = `${ev.pageX}px`;
dot.style.top = `${ev.pageY}px`;
document.body.append(dot);
}
function moveTouch(ev) {
const dot = document.getElementById(ev.pointerId);
if (!dot) return;
dot.style.left = `${ev.pageX}px`;
dot.style.top = `${ev.pageY}px`;
}
function endTouch(ev) {
const dot = document.getElementById(ev.pointerId);
if (!dot) return;
removeDot(dot);
}
function removeDot(dot) {
dot.remove();
}
canvas.addEventListener('pointerdown', startTouch);
addEventListener('pointermove', moveTouch);
addEventListener('pointerup', endTouch);
addEventListener('pointercancel', endTouch);
.dot {
background-color: deeppink;
width: 2rem;
height: 2rem;
border-radius: 50%;
transform: translate(-50%, -50%);
position: absolute;
pointer-events: none; /* ADD THIS! */
}
#canvas {
height: 50vh;
background-color: black;
touch-action: none;
}
body {
margin: 0;
}
<div id="canvas"></div>
The code needs also this improvement:
Don't query the DOM inside a pointermove event
Using CSS vars
As per the comments section here's a viable solution that uses custom properties CSS variables and JS's CSSStyleDeclaration.setProperty() method.
Basically the --x and --y CSS properties values are updated from the pointerdown/move event handlers to reflect the current clientX and clientY values:
const el = (sel, par) => (par || document).querySelector(sel);
const elNew = (tag, prop) => Object.assign(document.createElement(tag), prop);
const canvas = document.getElementById('canvas');
const pointersDots = (parent) => {
const elParent = typeof parent === "string" ? el(parent) : parent;
const dots = new Map();
const moveDot = (elDot, {clientX: x,clientY: y}) => {
elDot.style.setProperty("--x", x);
elDot.style.setProperty("--y", y);
};
const onDown = (ev) => {
ev.preventDefault();
const elDot = elNew("div", { className: "dot" });
moveDot(elDot, ev);
elParent.append(elDot);
dots.set(ev.pointerId, elDot);
};
const onMove = (ev) => {
if (dots.size === 0) return;
const elDot = dots.get(ev.pointerId);
moveDot(elDot, ev);
};
const onUp = (ev) => {
if (dots.size === 0) return;
const elDot = dots.get(ev.pointerId);
elDot.remove();
dots.delete(ev.pointerId);
};
canvas.addEventListener('pointerdown', onDown);
addEventListener('pointermove', onMove);
addEventListener('pointerup', onUp);
addEventListener('pointercancel', onUp);
};
// Init: Pointers helpers
pointersDots("#canvas");
* {
margin: 0;
}
.dot {
--x: 0;
--y: 0;
pointer-events: none;
position: absolute;
width: 2rem;
height: 2rem;
border-radius: 50%;
background-color: deeppink;
transform: translate(-50%, -50%);
left: calc(var(--x) * 1px);
top: calc(var(--y) * 1px);
}
#canvas {
margin: 10vh;
height: 80vh;
background-color: black;
touch-action: none;
}
<div id="canvas"></div>
here is what i try to code
i want my mouse click on any element on page and target will boxshadow ,
and after i click the element i can click another element and the previus element will lost its boxshadow and i am using code like this
document.onclick = function(evt){
console.log('clicked');
var target = null,
target = evt.target;
var obj = document.querySelector(target);
obj.style.boxShadow = '3px 10px 100px yellow';
if(target === 'null'){
console.log('ye');
obj.style.boxShadow = '0';
obj = document.querySelector(target)
console.log(obj)}
return target}
Add element selector once you have applied css and select those elements using provided selector.
Remove applied css by selecting applied attribute.
document.onclick = function(evt) {
var target = evt.target;
var pastElems = document.querySelectorAll('.shadowed');
[].forEach.call(pastElems, function(el) {
el.style.boxShadow = 'none';
target.classList.remove('shadowed');
})
target.style.boxShadow = '3px 10px 100px yellow';
target.classList.add('shadowed');
}
.elem {
width: 100px;
height: 100px;
border: 1px solid black;
float: left;
}
<div class='elem'></div>
<div class='elem'></div>
<div class='elem'></div>
<div class='elem'></div>
It's easier to change styling by adding/removing classes.
If you use an object, it will allow you to keep track of what element currently has the shadow and remove the class from it.
var setBoxShadow = {
target: null,
clearShadow: function() {
if (this.target != null && this.target != undefined) {
this.target.classList.remove("highlight");
}
},
addShadow: function(newTarget) {
this.target = newTarget;
this.target.classList.add("highlight");
},
}
body.onclick = function(evt) {
setBoxShadow.clearShadow();
setBoxShadow.addShadow(evt.target);
}
And the CSS:
.highlight {
box-shadow: 3px 10px 100px yellow;
}
I have implemented the drag and drop API of HTML5 in my app, and I need to disable the default ghost image when the user drag an item.
The items aren't images but row from a table like :
<table>
<tr draggable droppable ><td></td></tr>
<tr draggable droppable ><td></td></tr>
<tr draggable droppable ><td></td></tr>
</table>
Each row can be draggable in to another one (see it as a filesystem with folder and files).
In my dragstart I've done something like this to hide the default ghost image :
e.originalEvent.dataTransfer.setDragImage(disableImg[0], 0, 0);
Where diableImg is a dom element with 0 width and 0 height opacity 0 etc...
The issue here is that this is not working for IE since it doesn't support the setDragImage.
Is there another way to disable this ghost image of my row on drag ?
I just need to have it working from IE 11 -> Edge.
Thanks.
Example of set custom ghost image in IE.
var ghostImg = document.getElementById("ghostImg");
document.getElementById('dragme').addEventListener('dragstart', function(e) {
var target = e.srcElement || e.target;
var cloneNode = target.cloneNode(true);
target.parentNode.insertBefore(cloneNode, target);
target.style.display = "none";
window.setTimeout(function() {
target.parentNode.removeChild(cloneNode);
target.style.display = "block";
}, 0);
ghostImg.style.zIndex = '99';
ghostImg.style.visibility = 'visible'
ghostImg.style.top = e.clientY + 'px';
ghostImg.style.left = e.clientX + 'px';
})
document.getElementById('dragme').addEventListener('drag', function(e) {
ghostImg.style.zIndex = '99';
ghostImg.style.top = e.clientY + 'px';
ghostImg.style.left = e.clientX + 'px';
});
document.getElementById('dragme').addEventListener('dragend', function(e) {
ghostImg.removeAttribute('style');
});
#dragme {
width: 100px;
height: 100px;
background: #78ebff;
border: 1px solid #56bdff;
text-align: center;
line-height: 100px;
border-radius: 10px;
}
#ghostImg {
position: fixed;
left: 0;
top: 0;
z-index: -1;
visibility: hidden;
}
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div id="dragme" draggable="true">
Drag me
</div>
<img id="ghostImg" src="data:image/png;base64,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"/>
</body>
</html>
On dragStart event, implement:
function dragStart(e)
{
var target = e.srcElement || e.target;
if (isIEBrowser()) // check its IE browser
{
var cloneNode = target.cloneNode(true);
target.parentNode.insertBefore(cloneNode, target);
target.style.visibility = "collapse";
window.setTimeout(() => {
target.parentNode.removeChild(cloneNode);
target.style.visibility = "visible";
}, 0);
}
}
I was having this problem as well. I simply set the display to none before the drag.
if (event.dataTransfer.setDragImage)
{
let dragImage = document.createElement("div");
dragImage.style.visibility = "hidden";
event.dataTransfer.setDragImage(dragImage, 0, 0);
}
else
{
//Well if we cannot remove the ghost image then we need to make the initial image invisible when a ghost image would be captured
//then make the item visible again.
var initialDisplay = event.srcElement.style.display;
event.srcElement.style.display = "none";
window.setTimeout(() =>
{
event.srcElement.style.display = initialDisplay;
});
}
Seems after 1 frame (notice the settimeout doesn't specify a delay time) the display went back to normal, but when the ghost image was captured it was invisible.
I need to set the icon for cursor when a user is dragging DIV (red div in the following example).
I have tried several attempt, including using CSS cursor:move and event.dataTransfer.dropEffect with no success, as the icon always show up a "crossed circle".
Any ideas how to solve this issue using HTML5 drag-and-drop API?
http://jsbin.com/hifidunuqa/1/
<script>
window.app = {
config: {
canDrag: false,
cursorOffsetX: null,
cursorOffsetY: null
},
reset: function () {
this.config.cursorOffsetX = null;
this.config.cursorOffsetY = null;
},
start: function () {
document.getElementById('target').addEventListener('dragstart', function (event) {
console.log('+++++++++++++ dragstart')
this.config.cursorOffsetX = event.offsetX;
this.config.cursorOffsetY = event.offsetY;
this.adjustPostion(event);
event.dataTransfer.effectAllowed = 'move';
event.dataTransfer.dropEffect = 'move';
}.bind(this));
document.getElementById('target').addEventListener('drag', function (event) {
console.log('+++++++++++++ drag')
this.adjustPostion(event);
}.bind(this));
document.getElementById('target').addEventListener('dragend', function (event) {
console.log('+++++++++++++ dragend')
this.reset();
}.bind(this));;
},
adjustPostion: function (event) {
if (event.pageX <= 0 || event.pageY <= 0) {
console.log('skipped');
return;
}
var elm = document.getElementById('target');
elm.style.left = (event.pageX - this.config.cursorOffsetX) + 'px';
elm.style.top = (event.pageY - this.config.cursorOffsetY) + 'px';
console.log(event.pageX);
console.log(event.pageY);
}
};
</script>
use mousedown and mousemove
window.app = {
dragging: false,
config: {
canDrag: false,
cursorOffsetX: null,
cursorOffsetY: null
},
reset: function () {
this.config.cursorOffsetX = null;
this.config.cursorOffsetY = null;
},
start: function () {
document.getElementById('target').addEventListener('mousedown', function (event) {
console.log('+++++++++++++ dragstart');
this.dragging = true;
this.config.cursorOffsetX = event.offsetX;
this.config.cursorOffsetY = event.offsetY;
this.adjustPostion(event);
}.bind(this));
document.getElementById('target').addEventListener('mousemove', function (event) {
if (this.dragging) {
console.log('+++++++++++++ drag');
event.target.style.cursor = 'move';
this.adjustPostion(event);
}
}.bind(this));
document.getElementById('target').addEventListener('mouseup', function (event) {
console.log('+++++++++++++ dragend');
this.dragging = false;
event.target.style.cursor = 'pointer';
this.reset();
}.bind(this));
},
adjustPostion: function (event) {
if (event.clientX <= 0 || event.clientY <= 0) {
console.log('skipped');
return;
}
var elm = document.getElementById('target');
elm.style.left = (event.clientX - this.config.cursorOffsetX) + 'px';
elm.style.top = (event.clientY - this.config.cursorOffsetY) + 'px';
console.log(event.pageX);
console.log(event.pageY);
}
};
#target {
position: absolute;
top: 100px;
left: 100px;
width: 400px;
height: 400px;
background-color: red;
-moz-user-select: none;
-ms-user-select: none;
-webkit-user-select: none;
user-select: none;
}
#ui1 {
position: absolute;
top: 50px;
left: 50px;
width: 100px;
height: 400px;
background-color: blue;
z-index: 100;
}
#ui2 {
position: absolute;
top: 50px;
left: 550px;
width: 100px;
height: 400px;
background-color: green;
z-index: 100;
}
<!-- simulate -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>title</title>
</head>
<body onload="window.app.start();">
<div id="ui1"></div>
<div id="ui2"></div>
<div id="target"></div>
</body>
</html>
Do you actually need the Drag API? I found that I was using the Drag API because I was having trouble with the reliability of mouse events (mouseups not being captured, for example).
The Drag API is only for drag-and-drop functionality, and, if you're simply fiddling with the reliability of your clicking and pointing events, a new API, .setPointerCapture is made to handle these cases more effectively. Here's the minimal viable way to achieve this:
el.onpointerdown = ev => {
el.onpointermove = pointerMove
el.setPointerCapture(ev.pointerId)
}
pointerMove = ev => {
console.log('Dragged!')
}
el.onpointerUp = ev => {
el.onpointermove = null
el.releasePointerCapture(ev.pointerId)
}
Beautifully, you will maintain full control over your cursor's display style.
I didn't care about a particular cursor, I just wanted to get rid of the "crossed circle" one. My solution was to include dragover event (with following function) to all elements, that already had dragenter, dragstart and dragend events.
function dragover(event)
{
event.dataTransfer.dropEffect = "move";
event.preventDefault();
}
Adding event.dataTransfer.setData(); should solve the problem. Once the element is recognized as draggable the browser will add a move cursor automatically once you drag. Of course, you will have to remove all other cursor: move declarations to see the cursor changing while dragging.
Minimal example:
document.getElementById('target').addEventListener('dragstart', function (event) {
event.dataTransfer.setData( 'text/plain', '' );
}.bind(this));
If you still want to change the icon (e.g. to use a custom drag icon), you could access the element style using event.target.style.cursor.
For more info see MDN Drag & Drop and MDN Recommended Drag Types