I wanted to change height of a div when window is resized. I know it can be done with css using height:100%; but that doesn't work on what i need. I wanted to make this happen in pure javascript without JQuery or any other framework.
Here is what i have done:
<div id="left">
<div id="inner">
</div>
</div>
CSS
#left{
margin-top:40px;
width:200px;
height:576px;
background:white;
}
#inner{
height:100%;
overflow-y:scroll;
}
JAVASCRIPT
window.onload=
window.onresize=function(){
var left=document.getElementById('left');
var window_height = window.innerheight;
if ( window_height > 600px ) { left.style.height = document.body.offsetHeight
+"px"; }
else { }
}
The div with id left has to have the same margin. I just wanted to change the height of div to match the inner window height (in px no %).
Thank You.
window.innerheight should be window.innerHeight (capital H). Note that IE doesn't support it prior to IE9.
Also note that you're comparing an element with a number here:
if ( left < window_height )
// ^--- element
You probably wanted to get the height from left instead, as that condition will never be true.
please see jsfiddle jsfiddle
try to use console.log to know what kind of value or object you dealing with
window.onload = window.onresize = function () {
var left = document.getElementById('left');
var window_height = window.innerHeight;
console.log(left.offsetHeight);
console.log(window_height);
if (left.offsetHeight < window_height) {
left.style.height = window_height + "px";
} else {}
}
set 100% first to know the exact height number, then assign back to height.
updated code updated jsfiddle
window.onload = window.onresize = function () {
var left = document.getElementById('left');
console.log(left.offsetHeight);
var window_height = window.innerHeight;
if (left.offsetHeight < window_height) {
left.style.height = '100%';
left_height=left.offsetHeight;
console.log(left_height);
left.style.height = left_height + "px";
} else {}
};
For those looking for old-school solution that uses debounce based on timeouts, here is what you can do:
function debounce(func, wait = 20, immediate = true) {
let timeout;
return function() {
const context = this,
args = arguments;
const later = function() {
timeout = null;
if (!immediate) { func.apply(context, args); }
};
const callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) { func.apply(context, args); }
};
}
function updateHeight(div, height) {
div.style.height = `${height}px`;
}
window.addEventListener('resize', debounce(() => {
const div = document.querySelector('.selector');
updateHeight(div, 50);
}));
Debounce will throttle updates down (by default update will fire every 20ms during resizing). Note you need to update updateHeight arguments and .selector to match your div.
Related
I am definitely new to Javascript.My goal is to build two divs and animate the child just by using Javascript.But there is some kind of problem in my function, and despite this being a trivial task I couldn’t find anything.
So, these are my buttons and my divs(I’m just trying to figure out how the start button works, then I am going to deal with the others
//create elements
const start = document.createElement('button');
const reset = document.createElement('button');
const stop = document.createElement('button');
const parent = document.createElement("div");
const child= document.createElement("div");
document.body.append(parent);
parent.append(child);
document.body.append(start);
document.body.append(reset);
document.body.append(stop);
// style
parent.style.width = "200px";
parent.style.height = "200px";
child.style.width = "20px";
child.style.height = "20px";
child.style.background = "green"
parent.style.background = "red";
start.innerHTML = "start";
reset.innerHTML = "reset";
stop.innerHTML = "stop";
and this is my useless function which doesn’t look right
/functions and listeners
var g =setInterval(move(),2000);
function move(){
var pos = 0;
if (pos == 200) {
clearInterval(g);
}
else {
pos++;
child.style.top = pos + "px";
child.style.left = pos + "px";
}
}
start.addEventListener("click",move());
any kind of tip or advice is appreciated =)
You have several problems:
The pos variable needs to be declared outside of the function that
uses it so that its value won't be lost when the function runs and
then can be used when the function runs additional times.
The start button's click event handler should be where the interval
timer is started, otherwise it begins immediately.
Both setInterval() and .addEventListener() take
function references - - you do not invoke a function in
their arguments (unless that function returns a function and that
returned function is what you want to reference). So, neither should
have () after the function name.
Your parent and child elements need to be positioned so that they are
not in the normal document flow, otherwise setting a top or left
CSS property won't do anything.
Don't use .innerHTML when you aren't working with HTML strings as
.innerHTML has security and performance implications. When you just
have text to work with, use .textContent.
See other comments inline:
//create elements
const start = document.createElement('button');
const reset = document.createElement('button');
const stop = document.createElement('button');
const parent = document.createElement("div");
const child= document.createElement("div");
document.body.append(parent);
parent.append(child);
document.body.append(start);
document.body.append(reset);
document.body.append(stop);
/* Use CSS classes instead of inline styles */
parent.classList.add("parent");
child.classList.add("child");
start.textContent = "start";
reset.textContent = "reset";
stop.textContent = "stop";
//functions and listeners
var timer = null;
var pos = 0;
function move(){
// Since it's the top and left of the child that are being set, we
// need to subtract the width of the box from the size of the parent
// so that the child doesn't end with its top and left outside of the
// parent.
if (pos == 180) {
clearInterval(timer);
} else {
pos++;
child.style.top = pos + "px";
child.style.left = pos + "px";
}
}
start.addEventListener("click", function() {
// The timer should start when the button is clicked
timer = setInterval(move,20);
});
reset.addEventListener("click", function() {
clearInterval(timer); // Stop the timer so motion stops
pos = 0;
child.style.top = pos+ "px";
child.style.left = pos + "px";
});
/* The child needs to be taken out of the normal document flow so it can be
explicitly positioned, but we want it to be relative to the parent it is
inside of, so the parent also has to be positioned explicitly. */
.parent { position:relative; width: 200px; height:200px; background-color:red; }
.child { position:relative; width: 20px; height:20px; background-color:green; }
I want to call a function only once every time the div #blinds reach their max-height at 430px, how can I do this?
My Codepen: https://codepen.io/cocotx/pen/YzGBpVJ
window.addEventListener('mousemove', function(event) {
var blinds = document.getElementById("blinds");
blinds.style.height = event.clientY + 'px';
});
One polling way is adding the code below in your js if there are other behaviours changing the size of the element. Simply change 400 to the value you want.
var blinds = document.getElementById("blinds");
setInterval(() => {
let rect = blinds.getBoundingClientRect();
if (rect.height > 400)
console.log(" reach 400");
}, 100);
window.addEventListener('mousemove', function(event) {
var blinds = document.getElementById("blinds");
blinds.style.height = event.clientY + 'px';
// i added here the condition
if(blinds.offsetHeight > 430 /*the value you want*/){
//call your function
}
});
Notice that this doesn't work if you use blinds.style.height instead of blinds.offsetHeight, there's a difference between using these but i im still trying to figure it out.
I would suggest to clean your code:
window.addEventListener('mousemove',handler);
function handler(event){
...
if(blinds.offsetHeight >430){
//call your function
...
//and maybe remove the listener
window.removeEventListener('mousemove',handler);
}
};
EDIT: try this code
function hasReachedMax(){
var styles = getComputedStyle(blinds);
var borderBottom = styles.borderBottom.split("px")[0]; //this is to get the number of pixels
var borderTop = styles.borderTop.split("px")[0];
var maxH = styles.maxHeight.split("px")[0];
var currentDivSize = blinds.offsetHeight-borderBottom-borderTop;
return maxH == currentDivSize;
};
function resetTrigger(){
//the condition to reset your trigger, for example making the div element at least 5 px smaller than maxHeight
var styles = getComputedStyle(blinds);
var borderBottom = styles.borderBottom.split("px")[0];
var borderTop = styles.borderTop.split("px")[0];
var maxH = styles.maxHeight.split("px")[0];
var currentDivSize = blinds.offsetHeight-borderBottom-borderTop;
return maxH-currentDivSize>5;
};
//this should be part of your main code
var trigger = true;
window.addEventListener('mousemove', function(event) {
var blinds = document.getElementById("blinds");
blinds.style.height = event.clientY + 'px';
if(hasReachedMax()&&trigger){
//call your function
console.log("Im called now");
trigger=false;
}
if(resetTrigger()) trigger=true;
});
I have a function which basically runs when an arrow with the class 'downArrow' is click. The function will find the parent of that arrow then find the next sibling with a class of 'scrollPoint' and then scroll to that area. Everything I just described works fine for me the issue I am having is if the bottom of the document hits the bottom of my viewport before the top of the element I am scrolling to hits the top of the viewport it just glitches out and scrolls back to the very top of the document. So I think What I need to do is detect if this scenario is going to happen and then set a max scroll value so the scroll functions doesnt try to scroll passed the bottom of the document.
How would I detect if the bottom of the document will be visible on the viewport and prevent from scrolling that far?
I will provide my code below in hopes that it will help, if you have any questions or need more clarification of what I am asking for just let me know. Thanks
This is my component although for what i am asking only the scrollTo function is really relevant
exports.init = init;
function init (options){
var downArrows = document.querySelectorAll(options.selector);
downArrows.forEach(triggerScrollHandler);
}
function scrollTo(element, to, duration) {
if (duration < 0) return;
var difference = to - element.scrollTop;
var perTick = difference / duration * 10;
setTimeout(function() {
element.scrollTop = element.scrollTop + perTick;
if (element.scrollTop === to) return;
scrollTo(element, to, duration - 10);
}, 10);
}
function scrollHandler (e) {
e.preventDefault();
var el = this,
scrollPoint = findSibling(el),
offsetVal = scrollPoint.getBoundingClientRect(),
windowOffset = window.pageYOffset;
offsetVal = offsetVal.top + windowOffset - 1;
scrollTo(document.body, offsetVal, 600);
}
function findParent(el) {
while (el && el.parentNode) {
el = el.parentNode;
if (el.tagName) {
return el;
}
}
return null;
}
function findSibling (el) {
var parent = findParent(el),
siblings = document.querySelectorAll('.scrollPoint'),
scrollTo;
siblings.forEach(function (currentSib, i) {
if(scrollTo == 'found'){
scrollTo = currentSib;
}
if(currentSib == parent){
scrollTo = 'found'
}
});
return scrollTo;
}
function triggerScrollHandler (el) {
el.addEventListener('click', scrollHandler);
}
And this is where I call in my app.js
var scrollHandler = require('./components/scrollHandler.js');
(function(){
scrollHandler.init({
selector: '.downArrow'
});
}())
Put this in your scroll listener:
if (document.body.scrollHeight <= document.body.scrollTop + document.body.clientHeight ){
console.log('scrolled to bottom');
}
Simple, pure JS solution :)
I'm making a JavaScript function that auto-resizes a div to same width/height of the window, when the window is resized.
The function is pretty basic, however I've noticed significant "paint" lag when the window is resized. In a JS fiddle, with no other elements on the page or other JavaScript, performance isn't really an issue. However in a real-world project, the lag is really annoying and something I'd like to fix.
I've iterated over a few different techniques but haven't really noticed much performance increase. Is there something I'm missing here? There must be a way to do this that's doesn't kill browser performance.
Here is the first function:
1.
window.onresize = function (event) {
var resize = document.querySelector(".resize");
var w = window.innerWidth;
resize.style.width = w + "px";
resize.style.height = w + "px";
};
This has pretty much the worst performance out of all - http://jsfiddle.net/SY5Tn/
2.
function resizer(e,w) {
e.style.width = w + "px";
e.style.height = w + "px";
}
window.onresize = setInterval(function() {
var e = document.querySelector(".resize");
var w = window.innerWidth;
resizer(e,w);
}, 100);
this has a little better performance. Not much difference though http://jsfiddle.net/SY5Tn/2/
3.
function resizer() {
var resizeLoop;
resizeLoop = setInterval(function() {
var e = document.querySelector(".resize");
var w = window.innerWidth;
e.style.width = w + "px";
e.style.height = w + "px";
}, 100);
function clear() {
clearInterval(resizeLoop);
}
window.onresize = function () {
resizeLoop();
}
document.addEventListener('mouseup', function() {
clear();
document.removeEvenetListener('mouseup');
});
}
resizer();
This was the best I could come up with, although I still get an error "number is not a function"
http://jsfiddle.net/SY5Tn/3/
Is there a better way of doing this? (no Jquery please);
P.S - I can't post this on Code Review as only have 1 rep point over there so it doesn't allow me to post multiple links.
Try this:
resizeLoop = function(){
setInterval(function() {
var e = document.querySelector(".resize");
var w = window.innerWidth;
e.style.width = w + "px";
e.style.height = w + "px";
}, 100);
}
You can solve this by pure CSS also using viewport units.
.resize {
width: 100vw;
}
You can check the support here..
you can add
.resize {
width: 100%;
height: 100%;
}
This question already has answers here:
Moveable/draggable <div>
(9 answers)
Closed 5 years ago.
I want to create a movable/draggable div in native javascript without using jquery and libraries. Is there a tutorial or anythign?
OK, here's my personal code that I use for lightweight deployments (projects where using a library is either not allowed or overkill for some reason). First thing first, I always use this convenience function so that I can pass either an id or the actual dom element:
function get (el) {
if (typeof el == 'string') return document.getElementById(el);
return el;
}
As a bonus, get() is shorter to type than document.getElementById() and my code ends up shorter.
Second realize that what most libraries are doing is cross-browser compatibility. If all browsers behave the same the code is fairly trivial. So lets write some cross-browser functions to get mouse position:
function mouseX (e) {
if (e.pageX) {
return e.pageX;
}
if (e.clientX) {
return e.clientX + (document.documentElement.scrollLeft ?
document.documentElement.scrollLeft :
document.body.scrollLeft);
}
return null;
}
function mouseY (e) {
if (e.pageY) {
return e.pageY;
}
if (e.clientY) {
return e.clientY + (document.documentElement.scrollTop ?
document.documentElement.scrollTop :
document.body.scrollTop);
}
return null;
}
OK, the two functions above are identical. There're certainly better ways to write them but I'm keeping it (relatively) simple for now.
Now we can write the drag and drop code. The thing I like about this code is that everything's captured in a single closure so there are no global variables or helper functions littering the browser. Also, the code separates the drag handle from the object being dragged. This is useful for creating dialog boxes etc. But if not needed, you can always assign them the same object. Anyway, here's the code:
function dragable (clickEl,dragEl) {
var p = get(clickEl);
var t = get(dragEl);
var drag = false;
offsetX = 0;
offsetY = 0;
var mousemoveTemp = null;
if (t) {
var move = function (x,y) {
t.style.left = (parseInt(t.style.left)+x) + "px";
t.style.top = (parseInt(t.style.top) +y) + "px";
}
var mouseMoveHandler = function (e) {
e = e || window.event;
if(!drag){return true};
var x = mouseX(e);
var y = mouseY(e);
if (x != offsetX || y != offsetY) {
move(x-offsetX,y-offsetY);
offsetX = x;
offsetY = y;
}
return false;
}
var start_drag = function (e) {
e = e || window.event;
offsetX=mouseX(e);
offsetY=mouseY(e);
drag=true; // basically we're using this to detect dragging
// save any previous mousemove event handler:
if (document.body.onmousemove) {
mousemoveTemp = document.body.onmousemove;
}
document.body.onmousemove = mouseMoveHandler;
return false;
}
var stop_drag = function () {
drag=false;
// restore previous mousemove event handler if necessary:
if (mousemoveTemp) {
document.body.onmousemove = mousemoveTemp;
mousemoveTemp = null;
}
return false;
}
p.onmousedown = start_drag;
p.onmouseup = stop_drag;
}
}
There is a reason for the slightly convoluted offsetX/offsetY calculations. If you notice, it's just taking the difference between mouse positions and adding them back to the position of the div being dragged. Why not just use the mouse positions? Well, if you do that the div will jump to the mouse pointer when you click on it. Which is a behavior I did not want.
You can try this
HTML
<div id="one" style="height:50px; width:50px; border:1px solid #ccc; background:red;">
</div>
Js Script for draggable div
window.onload = function(){
draggable('one');
};
var dragObj = null;
function draggable(id)
{
var obj = document.getElementById(id);
obj.style.position = "absolute";
obj.onmousedown = function(){
dragObj = obj;
}
}
document.onmouseup = function(e){
dragObj = null;
};
document.onmousemove = function(e){
var x = e.pageX;
var y = e.pageY;
if(dragObj == null)
return;
dragObj.style.left = x +"px";
dragObj.style.top= y +"px";
};
Check this Demo
This code corrects the position of the mouse (so the dragged object doesn't jump when you start dragging) and works with touch screens/phones as well
var dragObj = null; //object to be moved
var xOffset = 0; //used to prevent dragged object jumping to mouse location
var yOffset = 0;
window.onload = function()
{
document.getElementById("menuBar").addEventListener("mousedown", startDrag, true);
document.getElementById("menuBar").addEventListener("touchstart", startDrag, true);
document.onmouseup = stopDrag;
document.ontouchend = stopDrag;
}
function startDrag(e)
/*sets offset parameters and starts listening for mouse-move*/
{
e.preventDefault();
e.stopPropagation();
dragObj = e.target;
dragObj.style.position = "absolute";
var rect = dragObj.getBoundingClientRect();
if(e.type=="mousedown")
{
xOffset = e.clientX - rect.left; //clientX and getBoundingClientRect() both use viewable area adjusted when scrolling aka 'viewport'
yOffset = e.clientY - rect.top;
window.addEventListener('mousemove', dragObject, true);
}
else if(e.type=="touchstart")
{
xOffset = e.targetTouches[0].clientX - rect.left; //clientX and getBoundingClientRect() both use viewable area adjusted when scrolling aka 'viewport'
yOffset = e.targetTouches[0].clientY - rect.top;
window.addEventListener('touchmove', dragObject, true);
}
}
function dragObject(e)
/*Drag object*/
{
e.preventDefault();
e.stopPropagation();
if(dragObj == null) return; // if there is no object being dragged then do nothing
else if(e.type=="mousemove")
{
dragObj.style.left = e.clientX-xOffset +"px"; // adjust location of dragged object so doesn't jump to mouse position
dragObj.style.top = e.clientY-yOffset +"px";
}
else if(e.type=="touchmove")
{
dragObj.style.left = e.targetTouches[0].clientX-xOffset +"px"; // adjust location of dragged object so doesn't jump to mouse position
dragObj.style.top = e.targetTouches[0].clientY-yOffset +"px";
}
}
function stopDrag(e)
/*End dragging*/
{
if(dragObj)
{
dragObj = null;
window.removeEventListener('mousemove', dragObject, true);
window.removeEventListener('touchmove', dragObject, true);
}
}
div{height:400px; width:400px; border:1px solid #ccc; background:blue; cursor: pointer;}
<div id="menuBar" >A</div>
<div draggable=true ondragstart="event.dataTransfer.setData('text/plain', '12345')">
drag me
</div>
<div ondragover="return false;" ondrop="this.innerHTML=event.dataTransfer.getData('text/plain')">
drop on me
</div>