Resizable flex box - javascript

Intentionally posting this question on stackoverflow instead of posting it on salesforce.stackexchange.com as this problem is specific to JS/CSS
I have below LWC playground where it is not working as expected
https://app.lwc.studio/edit/CTHEQCGrn18rKmQQ0zs1 (unfortunately you might have to login to webcomponents.dev to access this link)
but on the below code pen the same is working as expected not sure what am I doing wrong.
https://codepen.io/gs650x/pen/qByPQKP
I have below HTML
<section class="resizeable-container" >
<div class="resizeable-item">
DIV1
</div>
<div class="resizer-x" onmousedown={handleOnMouseDown} onmouseup={handleOnMouseUp}></div>
<div class="resizeable-item">
DIV2
</div>
</section>
CSS
.resizeable-container {
display: flex;
min-height: 80vh;
}
.resizeable-item {
flex: 50%;
overflow: auto;
}
.resizer-x {
position: relative;
display: flex;
justify-content: center;
align-items: center;
background: hsl(212, 100%, 17%);
padding: 4px;
}
.resizer-x {
z-index: 2;
cursor: col-resize;
}
.resizer-x::before,
.resizer-x::after {
content: "";
width: 2px;
height: 16px;
margin: 2px;
background: lightgray;
}
Below is the javascript
renderedCallback() {
if (!resizer)
resizer = this.template.querySelector(".resizer-x")
//In case mouse up event occurs outside the resizer element
document.addEventListener("mouseup", this.handleOnMouseUp)
}
handleOnMouseDown(event) {
event.preventDefault();
document.addEventListener("mousemove", this.handleOnMouseMove)
document.addEventListener("mouseup", this.handleOnMouseUp)
}
handleOnMouseMove(event) {
event.preventDefault();
const clientX = event.clientX;
const deltaX = clientX - (resizer._clientX || clientX);
resizer._clientX = clientX;
const { previousElementSibling, nextElementSibling } = resizer
// LEFT
if (deltaX < 0) {
const width = Math.round(parseInt(window.getComputedStyle(previousElementSibling).width) + deltaX)
previousElementSibling.style.flex = `0 ${clientX < 10 ? 0 : clientX}px`
nextElementSibling.style.flex = "1 0"
}
// RIGHT
if (deltaX > 0) {
const width = Math.round(parseInt(window.getComputedStyle(nextElementSibling).width) - deltaX)
nextElementSibling.style.flex = `0 ${width < 10 ? 0 : width}px`
previousElementSibling.style.flex = "1 0"
}
}
handleOnMouseUp(event) {
event.preventDefault();
document.removeEventListener("mousemove", this.handleOnMouseMove)
document.removeEventListener("mouseup", this.handleOnMouseUp)
delete event._clientX
}
This works well on my 32 inches monitor but it is not working on my 14 inch laptop
expectation is to move the cursor and resizer-x at the same time but resizer-x moves first and then the cursor moves and mouse up only works if it is coming from the resizer-x anywhere else it is not working. I have added eventListener to document not on a particular object but still removeEventListener to stop handleMouseMove function doesn't stop.
Below is the code pen where it is working as expected but in LWC it doesn't behave in the same manner
https://codepen.io/gs650x/pen/qByPQKP

Related

jQuery mouseover doesn't work as expected on document

I would like to have my own cursor only displayed over certain images with a certain class.
I've already written a few lines for that.
Here is my code:
function registerCursorHoverEffect() {
if (!isTouch()) {
const el = document.body;
var cursorDiv = document.createElement("div");
cursorDiv.setAttribute("id", "cursor");
cursorDiv.setAttribute("class", "light-spot light-spot--cursor light-spot--center-center light-spot--color-red light-spot--filled light-spot--outside");
el.before(cursorDiv);
document.getElementById("cursor").innerHTML = '<svg class="cursor-main" xmlns="http://www.w3.org/2000/svg" width="70" height="70" viewport="0 0 100 100" style="stroke: white; fill:white;font-size:300px; z-index: 9999999;position: absolute; top: 40px; right: 40px; bottom: 0;"><path d="M59.71,31.29l-10-10a1,1,0,0,0-1.42,1.42L56.59,31H5a1,1,0,0,0,0,2H56.59l-8.3,8.29a1,1,0,0,0,0,1.42,1,1,0,0,0,1.42,0l10-10A1,1,0,0,0,59.71,31.29Z"/></svg>';
var cursorDivAppend = document.createElement("div");
cursorDivAppend.setAttribute("id", "cursor-append");
cursorDivAppend.setAttribute("class", "cursor-append");
el.before(cursorDivAppend);
// Mousemove
$(document).on('mousemove', function (event) {
if($('.col-3:hover').length != 0) {
const appendScale = 1
var destinationX = event.pageX;
var destinationY = event.pageY;
var transformScale = `translate(calc(${destinationX}px - 50%), calc(${destinationY}px - 50%)) scale(${appendScale})`
$('#cursor').css('transform', transformScale);
}
})
}
}
The following screenshot shows what is generated when you hover over an image with a certain class:
The critical part of it all is here:
// Mousemove
$(document).on('mousemove', function (event) {
if($('.col-3:hover').length != 0) {
const appendScale = 1
var destinationX = event.pageX;
var destinationY = event.pageY;
var transformScale = `translate(calc(${destinationX}px - 50%), calc(${destinationY}px - 50%)) scale(${appendScale})`
$('#cursor').css('transform', transformScale);
}
})
event.pageX should always give me the current mouse position of the $(document) and not of the event itself. Exactly the same for event.pageY. But I always get the current position of the event and I don't know why.
Can somebody help me please?
UPDATE:
However, the width of the cursor element hinders me because I get the coordinates of the $ (documents). The event is only triggered when I am outside the cursor.
Here is a screenshot and to clarify the problem:
I would like to have my own cursor only displayed over certain images with a certain class.
You can do that only with css,
.cursors {
display: flex;
justify-content: flex-start;
align-items: stretch;
height: 100vh;
}
.cursors > div {
display: flex;
justify-content: center;
align-items: center;
flex-grow: 1;
box-sizing: border-box;
padding: 10px 2px;
text-align: center;
}
.cursors > div:nth-child(odd) {
background: #eee;
}
.cursors > div:hover {
opacity: 0.25;
}
.png {
cursor: url("https://s3-us-west-2.amazonaws.com/s.cdpn.io/9632/heart.png"), auto;
}
.gif {
cursor: url("https://s3-us-west-2.amazonaws.com/s.cdpn.io/9632/happy.png"), auto;
}
.rotated {
transform: rotate(45deg); /* Equal to rotateZ(45deg) */
background-color: pink;
}
<div class="cursors">
<div><img class="png rotated"src="https://uxwing.com/wp-content/themes/uxwing/images/patreon_btn.png"/> </div>
<div class="gif">GIF</div>
</div>

ReactJs carousel - how to force items to snap after a swipe?

I'm building a react carousel and have the basic app set up. It's a slider that follows your finger on mobile, basically a flexbox with overflow: scroll. The buttons work by scrolling the container by (item index * the width of the item) times, so if I scroll to item #3, it will scroll by 300% the width of the item from the starting position.
Here's the code:
function Carousel(props) {
const {children} = props
const [index, setIndex] = useState(0)
const [length, setLength] = useState(children.length)
const [touchPosition, setTouchPosition] = useState(null)
const [movement, setMovement] = useState(0) // saves the distance swiped
useEffect(() => {
setLength(children.length)
}, [children])
const next = () => {
if (index < (length-1)) {
setIndex(prevState => prevState + 1)
}
// sets the index to next if you are not on the last slide
}
const previous = () => {
if (index > 0) {
setIndex(prevState => prevState - 1)
}
// sets the index to be the previous if you are further than first slide
}
const handleTouchStart = (e) => {
const touchDown = e.touches[0].clientX
setTouchPosition(touchDown)
// saves the touch position on touch start
}
const handleTouchEnd = (e) => {
const touchDown = touchPosition
if (touchDown === null) {
return
}
const currentTouch = e.changedTouches[0].clientX
const diff = touchDown - currentTouch
console.log(diff) // for testing
setMovement(diff)
if (diff > 5) {
setTimeout(() => next(), 100)
}
if (diff < -5) {
setTimeout(() => previous(), 100)
}
setTouchPosition(null)
// compares the starting and ending touch positions, calculates the difference
}
// to test the distance swiped
const transformMultiplier =() => {
let mu = (movement / window.innerWidth) * 100
console.log(`m = ${mu}`)
}
useEffect(()=>{
transformMultiplier()
}, [movement])
return (
<div className="carousel-container">
<div className="carousel-wrapper"
onTouchStart={handleTouchStart}
onTouchEnd={handleTouchEnd}
>
{ index > 0 && <button className="left-arrow" onClick={previous}>
<
</button> }
<div className="carousel-content-wrapper">
{ index < children.length -1 && <button className="right-arrow" onClick={next}>
>
</button>}
{/* the sliding is done by the translateX below. it translates by (100% of the slides * the index of the slide) from the starting position. */}
<div className="carousel-content"
style={{transform: `translateX(-${index * (window.innerWidth > 480 ? 100 : (100 - (movement / window.innerWidth) * 100))}%)`}}
>
{ children}
</div>
</div>
</div>
</div>
)
}
.carousel-container {
width: 100vw;
display: flex;
flex-direction: column;
}
.carousel-wrapper {
display: flex;
width: 100%;
position: relative;
}
.carousel-content-wrapper {
overflow: scroll;
-webkit-overflow-scrolling: auto;
width: 100%;
height: 100%;
-ms-overflow-style: none; /* hide scrollbar in IE and Edge */
scrollbar-width: none; /* hide scrollbar in Firefox */
}
.carousel-content {
display: flex;
transition: all 250ms linear;
-ms-overflow-style: none; /* hide scrollbar in IE and Edge */
scrollbar-width: none; /* hide scrollbar in Firefox */
}
.carousel-content::-webkit-scrollbar, .carousel-content::-webkit-scrollbar {
display: none;
}
.carousel-content-wrapper::-webkit-scrollbar, .carousel-content::-webkit-scrollbar {
display: none;
}
.carousel-content > * {
width: 100%;
flex-shrink: 0;
flex-grow: 1;
}
.left-arrow, .right-arrow {
position: absolute;
z-index: 1;
top: 50%;
transform: translateY(-50%);
width: 48px;
height: 48px;
border-radius: 24px;
background-color: white;
border: 1px solid #ddd;
}
.left-arrow {
left: 24px;
}
.right-arrow {
right: 24px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
When I used to swipe on mobile, the slider transitions by the swipe amount + the default transition amount. I tried to fix that by trying to subtract the percentage of the screen the swipe took from the transition amount, so if I swipe for 15% of the screen, the slide should transition the remaining 85%.
The problems:
I try to set the amount of swipe movement as a state value "movement", which seems to be causing trouble and doesn't update properly during every swipe. So sometimes the slider uses the "movement" state from the previous swipe.
The inertial scrolling on mobile makes the swipes unpredictable. I couldn't turn it off with some methods I found online.
If anyone could take a look at the code, and maybe point me toward how I should try and fix these problems, that would be great. Or better yet, if someone knows a less jank way of making such a carousel snap to the next/previous item while maintaining the finger-following scroll that would be perfect.
I know this isn't ideal, but the SO snippet editor is giving me an unexplainable error so here's codesandbox if anyone wants to play around with it in action: https://codesandbox.io/s/hardcore-goodall-usspz?file=/src/carousel.js&resolutionWidth=320&resolutionHeight=675
for scrolling use on parent container where you have all images next styles >>
scroll-snap-type: x mandatory;
-webkit-overflow-scrolling: touch;
display: flex;
overflow-x: scroll;
and then for each slide, child of parent container each this style
scroll-snap-align: start;

How to move a button near to cursor when cursor is coming and move a little more far when cursor is leaving

I am trying to create a little mouse moving animation. When cursor comes near to the button I call it borderline - Certain distance from the button, the button moves to the cursor direction.
Here I have shown two steps dashed borderline with css just for clarity and understanding.
I have created the nearest borderline from code by calculating the center point of button and decreasing and adding width and height of the button for both x and y axis.
And I want to solve this in the same process I'm working not by adding other event-listener tothe parent-elements of the button.
Here is what I have tried..
const button = document.querySelector(".button");
let { width, height, x: buttonX, y: buttonY } = button.getBoundingClientRect(); // gives you width, height, left-X,top-y of the button
buttonX = buttonX + width / 2; // center point of button on x-axis
buttonY = buttonY + height / 2; // center point of button on y-axis
/*************** Functions ***************/
let distance = width;
let mouseHasEntered = true;
let mouseIsInButtonTerritory;
function mouseMove(e) {
const x = e.x; // current x of cursor
const y = e.y; // current y of cursor
const leftBorderLine = buttonX - distance;
const rightBorderLine = buttonX + distance;
const topBorderLine = buttonY - distance;
const bottomBorderline = buttonY + distance;
const xWalk = (x - buttonX) / 2; // the distance to move the button when mouse moves on X axis
const yWalk = (y - buttonY) / 2; // the distance to move the button when mouse moves on Y axis
mouseIsInButtonTerritory =
x > leftBorderLine &&
x < rightBorderLine &&
y > topBorderLine &&
y < bottomBorderline; // becomes true if mouse is inside all of these border-line
if (mouseIsInButtonTerritory) {
if (mouseHasEntered) {
// this must happen only once to create outside borderline
//creating another level borderline by incresing distance;
// while cursor is returing the button comes out of nearest border-line and return from this borderline
distance = distance + distance;
mouseHasEntered = false;
}
catchCursor(xWalk, yWalk); // call the function when mouse in in the button's territory
} else {
resetPositon();
}
}
function catchCursor(xWalk, yWalk) {
// translates the button in the direction where cursor is.
button.style.transform = `translate(${xWalk}px, ${yWalk}px)`;
}
function resetPositon() {
// resets the postion of the button as it was initial.
button.style.transform = `translate(${0}px, ${0}px)`;
mouseHasEntered = true;
// when button is return to it's position (mouseHasEntered = true) lets to increase the initial borderline of button for the next time
}
/*************** Event-handler ***************/
window.addEventListener("mousemove", mouseMove);
window.addEventListener("mouseout", resetPositon);
*,
*::before,
*::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--gutter-lg: 4rem;
--gutter-md: 3rem;
--gutter-sm: 1rem;
--gutter-xm: 1rem;
--color-white: #fff;
--color-black: #000;
}
body {
background: var(--color-black);
font: 16px verdana;
color: var(--color-white);
}
.banner {
display: flex;
height: 100vh;
}
.button {
margin: auto;
cursor: pointer;
transition: all 0.2s ease-out;
}
.button-wrap-wrapper {
width: 192px;
height: 192px;
border: 1px dashed #fff;
margin: auto;
display: flex;
}
.button-wrap {
width: 128px;
height: 128px;
margin: auto;
/* background: orange; */
display: flex;
justify-content: center;
align-items: center;
border: 1px dashed #fff;
}
.button__like-text {
display: block;
color: var(--color-black);
background: var(--color-white);
width: var(--gutter-lg);
height: var(--gutter-lg);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
<section class="banner">
<div class="button-wrap-wrapper">
<div class="button-wrap">
<div class="button">
<span class="button__like-text">
Like
</span>
</div>
</div>
</div>
</section>
What is not working as expected is: mouseIsInButtonTerritory becomes true and I am trying to increase the borderline here
if (mouseHasEntered) {
// this must happen only once to create outside borderline
//creating another level borderline by incresing distance;
// while cursor is returing the button comes out of nearest border-line and return from this borderline
distance = distance + distance;
}
the button keep following the cursor all the time.
What I am trying to solve is if the cursor is coming out of the both borderlines the button must cross the first borderline and come near to the last borderline and go back where it was in initial phase.
I am not getting where I am doing wrong. is there a anything that is missing ?
you should reset the distance when mouse leave. (I'm not sure, just guess this is what you want, since you write mouseHasEntered = true when reset)
since you handle mouse leave yourself (the else mouseIsInButtonTerritory part) do not listen to window.
const button = document.querySelector(".button");
let { width, height, x: buttonX, y: buttonY } = button.getBoundingClientRect(); // gives you width, height, left-X,top-y of the button
buttonX = buttonX + width / 2; // center point of button on x-axis
buttonY = buttonY + height / 2; // center point of button on y-axis
/*************** Functions ***************/
let distance = width;
let mouseHasEntered = true;
let mouseIsInButtonTerritory;
function mouseMove(e) {
const x = e.x; // current x of cursor
const y = e.y; // current y of cursor
const leftBorderLine = buttonX - distance;
const rightBorderLine = buttonX + distance;
const topBorderLine = buttonY - distance;
const bottomBorderline = buttonY + distance;
const xWalk = (x - buttonX) / 2; // the distance to move the button when mouse moves on X axis
const yWalk = (y - buttonY) / 2; // the distance to move the button when mouse moves on Y axis
mouseIsInButtonTerritory =
x > leftBorderLine &&
x < rightBorderLine &&
y > topBorderLine &&
y < bottomBorderline; // becomes true if mouse is inside all of these border-line
if (mouseIsInButtonTerritory) {
if (mouseHasEntered) {
// this must happen only once to create outside borderline
//creating another level borderline by incresing distance;
// while cursor is returing the button comes out of nearest border-line and return from this borderline
distance = distance + distance;
mouseHasEntered = false;
}
catchCursor(xWalk, yWalk); // call the function when mouse in in the button's territory
} else {
resetPositon();
}
}
function catchCursor(xWalk, yWalk) {
// translates the button in the direction where cursor is.
button.style.transform = `translate(${xWalk}px, ${yWalk}px)`;
}
function resetPositon() {
// resets the postion of the button as it was initial.
button.style.transform = `translate(${0}px, ${0}px)`;
if(!mouseHasEntered)distance/=2;
mouseHasEntered = true;
// when button is return to it's position (mouseHasEntered = true) lets to increase the initial borderline of button for the next time
}
/*************** Event-handler ***************/
window.addEventListener("mousemove", mouseMove);
//window.addEventListener("mouseout", resetPositon);
*,
*::before,
*::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--gutter-lg: 4rem;
--gutter-md: 3rem;
--gutter-sm: 1rem;
--gutter-xm: 1rem;
--color-white: #fff;
--color-black: #000;
}
body {
background: var(--color-black);
font: 16px verdana;
color: var(--color-white);
}
.banner {
display: flex;
height: 100vh;
}
.button {
margin: auto;
cursor: pointer;
transition: all 0.2s ease-out;
}
.button-wrap-wrapper {
width: 192px;
height: 192px;
border: 1px dashed #fff;
margin: auto;
display: flex;
}
.button-wrap {
width: 128px;
height: 128px;
margin: auto;
/* background: orange; */
display: flex;
justify-content: center;
align-items: center;
border: 1px dashed #fff;
}
.button__like-text {
display: block;
color: var(--color-black);
background: var(--color-white);
width: var(--gutter-lg);
height: var(--gutter-lg);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
<section class="banner">
<div class="button-wrap-wrapper">
<div class="button-wrap">
<div class="button">
<span class="button__like-text">
Like
</span>
</div>
</div>
</div>
</section>
If I understood your intention correctly, I think you need to:
add buttonWrapWrapper selector
const button = document.querySelector(".button");
const buttonWrapWrapper = document.querySelector(".button-wrap-wrapper");
attach the event listeners to buttonWrapWrapper instead of window:
buttonWrapWrapper.addEventListener("mousemove", mouseMove);
buttonWrapWrapper.addEventListener("mouseout", resetPositon);

Vertical dragBar for resizing two divs

I wanted a vertical dragBar for resizing two divs. I have created an example for the same but I am facing an issue.
Actual : As and when I resize the the upper div and move the slider down, the area of parent div increases and hence a scroll bar is given.
Expected: When Resizing, if the slider is moved down, it should only show the data contained in the upper div and when slider is moved up, it should show the content of lower div and should not increase the over all length of the parent div.
var handler = document.querySelector('.handler');
var wrapper = handler.closest('.wrapper');
var boxA = wrapper.querySelector('.box1');
var boxB = wrapper.querySelector('.box2');
var isHandlerDragging = false;
document.addEventListener('mousedown', function(e) {
// If mousedown event is fired from .handler, toggle flag to true
if (e.target === handler) {
isHandlerDragging = true;
}
});
document.addEventListener('mousemove', function(e) {
// Don't do anything if dragging flag is false
if (!isHandlerDragging) {
return false;
}
// Get offset
var containerOffsetTop= wrapper.offsetTop;
var containerOffsetBottom= wrapper.offsetBottom;
// Get x-coordinate of pointer relative to container
var pointerRelativeXpos = e.clientY - containerOffsetTop;
var pointerRelativeXpos2 = e.clientY - e.offsetTop + e.offsetHeight;
var boxAminWidth = 30;
boxA.style.height = (Math.max(boxAminWidth, pointerRelativeXpos - 2)) + 'px';
boxA.style.flexGrow = 0;
boxB.style.height = (Math.max(boxAminWidth, pointerRelativeXpos2 - 8)) + 'px';
boxB.style.flexGrow = 0;
});
document.addEventListener('mouseup', function(e) {
// Turn off dragging flag when user mouse is up
isHandlerDragging = false;
});
body {
margin: 40px;
}
.wrapper {
background-color: #fff;
color: #444;
/* Use flexbox */
}
.box1, .box2 {
background-color: #444;
color: #fff;
border-radius: 5px;
padding: 20px;
font-size: 150%;
margin-top:2%;
/* Use box-sizing so that element's outerwidth will match width property */
box-sizing: border-box;
/* Allow box to grow and shrink, and ensure they are all equally sized */
}
.handler {
width: 20px;
height:7px;
padding: 0;
cursor: ns-resize;
}
.handler::before {
content: '';
display: block;
width: 100px;
height: 100%;
background: red;
margin: 0 auto;
}
<div class="wrapper">
<div class="box1">A</div>
<div class="handler"></div>
<div class="box2">B</div>
</div>
Hope I was clear in explaining the issue I am facing in my project. Any help is appreciated.
It looks like your on the right track. You just need to make the wrapper a flexbox with the flex direction column and assign it a height. Also box 2 needs to have a flex of 1 so it can grow and shrink as needed. Finally I needed to remove the code that set the flex grow to 0 in the JavaScript. Here is the result.
var handler = document.querySelector('.handler');
var wrapper = handler.closest('.wrapper');
var boxA = wrapper.querySelector('.box1');
var boxB = wrapper.querySelector('.box2');
var isHandlerDragging = false;
document.addEventListener('mousedown', function(e) {
// If mousedown event is fired from .handler, toggle flag to true
if (e.target === handler) {
isHandlerDragging = true;
}
});
document.addEventListener('mousemove', function(e) {
// Don't do anything if dragging flag is false
if (!isHandlerDragging) {
return false;
}
e.preventDefault();
// Get offset
var containerOffsetTop= wrapper.offsetTop;
var containerOffsetBottom= wrapper.offsetBottom;
// Get x-coordinate of pointer relative to container
var pointerRelativeXpos = e.clientY - containerOffsetTop;
var pointerRelativeXpos2 = e.clientY - e.offsetTop + e.offsetHeight;
var boxAminWidth = 30;
boxA.style.height = (Math.max(boxAminWidth, pointerRelativeXpos - 2)) + 'px';
boxB.style.height = (Math.max(boxAminWidth, pointerRelativeXpos2 - 8)) + 'px';
});
document.addEventListener('mouseup', function(e) {
// Turn off dragging flag when user mouse is up
isHandlerDragging = false;
});
body {
margin: 40px;
}
.wrapper {
background-color: #fff;
color: #444;
/* Use flexbox */
display: flex;
flex-direction: column;
height: 200px;
}
.box1, .box2 {
background-color: #444;
color: #fff;
border-radius: 5px;
padding: 20px;
font-size: 150%;
margin-top:2%;
/* Use box-sizing so that element's outerwidth will match width property */
box-sizing: border-box;
/* Allow box to grow and shrink, and ensure they are all equally sized */
}
.box2 {
flex: 1;
}
.handler {
width: 20px;
height:7px;
padding: 0;
cursor: ns-resize;
}
.handler::before {
content: '';
display: block;
width: 100px;
height: 100%;
background: red;
margin: 0 auto;
}
<div class="wrapper">
<div class="box1">A</div>
<div class="handler"></div>
<div class="box2">B</div>
</div>

How to drag or move a span into the Div by using javascript

How to move or drag the span into the Div element. My element structure is the Div -> Span. Here I need to drag the Span inside the div element without drag beyond that div. I have tried this by calculating pixels but didn't give a solution. I don't need a native onDrag method.
I need to calculate pixels and drag the Span inside the Div. Here is my code.
var handleClick = false;
window.dragging = function(event) {
if (handleClick) {
var bar = document.getElementsByClassName('bar')[0],
handle = document.getElementsByClassName('handle')[0];
var left = bar.offsetWidth - handle.offsetWidth;
tops = (bar.offsetWidth - handle.offsetWidth);
pixel = left < ((pixel - 0) / 1.233445) ? left : ((pixel - 0) / 1.233445);
handle.style.left = pixel + "px";
}
}
document.addEventListener('mouseup', function() {
handleClick = false;
});
window.handlersDown = function() {
handleClick = true;
}
.bar {
width: 100px;
height: 30px;
border: 1px solid;
position: relative;
}
.handle {
width: 20px;
height: 20px;
left: 2px;
top: 5px;
background-color: rgba(255, 0, 0, 0.5);
position: absolute;
}
<div class="bar">
<span class="handle" onmousedown="handlersDown()" onmousemove="dragging(event)"></span>
</div>
I have modified your code a bit and changed the selectors from class to ID. I also would advice you to use external libraries to make it more easy for you. Besides that I also removed the event listeners inside your HTML and translate them to Javascript. Is this what you want?
window.onload = addListeners();
function addListeners(){
document.getElementById('handle').addEventListener('mousedown', mouseDown, false);
window.addEventListener('mouseup', mouseUp, false);
}
function mouseUp()
{
window.removeEventListener('mousemove', spanMove, true);
}
function mouseDown(e){
window.addEventListener('mousemove', spanMove, true);
}
function spanMove(e){
var bar = document.getElementById('bar')
var span = document.getElementById('handle');
// variables
var bar_width = bar.offsetWidth;
var handle_width = span.offsetWidth;
// stop scroll left if the minimum and maximum is reached
if(e.clientX < bar_width - handle_width - 1 && e.clientX > 1){
span.style.left = e.clientX + 'px';
}
}
#bar {
width: 100px;
height: 30px;
border: 1px solid;
position: relative;
}
#handle {
width: 20px;
height: 20px;
left: 2px;
top: 5px;
background-color: rgba(255, 0, 0, 0.5);
position: absolute;
}
<div id="bar">
<span id="handle"></span>
</div>
In 2020, following solution works perfectly on last version of Chrome, Opera, Firefox and Edge Chromium.
window.onload = addListeners();
function addListeners()
{
var div = document.getElementById('div');
var span = document.getElementById('span');
span.addEventListener('mousedown', onMouseDown, false);
window.addEventListener('mouseup', onMouseUp, false);
//compute space between left border of <div> and left border of <span>
// this value is also used to compute space at right
iMinLeft = span.offsetLeft;
// compute max left value allowed so that span remains in <div>
iMaxLeft = div.clientWidth - span.offsetWidth - iMinLeft;
}
function onMouseDown(e)
{
if (e.which === 1) // left button is pressed
{
e.preventDefault();
window.addEventListener('mousemove', onMouseMove, true);
// save mouse X position to compute deplacement
posMouseX = e.clientX;
span.style.background = "yellow";
}
}
function onMouseMove(e)
{
e.preventDefault();
//compute mouse deplacement
deltaX = posMouseX - e.clientX;
//compute new left position of <span> element
iNewLeft = span.offsetLeft - deltaX;
if (iNewLeft < iMinLeft)
{
iNewLeft = iMinLeft;
}
else
{
if (iNewLeft > iMaxLeft)
{
iNewLeft = iMaxLeft;
}
}
span.style.left = iNewLeft + 'px';
// save mouse X position to compute NEXT deplacement
posMouseX = e.clientX;
}
function onMouseUp(e)
{
if (e.which === 1) // left button is pressed
{
e.preventDefault();
span.style.background = "white";
window.removeEventListener('mousemove', onMouseMove, true);
}
}
#div
{
width: 200px;
height: 50px;
border: 1px solid;
position: relative;
left: 50px;
}
#span
{
cursor: pointer;
font-size: 30px;
width: auto;
height: 40px;
left: 2px;
top: 5px;
position: absolute;
}
<div id="div">
<span id="span">&#x1F603</span>
</div>
JavaScript line e.preventDefault(); is necessary to avoid <span> to become 'blue' when dragging.
CSS code cursor: pointer; is only to see that unicode is clickable.
Javascript line if (e.which === 1) has been added to prevent emoticon to move when RIGHT mouse button is clicked.
The rectangle around emoticon when <span> is dragged move without being shifted (see previous solution) and space remaining in left or in right are equal.
Thanks to w3schools-exemple

Categories

Resources