I'm looking to change opacity and then completely hide div on swipe up on certain threshold, like in the video below or in Photoswipe:
https://www.loom.com/share/29741bdadc7846bfbc747d3870815340
Unfortunately most off libraries only allow to register actual event start end, but not the amount of swiped pixels. How would I get the actual swiped distance and connect it to the swipe event?
Note: You can apply the animations used in this example on other elements like an overlay instead. The technique is the same.
Here is some code to move up an element, fade it out and remove it from display. Note that I only implemented the PointerEvent-api. You should also implement a fallback.
A summary about what is going on:
Detect a pointerdown on the element and allow the pointer to be used outside the element with setPointerCapture().
Detect a pointermove on the element. If the mouse/touch is moved up, also move up the element. ( I also restricted movement to the left, right, bottom, but you don't have to)
Detect a pointerup. After releasePointerCapture() the pointer will once more only be available in the default element and not outside it. Depending on the amount the element has moved up, the element is returned to its original position or animated out.
class SwipeOutBehaviour {
constructor(element) {
this.element = element;
this.dy = null;
this.initial_y = null;
this.animation_frame_state = 'completed';
if( window.PointerEvent ) {
this.element.addEventListener('pointerdown', this.start_drag.bind(this), true);
this.element.addEventListener('pointermove', this.drag.bind(this), true);
this.element.addEventListener('pointerup', this.drag_end.bind(this), true);
} else {
//should use composition instead if you re serious, for this example I only implemented PointerEvent some browsers will use Tpuchevent and MouseEvent
}
}
start_drag( event ){
event.preventDefault();
// only respond to a single touch
if( event.touches && event.touches.length > 1 ) return;
// allow pointerevents outside the target
event.target.setPointerCapture(event.pointerId);
// set initial pos
this.initial_y = ( event.targetTouches ) ? event.targetTouches[0].clientY : event.clientY;
}
drag( event ){
event.preventDefault();
if( this.initial_y === null ) return;
if( this.animation_frame_state === 'pending' ) return;
this.dy = ( event.targetTouches ) ? Math.floor( event.targetTouches[0].clientY - this.initial_y ) : Math.floor( event.clientY - this.initial_y );
if( this.dy > 0 ) return;
this.animation_frame_state = 'pending'
window.requestAnimationFrame( () => {
this.element.style.transform = `translateY(${this.dy}px)`
this.animation_frame_state = 'completed';
});
}
drag_end(event) {
event.preventDefault();
if(event.touches && event.touches.length > 0) return;
event.target.releasePointerCapture(event.pointerId);
if( this.dy < -100 ) {
window.requestAnimationFrame( () => {
this.element.style.transition = 'opacity 500ms, translateY 200ms';
this.element.style.transform = `translateY(-175px)`;
this.element.style.opacity = `0`;
this.animation_frame_state = 'completed';
window.setTimeout( () => {
// set display to none, you could remove it from the DOM instead
this.element.style.display = 'none';
}, 500)
});
} else {
window.requestAnimationFrame( () => {
this.element.style.transform = `translateY(0px)`
this.animation_frame_state = 'completed';
});
}
this.initial_y = null;
}
}
let element = document.getElementById('container');
new SwipeOutBehaviour( element );
#container {
margin: auto;
width: 150px;
height: 150px;
border: 1px solid black;
}
#box-of-doom {
margin: auto;
width: 200px;
height: 200px;
border: 1px solid red;
background: orange;
}
p {
text-align: center;
}
<p>Drag the item in the box of doom<p>
<div id='box-of-doom'>
<p>The box of doom<p>
</div>
<div id='container'>
<img alt='a placeholder' src='https://via.placeholder.com/150' />
</div>
Note: This answer is inspired by this documentation/article from Google about touch events, so you may want to read more there.
With a lot of event listeners and computed properties; I made a quick code pen using W3's draggable function, but added the opacity change myself:
// Make the DIV element draggable:
dragElement(document.getElementById("mydiv"));
function dragElement(elmnt) {
var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
if (document.getElementById(elmnt.id + "header")) {
// if present, the header is where you move the DIV from:
document.getElementById(elmnt.id + "header").onmousedown = dragMouseDown;
} else {
// otherwise, move the DIV from anywhere inside the DIV:
elmnt.onmousedown = dragMouseDown;
}
function dragMouseDown(e) {
e = e || window.event;
e.preventDefault();
// get the mouse cursor position at startup:
pos3 = e.clientX;
pos4 = e.clientY;
document.onmouseup = closeDragElement;
// call a function whenever the cursor moves:
document.onmousemove = elementDrag;
}
function elementDrag(e) {
e = e || window.event;
e.preventDefault();
// calculate the new cursor position:
pos1 = pos3 - e.clientX;
pos2 = pos4 - e.clientY;
pos3 = e.clientX;
pos4 = e.clientY;
// set the element's new position:
elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
//change background opacity:
const background = document.getElementById("background");
const bgHeight = background.offsetHeight;
const elmntHeight = elmnt.offsetHeight;
const adjustedBottom = bgHeight - elmntHeight;
const percentage = 1 - elmnt.offsetTop / adjustedBottom;
console.log(percentage)
background.style.opacity = percentage;
}
function closeDragElement() {
// stop moving when mouse button is released:
document.onmouseup = null;
document.onmousemove = null;
}
}
body {
margin: 0;
}
#background {
background: black;
width: 100vw;
height: 100vh;
position: absolute;
}
#mydiv {
position: absolute;
z-index: 9;
background-color: #f1f1f1;
border: 1px solid #d3d3d3;
text-align: center;
}
#mydivheader {
padding: 10px;
cursor: move;
z-index: 10;
background-color: #2196F3;
color: #fff;
}
<div id="background"></div>
<!-- Draggable DIV -->
<div id="mydiv">
<!-- Include a header DIV with the same name as the draggable DIV, followed by "header" -->
<div id="mydivheader">Click here to move</div>
<p>Move</p>
<p>this</p>
<p>DIV</p>
</div>
</div>
Far from perfect, but hopefully demonstrates an idea to expand on.
Related
I am working on Blazor components in Core 3.1. I need to make a custom draggable dialog in blazor using only javscript(without jquery-ui). Can someone help me in achieving this. I tried some fiddles but controls inside them are not working.
This is just a sample you can modify according to your requirements.
You can write this CSS in site.css or in the style tag
<style>
#mydiv {
position: absolute;
z-index: 9;
background-color: #f1f1f1;
text-align: center;
border: 1px solid #d3d3d3;
}
#mydivheader {
padding: 10px;
cursor: move;
z-index: 10;
background-color: #2196F3;
color: #fff;
}
</style>
In your blazor component
#page "/"
#inject IJSRuntime JsRuntime;
<h1>Draggable DIV Element</h1>
<div id="mydiv">
<div id="mydivheader">Header</div>
<p>This is only one sample</p>
</div>
#code {
protected override Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
JsRuntime.InvokeVoidAsync("blazorjs.dragable");
return base.OnAfterRenderAsync(firstRender);
}
}
You write this any JavaScript (.js) file or in the script tag
<script>
window.blazorjs = {
dragable: function () {
dragElement(document.getElementById("mydiv"));
function dragElement(elmnt) {
var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
if (document.getElementById(elmnt.id + "header")) {
/* if present, the header is where you move the DIV from:*/
document.getElementById(elmnt.id + "header").onmousedown = dragMouseDown;
} else {
/* otherwise, move the DIV from anywhere inside the DIV:*/
elmnt.onmousedown = dragMouseDown;
}
function dragMouseDown(e) {
e = e || window.event;
e.preventDefault();
// get the mouse cursor position at startup:
pos3 = e.clientX;
pos4 = e.clientY;
document.onmouseup = closeDragElement;
// call a function whenever the cursor moves:
document.onmousemove = elementDrag;
}
function elementDrag(e) {
e = e || window.event;
e.preventDefault();
// calculate the new cursor position:
pos1 = pos3 - e.clientX;
pos2 = pos4 - e.clientY;
pos3 = e.clientX;
pos4 = e.clientY;
// set the element's new position:
elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
}
function closeDragElement() {
/* stop moving when mouse button is released:*/
document.onmouseup = null;
document.onmousemove = null;
}
}
}
}
</script>
You can check code in blazorfiddle, https://blazorfiddle.com/s/uwjknuwx
I just copied from w3schools and implemented in blazor, https://www.w3schools.com/howto/howto_js_draggable.asp
I need to just drag/move around some images. Each image is linked to some other page. When I use drag functions I can drag the image but when I release it the link of the image fires up. I would need to drag around, release, and then click the image if I want to open the link. What can I do?
The JSFiddle: http://jsfiddle.net/grundum/wp0zhjbn/21/
I found How to HTML5-drag an element that has a link in it but is not clear and doesn't have a concrete answer. Any ideas?
Thanks in advance.
HTML
<div class="dragme" draggable="true">
<a draggable="false" href="https://placeholder.com/"><img class="dragme" draggable="false" src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/microformat.svg"></a>
</div>
CSS
.dragme {
position: relative;
width: 270px;
height: 203px;
cursor: move;
}
#draggable {
background-color: #ccc;
border: 1px solid #000;
}
JS
function startDrag(e) {
// determine event object
if (!e) {
var e = window.event;
}
// IE uses srcElement, others use target
var targ = e.target ? e.target : e.srcElement;
if (targ.className != 'dragme') {
return
};
// calculate event X, Y coordinates
offsetX = e.clientX;
offsetY = e.clientY;
// assign default values for top and left properties
if (!targ.style.left) {
targ.style.left = '0px'
};
if (!targ.style.top) {
targ.style.top = '0px'
};
// calculate integer values for top and left
// properties
coordX = parseInt(targ.style.left);
coordY = parseInt(targ.style.top);
drag = true;
// move div element
document.onmousemove = dragDiv;
}
function dragDiv(e) {
if (!drag) {
return
};
if (!e) {
var e = window.event
};
var targ = e.target ? e.target : e.srcElement;
// move div element
targ.style.left = coordX + e.clientX - offsetX + 'px';
targ.style.top = coordY + e.clientY - offsetY + 'px';
return false;
}
function stopDrag() {
drag = false;
}
window.onload = function() {
document.onmousedown = startDrag;
document.onmouseup = stopDrag;
}
When I use drag functions I can drag the image but when I release it
the link of the image fires up. I would need to drag around, release,
and then click the image if I want to open the link. What can I do?
Then how can you recognize if element is being dragged or clicked? Time interval between onmousedown, onmouseup calls? Mouse movement?
One thing for sure you have to get rid of anchor tag or call in its click event handler preventDefault() as its getting in the way.
Ugly example of how that might work.
let state = {
startDrag: false,
drag: false,
clicked: false,
offsetX: -1,
offsetY: -1,
target: null,
anchor: null
}
let href = "https://placeholder.com/";
window.addEventListener("load", (event) => {
state.anchor = document.querySelector("#anchor");
state.anchor.addEventListener('click', (event) => {
if(!state.clicked) {
event.preventDefault()
}
});
document.addEventListener('mousedown', startDrag);
document.addEventListener('mouseup', stopDrag);
})
function startDrag(event) {
const target = event.target ? event.target : event.srcElement;
state.target = target;
const { clientX, clientY } = event;
state.offsetX = clientX;
state.offsetY = clientY;
state.startDrag = true;
if (!target.style.left) {
target.style.left = '0px'
};
if (!target.style.top) {
target.style.top = '0px'
};
state.coordX = parseInt(target.style.left);
state.coordY = parseInt(target.style.top);
document.onmousemove = dragDiv;
}
function dragDiv({clientX, clientY}) {
if(!state.startDrag) {
return;
}
const { target, coordX, coordY, offsetX, offsetY } = state;
state.drag = state.startDrag;
target.style.left = coordX + clientX - offsetX + 'px';
target.style.top = coordY + clientY - offsetY + 'px';
return false;
}
function stopDrag() {
document.onmousemove = null;
if(state.startDrag && state.drag) {
// handle stop dragging;
}
else {
// handle click;
state.clicked = true;
state.anchor.click();
// or location.href = href;
}
state.clicked = false;
state.startDrag = false;
state.drag = false;
}
.dragme {
position: relative;
width: 270px;
height: 203px;
cursor: move;
}
#draggable {
background-color: #ccc;
border: 1px solid #000;
}
<div class="dragme" draggable="true">
<a id="anchor" draggable="false" href="https://placeholder.com/"><img class="dragme" draggable="false" src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/microformat.svg"></a>
</div>
I am facing an issue, where I am dragging a div.
While the ghost element looks good on MacOs(yes both on Chrome and FireFox),it appears to be too transparent,in Windows (yes both on Chrome and FireFox.
I tried multiple approaches but nothing seems to work.
So is it possible to style the ghost element?
Also, I tried to make an image of that element on the go, and use it as ghost dragging image, but the transparency issue still remains.
You can do this by implementing dragging of the element yourself in JavaScript. That way, you can apply a CSS class to the element while it is being dragged, which styles it in any way you wish.
const d = 'dragging';
const container = document.getElementById('container');
const el = document.getElementById('drag');
var cOffX = 0;
var cOffY = 0;
el.addEventListener('mousedown', dragStart);
function dragStart(e) {
e = e || window.event;
e.preventDefault();
cOffX = e.clientX - el.offsetLeft;
cOffY = e.clientY - el.offsetTop;
document.addEventListener('mousemove', dragMove);
document.addEventListener('mouseup', dragEnd);
el.classList.add(d);
container.style.cursor = 'move';
};
function dragMove(e) {
e = e || window.event;
e.preventDefault();
el.style.top = (e.clientY - cOffY).toString() + 'px';
el.style.left = (e.clientX - cOffX).toString() + 'px';
};
function dragEnd(e) {
e = e || window.event;
e.preventDefault();
document.removeEventListener('mousemove', dragMove);
document.removeEventListener('mouseup', dragEnd);
el.classList.remove(d);
container.style.cursor = null;
};
#container {
width: 100vw;
height: 100vh;
margin: 0;
padding: 0;
}
#drag {
position: absolute;
height: 100px;
width: 100px;
background-color: lime;
border-radius: 0;
transition: background-color 0.25s, border-radius 0.25s;
cursor: move;
}
#drag.dragging {
background-color: navy;
border-radius: 50%;
}
<div id="container">
<div id="drag"></div>
</div>
As others have said, the ghosting is browser-based and can't be changed, so it seems you need your own solution if you want to get around that.
Hi I would like to create one very simple meme creator tool. Here is the code to Image and Text. I have drag text on image. could you help ?
<html>
<body>
<div id="draggable-element">Drag me!</div>
<style>
body {padding:10px}
#draggable-element {
width:100px;
height:10px;
background-color:#fff;
color:black;
padding:10px 12px;
cursor:move;
position:relative; /* important (all position that's not `static`) */
}
</style>
<Script>
var selected = null, // Object of the element to be moved
x_pos = 0, y_pos = 0, // Stores x & y coordinates of the mouse pointer
x_elem = 0, y_elem = 0; // Stores top, left values (edge) of the element
// Will be called when user starts dragging an element
function _drag_init(elem) {
// Store the object of the element which needs to be moved
selected = elem;
x_elem = x_pos - selected.offsetLeft;
y_elem = y_pos - selected.offsetTop;
}
// Will be called when user dragging an element
function _move_elem(e) {
x_pos = document.all ? window.event.clientX : e.pageX;
y_pos = document.all ? window.event.clientY : e.pageY;
if (selected !== null) {
selected.style.left = (x_pos - x_elem) + 'px';
selected.style.top = (y_pos - y_elem) + 'px';
}
}
// Destroy the object when we are done
function _destroy() {
selected = null;
}
// Bind the functions...
document.getElementById('draggable-element').onmousedown = function () {
_drag_init(this);
return false;
};
document.onmousemove = _move_elem;
document.onmouseup = _destroy;
</script>
</body>
</html>
This is code for drag text. But I need to drag this on image. How to do this in easy way.
Just use position: absolute; instead of relative.
var selected = null, // Object of the element to be moved
x_pos = 0,
y_pos = 0, // Stores x & y coordinates of the mouse pointer
x_elem = 0,
y_elem = 0; // Stores top, left values (edge) of the element
// Will be called when user starts dragging an element
function _drag_init(elem) {
// Store the object of the element which needs to be moved
selected = elem;
x_elem = x_pos - selected.offsetLeft;
y_elem = y_pos - selected.offsetTop;
}
// Will be called when user dragging an element
function _move_elem(e) {
x_pos = document.all ? window.event.clientX : e.pageX;
y_pos = document.all ? window.event.clientY : e.pageY;
if (selected !== null) {
selected.style.left = (x_pos - x_elem) + 'px';
selected.style.top = (y_pos - y_elem) + 'px';
}
}
// Destroy the object when we are done
function _destroy() {
selected = null;
}
// Bind the functions...
document.getElementById('draggable-element').onmousedown = function() {
_drag_init(this);
return false;
};
document.onmousemove = _move_elem;
document.onmouseup = _destroy;
body {
padding: 10px
}
#draggable-element {
width: 100px;
height: 10px;
background-color: #fff;
color: black;
padding: 10px 12px;
cursor: move;
position: absolute;
/* important (all position that's not `static`) */
}
<div id="draggable-element">Drag me!</div>
<img src="https://www.google.co.in/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png"/>
I'm trying to create my own click and drag function in JavaScript without the use of jquery. I know that jquery is easy to implement, but I prefer my own code. What I have, as i click the div, then move the mouse, the div moves to the same spot and doesn't implement a "dragging" look to it. I'm not sure why this is. I want my outcome to be able to move the div over the image that way I can "crop" the image based on the div, etc. My code is:
index.js
function _(element) {
return document.getElementById(element);
}
index.css
body {
background-color: rgb(33, 66, 99);
margin: 0px;
padding: 0px;
}
img {
position:absolute;
}
.selection {
width: 200px;
height: 200px;
background-color: rgb(255,255,255);
position: absolute;
}
index.php
<!DOCTYPE html>
<html>
<head>
<meta charset = "UTF-8"/>
<title>Image Cropping</title>
<link rel = "stylesheet" href = "index.css"/>
<script src = "index.js"></script>
</head>
<body>
<div class = "image">
<img src = "model.jpg" alt = "Model" id = "theImage"/>
<div class = "selection" id = "selection"/>
</div>
<script>
_("theImage").ondragstart = function() { return false; };
var m = _("selection");
m.addEventListener("mousedown", mouseDown, false);
window.addEventListener("mouseup", mouseUp, false);
function mouseUp() {
window.removeEventListener("mousemove", move, true);
}
function mouseDown(e) {
window.addEventListener("mousemove", move, true);
}
function move(e) {
var x = m.style.left;
var y = m.style.top;
var mouseX = e.clientX;
var mouseY = e.clientY;
m.style.top += (mouseX - x) + "px";
m.style.left += (mouseY - y) + "px";
// Also tried: m.style.top = (mouseX - x) + "px";
// And : m.style.left = (mouseY - y) + "px";
}
</script>
</body>
</html>
To add the "dragging look to it", you can:
change the cursor (cursor: move;)
keep the cursor's offset relative to the mouse
For the second one, I reused a function I created for one of my projects, for which I implemented drag and drop for mobile, not wanting to use a big library:
/*
* Returns the given element's offset relative to the document.
*/
function realOffset(elem) {
var top = 0, left = 0;
while (elem) {
top = top + parseInt(elem.offsetTop, 10);
left = left + parseInt(elem.offsetLeft, 10);
elem = elem.offsetParent;
}
return { top: top, left: left };
}
Using this function, the math becomes simple:
m.style.left = (mouseX - offset.left) + "px";
m.style.top = (mouseY - offset.top) + "px";
Full demo
_("theImage").ondragstart = function () { return false; };
var m = _("selection"), offset;
m.addEventListener("mousedown", mouseDown, false);
window.addEventListener("mouseup", mouseUp, false);
function mouseUp() { window.removeEventListener("mousemove", move, true); }
function mouseDown(e) {
// SAVE THE OFFSET HERE
offset = {
left: e.pageX - realOffset(m).left,
top: e.pageY - realOffset(m).top
};
window.addEventListener("mousemove", move, true);
}
function move(e) {
// REUSE THE OFFSET HERE
m.style.left = (e.pageX - offset.left) + "px";
m.style.top = (e.pageY - offset.top) + "px";
}
/*
* Returns the given element's offset relative to the document.
*/
function realOffset(elem) {
var top = 0, left = 0;
while (elem) {
top = top + parseInt(elem.offsetTop, 10);
left = left + parseInt(elem.offsetLeft, 10);
elem = elem.offsetParent;
}
return { top: top, left: left };
}
function _(element) { return document.getElementById(element); }
body {
background-color: rgb(33, 66, 99);
margin: 0px;
padding: 0px;
}
img {
position:absolute;
}
.selection {
width: 200px;
height: 200px;
background-color: rgba(255,255,255,.5);
position: absolute;
cursor: move;
}
<div class="image">
<img src="http://i.imgur.com/vxkljMP.jpg" alt="Model" id="theImage" />
<div class="selection" id="selection"></div>
</div>