And I want to get the width or distance or pixel that between the div and left side of of window/viewport.
And another width again between the div to the right side of the window.
I will use the width to create a left line and right line.
But I am poor in jQuery, I try offset but seems nothing happen.
So I back to 0 again so I didn't include fiddle here since I got nothing inside.
But I have attached with the image link as below, to explain my question.
Please help me on try to get the width, I can create the line myself.
Thank you.
var of = $(ele).offset(), // this will return the left and top
left = of.left, // this will return left
right = $(window).width() - left - $(ele).width() // you can get right by calculate
Maybe this can help you.
After all, .width() isn't the only answer, like innerWidth() or outerWidth()
There is two options
One is you can use red line as image and you can place the div over the red line.
Second one,
If you want to calculate:
Left div width = parent div width - child div offset;
Right div width = parent div width - child div offset + child div width;
var parentdiv = document.getElementById("ParentDivID");
var parentWidth = parentdiv.offsetWidth;
var childdiv = document.getElementById("childDivID");
var childWidth = childdiv.offsetLeft;
This is easier to do with POJ (plain old javascript). Get the position of the element on the screen. Then evaluate its left property. That will be the width of your left line. Then subtract its right property from the width of the screen. That will be the width of your right line.
var x = document.getElementById('myDiv').getBoundingClientRect();
var myLeftLineWidth = x.left;
var myRightLineWidth = screen.width - x.right;
For more information see this post.
If you want the width of the window instead of the screen, change screen.width to window.innerWidth. If you don't want the scrollbar, etc. to be included in the width, use document.documentElement.clientWidth. (For more info on these, see this.)
We can work out that where the box starts with .offset().
Next, we can work out where the box ends with .offset() + .width().
We now know where our box sits on the x-axis.
Now let's see what we have to the left of our box with .left which can run on our .offset().
We've now worked out how much space there is to the left and how wide our box is.
Finally, we can put what we've worked out together, we can get the page width $(window).width() and minus what there is to the left of our box (stage 2) and the width of our box (stage 1) and that will only leave what is to the right of our box.
That's the theory anyway now let's have a look at some code. You'll see I'm working out all the bits from the theory and then adding some visual representation.
calcSizes = function() {
var boxPos = $(".box").offset(),
toLeft = boxPos.left,
toRight = $(window).width() - ($(".box").width() + toLeft);
$(".left").width(toLeft + "px");
$(".right").width(toRight + "px");
console.log("Right: " + toRight + "px");
console.log("Left: " + toLeft + "px");
console.log("Width: " + $(".box").width() + "px");
console.log(
$(window).width() + "px = " +
toRight + "px + " +
toLeft + "px + " +
$(".box").width() + "px"
);
console.log(" ");
}
calcSizes();
body {
margin: 0
}
.box,
.indicator {
padding: 10px 0;
text-align: center
}
.box {
width: 100px;
background: #FF5722;
margin-left: 60%
}
.indicator {
background: repeating-linear-gradient( 45deg, #F44336, #F44336 10px, #D32F2F 10px, #D32F2F 20px);
overflow: hidden;
transform: translatey(-100%);
opacity: .8
}
.left {
float: left
}
.right {
float: right
}
button {
position: fixed;
top: 55px;
left: 30px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="box">BOX</div>
<div class="left indicator">
LEFT
</div>
<div class="right indicator">
RIGHT
</div>
<button onclick="calcSizes()">
Recalculate
</button>
Hope this makes sense and helps you with your project.
You can do that with JavaScript, no need for jQuery:
var mydiv = document.getElementById('mydiv');
var offset = mydiv.getBoundingClientRect();
var offsetRight = document.documentElement.clientWidth - offset.right;
var offsetLeft = offset.left;
JSFiddle
Related
I'm working on a popup box that shows some text some position away from an element when the cursor hovers over it. You can see a simplified demo here: https://jsfiddle.net/xsvm2Lur/61/
Right now the popup box will squash up when it is near the bounding box. I want the popup to appear to the bottom-left (if the popup will overflow to the right) or top-left (if the popup will overflow to the bottom and to the right) of the hovered element's position if the popup will overflow.
The position and text that will be shown are dynamically generated (e.g. I don't know before rendering).
Right now I have a working version using Javascript. The way I go about it is:
Get the text that will be displayed. Count the number of characters that is going to be displayed x 0.25em for each character to get the width of the text.
Calculate the width of the displayed string + padding (left and right). Let's call it textLength. This will be set as the popup's width so all the text goes into 1 line.
If textLength + x position of the cursor > box width, "invert" the popup box on the x-axis by deducting the popup's "left" value by textLength and some distance away from the element.
Repeat the same check for the y position, i.e. if cursor position + line height (1em) + bottom padding > box height, invert y.
The solution works, but I'm wondering if there's a better way to do this without character counting, or if there is another way to do it elegantly, maybe CSS only without Javascript?
Sadly, I don't believe there is a way to do it with CSS only. However, by working on your fiddle, I've managed to add the functionality you wanted.
The way I went about it was just to include a reference to the container and check whether the popup position and size were inside the container BoundingClientRect.
This is the updated code for the popupShow function:
const showPopup = (top, left, text, container) => {
popup.textContent = text;
const containerBCR = container.getBoundingClientRect();
const popupBCR = popup.getBoundingClientRect();
const popupWidth = popupBCR.width,
popupHeight = popupBCR.height;
let popupTop = top + 20,
popupLeft = left + 20,
newPopupWidth;
console.log("height: ", popupHeight);
console.log("top: ", top);
console.log("bottomPopup: ", top + 20 + popupHeight);
console.log("bottomBoundary", containerBCR.bottom);
if (left + 20 + popupWidth > containerBCR.right) {
popupLeft = left - popupWidth;
if (popupLeft < containerBCR.left) {
popupLeft = containerBCR.left;
newPopupWidth = left - containerBCR.left;
}
}
if (top + 20 + popupHeight > containerBCR.bottom) {
popupTop = top - popupHeight;
if (popupTop < containerBCR.top) {
popupTop = containerBCR.top;
}
}
popup.style.top = popupTop + "px";
popup.style.left = popupLeft + "px";
popup.style.width = newPopupWidth;
popup.style.visibility = 'visible';
}
As you can see, I've also edited the popup to use "visibility: hidden" instead of "display: none". This is because if the display is set to "none", we won't be able to get his size (there might be workarounds for this, though).
Try checking out the updated fiddle and tell me what you think.
I've pushed one circle a little bit further down because the code doesn't currently check for the padding of the popup, so it was overflowing a little (few pixels).
This is based on quadrants, simple calculates if we are over 50% width and/or height and swaps the style to use the right or bottom instead. This doesn't care about the content of the popup, no measuring required.
const popup = document.getElementById("pop-up")
const parsePx = (px) => parseFloat(px.slice(0, -2))
const showPopup = (text, position) => {
popup.textContent = text;
popup.style.top = position.top;
popup.style.left = position.left;
popup.style.right = position.right;
popup.style.bottom = position.bottom;
popup.style.display = 'inline-block';
}
const hidePopup = () => {
popup.style.display = 'none';
}
const circles = document.querySelectorAll(".red-circle")
circles.forEach(el => el.addEventListener('mouseover', (e) => {
const hoveredEl = e.target;
const textContent = hoveredEl.getAttribute('data-content');
//get absolute position of elements
let elBounds = hoveredEl.getBoundingClientRect();
//get absolute position of parent;
let ctBounds = popup.parentElement.getBoundingClientRect();
//calculate relative positions
let left = elBounds.left - ctBounds.left + (elBounds.width / 2),
top = elBounds.top - ctBounds.top + (elBounds.height / 2),
width = ctBounds.width,
height = ctBounds.height
//prepare position settings
let position = { left: "auto", top: "auto", bottom: "auto", right: "auto" }
//calculate if we're over 50% of box size
if(top>ctBounds.height/2) position.bottom = ctBounds.height - top + 20 + 'px'; else position.top = top + 20 + 'px';
if(left>ctBounds.width/2) position.right = ctBounds.width - left + 20 + 'px'; else position.left = left + 20 + 'px';
showPopup(textContent, position);
}))
circles.forEach(el => el.addEventListener('mouseout', (e) => { hidePopup() }))
.container { width: 200px; height: 200px; border: 1px solid black; position: relative;}
.red-circle { border-radius: 50%; background: red; width: 20px; height: 20px; position: absolute;}
#pop-up { background-color: #EFEFEF; padding: 0.25em; position: absolute;}
<div class="container">
<div style="top:20px;left:20px;" class="red-circle" data-content="This is a red circle"></div>
<div style="top:10px;left:150px;" class="red-circle" data-content="This is the top-right red circle"></div>
<div style="top:140px;left:150px;" class="red-circle" data-content="This is the bottom-right red circle"></div>
<div style="top:140px;left:15px;" class="red-circle" data-content="This is the bottom-left red circle"></div>
<span style="display:hidden" id="pop-up"></span>
</div>
There is one div element positioned absolutely in a relative container. It is initially positioned under one of four buttons. Based on which button is clicked, I calculate with JS the x coordinate of the button and move the div element underneath that button. Here's my markup and JS:
<div id='container-of-four-buttons' style="width: 100%; position: relative;">
<button>Foo</button>
<button>Buzz</button>
<button>Foo</button>
<button>Buzz</button>
</div>
<div id='followAlong-container' style="width: 100%; position: relative;">
<div class='followAlong-div' style="position:absolute; width: 15px; height: 13px;">Some stylized arrow</div>
</div>
var initialDiv = /* selected the second button to be initial */
var followAlongDiv = document.querySelector('followAlong-div');
var buttons = document.querySelectorAll('button');
followAlongDiv.style.left = initialDiv + 89 + 'px';
buttons.forEach(function(btn) {
btn.addEventListener('click', function() {
let xCoord = 0;
xCoord += (div.offsetLeft - div.scrollLeft + div.clientLeft);
followAlongDiv.style.left = xPos + 17 + 'px';
});
});
However, if I resize the browser, the four button elements shrink towards eachother, but the followAlongDiv stays at the same spot because it is positioned absolutely in its relative container.
How do I calculate the amount of width the browser has resized and update the position of the followAlongDiv?
I will use window.addEventListener('resize', updatePosition), but I just don't know how to approach the formulation of the updatePosition function.
First, 'followAlong-div' is a class (needs '.' before the className ):
var followAlongDiv = document.querySelector('.followAlong-div');
Second, I do not understand why you have this line:
xCoord += (div.offsetLeft - div.scrollLeft + div.clientLeft);
For resizing just needs:
window.onresize = ()=>{
var xCoord = 0;
xCoord += (selectedButton.offsetLeft);
followAlongDiv.style.left = xCoord + 'px';
}
Based on your code, I think this is what you want: https://jsfiddle.net/vua4eLhc/
Hope it helps!
I've been working on a website (scibowltest.github.io) in which the font-size for an element is determined by javascript. If you go in to the website, it looks fine when displayed on a laptop/desktop with the browser at full width and height. However, if you resize the window to make the width smaller, the font starts to overflow the div in which it is supposed to be contained.
The following code is for the function font-sizer, which determines how big the font-size will be.
function fontSizer(text, box, scale) {
var textID = "#" + text;
var boxID = "#" + box;
var boxHeight = $(boxID).height();
var boxWidth = $(boxID).width();
var fontSize = 0;
if (boxHeight >= boxWidth) {
fontSize = (boxWidth * scale) + "px";
} else if (boxHeight < boxWidth) {
fontSize = (boxHeight * scale) + "px";
} else {}
var textHeight = $(textID).height();
var textWidth = $(textID).width();
if (textWidth > boxWidth) {
fontSize = ((fontSize * (scale * boxWidth)) / (textWidth)) + "px";
} else {}
$(textID).css("font-size", fontSize);
}
The function works based on the smaller dimension of the div (box) containing the text. However, the last if statement tries to compensate for those situations in which the text's width is greater than the div's width to try to shrink the fontsize so that the text's width is equal to the div's width times the scale.
Obviously, from looking at the website, this last if statement isn't working. If anyone could help, I would appreciate it!
For a pure CSS solution you can use some of the new length units that are intended exactly for your usecase - different screen sizes.
Play around with vw,vh,vmin,vmax and see what gives you the best results. I personally use vmin a lot.
It requires a bit of fiddling but would eliminate the use of javascript.
Also I used <wbr> in this example (although it should not be needed) - a "word break opportunity" to additionally prevent overflowing.
div {
width: 40vmin;
font-size: 8vmin;
border: 1px solid red;
resize: both;
text-align: center;
}
p {
width: 40vw;
font-size: 8vw;
border: 1px solid red;
resize: both;
text-align: center;
}
resize the screen to see the fonts scale:
<div>Start/<wbr>Stop</div>
<p>Start/<wbr>Stop</p>
I have created a magnifier in pure js. What I discovered in needing to translate the mouse position of a div relative to its parents is that in calculating the top for the overlaying magnifier div, the offsetTop works differently than the offsetLeft. After adjusting for what should be the top, I need to subtract the whole container div's offsetHeight.
The line in the code in question is this:
magnifier.style.top = yPosition - container.offsetHeight + "px";
Why do I need to subtract container.offsetHeight?
I know I've read something regarding this, but can't find it.
Disclaimers This code is working. I am asking so I (and those following) can understand how the box model works.
I know there are jQuery alternatives that are more cross browser reliable. I like to code it myself so that I can learn how it all works. If you see something which is not compatible for a modern browser, feel free to comment.
Lastly, For anyone using this, I removed code from this example to adjust for transforms. For example, if the wrapper has a transform: translate(-50%, 0); to center the wrapper horizontally, you will need to add the resulting amount of the translation (which translates to the wrapper's left position) back into the calculation.
I have created a jsfiddle here. I left more comments in the Fiddle as to methodology if anyone is interested.
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="../css/ms.js"></script>
<style type="text/css">
/********************/
body {
background-color: #FFF;
margin-left: 30px;
margin-top: 10px;
}
.wrapper {
position: absolute;
left: 100px;
}
#container {
width: 527px;
height: 450px;
border: 5px black solid;
overflow: hidden;
background-color: #F2F2F2;
cursor: pointer;
}
#image {
width: 527px;
height: 450px;
}
#magnifier {
width: 250px;
height: 250px;
overflow:hidden;
position:relative;
z-index: 1000;
border: solid 1px;
}
#magnifier img {
position: absolute;
}
</style>
</head>
<body>
<div class="wrapper" id="wrapper">
<div id="container">
<img id="image" src="../docs/grade-2/jpg/g2-bb-saints-francis.jpg">
<div id="magnifier" class="magnifier">
<img id="imagecopy">
</div>
<br>
</div>
<input type="button" value="Zoom" onClick="initmagnifier('magnifier', 'image', 'imagecopy');"><br>
</div>
<script>
function initmagnifier(magnifier, image, imagecopy){
var magnifier = document.getElementById("magnifier");
var container = document.getElementById("container");
var wrapper = document.getElementById("wrapper");
var img = document.getElementById(image);
var imgcopy = document.getElementById(imagecopy);
var zoom = 2;
container.addEventListener("mousemove",
function(e){
movemagnifier(e, img, imgcopy, magnifier, container, wrapper, zoom)
}, false);
var src = img.src;
imgcopy.src = src;
var src2 = imgcopy.src;
imgcopy.height = img.height * zoom;
imgcopy.width = img.width * zoom ;
}
function movemagnifier(e, img, imgcopy, magnifier, container, wrapper, zoom) {
// to get the left & top of the magnifier
// position needs to be adjusted for WRAPPER & CONTAINER top and left
// gets the top and left of the container
var containerPosition = getPosition(e.currentTarget);
// adjust out the CONTAINER's top / left
// Then takes 1/2 the hight of the MAGNIFIER and subtracts it from the MOUSE position to center MAGNIFIER around the MOUSE cursor
var xPosition = e.clientX - containerPosition.x - (magnifier.clientWidth / 2);
var yPosition = e.clientY - containerPosition.y - (magnifier.clientHeight / 2);
magnifier.style.left = xPosition + "px";
magnifier.style.top = yPosition - container.offsetHeight + "px";
// Adjust for zoom
// adjust the MAGNIFIER's top/left at an equal pace to the zoom amount
var yTravel = (e.clientY - containerPosition.y ) * (zoom - 1);
var yimgPosition = -(yPosition - container.clientTop + yTravel);
imgcopy.style.top = yimgPosition + "px";
var xTravel = (e.clientX - containerPosition.x) * (zoom - 1); // * 1.5
var ximgPosition = -(xPosition + xTravel);
imgcopy.style.left = ximgPosition + "px";
console.log('****');
console.log(e.clientY); // MOUSE POSTION
console.log(containerPosition.y);
console.log(wrapper.offsetTop);
console.log(wrapper.clientHeight);
console.log(container.offsetTop);
console.log(container.clientHeight);
console.log(yPosition);
console.log(container.offsetHeight);
console.log(magnifier.style.top);
}
function getPosition(element) {
var xPosition = 0;
var yPosition = 0;
// element is the CONTAINER
// This calculates the postion of the element (CONTAINER) TOP & LEFT relative to ALL parents
while (element) {
// if transform: translate in place for x and y,
// add it back as it skews the offsetLeft offsetTop values by the translate amount
xPosition += ((element.offsetLeft) - element.scrollLeft);
yPosition += ((element.offsetTop) - element.scrollTop);
element = element.offsetParent;
}
return { x: xPosition, y: yPosition };
}
</script>
</body>
</html>
It took me longer than I care to admit, but I have found the reason. In your fiddle you position the #magnifier-element relative, which means you have to move it from its 'natural' position, which is below the image inside the container.
So with every move you have to compensate for this, by pulling the #magnifier to the top/left position of the container, the left position already matches, but the 'natural' top position of the #magnifier is the full height of the container, as you calculate from the top/left position of the #container, you need to subtract the #container height.
A simple fix is to add position: relative to the #container and change position: relative on the #magnifier to position: absolute.
This will give you the expected coordinate system for the #magnifier as top: 0; left: 0 for the absolute positioned element is the top left corner of the its relative parent (the first positioned parent element, in this case #container).
a working example without the need to to subtract container.offsetHeight.
While I'm at it, you may want to look into the Element.getBoundingClientRect function, as you can get all information you need to determine the position in a single call.
I have three blocks, I want them positioned at the bottom always, regardless of the viewport height, and when there's not enough height to show all of it, I want them to hide from the bottom, NOT the top.
I tired a flexbox solution: http://jsbin.com/kutipequxe/1/edit?css,output
.. it almost works, except on low resolutions, the blocks hide from top, bottom remains visible.
I also tried another solution: http://jsbin.com/ruhigijeba/1/edit?css,output
.. well this keeps the top always visible, but just hides the bottom altogether, including the other two blocks.
I even tried a JS solution:
var vh = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
var topHeight = document.getElementById('top').offsetHeight;
console.log('Viewport Height: ' + vh);
function getHeight(element) {
console.log(document.getElementsByClassName(element));
var offsetHeight = document.getElementsByClassName(element)[0].offsetHeight;
console.log('offsetHeight: ' + offsetHeight);
var marginTop = vh - (topHeight + offsetHeight);
console.log('marginTop: ' + marginTop);
document.getElementsByClassName(element)[0].style.marginTop = marginTop + "px";
}
getHeight("card-1");
getHeight("card-2");
getHeight("card-3");
... but it still hides the blocks from top!
try it with CSS media queries:
At the end of your CSS just add
#media screen and (max-height: 120px) {
div#top {
display: none;
height: 0px;
}
#main {
height: 100vh;
}
}
[edit] appearently thats not what oyu were asking for.
so... in your second jsbin example, add this to your .cards class:
position: sticky;
bottom: 0;
and to your #cards id:
overflow: hidden;
http://jsbin.com/zijedofija/1/
it does not work on chrome 35+ though: Why doesn't position: sticky work in Chrome?
my best bet would be to use a jquery plugin for chrome: https://github.com/filamentgroup/fixed-sticky
Ended up using Javascript and CSS media queries to achieve the desired results:
var vh = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
var topHeight = document.getElementById('top').offsetHeight;
function getHeight(element) {
var elementHeight = document.getElementsByClassName(element)[0].offsetHeight;
var offsetTop = vh - (topHeight + elementHeight);
var cardsContainerHeight = document.getElementById('cards').offsetHeight;
if (elementHeight < cardsContainerHeight) {
document.getElementsByClassName(element)[0].style.top = offsetTop + "px";
}
}
var resize = function(event) {
getHeight("card");
}();