I am using this code for dragging container left / right. This works well. User can also click on the "thumb". The problem is that click happens also after drag. It should be either drag or click. How can I isolate one or another? It has to work on tablets of course.
var thumbContainer = document.querySelector('.aplbox-thumb-container'),
thumbContainerWrap = document.querySelector('.aplbox-thumb-container-wrap'),
startXThumb,
startTouchThumb
if ("ontouchstart" in window) {
thumbContainer.addEventListener("touchstart", dragStartThumb);
}
thumbContainer.addEventListener("mousedown", dragStartThumb);
function dragStartThumb(e) {
if (e.preventDefault) e.preventDefault();
e.stopPropagation()
if (!startTouchThumb) {
startTouchThumb = true;
document.addEventListener('mousemove', dragMoveThumb)
document.addEventListener('mouseup', dragEndThumb);
if ("ontouchstart" in window) {
document.addEventListener('touchmove', dragMoveThumb)
document.addEventListener('touchend', dragEndThumb);
}
var point;
if (e.type == 'touchstart') {
var touches = e.changedTouches;
if (touches.length > 1) {
return false;
}
point = touches[0];
e.preventDefault();
} else {
point = e;
e.preventDefault();
}
var currX = thumbContainer.style.transform.replace(/[^\d.]/g, '');
currX = parseInt(currX) || 0;
startXThumb = point.pageX + currX;
}
}
function dragMoveThumb(e) {
if (startTouchThumb) {
var point;
if (e.type == 'touchmove') {
var touches = e.changedTouches;
if (touches.length > 1) {
return false;
}
point = touches[0];
e.preventDefault();
} else {
point = e;
e.preventDefault();
}
var diff = point.pageX - startXThumb;
if (diff > 0) diff = 0;
else if (diff < -thumbContainer.offsetWidth + thumbContainerWrap.offsetWidth) diff = -thumbContainer.offsetWidth + thumbContainerWrap.offsetWidth;
thumbContainer.style.transform = 'translateX(' + diff + 'px)';
}
}
function dragEndThumb(e) {
e.stopPropagation()
if (startTouchThumb) {
startTouchThumb = false;
document.removeEventListener('mousemove', dragMoveThumb)
document.removeEventListener('mouseup', dragEndThumb);
if ("ontouchstart" in window) {
document.removeEventListener('touchmove', dragMoveThumb)
document.removeEventListener('touchend', dragEndThumb);
}
}
}
//click thumb
thumbContainerWrap.addEventListener('click', function(e) {
if (e.target.closest('.aplbox-thumb')) {
console.log('click')
}
})
.aplbox-thumb-container-wrap {
position: absolute;
top: 0;
left: 0;
background-color: #ccc;
width: 100%;
height: 100px;
overflow: hidden;
box-sizing: border-box;
}
.aplbox-thumb-container {
position: relative;
padding: 5px 0;
height: 100%;
display: flex;
flex-direction: row;
transform: translateX(0);
touch-action: none;
}
.aplbox-thumb {
width: 100px;
height: 70px;
margin-right: 5px;
box-sizing: border-box;
background: #333;
flex-shrink: 0;
overflow: hidden;
margin-bottom: 5px;
}
<div class="aplbox-thumb-container-wrap">
<div class="aplbox-thumb-container" style="width: 1300px;">
<div class="aplbox-thumb" data-id="0"></div>
<div class="aplbox-thumb" data-id="1"></div>
<div class="aplbox-thumb" data-id="2"></div>
<div class="aplbox-thumb" data-id="3"></div>
<div class="aplbox-thumb" data-id="4"></div>
<div class="aplbox-thumb" data-id="5"></div>
<div class="aplbox-thumb" data-id="6"></div>
<div class="aplbox-thumb" data-id="7"></div>
<div class="aplbox-thumb" data-id="8"></div>
<div class="aplbox-thumb" data-id="9"></div>
<div class="aplbox-thumb" data-id="10"></div>
<div class="aplbox-thumb" data-id="11"></div>
</div>
</div>
Declare the variable moved. In the dragStartThumb function set this variable to false, and in the dragMoveThumb function set it to true and in the onclick event check this variable. Like below. Something like #Amirhoseinh73 wrote, but instead of setting the flag to true in the touchend function we set the flag to true in the mousemove function, because we don't want have always variable set to true.
var thumbContainer = document.querySelector('.aplbox-thumb-container'),
thumbContainerWrap = document.querySelector('.aplbox-thumb-container-wrap'),
startXThumb,
startTouchThumb
let moved = false;
if ("ontouchstart" in window) {
thumbContainer.addEventListener("touchstart", dragStartThumb);
}
thumbContainer.addEventListener("mousedown", dragStartThumb);
function dragStartThumb(e) {
moved = false;
//if (e.preventDefault) e.preventDefault();
e.stopPropagation()
if (!startTouchThumb) {
startTouchThumb = true;
document.addEventListener('mousemove', dragMoveThumb)
document.addEventListener('mouseup', dragEndThumb);
if ("ontouchstart" in window) {
document.addEventListener('touchmove', dragMoveThumb)
document.addEventListener('touchend', dragEndThumb);
}
var point;
if (e.type == 'touchstart') {
var touches = e.changedTouches;
if (touches.length > 1) {
return false;
}
point = touches[0];
//e.preventDefault();
} else {
point = e;
//e.preventDefault();
}
var currX = thumbContainer.style.transform.replace(/[^\d.]/g, '');
currX = parseInt(currX) || 0;
startXThumb = point.pageX + currX;
}
}
function dragMoveThumb(e) {
moved = true;
if (startTouchThumb) {
var point;
if (e.type == 'touchmove') {
var touches = e.changedTouches;
if (touches.length > 1) {
return false;
}
point = touches[0];
e.preventDefault();
} else {
point = e;
e.preventDefault();
}
var diff = point.pageX - startXThumb;
if (diff > 0) diff = 0;
else if (diff < -thumbContainer.offsetWidth + thumbContainerWrap.offsetWidth) diff = -thumbContainer.offsetWidth + thumbContainerWrap.offsetWidth;
thumbContainer.style.transform = 'translateX(' + diff + 'px)';
}
}
function dragEndThumb(e) {
e.stopPropagation()
if (startTouchThumb) {
startTouchThumb = false;
document.removeEventListener('mousemove', dragMoveThumb)
document.removeEventListener('mouseup', dragEndThumb);
if ("ontouchstart" in window) {
document.removeEventListener('touchmove', dragMoveThumb)
document.removeEventListener('touchend', dragEndThumb);
}
}
}
//click thumb
thumbContainerWrap.addEventListener('click', function(e) {
if (e.target.closest('.aplbox-thumb') && !moved) {
console.log('click')
}
})
.aplbox-thumb-container-wrap {
position: absolute;
top: 0;
left: 0;
background-color: #ccc;
width: 100%;
height: 100px;
overflow: hidden;
box-sizing: border-box;
}
.aplbox-thumb-container {
position: relative;
padding: 5px 0;
height: 100%;
display: flex;
flex-direction: row;
transform: translateX(0);
touch-action: none;
}
.aplbox-thumb {
width: 100px;
height: 70px;
margin-right: 5px;
box-sizing: border-box;
background: #333;
flex-shrink: 0;
overflow: hidden;
margin-bottom: 5px;
}
<div class="aplbox-thumb-container-wrap">
<div class="aplbox-thumb-container" style="width: 1300px;">
<div class="aplbox-thumb" data-id="0"></div>
<div class="aplbox-thumb" data-id="1"></div>
<div class="aplbox-thumb" data-id="2"></div>
<div class="aplbox-thumb" data-id="3"></div>
<div class="aplbox-thumb" data-id="4"></div>
<div class="aplbox-thumb" data-id="5"></div>
<div class="aplbox-thumb" data-id="6"></div>
<div class="aplbox-thumb" data-id="7"></div>
<div class="aplbox-thumb" data-id="8"></div>
<div class="aplbox-thumb" data-id="9"></div>
<div class="aplbox-thumb" data-id="10"></div>
<div class="aplbox-thumb" data-id="11"></div>
</div>
</div>
Related
I want to do section-by-section scrolling on the site. I'm not happy with the jquery option and ready-made libraries, so I decided to write my own in pure javascript. But nothing works for me. Can you tell me what's wrong?
let sections = [...document.querySelectorAll('.slide')];
let currentSection = 0;
let length = sections.length - 1;
window.addEventListener('wheel', function(e) {
e.preventDefault();
(e.deltaY > 0) ? ++currentSection : --currentSection;
if (currentSection < 0) currentSection = 0;
else if (currentSection > (length)) currentSection = (length);
scrollToSection(currentSection);
});
function scrollToSection(currentSection) {
sections.forEach((item, i) => {
if (i === currentSection) {
item.scrollIntoView({
behavior: 'smooth'
})
}
});
}
* {
padding: 0;
margin: 0;
}
div {
height: 100vh;
background-color: pink;
display: flex;
flex-wrap: wrap;
border:3px solid red;
}
<main>
<div className='slide'>1</div>
<div className='slide'>2</div>
<div className='slide'>3</div>
<div className='slide'>4</div>
</main>
I was hoping a kind soul might be able to assist.
I have a slideshow which auto-plays, my intention is to have the next button act as a visual aid, highlighting the when the next frame is coming in.
sync with the autoPlay interval.
Right now, the update func concludes too early, which is the best I have managed to do. Typically I have the clearInterval and setInterval conflicting creating shuddering animations.
What am I doing wrong?
<!doctype html>
<html lang="en">
<head>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
.carousel_wrapper {
height: 50vh;
width: 100%;
position: relative;
}
.carousel_frame {
width: 100%; height: 100%;
}
.carousel_controls {
position: absolute;
bottom: 0;
left: 0;
}
.prev, .next {
height: 50px;
width: 100px;
background: aqua;
display: inline-block;
}
.next {
background: linear-gradient(to right, white 0%, aqua);
}
.carousel_frame:nth-child(1) {
background: red;
}
.carousel_frame:nth-child(2) {
background: blue;
}
.carousel_frame:nth-child(3) {
background: green;
}
</style>
<script>
window.addEventListener('DOMContentLoaded', () => {
const homepage_carousel = new carousel();
});
function carousel() {
const carousel = document.getElementsByClassName('.carousel_wrapper')[0];
const frames = [...document.getElementsByClassName('carousel_frame')];
const prev_button = document.getElementsByClassName('prev')[0];
const next_button = document.getElementsByClassName('next')[0];
this.frameIndex = 1;
prev_button.addEventListener('click', () => {
this.resetPlay();
this.move(-1);
})
next_button.addEventListener('click', () => {
this.resetPlay();
this.move(+1);
})
this.hideAll = () => {
frames.forEach((f) => {
f.style.display = 'none';
});
}
this.show = () => {
this.hideAll();
frames[this.frameIndex - 1].style.display = 'block';
this.update_bg();
}
this.move = (amount) => {
this.frameIndex += amount;
this.frameIndex = (this.frameIndex > frames.length ? 1 : (this.frameIndex < 1) ? frame.lengh : this.frameIndex);
this.show();
}
this.update_bg = () => {
let w = 1;
let test = setInterval(adjust, 10);
function adjust() {
if (w >= 100) {
clearInterval(test);
w = 0;
} else {
w++;
next_button.style.backgroundImage = `linear-gradient(to right, white ${w}%, aqua)`
}
}
setInterval(adjust, 3000);
}
this.autoPlay = () => {
this.move(+1)
this.update_bg();
}
this.resetPlay = () => {
// clearInterval(timer);
// timer = setInterval(this.autoPlay(), 4000);
}
this.show();
const timer = setInterval(this.autoPlay, 3000);
}
</script>
</head>
<body>
<div class='carousel_wrapper'>
<div class='carousel_frame'>
<span>Headline</span>
<span>Description</span>
<span>CTA</span>
</div>
<div class='carousel_frame'>
<span>Headline</span>
<span>Description</span>
<span>CTA</span>
</div>
<div class='carousel_frame'>
<span>Headline</span>
<span>Description</span>
<span>CTA</span>
</div>
<div class='carousel_controls'>
<span class='prev'>Previous</span>
<span class='next'>
Next
</span>
</div>
</div>
</body>
</html>
I have a grid and when selecting an item in it, i want to add different classes to every column that is before or after the current item. I came up with the following function to do this, but wondering if theres an easier and simpler way to do this:
var items = document.querySelectorAll('.item');
var bodyWidth = 200;
var itemWidth = 50;
var itemsInRow = Math.floor(bodyWidth/itemWidth);
var activeItemIndexInRow;
var directionClass;
var otherItemIndexInRow;
var removeClasses = function(){
items.forEach(function (item, i) {
item.className = 'item';
});
}
items.forEach(function (selectedItem, selectedItemIndex) {
selectedItem.addEventListener('click', function(event) {
removeClasses();
activeItemIndexInRow = selectedItemIndex-Math.floor(selectedItemIndex/itemsInRow)*itemsInRow;
selectedItem.classList.add('active');
items.forEach(function (otherItem, otherItemIndex) {
otherItemIndexInRow = otherItemIndex-Math.floor(otherItemIndex/itemsInRow)*itemsInRow;
if(otherItemIndexInRow < activeItemIndexInRow) directionClass = 'green';
if(otherItemIndexInRow === activeItemIndexInRow) directionClass = 'red';
if(otherItemIndexInRow > activeItemIndexInRow) directionClass = 'blue';
otherItem.classList.add(directionClass);
});
});
});
* {
margin:0;
padding:0;
}
#wrapper {
width: 400px;
}
.item {
width:25%;
background:gray;
text-align:center;
height:100px;
line-height:100px;
color:#fff;
font-size:30px;
float:left;
}
.item.green {background:green}
.item.red {background:red}
.item.blue {background:blue}
.item.active {background:black}
<div id="wrapper">
<div class="item">1</div><div class="item">2</div><div class="item">3</div><div class="item">4</div><div class="item">5</div><div class="item">6</div><div class="item">7</div><div class="item">8</div><div class="item">9</div><div class="item">10</div>
</div>
This should work.
var items = document.querySelectorAll('.item');
var itemsInRow = 4;
items.forEach(function(selectedItem, selectedItemIndex) {
selectedItem.addEventListener('click', function(event) {
var directionClass;
selectedItem.classList.add('active');
var selectedCol = selectedItemIndex % itemsInRow;
items.forEach(function(otherItem, otherItemIndex) {
otherItem.className = 'item';
var otherCol = otherItemIndex % itemsInRow;
if (otherItemIndex === selectedItemIndex) directionClass = 'active';
else if (otherCol === selectedCol) {
directionClass = 'red';
} else {
directionClass = selectedCol < otherCol ? 'blue' : 'green'
}
otherItem.classList.add(directionClass);
});
});
});
* {
margin: 0;
padding: 0;
}
#wrapper {
width: 400px;
}
.item {
width: 25%;
background: gray;
text-align: center;
height: 100px;
line-height: 100px;
color: #fff;
font-size: 30px;
float: left;
}
.item.green {
background: green
}
.item.red {
background: red
}
.item.blue {
background: blue
}
.item.active {
background: black
}
<div id="wrapper">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
<div class="item">6</div>
<div class="item">7</div>
<div class="item">8</div>
<div class="item">9</div>
<div class="item">10</div>
</div>
When I click-drag (#cssNav) to the right, it is not moving proportionately along with the #html and #css div.
This might be something very obvious, but still am not able to figure it out, what am I missing here, please help?
Note: I don't want to use display:flex
codepen
$("#htmlNav").on("mousedown", dragStartH);
$("#cssNav").on("mousedown", dragStartH);
$("#jsNav").on("mousedown", dragStartH);
function dragStartH(e) {
e.preventDefault();
dragMeta = {};
dragMeta.pageX0 = e.pageX;
dragMeta.elem = this;
dragMeta.offset0 = $(this).offset();
dragMeta.codeWindow = "#" + $(e.target).attr("id").replace("Nav", "");
function handle_dragging(e) {
var change = e.pageX - dragMeta.pageX0;
var left = dragMeta.offset0.left + change;
$(dragMeta.elem).offset({ left: left });
$("#css").width($("#css").width() - change + "px");
$("#html").width($("#html").width() + change + "px");
}
function handle_mouseup(e) {
$("body")
.off("mousemove", handle_dragging)
.off("mouseup", handle_mouseup);
}
$("body").on("mouseup", handle_mouseup).on("mousemove", handle_dragging);
}
$(document).ready(function() {
var widthPercent = ($(window).width() - 30) / 3;
$("#html").width(widthPercent + "px");
$("#css").width(widthPercent + "px");
$("#js").width(widthPercent + "px");
});
html, body {
height: 100%;
margin: 0;
}
.container{
width:100%;
height: 100%;
background-color:#343;
display: flex;
flex-direction: column;
color: #fff;
margin: 0;
}
#preview, #code{
background-color:#433;
height: 50%;
width: 100%;
margin: 0;
}
#code{
border-bottom: #333 solid 2px;
width: 100%
}
#previewNav, #codeNav{
background-color:#bbb;
height: 10px;
width: 100%;
cursor: row-resize;
}
#html{
background-color: #BFB;
}
#css{
background-color: #FBB;
}
#js{
background-color: #BBF;
}
#html, #css, #js{
float: left;
width: 32%;
height: 100%;
}
#htmlNav, #cssNav, #jsNav{
background-color:#bbb;
float: left;
height:100%;
width: 10px;
cursor: col-resize;
z-index:10;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<div id="codeNav"></div>
<div id="code">
<div id="htmlNav"></div>
<div id="html">H</div>
<div id="cssNav"></div>
<div id="css">C</div>
<div id="jsNav"></div>
<div id="js">J</div>
</div>
<div id="previewNav"></div>
<div id="preview">P</div>
</div>
This is how I would do it:
Keep track of which handle you press with navTypeand check if the user is holding its mouse down with dragging.
Then when the user moves the mouse in the document and it is holding its mouse down (dragging) it will move the #html, #css and #js accordingly
Change your javascript into this:
var mouseX, prevMouseX, navType, change;
var dragging = false;
$("#cssNav").mousedown(function () {
dragging = true;
navType = "css";
});
$("#jsNav").mousedown(function () {
dragging = true;
navType = "js";
});
$(document).mousemove(function (e) {
mouseX = e.pageX;
if(dragging){
e.preventDefault();
change = mouseX - prevMouseX;
if(navType == "css" && ($("#css").width() - (change)) > 0 && ($("#html").width() + (change)) > 0){
var hw = $("#html").width();
var cw = $("#css").width();
$("#html").width(hw + change);
$("#css").width(cw - change);
} else if(navType == "js" && ($("#css").width() + (change)) > 0 && ($("#js").width() - (change)) > 0){
var cw = $("#css").width();
var jw = $("#js").width();
$("#css").width(cw + change);
$("#js").width(jw - change);
}
}
prevMouseX = mouseX;
}).mouseup(function () {
dragging = false;
}).mouseleave(function () {
dragging = false;
});
Javascript report designer should allow to create copies of selected divs into same panel.
I tried to use
function DesignerClone() {
$(".ui-selected").each(function () {
var newDiv = $(this).prop('outerHTML'),
parentpanel = $(this).parent(".designer-panel-body");
parentpanel.prepend(newDiv);
});
}
but all divs are lost. and empty panel appears.
To reproduce, run code snippet and select some divs by mouse click.
After that press clone button.
How to clone boxes ?
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<link rel="stylesheet" href="http://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css">
<style>
.designer-panel-body {
min-height: 1px;
overflow: hidden;
margin: 0;
padding: 0;
}
.panel-footer {
background-color: inherit;
}
.designer-panel,
.designer-resetmargins {
margin: 0;
padding: 0;
}
.designer-verticalline,
.designer-horizontalline,
.designer-rectangle {
font-size: 1pt;
border: 1px solid #000000;
}
.designer-field {
border: 1px solid lightgray;
white-space: pre;
overflow: hidden;
}
.ui-selecting {
background-color: lightskyblue;
color: white;
}
.ui-selected {
background-color: lightskyblue;
border-color: darkblue;
color: white;
}
.designer-label {
white-space: pre;
}
.designer-field,
.designer-label {
font-family: "Times New Roman";
font-size: 10pt;
z-index: 2;
}
.designer-verticalline,
.designer-horizontalline,
.designer-rectangle,
.designer-field,
.designer-image,
.designer-label {
position: absolute;
}
</style>
<script src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
<script src="http://code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
<script>
function DesignerClone() {
$(".ui-selected").each(function () {
var newDiv = $(this).prop('outerHTML'),
parentpanel = $(this).parent(".designer-panel-body");
parentpanel.prepend(newDiv);
});
}
function getpos(e) {
return {
X: e.pageX,
Y: e.pageY
};
}
function Rect(start, stop) {
this.left = Math.min(start.X, stop.X);
this.top = Math.min(start.Y, stop.Y);
this.width = Math.abs(stop.X - start.X);
this.height = Math.abs(stop.Y - start.Y);
}
$(function () {
var startpos;
var selected = $([]),
offset = {
top: 0,
left: 0
};
$(".designer-verticalline, .designer-rectangle, .designer-field, .designer-image").resizable();
var $liigutatavad = $(".designer-verticalline, .designer-horizontalline, .designer-rectangle, .designer-field, .designer-image, .designer-label");
$liigutatavad.draggable({
start: function (event, ui) {
var $this = $(this);
if ($this.hasClass("ui-selected")) {
// if this is selected, attach current offset
// of each selected element to that element
selected = $(".ui-selected").each(function () {
var el = $(this);
el.data("offset", el.offset());
});
} else {
// if this is not selected, clear current selection
selected = $([]);
$liigutatavad.removeClass("ui-selected");
}
offset = $this.offset();
},
drag: function (event, ui) {
// drag all selected elements simultaneously
var dt = ui.position.top - offset.top,
dl = ui.position.left - offset.left;
selected.not(this).each(function () {
var $this = $(this);
var elOffset = $this.data("offset");
$this.css({
top: elOffset.top + dt,
left: elOffset.left + dl
});
});
}
});
// ...but manually implement selection to prevent interference from draggable()
$(".designer-panel-body").on("click", "div", function (e) {
if ( /*!e.metaKey &&*/ !e.shiftKey && !e.ctrlKey) {
// deselect other elements if meta/shift not held down
$(".designer-panel-body").removeClass("ui-selected");
$(this).addClass("ui-selected");
} else {
if ($(this).hasClass("ui-selected")) {
$(this).removeClass("ui-selected");
} else {
$(this).addClass("ui-selected");
}
}
});
$(".designer-panel-body").selectable({});
});
</script>
</head>
<body>
<button type="button" class="btn btn-default" onclick="javascript:false;DesignerClone()">
<span class="glyphicon glyphicon-paste"></span>
</button>
<div class='panel designer-panel'>
<div class='panel-body designer-panel-body panel-warning' style='height:4cm'>
<div class='designer-field' contenteditable='true' style='top:2.30cm;left:5.84cm;width:10.24cm;height:0.63cm;font-family:Arial;font-size:14pt;font-weight:bold;'>vnimi+' '+dok.tasudok</div>
<div class='designer-field' contenteditable='true' style='top:2.30cm;left:16.37cm;width:2.68cm;height:0.61cm;font-size:14pt;'>DOK.kuupaev</div>
<div class='rectangle' style='border-width: 1px;background-color:#FFFFFF;top:2.99cm;left:1.34cm;width:18.05cm;height:5.29cm'></div>
<div class='designer-field' contenteditable='true' style='top:3.01cm;left:1.53cm;width:9.71cm;height:0.55cm;font-size:12pt;'>m.FIRMA</div>
<div class='designer-field' contenteditable='true' style='top:3.01cm;left:12.13cm;width:3.13cm;height:0.53cm;font-size:12pt;'>ise.telefon</div>
</div>
<div class='bg-warning'>
<div class='panel-footer'><i class='glyphicon glyphicon-chevron-up'></i> GroupHeader 1: str(dokumnr)+str(koopia,2)</div>
</div>
</div>
</body>
</html>
.appendTo takes selected element and removes it from previous position in the DOM.
jQuery.clone() is what you might be looking for.