Position bottom element of top parent element - javascript

I am making this simple tooltip where I want to position the tooltip bottom at the top of the parent element. I want to do this by getting the height of the tooltip element and set this number negative to the top positioning.
The problem is that at the time that I hover the element, the tooltip height is 0, according to console.log();
$('.tooltip').hover(function() {
var content = $(this).data('tip-content');
var element = $(this).find('.tip-content');
if(element.length == 0 ) {
var html = $('<p class="tip-content">' + content + '</p>');
var height = html.height();
console.log(height);
html.css('top', - height);
$(this).prepend(html);
} else {
element.remove();
}
});
.element {
height: 50px;
width: 50px;
margin: 50px auto;
background: #000;
}
.tooltip {
position: relative;
}
.tooltip .tip-content {
width: 180px;
margin-left: -98px;
padding: 10px 5px;
position: absolute;
left: 50%;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
background: #294a72;
font-size: 0.75em;
color: #fff;
text-align: center;
}
.tooltip .tip-content:after {
top: 100%;
left: 50%;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none;
border-top-color: #294a72;
border-width: 5px;
margin-left: -5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="element tooltip" data-tip-content="This is a test content">
</div>

At the time you're checking the height, the element has not yet been added to the DOM, and therefore can have no height. You simply need to switch the order of your statements. jQuery can and will change the CSS of the element even after it has been added.
var html = $('<p class="tip-content">' + content + '</p>');
$(this).prepend(html); //This line must go before the next
var height = html.height();
console.log(height);
However, you're still missing some pieces. height() does not include either margin or padding. To get padding, you can use outerHeight(), but margin you'll have to either read from the CSS or use a hard-coded value. Even worse, your arrow is using a pseudo-element, which *cannot* be read by DOM traversal, so your best bet there is to just hardcode it, sadly.
A better height calculation might look like:
var ARROW_HEIGHT = 5;
html.outerHeight() + parseInt(html.css('marginBottom'), 10) + ARROW_HEIGHT;

I think you have to prepend the HTML, and then get the height and reposition the element. Right now, you are getting the height of a variable, not an HTML element.

You just need to get height of 'tooltip' instead of 'tip-content'.
$('.tooltip').hover(function() {
var content = $(this).data('tip-content');
var element = $(this).find('.tip-content');
if(element.length == 0 ) {
var html = $('<p class="tip-content">' + content + '</p>');
// Get height of parent element
var height = $(this).height();
console.log(height);
html.css('top', - height);
$(this).prepend(html);
} else {
element.remove();
}
});
.element {
height: 50px;
width: 50px;
margin: 50px auto;
background: #000;
}
.tooltip {
position: relative;
}
.tooltip .tip-content {
width: 180px;
margin-left: -98px;
padding: 10px 5px;
position: absolute;
left: 50%;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
background: #294a72;
font-size: 0.75em;
color: #fff;
text-align: center;
}
.tooltip .tip-content:after {
top: 100%;
left: 50%;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none;
border-top-color: #294a72;
border-width: 5px;
margin-left: -5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="element tooltip" data-tip-content="This is a test content">
</div>

For html object gets a height automatically, you need first put in DOM. That the reason for you get height = 0. You need first append your object and then get the height.
See my example: https://jsfiddle.net/bwun82q4/
$('.tooltip').hover(function() {
var content = $(this).data('tip-content');
var element = $(this).find('.tip-content');
if(element.length == 0 ) {
var html = $('<p class="tip-content">' + content + '</p>');
var height = html.height();
console.log(height);
html.css('top', - height);
$(this).prepend(html);
$(this).find("p").css("top",- $(this).find("p").height());
} else {
element.remove();
}});

Related

JavaScript and CSS not working as intended

In the following code, when I put the div with class thumb-bar, the JavaScript I have written works but if place use it after full-img div tag, it doesn't work also the CSS attribute cursor: pointer for the thumb-bar div is not applied.
Edit - I mean the click listeners I apply using JavaScript are not working
CSS:
body {
width: 640px;
margin: 0 auto;
}
.full-img {
position: relative;
display: block;
width: 640px;
height: 480px;
}
button {
border: 0;
background: rgba(150, 150, 150, 0.6);
text-shadow: 1px 1px 1px white;
border: 1px solid #999;
position: absolute;
cursor: pointer;
top: 2px;
left: 2px;
}
.thumb-bar img {
display: block;
width: 20%;
float: left;
cursor: pointer;
}
HTML:
<div class="thumb-bar"></div>
<div class="full-img">
<img class="displayed-img" src="images/pic1.jpg">
<button class="dark">Darken</button>
</div>
JavaScript:
var displayedImage = document.querySelector('.displayed-img');
var thumbBar = document.querySelector('.thumb-bar');
btn = document.querySelector('button');
var overlay = document.querySelector('.overlay');
for (var i = 1; i <= 5; i++) {
var newImage = document.createElement('img');
newImage.setAttribute('src', 'images/pic' + i + '.jpg');
thumbBar.appendChild(newImage);
newImage.addEventListener('click', function(e) {
displayedImage.setAttribute('src', e.target.getAttribute('src'))
});
}
Because you're floating .thumb-bar img, those images are taken out of the page flow which results in the .thumb-bar element to have a height of 0, which in turn causes subsequent content to not be pushed down. That means that the .full-img element is rendered on top of the images and obscures them from the mouse pointer.
You need to clear the floats in order to get the .full-img element to render below them. This can be done by either making sure the .thumb-bar clear it's own content:
.thumb-bar {
overflow: hidden;
}
... or make the .full-img element itself clear them:
.full-img {
clear: both;
}

Custom Drag & Drop not working perfectly

I want to drag a div and drop anywhere in its parent div . For dragging I use css style
draggable="true"
and for drop, I use 'mousemove' event X and Y values and use this values for div top and left .The code I used is
$(".drop").mousedown(function () {
$(this).mousemove(function (e) {
var k = e.clientX ;
var f = e.clientY;
$(".drop").text(k+ ", " + f);
$(".drop").css("top",f);
$(".drop").css("left",k);
});
}).mouseup(function () {
$(this).unbind('mousemove');
}).mouseout(function () {
$(this).unbind('mousemove');
});
.drop{
position: absolute;
left: 300;
top: 200; /* set these so Chrome doesn't return 'auto' from getComputedStyle */
width: 200px;
background: rgba(255,255,255,0.66);
border: 2px solid rgba(0,0,0,0.5);
border-radius: 4px; padding: 8px;
z-index: 3;
}
.gridPart{
padding: 20px;
background-color: #FFF;
border-radius: 5px;
margin: auto;
margin: 20px;
padding-right: 0px;
padding-bottom: 3px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="gridpart">
<div class="drop" draggable="true" ></div>
<div>
Now it's drag & drop if I drag with increasing left value. But if I drag with decreasing left value it's not dropping. And how I stop the drag if it reach the end of the main div(GridPart)?
I have fixed your code. All you did is quite good but you should have to use the mousemove event with $(document) element and not with the div. Since when you drag backwards, mouse movement is going out of the div and so its no longer dragging.
Also, as you used custom dragging, you don't need to use draggable="true".
$(".drop").mousedown(function () {
$(document).mousemove(function (e) {
var k = e.clientX;
var f = e.clientY;
$(".drop").text(k+ ", " + f);
$(".drop").css("top", f + 'px');
$(".drop").css("left", k + 'px');
});
});
$(document).mouseup(function () {
$(document).unbind('mousemove');
});
.drop{
position: absolute;
left: 300;
top: 200; /* set these so Chrome doesn't return 'auto' from getComputedStyle */
width: 200px;
background: rgba(255,255,255,0.66);
border: 2px solid rgba(0,0,0,0.5);
border-radius: 4px; padding: 8px;
z-index: 3;
}
.gridPart{
padding: 20px;
background-color: #FFF;
border-radius: 5px;
margin: auto;
margin: 20px;
padding-right: 0px;
padding-bottom: 3px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="gridpart">
<div class="drop" ></div>
<div>
Simply use the JQueryUi Draggable:
https://jqueryui.com/draggable/
UPDATE: sample code here:
http://embed.plnkr.co/5W3ACU/
I think what i have discerned from your question you are trying to do, is limit dragging to within the .gridpart div.
The key was moving the drag detection to the container div, and then moving the drag component based on the mousedown position
JSFIDDLE
JS
$(".gridpart").mousedown(function () {
var containerDims = $(this)[0].getBoundingClientRect();
var dropEl = $(this).find('.drop');
// measure the size of the drop element
var dropDims = dropEl[0].getBoundingClientRect()
$(this).mousemove(function (e) {
// position the element centered under the cursor
var k = e.clientX - dropDims.width / 2;
var f = e.clientY - dropDims.height / 2;
if( k >= 0 && k <= containerDims.width - dropDims.width){
dropEl.css("left",k);
}
if(f >= 0 && f <= containerDims.height - dropDims.height){
dropEl.css("top", f);
}
dropEl.text(k + ', ' + f);
});
}).mouseup(function () {
$(this).unbind('mousemove');
});
CSS
.drop{
position: absolute;
left: 0;
top: 20px;
width: 200px;
background: rgba(255,255,255,0.66);
border: 2px solid rgba(0,0,0,0.5);
border-radius: 4px; padding: 8px;
z-index: 3;
/* prevent 'shadow' drag preventing mouseup firing */
-webkit-user-drag: none;
-khtml-user-drag: none;
-moz-user-drag: none;
-o-user-drag: none;
user-drag: none;
}
.gridpart{ /* correct camelcase typo */
background-color: #F00;
border-radius: 5px;
margin: 20px;
padding-right: 0px;
position: relative;
height: 58px;
}
HTML
<div class="gridpart">
<div class="drop" draggable="true">0, 0</div>
<div>

Removing and readding an element pushes another element down, toggling the float in dev tools causes the element to move back to the correct position

I have a container that holds three items.
One is floated left, another is centered and the last is floated right. If I remove the center item and add it back the right most item gets pushed down and I don't know why.
If you select the right item and view it in Chrome dev tools you can toggle the float: right off/on and then it will be positioned correctly.
This happens in Chrome but does not happen in FireFox. (I have not tested in IE)
I have a demo of the issue here: http://codepen.io/anon/pen/rVyRmy?editors=001
var on = true;
var l = $('<div class="left"></div>');
var r = $('<div class="right"></div>');
var clicky = function() {
if (on) {
$('.container').empty();
$('.container').append(l);
$('.container').append($(
'<div class="fill">' +
'<span>text</span>' +
'<span>text</span>' +
'<span>text</span>' +
'<span>text</span>' +
'</div>'
));
$('.container').append(r);
on = false;
} else {
$('.container').empty();
$('.container').append(l);
$('.container').append($('<input type="text" />'));
$('.container').append(r);
on = true;
}
$('.right').on('click', clicky);
};
$('.right').on('click', clicky);
.container {
width: 400px;
height: 20px;
text-align: center;
background-color: lightgray;
}
.left, .right {
display: inline-block;
width: 14px;
}
.left {
position: relative;
float: left;
}
.left:before {
position: absolute;
top: 4px;
left: 4px;
content: "";
width: 0;
height: 0;
border-style: solid;
border-width: 5px 8.7px 5px 0;
border-color: transparent orange transparent transparent;
}
.right {
position: relative;
float: right;
}
.right:before {
position: absolute;
top: 4px;
right: 4px;
content: "";
width: 0;
height: 0;
border-style: solid;
border-width: 5px 0 5px 8.7px;
border-color: transparent transparent transparent orange;
}
span {
width: 93px;
background-color: green;
display: block;
float: left;
}
div span:first-child {
margin-left: 14px;
}
<div class="container">
<div class="left"></div>
<input type="text" />
<div class="right"></div>
</div>
In the above I clear everything and redraw, I have also tried leaving the left and right elements and just removing/adding the center back but I get the same result.
You can fix this by forcing a redraw on the right element. There are a couple of ways to do this, but my preferred way is $(r).hide().show(0);
$(r).offsetHeight has been known to work, though it doesnt work in the codepen you linked to and it doesnt work in safari. For background I added the code as follows:
else {
$('.container').empty();
$('.container').append(l);
$('.container').append($('<input type="text" class="middle" />'));
$('.container').append(r);
$(r).hide().show(0);
on = true;
}
The original SO post from which I got my answer when I ran into a similar problem the other day: Force DOM redraw/refresh on Chrome/Mac

How to get a-link (a href) background image in css to resize with javascript code

I've been racking my brain trying to get two problems figured out. One is an image cropping and the other is and image resizing one. Here is a overview of the code I have:
HTML code:
<script src="main.js"></script>
<div class="mainDiv">
<div class="columnDiv1">
<!-- a div here a div there -->
</div>
<div class="columnDiv2">
<div class="iconDiv1">Icon 1</div>
<div class="iconDiv2"><img src="/images/div2Icon.png" id="div2IconImg" width="1" /></div>
</div>
<div class="columnDiv3">
<!-- a div here a div there -->
</div>
<div class="bottomRowDiv">
<!-- a div here a div there -->
</div>
</div>
CSS code:
<style type="text/css">
.mainDiv {
z-index: 2;
float: left;
width: 1112px;
position: relative;
overflow: hidden;
}
.columnDiv1 {
z-index: 20;
position: absolute;
width: 33.36%;
padding: 0px;
float: left;
border: 0px solid;
}
.columnDiv2 {
z-index: 20;
position: absolute;
width: 30.31%;
padding: 0px;
float: left;
border: 0px solid;
}
.columnDiv3 {
z-index: 20;
position: absolute;
width: 36.33%;
padding: 0px;
float: left;
border: 0px solid;
}
.bottomRowDiv {
z-index: 20;
position: absolute;
width: 100%;
padding: 0px;
float: left;
border: 0px solid;
}
/* stuff in here for columnDiv1 */
.iconDiv1 {
z-index: 20;
position: absolute;
width: 100%;
left: 0px;
top: 0px;
padding-top: 0px;
padding-left: 0px;
padding-bottom: 75px;
padding-right: 0px;
float: left;
border: 0px solid;
}
.iconDiv2 {
z-index: 20;
position: absolute;
width: 100%;
left: 0px;
top: 0px;
padding: 0px;
float: left;
border: 0px solid;
}
/* stuff in here for columnDiv3 */
/* stuff in here for bottomRowDiv */
#iconDiv1_link {
display:block;
text-indent: -10000px;
background: url(/images/div1.png) no-repeat;
background-position: center top;
}
#iconDiv1_link:hover {
background-image: url(/images/div1hover.png);
}
</style>
JavaScript code:
_spBodyOnLoadFunctionNames.push('sizeImageMap()');
function sizeImageMap()
{
// get screen information
var currentScreenWidth = screen.width;
var currentScreenHeight = screen.height;
// get images' information
//define Image Icon Hash keys
var imgIconHash = {};
imgIconHash['image1_link'] = {};
...
...
imgIconHash['iconDiv1_link'] = {};
imgIconHash['div2IconImg'] = {};
...
...
for (var imgLinkName in imgIconHash){
var imgLink = document.getElementById(imgLinkName);
if (imgLink.nodeName === "A") {
imgLinkStyle = imgLink.currentStyle || window.getComputedStyle(imgLink, false);
imgIconHash[imgLinkName]['src']=imgLinkStyle.backgroundImage.replace(/url\((['"])?(.*?)\1\)/gi, '$2').split(',')[0];
} else if (imgLink.nodeName === "IMG") {
imgIconHash[imgLinkName]['src']=imgLink.getAttribute('src');
} else {
// not A or IMG nodes
}
// get image width and height
var tmpImg = new Image();
imgIconHash[imgLinkName]['width']=tmpImg.width;
imgIconHash[imgLinkName]['height']=tmpImg.height;
}
// initialize scaling factors
var imgScale = 1;
//set scaling factors
if(currentScreenHeight >= /*given amount*/ ) // set scale
{
imgScale = 0.5676; // reset image scale
} else {
imgScale = 0.3784; // reset image scale
}
//resize images
for (var imgLinkName in imgIconHash){
var imgLink = document.getElementById(imgLinkName);
if (imgLink.nodeName === "A") {
imgLink.style.background.width = imgIconHash[imgLinkName]['width'] * imgScale + "px";
imgLink.style.background.height = imgIconHash[imgLinkName]['height'] * imgScale + "px";
} else if (imgLink.nodeName === "IMG") {
imgLink.style.width = imgIconHash[imgLinkName]['width'] * imgScale + "px";
imgLink.style.height = imgIconHash[imgLinkName]['height'] * imgScale + "px";
}
}
}
Note, this is a webpage content part in SharePoint, hence the "_spBodyOnLoadFunctionNames.push('sizeImageMap()');" to perform an operation similar to document.onload.
So, two problems I am having:
The image in the 'columnDiv2' of 'iconDiv1' seems to be being cropped. It's size is 322px width and 128px height. The left and top don't appear to be being cropped, but the bottom and right do appear, or more so, don't appear, as though they have been cropped. I have seven other images in my code that are handled the same way, and have no problems with them, but this one appears to have the problem. It's not noticeable on the first loaded image, but on the image that shows after a 'hover', you can see the cropping.
I can get the IMG's width and height, but not the a-href link's background width and height. Any direction for this would be helpful. Also, I am doing this so that the images can be resized. Note the links are id's and not class's, as I was unable to find an easy way to access the existing images width and height, before loading, and then how to resize the a-href link's size after getting it. As said, the IMG works fine, just the A doesn't want to cooperate.
Thank you in advance.

Child div elements not appearing in parent div element created by JavaScript function

I started learning JavaScript about a few weeks ago, and I have a problem. I have here two functions that are meant to bring up a menu when a button is clicked. In theory the menu that pops up should bring up a small div element from the left side, and 6 div elements within that div element. The main div element has the id "pokemonswitch" and when I click the button with the related function it only brings up "pokemonswitch" the other div elements don't seem to want to appear inside "pokemonswitch". I have tinkered with the code and have gotten various results.
1: Div elements appear in "pokemonswitch as programmed but after I click another button that removes "pokemonwitch" the div elements remain there despite the parent element not being there.
2: The div elements do not appear at all within "pokemonswitch".
3: The div elements appear in random places and the rest of the function doesn't work.
My goal is to have a function that calls up "pokemonswitch" with six div elements inside of it. Is there something I am missing about structure that is causing my child div elements to act so crazy? I hope this is clear enough to be answered, if not I will be more than happy to append more details to the problem.
//MAKE DIV ELEMENT pokemonswitch VISIBLE AND ASSOCIATIVE SLOTS AS WELL
function pkmnFunction() {
var element = document.getElementById('pokemonswitch');
var cancel = document.getElementById('optionsdiv');
element.style.visibility = "visible";
document.getElementById('slot1').style.visibility = "visible";
document.getElementById('slot2').style.visibility = "visible";
document.getElementById('slot3').style.visibility = "visible";
document.getElementById('slot4').style.visibility = "visible";
document.getElementById('slot5').style.visibility = "visible";
document.getElementById('slot6').style.visibility = "visible";
cancel.innerHTML = "<input id='cancelbutton' type='button' value='cancel' onclick='canFunction()' style='position:absolute; top:95px; left:35px;'></input>";
element.innerHTML = "<div id='slot1'></div><div id='slot2'></div><div id='slot3'></div><div id='slot4'></div><div id='slot5'></div><div id='slot6'></div>";
}
//MAKE DIV ELEMENT pokemonswitch HIDDEN AND ASSOCIATED slot ELEMENTS AS WELL
function canFunction() {
var element = document.getElementById('pokemonswitch');
var cancel = document.getElementById('optionsdiv');
document.getElementById('slot1').style.visibility = "hidden";
document.getElementById('slot2').style.visibility = "hidden";
document.getElementById('slot3').style.visibility = "hidden";
document.getElementById('slot4').style.visibility = "hidden";
document.getElementById('slot5').style.visibility = "hidden";
document.getElementById('slot6').style.visibility = "hidden";
element.style.visibility = "hidden"
cancel.innerHTML = "<input id='b5' type='button' onclick='setSlots()' value='Check Slot' ></input><input id='b1' type='button' value='Fight!'></input><input id='b2' type='button' onclick='pkmnFunction()' value='Pkmn'></input><input id='b3' type='button' value='Items' onclick='itemFunction()'></input><input id='b4' type='button' value='Run'></input>";
}
////////////ASSOCIATED CSS STYLE CODE//////////////////
#pokemonswitch {
position: absolute;
width: 180px;
margin - left: -15px;
height: 100 % ;
border: solid;
border - color: black;
border - width: 2px;
border - radius: 25px;
background - color: 0099CC;
z - index: 3;
visibility: hidden;
}
#slot1 {
position: absolute;
top: 0px;
left: -10px;
padding: 5px;
text - align: center;
border: solid;
border - width: 1px;
background - color: red;
width: 170px;
height: 65px;
z - index: 4;
}
#slot2 {
position: absolute;
top: 65px;
left: -10px;
padding: 5px;
text - align: center;
border: solid;
border - width: 1px;
background - color: red;
width: 170px;
height: 65px;
z - index: 4;
visibility: hidden;
}
#slot3 {
position: absolute;
top: 130px;
left: -500px;
padding: 5px;
text - align: center;
border: solid;
border - width: 1px;
background - color: red;
width: 170px;
height: 65px;
z - index: 4;
visibility: hidden;
}
#slot4 {
position: absolute;
top: 195px;
left: -500px;
padding: 5px;
text - align: center;
border: solid;
border - width: 1px;
background - color: red;
width: 170px;
height: 65px;
z - index: 4;
visibility: hidden;
}
#slot5 {
position: absolute;
top: 260px;
left: -500px;
padding: 5px;
text - align: center;
border: solid;
border - width: 1px;
background - color: red;
width: 170px;
height: 65px;
z - index: 4;
visibility: hidden;
}
#slot6 {
position: absolute;
top: 325px;
left: -250px;
padding: 5px;
text - align: center;
border: solid;
border - width: 1px;
background - color: red;
width: 170px;
height: 65px;
z - index: 4;
visibility: hidden;
}
The issue is, you are trying to refer an element that isn't even created yet.
element.innerHTML = "<div id='slot1'></div><div id='slot2'></div><div id='slot3'></div><div id='slot4'></div><div id='slot5'></div><div id='slot6'></div>";//Place this first
document.getElementById('slot1').style.visibility = "visible";
document.getElementById('slot2').style.visibility = "visible";
document.getElementById('slot3').style.visibility = "visible";
document.getElementById('slot4').style.visibility = "visible";
document.getElementById('slot5').style.visibility = "visible";
document.getElementById('slot6').style.visibility = "visible";
cancel.innerHTML = "<input id='cancelbutton' type='button' value='cancel' onclick='canFunction()' style='position:absolute; top:95px; left:35px;'></input>";
Also few other things I noticed were:
Instead of using style.visibility use style.display. <input> isn't a container element, so remove </input> everywhere.
document.getElementById('slot1').style.visibility = "visible";
element.innerHTML = "<div id='slot1'></div>";
This is not right. The first line suggests that an element with id slot already exists. The second line adds a new div with that same id.
If the element should already exist, you can add the existing element
var slot1 = document.getElementById('slot1');
slot1.style.visibility = "visible";
element.appendChild(slot);
If not, you can create it first:
var slot1 = document.createElement('div');
slot1.id = 'slot1';
slot1.style.visibility = "visible";
element.appendChild(slot);
I do it this way! Create a div that contains the form you want and make this div display:none. Then on click make it visible where you want to
<div style="display:none">
<div id="mycontent">
content content
</div>
</div>
then use
document.getElementById('ID')..style.display="value"

Categories

Resources