Issue
I'm having trouble dragging a panel with the mouse to resize it. I thought it was a problem similar to this question on Stackoverlow, therefore solvable with flexbox
, but by analyzing and testing the code i realized that they are not the right solutions for my case, because my case is different. Flexbox and that question don't seem to be the solution. Maybe it's a problem that concerns Javascript and not CSS.
WHAT I WANT? I would like to be able to drag the line of the right panel (the one indicated in the image) and resize the panel, moving it to the right or left. Inside the right panel is an iframe
. If i only set widht:100%
to the iframe (in the css with id #preview
), then its resize works correctly, but when i also apply height:100%
to the iframe
, then it no longer works, the resize stops. I actually need the iframe
to also have height:100%
because i want the iframe to extend as long as the entire panel.
WHEN DOES THE PROBLEM OCCUR? If you drag the right panel line (the one indicated in the image) and move it from right to left, then the panel expands correctly. Subsequently, after having enlarged the panel, if you try to shrink it (dragging the line from right to left) and bring it back to its initial size, then everything freezes.
SOLUTION ATTEMPTS. I tried various (useless) solutions with css, i also tried using flexbox
and i also tried the solutions to the Stackoverflow question i was talking about above at this link, but it's all useless. The problem doesn't appear to be flexbox. Flexbox seems useless. So I'm thinking the problem might be the Javascript code i use to resize. I add: The comment of the kind user who suggested drag events is interesting. I tried, but it doesn't work (maybe my mistake, I don't know)
P.S: I would like to continue using pure JavaScript, I would not like to use jQuery. Also I would like to extend the iframe to the container using height:100% with percentage and not height: ? px using px
Can any of you help me please? Thank you
const gutters = document.querySelectorAll(".gutter");
const panes = document.querySelectorAll(".pane");
const minWidth = document.querySelector(".wrapper").style.getPropertyValue("--min-width");
const minHeight = document.querySelector(".wrapper").style.getPropertyValue("--min-height");
function resizer(e) {
window.addEventListener("mousemove", mousemove);
window.addEventListener("mouseup", mouseup);
// check gutter if vertical or horizontal
const is_vertical = e.currentTarget.classList.contains("gutter-v");
// get previous position (x or y depending on is_vertical)
const prev = is_vertical ? e.x : e.y;
// get current pane, the parent pane of the gutter you are moving
const currentPane = e.currentTarget.parentNode;
const currentPanel = currentPane.getBoundingClientRect();
// get previous pane, when move gutter-v:
// if current pane is center, prev pane will be left pane
// if current pane is right, prev pane will be center pane
// left pane will never be current pane cause it don't have gutter
const prevPane = currentPane.previousElementSibling;
const prevPanel = prevPane.getBoundingClientRect();
function mousemove(e) {
// minWidth and minHeight are string ('200px' and '100px' in this case), change them to integer
const min = parseInt(is_vertical ? minWidth : minHeight);
// calculate distance between prev and current position
const distance = prev - (is_vertical ? e.x : e.y);
// calculate new width/height of current pane and prev pane
const newCurrentSize = (is_vertical ? currentPanel.width : currentPanel.height) + distance;
const newPrevSize = (is_vertical ? prevPanel.width : prevPanel.height) - distance;
// if new width/height is less than min, return and don't change pane style
if (newCurrentSize < min || newPrevSize < min) return;
// change pane width/height depending on is_vertical
if (is_vertical) {
currentPane.style.width = newCurrentSize + "px";
prevPane.style.width = newPrevSize + "px";
} else {
currentPane.style.height = newCurrentSize + "px";
prevPane.style.height = newPrevSize + "px";
}
}
function mouseup() {
window.removeEventListener("mousemove", mousemove);
window.removeEventListener("mouseup", mouseup);
}
}
gutters.forEach((gutter) => gutter.addEventListener("mousedown", resizer));
*,
*::before,
*::after {
box-sizing: border-box;
}
body {
margin: 0;
}
.wrapper {
height: 100vh;
width: 100vw;
background: #333;
border: 6px solid #666;
display: flex;
}
.pane {
position: relative;
color: #fff;
/*
--min-width in .wrapper inline style
<div class="wrapper" style="--min-width: 200px;--min-height: 100px;">
*/
min-width: var(--min-width);
}
.pane:last-child {
flex-grow: 1;
}
.pane:has(.pane) {
padding: 0;
display: flex;
flex-direction: column;
}
.pane>.pane {
/*
--min-height in .wrapper inline style
<div class="wrapper" style="--min-width: 200px;--min-height: 100px;">
*/
min-height: var(--min-height);
}
.gutter {
--l: 100%;
--s: 10px;
background: #666;
position: absolute;
z-index: 1;
top: 0;
left: 0;
}
.gutter-v {
width: var(--s);
height: var(--l);
cursor: col-resize;
}
.gutter-h {
height: var(--s);
width: var(--l);
cursor: row-resize;
}
.left {
width: 600px;
}
.center_container {
width: 650px;
}
.center1 {
height: 700px;
}
#preview {
display: block;
width: 100%;
height: 100%;
background: #991717;
border: 0;
}
<div class="wrapper" style="--min-width: 200px;--min-height: 100px;">
<div class="pane left">
This is the left pane.
</div>
<div class="pane center_container">
<div class="gutter gutter-v"></div>
<div class="pane center1">
This is the center pane1
</div>
<div class="pane">
<div class="gutter gutter-h"></div>
This is the center pane2.
</div>
</div>
<div class="pane">
<div class="gutter gutter-v"></div>
<iframe id="preview"></iframe>
</div>
</div>
Solution
That's because iframe
is another page, when the mouse on iframe
the mousemove
event is interrupted.
You can add pointer-events: none;
to prevent this issue.
#preview.resizing {
pointer-events: none;
}
Then add/remove .resizing
when move start and end by js.
const iframes = document.querySelectorAll("iframe");
...
// in resizer()
iframes.forEach((iframe) => iframe.classList.add("resizing"));
// in mouseup()
iframes.forEach((iframe) => iframe.classList.remove("resizing"));
const gutters = document.querySelectorAll(".gutter");
const panes = document.querySelectorAll(".pane");
const minWidth = document.querySelector(".wrapper").style.getPropertyValue("--min-width");
const minHeight = document.querySelector(".wrapper").style.getPropertyValue("--min-height");
const iframes = document.querySelectorAll("iframe");
function resizer(e) {
window.addEventListener("mousemove", mousemove);
window.addEventListener("mouseup", mouseup);
// add .resizing when mousedown
iframes.forEach((iframe) => iframe.classList.add("resizing"));
// check gutter if vertical or horizontal
const is_vertical = e.currentTarget.classList.contains("gutter-v");
// get previous position (x or y depending on is_vertical)
const prev = is_vertical ? e.x : e.y;
// get current pane, the parent pane of the gutter you are moving
const currentPane = e.currentTarget.parentNode;
const currentPanel = currentPane.getBoundingClientRect();
// get previous pane, when move gutter-v:
// if current pane is center, prev pane will be left pane
// if current pane is right, prev pane will be center pane
// left pane will never be current pane cause it don't have gutter
const prevPane = currentPane.previousElementSibling;
const prevPanel = prevPane.getBoundingClientRect();
function mousemove(e) {
// minWidth and minHeight are string ('200px' and '100px' in this case), change them to integer
const min = parseInt(is_vertical ? minWidth : minHeight);
// calculate distance between prev and current position
const distance = prev - (is_vertical ? e.x : e.y);
// calculate new width/height of current pane and prev pane
const newCurrentSize = (is_vertical ? currentPanel.width : currentPanel.height) + distance;
const newPrevSize = (is_vertical ? prevPanel.width : prevPanel.height) - distance;
// if new width/height is less than min, return and don't change pane style
if (newCurrentSize < min || newPrevSize < min) return;
// change pane width/height depending on is_vertical
if (is_vertical) {
currentPane.style.width = newCurrentSize + "px";
prevPane.style.width = newPrevSize + "px";
} else {
currentPane.style.height = newCurrentSize + "px";
prevPane.style.height = newPrevSize + "px";
}
}
function mouseup() {
// remove .resizing when mouseup
iframes.forEach((iframe) => iframe.classList.remove("resizing"));
window.removeEventListener("mousemove", mousemove);
window.removeEventListener("mouseup", mouseup);
}
}
gutters.forEach((gutter) => gutter.addEventListener("mousedown", resizer));
*,
*::before,
*::after {
box-sizing: border-box;
}
body {
margin: 0;
}
.wrapper {
height: 100vh;
width: 100vw;
background: #333;
border: 6px solid #666;
display: flex;
}
.pane {
position: relative;
color: #fff;
/*
--min-width in .wrapper inline style
<div class="wrapper" style="--min-width: 200px;--min-height: 100px;">
*/
min-width: var(--min-width);
}
.pane:last-child {
flex-grow: 1;
}
.pane:has(.pane) {
padding: 0;
display: flex;
flex-direction: column;
}
.pane>.pane {
/*
--min-height in .wrapper inline style
<div class="wrapper" style="--min-width: 200px;--min-height: 100px;">
*/
min-height: var(--min-height);
}
.gutter {
--l: 100%;
--s: 10px;
background: #666;
position: absolute;
z-index: 1;
top: 0;
left: 0;
}
.gutter-v {
width: var(--s);
height: var(--l);
cursor: col-resize;
}
.gutter-h {
height: var(--s);
width: var(--l);
cursor: row-resize;
}
.left {
width: 600px;
}
.center_container {
width: 650px;
}
.center1 {
height: 700px;
}
#preview {
display: block;
width: 100%;
height: 100%;
background: #991717;
border: 0;
}
#preview.resizing {
pointer-events: none;
}
<div class="wrapper" style="--min-width: 200px;--min-height: 100px;">
<div class="pane left">
This is the left pane.
</div>
<div class="pane center_container">
<div class="gutter gutter-v"></div>
<div class="pane center1">
This is the center pane1
</div>
<div class="pane">
<div class="gutter gutter-h"></div>
This is the center pane2.
</div>
</div>
<div class="pane">
<div class="gutter gutter-v"></div>
<iframe id="preview"></iframe>
</div>
</div>
Answered By - Shuo
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.