How can I split the resizable panel vertically using current code HTML,CSS and JavaScript. Right now this code is working for horizontal resizable split. What are the changes I would have to do in this current code.
How can I split the resizable panel vertically using current code HTML,CSS and JavaScript. Right now this code is working for horizontal resizable split. What are the changes I would have to do in this current code.
// A function is used for dragging and moving
function dragElement(element, direction) {
var md; // remember mouse down info
const first = document.getElementById("first");
const second = document.getElementById("second");
element.onmousedown = onMouseDown;
function onMouseDown(e) {
//console.log("mouse down: " + e.clientX);
md = {
e,
offsetLeft: element.offsetLeft,
offsetTop: element.offsetTop,
firstWidth: first.offsetWidth,
secondWidth: second.offsetWidth
};
document.onmousemove = onMouseMove;
document.onmouseup = () => {
//console.log("mouse up");
document.onmousemove = document.onmouseup = null;
}
}
function onMouseMove(e) {
//console.log("mouse move: " + e.clientX);
var delta = {
x: e.clientX - md.e.clientX,
y: e.clientY - md.e.clientY
};
if (direction === "H") // Horizontal
{
// Prevent negative-sized elements
delta.x = Math.min(Math.max(delta.x, -md.firstWidth),
md.secondWidth);
element.style.left = md.offsetLeft + delta.x + "px";
first.style.width = (md.firstWidth + delta.x) + "px";
second.style.width = (md.secondWidth - delta.x) + "px";
}
}
}
dragElement(document.getElementById("separator"), "H");
.splitter {
width: 100%;
height: 100px;
display: flex;
}
#separator {
cursor: col-resize;
background-color: #aaa;
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='30'><path d='M2 0 v30 M5 0 v30 M8 0 v30' fill='none' stroke='black'/></svg>");
background-repeat: no-repeat;
background-position: center;
width: 10px;
height: 100%;
/* Prevent the browser's built-in drag from interfering */
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
#first {
background-color: #dde;
width: 20%;
height: 100%;
min-width: 10px;
}
#second {
background-color: #eee;
width: 80%;
height: 100%;
min-width: 10px;
}
<body>
<div class="splitter">
<div id="first"></div>
<div id="separator"></div>
<div id="second"></div>
</div>
</body>
I would do it like this. You will need another SVG image to design properly the separator because the previous one was created for horizontal purpose.
// A function is used for dragging and moving
function dragElement(element, direction) {
var md; // remember mouse down info
const first = document.getElementById("first");
const second = document.getElementById("second");
element.onmousedown = onMouseDown;
function onMouseDown(e) {
//console.log("mouse down: " + e.clientX);
md = {
e,
offsetLeft: element.offsetLeft,
offsetTop: element.offsetTop,
firstHeight: first.offsetHeight,
secondHeight: second.offsetHeight
};
document.onmousemove = onMouseMove;
document.onmouseup = () => {
//console.log("mouse up");
document.onmousemove = document.onmouseup = null;
}
}
function onMouseMove(e) {
//console.log("mouse move: " + e.clientX);
var delta = {
x: e.clientX - md.e.clientX,
y: e.clientY - md.e.clientY
};
if (direction === "V") // Vertical
{
// Prevent negative-sized elements
delta.x = Math.min(Math.max(delta.y, -md.firstHeight),
md.secondHeight);
element.style.top = md.offsetTop + delta.x + "px";
first.style.height = (md.firstHeight + delta.x) + "px";
second.style.height = (md.secondHeight - delta.x) + "px";
}
}
}
dragElement(document.getElementById("separator"), "V");
.splitter {
width: 100%;
height: 100px;
}
#separator {
cursor: col-resize;
background-color: #aaa;
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='3'><path d='M2 30 0 M5 0 v30 M8 0 v30' fill='none' stroke='black'/></svg>");
background-repeat: no-repeat;
background-position: center;
width: 100%;
height: 5px;
/* Prevent the browser's built-in drag from interfering */
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
#first {
background-color: #dde;
width: 100%;
height: 100%;
min-width: 10px;
}
#second {
background-color: #eee;
width: 100%;
height: 100%;
min-width: 10px;
}
<body>
<div class="splitter">
<div id="first"></div>
<div id="separator"></div>
<div id="second"></div>
</div>
</body>
Related
I have a visible cursor element on some blocks. And it follows perfectly. Block needs to show the user when you can play, drag, on links on blocks. But, when I need to display this block on the swiper slider and drag start slider - the block stops and resumes when drag stop.
Maybe I miss other events? dragstart, dragstop, pointerdown, pointerup dont help. Any solutions? Thanks
const swiper2 = new Swiper('.swiper-container', {
// Optional parameters
loop: false,
slidesPerView: 2,
slidesPerGroup: 1,
speed: 600,
freeMode: true,
draggable: true,
autoplay: false,
spaceBetween: 20,
});
var box = document.getElementById("cursor-id");
window.addEventListener('mousemove', function (e) {
var pos = e.pageX;
box.style.left = e.clientX + "px";
box.style.top = e.clientY + "px";
});
window.addEventListener('pointerdown', function (e) {
var pos = e.pageX;
box.style.left = e.clientX + "px";
box.style.top = e.clientY + "px";
});
window.addEventListener('drag', function (e) {
var pos = e.pageX;
box.style.left = e.clientX + "px";
box.style.top = e.clientY + "px";
});
window.addEventListener('pointerup', function (e) {
var pos = e.pageX;
box.style.left = e.clientX + "px";
box.style.top = e.clientY + "px";
});
window.addEventListener('mouseover', (e) => {
if (e.target.closest('.cursor-js')) {
box.classList.add('go-cur');
var cur = e.target.closest('.cursor-js').dataset.cursor;
box.querySelector('.cursor-text').innerHTML = cur;
}
});
window.addEventListener('mouseout', (e) => {
if (e.target.closest('.cursor-js')) {
box.classList.remove('go-cur');
box.querySelector('.cursor-text').innerHTML = '';
}
});
.swiper-container {
width: 600px;
height: 300px;
background: #fff;
}
.swiper-container .swiper-wrapper {
width: 100%;
height: 100%;
}
.swiper-slide {
background: #000;
color: #fff !important;
height: 100%;
}
.cursor-block {
position: fixed;
z-index: 9;
pointer-events: none;
background: #FFFFFF;
//cursor: none;
border-radius: 50%;
width: 0;
height: 0;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
transform: translate(-50%, -50%);
transition: width 0.4s ease, height 0.4s ease, box-shadow 0.4s ease;
}
.cursor-block.go-cur {
width: 150px;
height: 150px;
box-shadow: 3px 4px 0px rgba(0, 0, 0, 0.12);
}
.cursor-block span {
font-style: normal;
font-weight: 400;
font-size: 20px;
line-height: 20px;
text-transform: uppercase;
color: #000000;
text-align: center;
display: inline-block;
width: 100%;
max-width: 95%;
cursor: none;
pointer-events: none;
}
<link href="https://unpkg.com/swiper/swiper-bundle.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://unpkg.com/swiper/swiper-bundle.min.js"></script>
<div class="swiper-container cursor-js" data-cursor="drag me">
<div class="swiper-wrapper">
<div class="swiper-slide">
<p>Swiper slide1</p>
</div>
<div class="swiper-slide">
<p>Swiper slide2</p>
</div>
<div class="swiper-slide">
<p>Swiper slide3</p>
</div>
</div>
</div>
<span class="cursor-block" id="cursor-id">
<span class="cursor-text"></span>
</span>
I am trying to fit a slide nav on the right side of the splitter, which is able to split when dragging the separator based on the width of the right side. https://jsfiddle.net/74bewsdu/
I tried modifying the width to auto as well as the z-index, it still doesn't work well.
index
<div class="splitter">
<div id="first">
<iframe src="{{ route('child') }}" style="width:100%; height:100%" frameBorder="0">
Your browser isn't compatible
</iframe>
</div>
<div id="separator"></div>
<div id="second">
<div id="mySidenav" class="sidenav"></div>
<div style="font-size:30px;cursor:pointer" onclick="openNav()">☰ open</div>
</div>
</div>
</div>
javascript
function openNav() {
document.getElementById("mySidenav").style.width = "250px";
}
css
.sidenav {
height: 100%;
width: 0;
position: fixed;
z-index: 1;
top: 0;
right: 0;
background-color: #111;
overflow-x: hidden;
transition: 0.5s;
padding-top: 60px;
}
You could get the offsetWidth of the right side div (#second) plus the offsetWidth of the separator, and set the sliding nav width to that value. If you don't want to completely overlap the menu button, you could subtract it by the width of the menu button (or some arbitrary constant).
Example (see comments in lines between /* added */ and /* end added */ areas in the snippet below). Update: I also added code to check to see if the slider nav is open. Now, if you drag the slider when the side nav is open, it should be dynamically resized.
let navIsOpen = false; // variable to keep track of if the slider nav is open
function openNav() {
/* added */
// calculate width of right side div + separator
let width = second.offsetWidth + separator.offsetWidth;
// uncomment below line to subtract a value so the slider doesn't obscure the menu button/text
//width = width - 95;
document.getElementById("mySidenav").style.width = width + "px";
navIsOpen = true; // slider nav is open
/* end added */
}
// function is used for dragging and moving
function dragElement(element, direction) {
var md; // remember mouse down info
const first = document.getElementById("first");
const second = document.getElementById("second");
element.onmousedown = onMouseDown;
element.onmousedown = onMouseDown;
function onMouseDown(e) {
//console.log("mouse down: " + e.clientX);
md = {
e,
offsetLeft: element.offsetLeft,
offsetTop: element.offsetTop,
firstWidth: first.offsetWidth,
secondWidth: second.offsetWidth
};
first.style.pointerEvents = 'none';
document.onmousemove = onMouseMove;
document.onmouseup = () => {
//console.log("mouse up");
document.onmousemove = document.onmouseup = null;
}
}
function onMouseMove(e) {
//console.log("mouse move: " + e.clientX);
var delta = {
x: e.clientX - md.e.clientX,
y: e.clientY - md.e.clientY
};
if (direction === "H") // Horizontal
{
// prevent negative-sized elements
delta.x = Math.min(Math.max(delta.x, -md.firstWidth),
md.secondWidth);
element.style.left = md.offsetLeft + delta.x + "px";
first.style.width = (md.firstWidth + delta.x) + "px";
second.style.width = (md.secondWidth - delta.x) + "px";
}
/* added */
if (navIsOpen) { // check if slider nav is open, if so resize
openNav();
}
/* end added */
}
}
dragElement(document.getElementById("separator"), "H");
.splitter {
width: 100%;
height: 300px;
display: flex;
}
#separator {
cursor: col-resize;
background-color: #aaa;
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='30'><path d='M2 0 v30 M5 0 v30 M8 0 v30' fill='none' stroke='black'/></svg>");
background-repeat: no-repeat;
background-position: center;
width: 10px;
height: 100%;
/* prevent browser's built-in drag from interfering */
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
#first {
background-color: #dde;
width: 20%;
height: 100%;
min-width: 10px;
}
#second {
background-color: #eee;
width: 80%;
height: 100%;
min-width: 10px;
}
.sidenav {
height: 100%;
width: 0;
position: fixed;
z-index: 1;
top: 0;
right: 0;
background-color: #111;
overflow-x: hidden;
transition: 0.5s;
padding-top: 60px;
}
<div class="splitter">
<div id="first">
<iframe src="{{ route('child') }}" style="width:100%; height:100%" frameBorder="0">
Your browser isn't compatible
</iframe>
</div>
<div id="separator"></div>
<div id="second">
<div id="mySidenav" class="sidenav"></div>
<div style="font-size:30px;cursor:pointer" onclick="openNav()">☰ open</div>
</div>
</div>
I am trying to create a div resizer and due to some restrictions, I cannot use jQuery and I am forced to use pure JavaScript for that. In the current state, it works, but it breaks if the div that will have the slider does not have the position set to absolute. Is there a way to solve that issue? Thank you very much.
I am a student learning to write JavaScript/CSS/HTML code and so I am relatively new to this.
const BORDER_SIZE = 4;
const panel = document.getElementById("left_panel");
const StationaryPanel = document.getElementById("right_panel");
const parent = document.getElementById("parent");
const label1 = document.getElementById("lb1");
const label2 = document.getElementById("lb2");
const label3 = document.getElementById("lb3");
let m_pos;
function resize(e) {
const dx = m_pos - e.x;
m_pos = e.x;
lb1.innerHTML = panel.offsetWidth;
lb2.innerHTML = StationaryPanel.offsetWidth;
lb3.innerHTML = parent.offsetWidth;
//lb3.innerHTML = document.body.clientWidth;
panel.style.width = (parseInt(getComputedStyle(panel, '').width) + dx) + "px";
StationaryPanel.style.width = (parent.offsetWidth - panel.offsetWidth) + "px";
//StationaryPanel.style.width = (document.body.clientWidth - panel.offsetWidth) + "px";
}
panel.addEventListener("mousedown", function(e) {
if (e.offsetX < BORDER_SIZE) {
m_pos = e.x;
if (panel.style.width < panel.minWidth || panel.style.width > panel.maxWidth) {
return;
}
document.addEventListener("mousemove", resize, false);
}
}, false);
document.addEventListener("mouseup", function() {
document.removeEventListener("mousemove", resize, false);
}, false);
#left_panel {
position: absolute;
width: 96px;
min-width: 50px;
max-width: 500px;
padding-left: 4px;
height: 100%;
right: 0;
background-color: #f0f0ff;
}
#left_panel::before {
content: " ";
background-color: #ccc;
position: absolute;
left: 0;
width: 4px;
height: 100%;
cursor: w-resize;
}
#right_panel {
width: 1000px;
height: 100%;
background-color: #ff0000;
}
#parent {
width: 800px;
}
<body>
<div id="parent">
<div id="left_panel">
This is the left div, the one that moves
</div>
<div id="right_panel">
This is the right div, the one that stays the same
</div>
</div>
<p id="lb1"></p>
<p>This is the left panel width ^</p>
<p id="lb2"></p>
<p>This is the right panel width ^</p>
<p id="lb3"></p>
<p>This is the parent width ^</p>
</body>
Here is the simplest way you can do it using CSS if that is not an issue here no need to use JS for this feature, it is just an example but it definitely help you on your way.
#MainDiv {
display: flex;
flex-direction: row;
height: 200px;
width: 400px;
border: 1px solid red;
position: relative;
}
#leftDiv {
width: 200px;
border: 1px solid yellow;
}
#rightDiv {
border: 2px solid;
padding: 20px;
width: 300px;
/* you can make this vertical/auto to make resize both ways */
resize: horizontal;
overflow: auto;
}
<div id="MainDiv">
<div id="leftDiv">
Left Div
</div>
<div id="rightDiv">
Right Div
</div>
</div>
Here is it in Javascript:
var h = $('#handle'),
l = $('#left'),
r = $('#right'),
w = $('body').width() - 18;
var isDragging = false;
h.mousedown(function(e) {
isDragging = true;
e.preventDefault();
});
$(document).mouseup(function() {
isDragging = false;
}).mousemove(function(e) {
if (isDragging) {
l.css('width', e.pageX);
r.css('width', w - e.pageX);
}
});
#left,
#right {
border: 1px solid #aaa;
float: left;
height: 100px;
width: 48%;
}
#handle {
background: #000;
float: left;
height: 100px;
margin: 1px;
/* Slider width */
width: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="left"> Left</div>
<div id="handle"></div>
<div id="right">Right</div>
I understand that we need to use transform: rotate(ndeg); in order to rotate a specific element in CSS. In this case, I want to do it dynamically. Using jQuery, I want to rotate the box/container div when the user drags the handle (the red background) on n degrees as the user wishes. Is it possible in jQuery?
body {
padding: 50px;
}
.box_element {
border: 1px solid black;
width: 200px;
height: 200px;
position: relative;
z-index: -1;
}
.handle {
position: absolute;
bottom: -10px;
right: -10px;
width: 10px;
height: 10px;
border: 1px solid;
background: red;
z-index: 10;
}
<body>
<div class="box_element">
THIS IS TEST
<div class="handle"></div>
</div>
</body>
Here you need to write few code to make it possible, try live code https://codepen.io/libin-prasanth/pen/xxxzbLg
var stop,
active = false,
angle = 0,
rotation = 0,
startAngle = 0,
center = {
x: 0,
y: 0
},
R2D = 180 / Math.PI;
function start(e) {
e.preventDefault();
var bb = this.getBoundingClientRect(),
t = bb.top,
l = bb.left,
h = bb.height,
w = bb.width,
x,
y;
center = {
x: l + w / 2,
y: t + h / 2
};
x = e.clientX - center.x;
y = e.clientY - center.y;
startAngle = R2D * Math.atan2(y, x);
return (active = true);
}
function rotate(e) {
e.preventDefault();
var x = e.clientX - center.x,
y = e.clientY - center.y,
d = R2D * Math.atan2(y, x);
rotation = d - startAngle;
return (rot.style.webkitTransform = "rotate(" + (angle + rotation) + "deg)");
}
function stop() {
angle += rotation;
return (active = false);
}
rot = document.getElementById("draggable");
rot.addEventListener("mousedown", start, false);
window.addEventListener("mousemove", function(event) {
if (active === true) {
event.preventDefault();
rotate(event);
}
});
window.addEventListener("mouseup", function(event) {
event.preventDefault();
stop(event);
});
#draggable {
left: 50px;
top: 50px;
width: 100px;
height: 100px;
position: relative;
border: 1px solid #000;
}
#draggable:before{
content: "";
position: absolute;
bottom: -5px;
right: -5px;
width: 10px;
height: 10px;
background: #f00;
}
<div id="draggable">
</div>
You can make use of a css-variable and then change the value of the variable when clicked.
const box_element = document.getElementById('box_element');
const handle = document.getElementById('handle');
handle.addEventListener('click', function() {
let currentVal = getComputedStyle(box_element).getPropertyValue('--rotate_deg');
box_element.style.setProperty(
'--rotate_deg', ((parseInt(currentVal.replace('deg', '')) + 90) % 360) + 'deg');
});
:root {
--rotate_deg: 0deg;
}
.box_element {
margin: 1em;
border: 1px solid black;
width: 100px;
height: 100px;
position: relative;
z-index: -1;
transform: rotate(var(--rotate_deg))
}
.handle {
position: absolute;
bottom: -10px;
right: -10px;
width: 10px;
height: 10px;
border: 1px solid;
background: red;
z-index: 10;
cursor: pointer;
}
<div class="box_element" id="box_element">
THIS IS TEST
<div class="handle" id="handle"></div>
</div>
I want to make a draggle splitter between 2 panels. The following is a working version.
Now, I want to make the width of handle as thin as possible (less than 0.1px?), so there is no way to make the width (appear) smaller than 1px?
Additionally, when the splitter is thin, it is hard to select by the mouse. Is there a way to make a splitter easy to grab?
Taking JSBin as example, how did they manage to realise the splitters among the panels?
(function($) {
$.fn.drags = function(opt) {
opt = $.extend({
handle: "",
cursor: "ew-resize",
min: 10
}, opt);
if (opt.handle === "") {
var $el = this;
} else {
var $el = this.find(opt.handle);
}
var priorCursor = $('body').css('cursor');
return $el.css('cursor', opt.cursor).on("mousedown", function(e) {
priorCursor = $('body').css('cursor');
$('body').css('cursor', opt.cursor);
if (opt.handle === "") {
var $drag = $(this).addClass('draggable');
} else {
var $drag = $(this).addClass('active-handle').parent().addClass('draggable');
}
var z_idx = $drag.css('z-index'),
drg_h = $drag.outerHeight(),
drg_w = $drag.outerWidth(),
pos_y = $drag.offset().top + drg_h - e.pageY,
pos_x = $drag.offset().left + drg_w - e.pageX;
var mouseMove = function(e) {
var prev = $('.draggable').prev();
var next = $('.draggable').next();
var total = prev.outerWidth() + next.outerWidth();
var totalPercentage = parseFloat(prev.css('flex')) + parseFloat(next.css('flex'));
var offset = prev.offset();
if(offset){
var leftPercentage = ((e.pageX - offset.left - drg_w / 2) / total) * totalPercentage;
var rightPercentage = totalPercentage - leftPercentage;
if (leftPercentage * 100 < opt.min || rightPercentage * 100 < opt.min) {
return;
}
prev.css('flex', leftPercentage.toString());
next.css('flex', rightPercentage.toString());
}
}
$drag.css('z-index', 1000).parent().on("mousemove", mouseMove).on("mouseup", function() {
$(this).off("mousemove", mouseMove).off("mouseup");
$('body').css('cursor', priorCursor);
$('.draggable').removeClass('draggable').css('z-index', z_idx);
});
e.preventDefault(); // disable selection
});
}
})(jQuery);
$('.handle').drags();
.flex-box {
display: flex;
width: 100%;
margin: 0;
height: 300px;
}
.flex-box .col {
border: 1px solid grey;
flex: 0.33;
padding: 12px;
overflow-y: auto;
overflow-x: hide;
}
.handle {
width: 1px;
text-align: center;
background: grey;
transition: all ease-in 0.1s;
}
.draggable {
background: grey;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="flex-box">
<div class="col">
<p>Pellentesque ...</p>
</div>
<div class="handle"></div>
<div class="col">
<p>Pellentesque ...</p>
</div>
</div>
If you'd like the handle to appear thinner try applying a negative value to the right "col" e.g. margin-left: -2px; so it overlaps the left "col" border on the left of it. I don't think you can make the width "appear" as 0.1px. Firefox is the only browser that renders such value. (https://css-tricks.com/forums/topic/0-1px-borders/)
.flex-box .col:last-child {
margin-left: -2px;
}
//raise handle layer to top
.handle {
.....
z-index: 9999;
}
Hope this helps...
*Edit:
This is the closest I could get to your request:
.flex-box {
display: flex;
width: 100%;
margin: 0;
height: 300px;
}
.flex-box .col {
border: 1px solid grey;
flex: 0.33;
padding: 12px;
overflow-y: auto;
overflow-x: hide;
}
.flex-box .col:last-child {
margin-left: -6px;
}
.handle {
width: 5px;
text-align: center;
transition: all ease-in 0.1s;
z-index: 999;
overflow: visible;
}
.handle-inner{
width: 5px;
height: 100%;
position: relative;
margin-left: -10px;
}
.draggable {
background: grey;
}
Jsbin :
https://jsbin.com/nupefekuhu/edit?html,css,js,output