sliderCursor not staying in slider - javascript

I'm trying to create a custom range slider. I'm having trouble keeping the slidersCursor in the slider.
Here's the relevant code:
var cursorPosition = 1 - clamp01((sliderDimention - (e.clientX - startPoint.left)) / sliderDimention);
sliderCursor.style.transform = 'translateX(' + (cursorPosition * sliderDimention - cursorRadius) + 'px)';
With the code above, when you drag the slider to the far right or left, the cursor goes halfway out of the slider on either side.
When I remove - cursorRadius, it goes too much to the right side. It stays in the slider when you drag to the left, but when you drag it to the right, it goes out of the slider.
When cursorRadius is equal to cursor.offsetWidth, it goes too much to the left side.
How can I make the sliderCursor stay in the slider when you drag to the far sides?
(Please don't post any JQuery or other "you can use 'this' plugin" answers. I'm doing this for learning purposes, and I want to create my own. Thanks!)
JSFiddle
function RangeSlider( /** DOM Elem */ parentElem) {
var wrapperElem = document.getElementsByClassName('wrapperElem')[0],
slider = document.getElementsByClassName('slider')[0],
sliderCursor = document.getElementsByClassName('sliderCursor')[0];
var sliderDimention = slider.offsetWidth,
cursorRadius = sliderCursor.offsetHeight / 2,
startPoint,
currentTarget;
function sliderDown(e) {
e.preventDefault();
currentTarget = null;
var sliderWithDescendents = wrapperElem.querySelectorAll('*');
for (var i = 0; i < sliderWithDescendents.length; i++) {
sliderWithDescendents[i]
if (sliderWithDescendents[i] === e.target || wrapperElem === e.target) {
currentTarget = wrapperElem.children[0];
break;
}
}
if (currentTarget === null) return;
startPoint = getOrigin(currentTarget);
sliderDimention = slider.offsetWidth;
window.addEventListener('mousemove', sliderMove);
sliderMove(e);
}
function sliderMove(e) {
var cursorPosition = 1 - clamp01((sliderDimention - (e.clientX - startPoint.left)) / sliderDimention);
sliderCursor.style.transform = 'translateX(' + (cursorPosition * sliderDimention - cursorRadius) + 'px)';
}
function mouseUpEvents() {
window.removeEventListener('mousemove', sliderMove);
}
wrapperElem.addEventListener('mousedown', sliderDown);
window.addEventListener('mouseup', mouseUpEvents);
}
var sliderTest = document.getElementById('sliderTest');
var test = new RangeSlider(sliderTest);
function clamp01(val) {
return Math.min(1, Math.max(0, val));
}
function getOrigin(elm) {
var box = (elm.getBoundingClientRect) ? elm.getBoundingClientRect() : {
top: 0,
left: 0
},
doc = elm && elm.ownerDocument,
body = doc.body,
win = doc.defaultView || doc.parentWindow || window,
docElem = doc.documentElement || body.parentNode,
clientTop = docElem.clientTop || body.clientTop || 0, // border on html or body or both
clientLeft = docElem.clientLeft || body.clientLeft || 0;
return {
left: box.left + (win.pageXOffset || docElem.scrollLeft) - clientLeft,
top: box.top + (win.pageYOffset || docElem.scrollTop) - clientTop
};
}
.wrapperElem {
height: 18px;
width: 100%;
cursor: pointer;
display: flex;
}
.slider {
height: 100%;
width: calc(100% - 62px);
border: 1px solid black;
}
.sliderCursor {
width: 14px;
height: 14px;
border-radius: 50%;
border: 2px solid black;
}
<div class="wrapperElem">
<div class="slider">
<div class="sliderCursor"></div>
</div>
</div>

It should be sliderCursor.style.transform = 'translateX(' + (cursorPosition * (sliderDimention - cursorRadius*2)) + 'px)';
You need the radius times x2 then the brackets are to perform the operations first then multiply by cursorPostions (which is from 0 to 1);
Although it works, I'd try clamp the final value (from [0 + radius] to [dimension - radius]). That way you won't get this weird drag where the mouse is in the left or right of the scroll_cursor. You want the mouse to be in the center of it at all times.
If you are doing it for learning, dissect rangeslider.js? It's very well coded.
function RangeSlider( /** DOM Elem */ parentElem) {
var wrapperElem = document.getElementsByClassName('wrapperElem')[0],
slider = document.getElementsByClassName('slider')[0],
sliderCursor = document.getElementsByClassName('sliderCursor')[0];
var sliderDimention = slider.offsetWidth,
cursorRadius = sliderCursor.offsetHeight / 2,
startPoint,
currentTarget;
function sliderDown(e) {
e.preventDefault();
currentTarget = null;
var sliderWithDescendents = wrapperElem.querySelectorAll('*');
for (var i = 0; i < sliderWithDescendents.length; i++) {
sliderWithDescendents[i]
if (sliderWithDescendents[i] === e.target || wrapperElem === e.target) {
currentTarget = wrapperElem.children[0];
break;
}
}
if (currentTarget === null) return;
startPoint = getOrigin(currentTarget);
sliderDimention = slider.offsetWidth;
window.addEventListener('mousemove', sliderMove);
sliderMove(e);
}
function sliderMove(e) {
var cursorPosition = 1 - clamp01((sliderDimention - (e.clientX - startPoint.left)) / sliderDimention);
sliderCursor.style.transform = 'translateX(' + (cursorPosition * (sliderDimention - cursorRadius*2)) + 'px)';;
}
function mouseUpEvents() {
window.removeEventListener('mousemove', sliderMove);
}
wrapperElem.addEventListener('mousedown', sliderDown);
window.addEventListener('mouseup', mouseUpEvents);
}
var sliderTest = document.getElementById('sliderTest');
var test = new RangeSlider(sliderTest);
function clamp01(val) {
return Math.min(1, Math.max(0, val));
}
function getOrigin(elm) {
var box = (elm.getBoundingClientRect) ? elm.getBoundingClientRect() : {
top: 0,
left: 0
},
doc = elm && elm.ownerDocument,
body = doc.body,
win = doc.defaultView || doc.parentWindow || window,
docElem = doc.documentElement || body.parentNode,
clientTop = docElem.clientTop || body.clientTop || 0, // border on html or body or both
clientLeft = docElem.clientLeft || body.clientLeft || 0;
return {
left: box.left + (win.pageXOffset || docElem.scrollLeft) - clientLeft,
top: box.top + (win.pageYOffset || docElem.scrollTop) - clientTop
};
}
.wrapperElem {
height: 18px;
width: 100%;
cursor: pointer;
display: flex;
}
.slider {
height: 100%;
width: calc(100% - 62px);
border: 1px solid black;
}
.sliderCursor {
width: 14px;
height: 14px;
border-radius: 50%;
border: 2px solid black;
}
<div class="wrapperElem">
<div class="slider">
<div class="sliderCursor"></div>
</div>
</div>

Related

how to resize div after rotating it (is it possible to modify the mouse event coordinates based on the rotation?)

there are 8 nodes around a div which can resize the div in 8 directions, when the div is not rotated, they can resize properly. However, when the div is rotated, for example, 90 degrees clockwise, then the behavior is weird, since the mouse event is different with the rotated div.
i've checked these but didn't help:
Logic to set fixed corner while resize after rotate?
How to resize with fixed corner after rotate?
i made a demo here: https://output.jsbin.com/nobasavaza
any ideas?
```
<!DOCTYPE html>
<html>
<head>
<title></title>
<style>
#cut {
opacity: 0.6;
height: 150px;
width: 150px;
position: absolute;
top: 150px;
left: 150px;
cursor: pointer;
border: 1px dotted red;
}
.box-resize {
border: 1px solid black;
width: 4px;
height: 4px;
position: absolute;
}
.box-top-left {
top: -3px;
left: -3px;
cursor: nw-resize;
}
.box-top-right {
top: -3px;
right: -3px;
cursor: ne-resize;
}
.box-left-center {
top: 50%;
left: -3px;
cursor: w-resize;
}
.box-right-center {
top: 50%;
right: -3px;
cursor: e-resize;
}
.box-bottom-left {
left: -3px;
bottom: -3px;
cursor: sw-resize;
}
.box-bottom-right {
right: -3px;
bottom: -3px;
cursor: se-resize;
}
.box-top-center {
left: 50%;
top: -3px;
cursor: n-resize;
}
.box-bottom-center {
left: 50%;
bottom: -3px;
cursor: s-resize;
}
</style>
</head>
<body>
<input type="text" id="rotate_degree" placeholder="degree in closewise">
<button id="rotate_submit">rorate</button>
<div id="cut">
hello
<div class="box-resize box-top-left"></div>
<div class="box-resize box-top-right"></div>
<div class="box-resize box-left-center"></div>
<div class="box-resize box-right-center"></div>
<div class="box-resize box-bottom-left"></div>
<div class="box-resize box-bottom-right"></div>
<div class="box-resize box-top-center"></div>
<div class="box-resize box-bottom-center"></div>
</div>
<script>
window.onload = function () {
var resize = document.getElementsByClassName("box-resize");
var cut = document.getElementById("cut");
var cutWidth = 0;
var cutHeight = 0;
var startX = 0;
var startY = 0;
var top = 0;
var left = 0;
var dir = "";
for (var i = 0; i < resize.length; i++) {
resize[i].onmousedown = function (e) {
startX = e.clientX;
startY = e.clientY;
cutWidth = cut.offsetWidth;
cutHeight = cut.offsetHeight;
top = cut.offsetTop;
left = cut.offsetLeft;
var className = this.className;
if (className.indexOf("box-right-center") > -1) {
dir = "E";
}
else if (className.indexOf("box-top-left") > -1) {
dir = "NW";
}
else if (className.indexOf("box-top-right") > -1) {
dir = "NE";
}
else if (className.indexOf("box-left-center") > -1) {
dir = "W";
}
else if (className.indexOf("box-bottom-left") > -1) {
dir = "SW";
}
else if (className.indexOf("box-bottom-right") > -1) {
dir = "SE";
}
else if (className.indexOf("box-bottom-center") > -1) {
dir = "S";
}
else if (className.indexOf("box-top-center") > -1) {
dir = "N";
}
document.addEventListener('mousemove', test);
e.preventDefault();
}
}
document.onmouseup = function (e) {
dir = "";
document.removeEventListener('mousemove', test);
e.preventDefault();
}
function test(e) {
var width = e.clientX - startX;
var height = e.clientY - startY;
if (dir == "E") {
cut.style.width = cutWidth + width + "px";
}
else if (dir == "S") {
cut.style.height = cutHeight + height + "px";
}
else if (dir == "N") {
if (height < cutHeight) {
cut.style.height = cutHeight - height + "px";
cut.style.top = top + height + "px";
}
}
else if (dir == "W") {
if (width < cutWidth) {
cut.style.width = cutWidth - width + "px";
cut.style.left = left + width + "px";
}
}
else if (dir == "NW") {
if (width < cutWidth && height < cutHeight) {
cut.style.width = cutWidth - width + "px";
cut.style.height = cutHeight - height + "px";
cut.style.top = top + height + "px";
cut.style.left = left + width + "px";
}
}
else if (dir == "NE") {
if (height < cutHeight) {
cut.style.width = cutWidth + width + "px";
cut.style.height = cutHeight - height + "px";
cut.style.top = top + height + "px";
}
}
else if (dir == "SW") {
if (width < cutWidth) {
cut.style.width = cutWidth - width + "px";
cut.style.height = cutHeight + height + "px";
cut.style.left = left + width + "px";
}
}
else if (dir == "SE") {
if (width < cutWidth) {
cut.style.width = cutWidth + width + "px";
cut.style.height = cutHeight + height + "px";
}
}
}
}
document.getElementById('rotate_submit').addEventListener('click', function () {
const degree = document.getElementById('rotate_degree');
document.getElementById("cut").style.transform = 'rotate(' + degree.value + 'deg)';
})
</script>
</body>
</html>
```

Why JS animation is stuck?

I want the box to traverse the inside of the container from left to right, then down, then right to left and finally back up to the original position. The examples I found all include extra array pos = [180,180]. I don't understand why do I need it when my IF conditions seem to cover all positions.
window.onload = function() {
var t = setInterval(slide, 5);
pos1 = [0, 0];
var box = document.getElementById('sqr');
function slide() {
if (pos1[0] < 180 && pos1[1] < 180) {
pos1[0]++;
box.style.left = pos1[0] + "px";
} else if (pos1[0] >= 180 && pos1[1] < 180) {
pos1[1]++;
box.style.top = pos1[1] + "px";
} else if (pos1[0] >= 180 && pos1[1] >= 180) {
pos1[0]--;
box.style.left = pos1[0] + "px";
} else if (pos1[0] <= 0 && pos1[1] >= 180) {
pos1[1]--;
box.style.top = pos1[1] + "px";
}
}
}
#contain {
position: relative;
width: 200px;
height: 200px;
background-color: pink;
}
#sqr {
position: absolute;
width: 20px;
height: 20px;
background-color: blue;
}
<div id="contain">
<div id="sqr"></div>
</div>
Once the box gets to the maximum X and Y positions, the program is still checking to make sure the box hasn't reached the maximum yet, which causes the all IF conditions to fail. You could do it by checking for Y=0 for the first "leg", X=MAX for the next, Y=MAX for the next, and then X=0 for the last, but instead of that, you can set a "state" which has 4 values to determine which "leg" of the animation is being run, and then just run it for 180 iterations each.
window.onload = function() {
var t = setInterval(slide, 5);
pos1 = [0, 0];
var box = document.getElementById('sqr');
state = 0;
iterations = 0;
function slide() {
if (iterations >= 180) {state = (state + 1) % 4; iterations = 0;}
if (state === 0) pos1[0]++;
else if (state == 1) pos1[1]++;
else if (state == 2) pos1[0]--;
else if (state == 3) pos1[1]--;
iterations++;
box.style.left = pos1[0] + "px";
box.style.top = pos1[1] + "px";
}
}
#contain {
position: relative;
width: 200px;
height: 200px;
background-color: pink;
}
#sqr {
position: absolute;
width: 20px;
height: 20px;
background-color: blue;
}
<div id="contain">
<div id="sqr"></div>
</div>
window.onload = function() {
var t = setInterval(slide, 5);
var box = document.getElementById('sqr');
var left = 0,
top = 0;
function slide() {
var pos1 = [parseInt(box.style.left || 0), parseInt(box.style.top || 0)]
console.log(pos1);
if (pos1[0] == 0 && pos1[1] == 0) { //Top left, go right
left = 1;
top = 0;
} else if (pos1[0] == 180 && pos1[1] == 0) { //Top right, go down
left = 0;
top = 1;
} else if (pos1[0] == 180 && pos1[1] == 180) { //Bottom right, go left
left = -1;
top = 0;
} else if (pos1[0] == 0 && pos1[1] == 180) { //Bottom left, go up
left = 0;
top = -1;
}
box.style.left = (parseInt(box.style.left || 0) + left) + "px";
box.style.top = (parseInt(box.style.top || 0) + top) + "px";
}
}
#contain {
position: relative;
width: 200px;
height: 200px;
background-color: pink;
}
#sqr {
position: absolute;
width: 20px;
height: 20px;
background-color: blue;
}
<div id="contain">
<div id="sqr"></div>
</div>
Here's my take on it. React according to the position of the element, when it reaches a corner, change directions. This makes things easier, since we do not rely on actual positions to know where to go next step...
It is because, when animation gets to pos1 = [180, 180], it executes:
else if (pos1[0] >= 180 && pos1[1] >= 180) {
pos1[0]--;
box.style.left = pos1[0] + "px";
}
And then pos1 = [179, 180], which is not covered by the code.
I suggest using something like that:
var direction = 0; //0 - right, 1 - down, 2 - left, 3 - up
function slide() {
if (pos1[0] < 180 && pos1[1] = 0) {
direction = 0;
} else if (pos1[0] = 180 && pos1[1] < 180) {
direction = 1;
} else if (pos1[0] > 0 && pos1[1] = 180) {
direction = 2;
} else if (pos1[0] = 0 && pos1[1] > 0) {
direction = 3;
}
switch(direction){
case 0:
pos1[0]++;
break;
case 1:
pos1[1]++;
break;
case 2:
pos1[0]--;
break;
case 3:
pos1[1]--;
break;
}
box.style.left = pos1[0] + "px";
box.style.top = pos1[1] + "px";
}
I'm not usually a fan of doing someone's homework for them, but I got intrigued as to what would make it work and couldn't help myself. shrugs
The if statements have been tailored to be more explicit with what they need. This of course was achieved by following the methods suggested to you by #j08691, by just adding a console.log(pos1); at the top of each if section.
This is just for reference, in fact, #Salketer has managed to post before me and it looks a lot cleaner than this. The real answer is in the comments by #j08691
window.onload = function() {
var t = setInterval(slide, 5),
pos1 = [0, 0],
box = document.getElementById('sqr');
function slide() {
if (pos1[0] < 180 && pos1[1] === 0) {
console.log(pos1);
pos1[0]++;
box.style.left = pos1[0] + "px";
} else if (pos1[0] === 180 && pos1[1] < 180) {
console.log(pos1);
pos1[1]++;
box.style.top = pos1[1] + "px";
} else if ((pos1[0] <= 180 && pos1[0] >= 1) && pos1[1] === 180) {
console.log(pos1);
pos1[0]--;
box.style.left = pos1[0] + "px";
} else if (pos1[0] === 0 && pos1[1] <= 180) {
console.log(pos1);
pos1[1]--;
box.style.top = pos1[1] + "px";
}
}
}
#contain {
position: relative;
width: 200px;
height: 200px;
background-color: pink;
}
#sqr {
position: absolute;
width: 20px;
height: 20px;
background-color: blue;
}
<div id="contain">
<div id="sqr"></div>
</div>

Move element with mouse starts to snap up and down

I am trying to make a drag on y axis functionality using mousedown, mousemove events. The formula is as follows:
var position = e.clientY - getOrigin(myDiv).top;
myDiv.style.transform = 'translate3d(0px, ' + position + 'px, 0px)';
function getOrigin(elm) {
...
return {
left: box.left + (win.pageXOffset || docElem.scrollLeft) - clientLeft,
top: box.top + (win.pageYOffset || docElem.scrollTop) - clientTop
};
}
When I drag the element, it snaps up and down really fast. Why is that happening, and how can I fix it?
JSFiddle
var myDiv = document.getElementById('myDiv');
myDiv.addEventListener('mousedown', handleMouseDown);
window.addEventListener('mouseup', handleMouseUp);
function handleMouseDown(e) {
window.addEventListener('mousemove', handleMouseMove);
}
function handleMouseUp(e) {
window.removeEventListener('mousemove', handleMouseMove);
}
function handleMouseMove(e) {
e.preventDefault();
var position = e.clientY - getOrigin(myDiv).top;
myDiv.style.transform = 'translate3d(0px, ' + position + 'px, 0px)';
}
function getOrigin(elm) {
var box = (elm.getBoundingClientRect) ? elm.getBoundingClientRect() : {
top: 0,
left: 0
},
doc = elm && elm.ownerDocument,
body = doc.body,
win = doc.defaultView || doc.parentWindow || window,
docElem = doc.documentElement || body.parentNode,
clientTop = docElem.clientTop || body.clientTop || 0, // border on html or body or both
clientLeft = docElem.clientLeft || body.clientLeft || 0;
return {
left: box.left + (win.pageXOffset || docElem.scrollLeft) - clientLeft,
top: box.top + (win.pageYOffset || docElem.scrollTop) - clientTop
};
}
body {
margin-top: 50px;
padding-top: 50px;
}
#myDiv {
background-color: orange;
width: 200px;
height: 100px;
}
<div id="myDiv"></div>
Because I couldn't exactly figure out what was causing the problem in OPs question (for an unknown reason box.top was returning 2 different values alternately on each pixel movement in OPs script), I've written a different script that works perfectly fine:
//document.addEventListener('DOMContentLoaded', function(){
var myDiv = document.getElementById('myDiv');
myDiv.addEventListener('mousedown', handleMouseDown);
window.addEventListener('mouseup', handleMouseUp);
function handleMouseDown(e) {
window.addEventListener('mousemove', mouseMove.start(this, 'body',e));
}
function handleMouseUp(e) {
window.removeEventListener('mousemove', mouseMove.stop('body'));
}
var mouseMove = function(){
return {
move: function(elm, posY){
elm.style.top = posY + "px";
},
start: function(elm, container, e){
e = e || window.event;
var posY = e.clientY,
elmTop = elm.style.top,
elmHeight = parseInt(elm.style.height),
conHeight = parseInt(document.getElementById(container).style.height);
elmTop = elmTop.replace('px','');
var diffY = posY - elmTop;
document.onmousemove = function(e){
e = e || window.event;
var posY = e.clientY,
Y = posY - diffY;
if (Y < 0) Y = 0;
if (Y + elmHeight > conHeight) Y = conHeight - elmHeight;
mouseMove.move(elm,Y);
}
},
stop : function(container){
var a = document.createElement('script');
document.onmousemove = function(){}
},
}
}();
//});
#body {
margin-top: 50px;
position: absolute;
}
#myDiv {
position: absolute;
background-color: orange;
width: 200px;
height: 100px;
}
<div id="body">
<div id="myDiv"></div>
</div>

Slider range not going to correct position

I'm trying to create a custom range slider. Everything works well besides for when you zoom in on the webpage, then reload. When I do that, the range slider (green background) doesn't drag to its correct position.
Here's the relevant code: (In function sliderMove line 30)
cursorPosition = ((e.touches && e.touches[0].clientX) || e.clientX) - startPoint.left;
rangePosition = clamp(cursorPosition, _sliderPositions.rangeStart, _sliderPositions.rangeEnd);
cursorPosition = clamp(cursorPosition - cursorRadius, _sliderPositions.cursorStart, _sliderPositions.cursorEnd);
What am I doing wrong, and how can I fix it?
JSFiddle
console.clear();
function RangeSlider( /** DOM Elem */ parentElem) {
var wrapperElem = document.getElementsByClassName('wrapperElem')[0],
slider = document.getElementsByClassName('slider')[0],
sliderRange = document.getElementsByClassName('sliderRange')[0],
sliderCursor = document.getElementsByClassName('sliderCursor')[0],
output = document.getElementById('output'),
myButton = document.getElementById('myButton');
var sliderDimention = slider.offsetWidth,
cursorRadius = sliderCursor.offsetHeight / 2,
startPoint,
currentTarget,
value = 0,
_sliderPositions = {},
borderWidth = 1;
startPoint = getOrigin(wrapperElem.children[0]);
sliderDimention = slider.offsetWidth;
function sliderDown(e) {
e.preventDefault();
window.addEventListener('mousemove', sliderMove);
sliderMove(e);
}
function sliderMove(e) {
var rangePosition = 0;
var cursorPosition = 0;
reconfigVars();
if (typeof e === 'object') {
cursorPosition = ((e.touches && e.touches[0].clientX) || e.clientX) - startPoint.left;
} else {
cursorPosition = pixelToPercent(value, 0, 500) / 100 * sliderDimention;
}
//console.log(cursorPosition);
rangePosition = clamp(cursorPosition, _sliderPositions.rangeStart, _sliderPositions.rangeEnd);
cursorPosition = clamp(cursorPosition - cursorRadius, _sliderPositions.cursorStart, _sliderPositions.cursorEnd);
sliderCursor.style.transform = 'translateX(' + cursorPosition + 'px)';
sliderRange.style.transform = 'scaleX(' + rangePosition + ')';
if (typeof e === 'object') {
value = percentToPixel((
(cursorPosition - _sliderPositions.cursorStart) / (_sliderPositions.currentValue - borderWidth * 2)
) * 100, 0, 500);
}
output.innerHTML = value;
}
function reconfigVars() {
_sliderPositions.rangeStart = borderWidth * 2;
_sliderPositions.rangeEnd = sliderDimention - borderWidth * 2
_sliderPositions.cursorStart = startPoint.left - cursorRadius + borderWidth * 2;
_sliderPositions.cursorEnd = sliderDimention - borderWidth * 2 - cursorRadius * 2;
_sliderPositions.currentValue = sliderDimention - borderWidth * 2 - startPoint.left - cursorRadius;
}
myButton.addEventListener('click', function() {
sliderMove(500);
value = 500;
});
function mouseUpEvents() {
window.removeEventListener('mousemove', sliderMove);
}
wrapperElem.addEventListener('mousedown', sliderDown);
window.addEventListener('mouseup', mouseUpEvents);
}
var sliderTest = document.getElementById('sliderTest');
var test = new RangeSlider(sliderTest);
function getOrigin(elm) {
var box = (elm.getBoundingClientRect) ? elm.getBoundingClientRect() : {
top: 0,
left: 0
},
doc = elm && elm.ownerDocument,
body = doc.body,
win = doc.defaultView || doc.parentWindow || window,
docElem = doc.documentElement || body.parentNode,
clientTop = docElem.clientTop || body.clientTop || 0, // border on html or body or both
clientLeft = docElem.clientLeft || body.clientLeft || 0;
return {
left: box.left + (win.pageXOffset || docElem.scrollLeft) - clientLeft,
top: box.top + (win.pageYOffset || docElem.scrollTop) - clientTop
};
}
function clamp(val, moreThan, lessThan) {
if (typeof lessThan === 'undefined') lessThan = 1;
if (typeof moreThan === 'undefined') moreThan = 0;
return Math.min(lessThan, Math.max(moreThan, val));
}
function pixelToPercent(pixel, min, max) {
if (typeof max === 'undefined') return;
return ((pixel - min) / (max - min)) * 100;
}
function percentToPixel(percent, min, max) {
if (typeof max === 'undefined') return;
return ((percent / 100) * (max - min)) + min;
}
.wrapperElem {
height: 18px;
width: 100%;
cursor: pointer;
display: flex;
}
.slider {
height: 100%;
width: calc(100% - 62px);
border: 1px solid black;
position: relative;
}
.sliderCursor {
width: 14px;
height: 14px;
border-radius: 50%;
border: 2px solid black;
}
.sliderRange {
background-color: green;
position: absolute;
width: 1px;
height: 100%;
transform-origin: left;
}
#output {
background-color: orange;
}
<div class="wrapperElem">
<div class="slider">
<div class="sliderRange"></div>
<div class="sliderCursor"></div>
</div>
</div>
<br />
<div id="output"></div>
<button id="myButton">Click Me</button>

Drag an HTML box and make another box follow it with JavaScript

I am trying to create something like drag a box (Hello World) to any location, and the second box (Follow World) will follow slowly.
In the code below, the drag box is fine, but the follow box will not follow properly. Also, the drag box cannot drop.
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;
return false;
}
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() {
timer();
drag = false;
}
window.onload = function() {
document.onmousedown = startDrag;
document.onmouseup = stopDrag;
}
function disp() {
var step = 1;
var y = document.getElementById('followme').offsetTop;
var x = document.getElementById('followme').offsetLeft;
var ty = document.getElementById('draggable').offsetTop;
var ty = document.getElementById('draggable').offsetLeft;
if (y < ty) {
y = y + step;
document.getElementById('followme').style.top = y + "px"; // vertical movment
} else {
if (x < tx) {
x = x + step;
document.getElementById('followme').style.left = x + "px"; // horizontal movment
}
}
}
function timer() {
disp();
var y = document.getElementById('followme').offsetTop;
var x = document.getElementById('followme').offsetLeft;
document.getElementById("msg").innerHTML = "X: " + tx + " Y : " + ty
my_time = setTimeout('timer()', 10);
}
.dragme {
position: relative;
width: 60px;
height: 80px;
cursor: move;
}
.followme {
position: relative;
width: 60px;
height: 80px;
}
#draggable {
background-color: #ccc;
border: 1px solid #000;
}
#followme {
background-color: #ccc;
border: 1px solid #000;
}
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Drag and drop</title>
</head>
<body>
<div id='msg'></div>
<div id="draggable" class="dragme">"Hello World!"</div>
<div id="followme" class="followme">"Follow World!"</div>
Fix yours disp and timer functions to this:
function disp()
{
var step = 1;
// in dragDiv() you modifying style.left/style.top properties, not offsetTop/offsetLeft
var x = parseInt(document.getElementById('followme').style.left) || 0;
var y = parseInt(document.getElementById('followme').style.top) || 0;
var tx = parseInt(document.getElementById('draggable').style.left) || 0;
var ty = parseInt(document.getElementById('draggable').style.top) || 0;
// properly calculate offset
var dx = ((dx = tx - x) == 0) ? 0 : Math.abs(dx) / dx;
var dy = ((dy = ty - y) == 0) ? 0 : Math.abs(dy) / dy;
document.getElementById('followme').style.left = (x + dx * step) + "px"; // horisontal movment
document.getElementById('followme').style.top = (y + dy * step) + "px"; // vertical movment
}
function timer()
{
disp();
var y=document.getElementById('followme').offsetTop;
var x=document.getElementById('followme').offsetLeft;
document.getElementById("msg").innerHTML="X: " + x + " Y : " + y; // typo was here
my_time = setTimeout(function () {
clearTimeout(my_time); // need to clear timeout or it'll be adding each time 'Hello world' clicked
timer();
},10);
}
In the following snippet, the pink box is draggable and the blue box follows it around. You can change pixelsPerSecond to adjust the speed of movement.
function message(s) {
document.getElementById('messageContainer').innerHTML = s;
}
window.onload = function () {
var pixelsPerSecond = 80,
drag = document.getElementById('drag'),
follow = document.getElementById('follow'),
wrapper = document.getElementById('wrapper'),
messageContainer = document.getElementById('messageContainer'),
leftMax,
topMax;
function setBoundaries() {
leftMax = wrapper.offsetWidth - drag.offsetWidth;
topMax = wrapper.offsetHeight - drag.offsetHeight;
drag.style.left = Math.min(drag.offsetLeft, leftMax) + 'px';
drag.style.top = Math.min(drag.offsetTop, topMax) + 'px';
}
setBoundaries();
window.onresize = setBoundaries;
[drag, follow, messageContainer].forEach(function (element) {
element.className += ' unselectable';
element.ondragstart = element.onselectstart = function (event) {
event.preventDefault();
};
});
var start = Date.now();
drag.onmousedown = function (event) {
event = event || window.event;
var x0 = event.pageX || event.clientX,
y0 = event.pageY || event.clientY,
left0 = drag.offsetLeft,
top0 = drag.offsetTop;
window.onmousemove = function (event) {
var x = event.pageX || event.clientX,
y = event.pageY || event.clientY;
drag.style.left = Math.max(0, Math.min(left0 + x - x0, leftMax)) + 'px';
drag.style.top = Math.max(0, Math.min(top0 + y - y0, topMax)) + 'px';
};
window.onmouseup = function () {
window.onmousemove = window.onmouseup = undefined;
};
};
follow.x = follow.offsetLeft;
follow.y = follow.offsetTop;
function update() {
var elapsed = Date.now() - start;
if (elapsed === 0) {
window.requestAnimationFrame(update);
return;
}
var x1 = drag.offsetLeft,
y1 = drag.offsetTop + (drag.offsetTop + drag.offsetHeight <= topMax ?
drag.offsetHeight : -drag.offsetHeight),
x0 = follow.x,
y0 = follow.y,
dx = x1 - x0,
dy = y1 - y0,
distance = Math.sqrt(dx*dx + dy*dy),
angle = Math.atan2(dy, dx),
dd = Math.min(distance, pixelsPerSecond * elapsed / 1000);
message('x: ' + x1 + ', y: ' + y1);
follow.x += Math.cos(angle) * dd;
follow.style.left = follow.x + 'px';
follow.y += Math.sin(angle) * dd;
follow.style.top = follow.y + 'px';
start = Date.now();
window.requestAnimationFrame(update);
}
window.requestAnimationFrame(update);
};
#wrapper {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: #eee;
font-family: sans-serif;
text-align: center;
}
.unselectable {
-webkit-user-select: none;
-khtml-user-drag: none;
-khtml-user-select: none;
-moz-user-select: none;
-moz-user-select: -moz-none;
-ms-user-select: none;
user-select: none;
}
#messageContainer {
position: absolute;
left: 80px;
top: 50px;
font-size: 36px;
color: #aaa;
cursor: default;
}
.box {
position: absolute;
width: 60px;
height: 80px;
}
.label {
margin: 30px auto;
font-size: 14px;
}
#drag {
left: 100px;
top: 120px;
background: #f0dddb;
border: 2px solid #deb7bb;
cursor: move;
}
#follow {
left: 0;
top: 0;
background-color: #ddebf3;
border: 2px solid #bfd5e1;
cursor: default;
}
<div id="wrapper">
<div id="messageContainer"></div>
<div class="box" id="follow"> <div class="label">it follows</div> </div>
<div class="box" id="drag"> <div class="label">drag me</div> </div>

Categories

Resources