Hi I'm looking at ways to specify the widths of a large number of objects on a page AND have each object's width displayed within it as text. The main aim is to avoid having a reference to the width anywhere (whether in the HTML, CSS or JS) more than once but I need potentially thousands of these objects on one page (currently I specify the width of the div and a text within it - too inefficient!).
So far I have this: https://jsfiddle.net/ghostfood/d6acdhq6/17/
<body onLoad="myFunction()">
<div id="object1" class="voteshare1" style="width:40.6%;">
This one is <span id="percentage1"></span></div>
<div id="object2" class="voteshare2" style="width:20.4%;">
This one is <span id="percentage2"></span></div>
<div id="object3" class="voteshare3" style="width:10.2%;">
This one is <span id="percentage3"></span></div>
<script>
function myFunction() {
var x1 = document.getElementById("object1").style.width;
var x2 = document.getElementById("object2").style.width;
var x3 = document.getElementById("object3").style.width;
document.getElementById("percentage1").innerHTML = x1;
document.getElementById("percentage2").innerHTML = x2;
document.getElementById("percentage3").innerHTML = x3;
}
</script>
</body>
The width must be a percentage but ideally would not include the percentage symbol in the displayed text (not sure how it's doing that as this is an example I found online then modified a bit - I do not know JS very well).
I've looked at D3 and amcharts for this briefly but I'm not sure they're best for handling hundreds of small stacked bar charts on one page and with lots of CSS control which is what I need. I may well be wrong!
Summary: Help me figure out a more efficient way of getting and displaying the (percentage) width (as set manually in HTML or JS and within a range of 10% to 100%) of an object within it as text (the caveat being that I need to do this for thousands of small objects on one page).
Set a common class to all divs that you want to get the width.
Select all of then with getElementsByClassName()
Loop through each one getting its width.
find the children span and add the string to it.
See below
function myFunction() {
var elements = document.getElementsByClassName("voteshare");
for (var i = 0; i < elements.length; i++){
var thisElement = elements[i];
var thisWidth = thisElement.style.width.toString();
thisElement.children[0].textContent += thisWidth;
}
}
<body onLoad="myFunction()">
<div id="object1" class="voteshare" style="width:40.6%;">
<span id="percentage1">This one is </span>
</div>
<div id="object2" class="voteshare" style="width:20.4%;">
<span id="percentage2">This one is </span>
</div>
<div id="object3" class="voteshare" style="width:10.2%;">
<span id="percentage3">This one is </span>
</div>
</body>
The problem with the JS is that you were referencing to object1 but the name of the <div> is object.
When a browser encounters an error, the execution of the script stops. That means that none of your code was running because the error was on the first line (of the function code).
Related
Sorry for being long and thank you very much for your usual time and guidance.
I have a div of unknown dimensions; in fact, its width and height are set using percentages so the final values in pixels depend on the window innerWidth an innerHeight properties.
I need to create an ajax pagination inside that div. In other words, I have two child div s (figure below). The second one is for pagination links. The first one is responsible of holding items (aligned horizontally and vertically). It will be (automatically) of unknown width . As a result, the number of items inside depend on its final width and height because all items have a fixed known width and hieght (Let's say 80 pixels width and 50 pixels height).
I hope the following figure is illustrating my issue in the best manner:
The goal is to find a good approach to find the values of X and Y.
X= number of items per row
Y= the number of items per column
These two values will help finding the number of items per page (to be used server side for pagination). Pagination links will be created by dividing the total number of pages by this value. Note: Everything is done with ajax.
What I am planning to do:
create a javascript function calculate_viewport() to be the first thing to execute before any other thing parsed/exectued.
create a javascript function that calculates X and Y values based on values returned by calculate_viewport().
use the X and Y for an ajax call that request a certain page.
<script type="text/javascript">
function calculate_viewport() {
var width_and_height_object;
// calcluate width and height using of current window.innerWidth and window.innerHeight
// put values in an object width_and_height_object
return width_and_height_object; }
function calculate_XandY(width_and_height_object) {
var XandY_object;
// calcluate X and Y values by perfoming necessary division operations
return XandY_object; }
var XandY = calculate_XandY(viewport()); </script>
<!DOCTYPE html> <html>
<head>
</head>
<body>
<div id="parent" style="height: 70%; width: 50%">
<div id="items_container" style="height: calc(100% - 30px); width: 100%"></div>
<div id="pagination" style="height: 30px; width: 100%">></div>
</div>
</body>
<script src="jquery.js"></script>
<script type="text/javascript">
$('a.next a.previous').click(function(e){
e.preventDefault();
$.ajax({
type: "GET",
url: url_to_page_of_items,
data: { number_of_items_per_page : X_times_Y },
cache: false,
success: callback // append result to items container div
});
return false;
});
</script> </html>
What do you think about this approach? Are there any other better ways to achieve this goal? Is it acceptable to create a <script> tag before the <html> tag just to make early window size calculation?
N.B: For the server side part, I manage to paginate results via some functions offered by the ORM library I am using. I use a server-side template engine that renders a page of items as HTML. I am ready to provide any code upon request for this part. Thanks
You'll never get the layout math right on your own. My recommendation is to lay out all of the items before hand (flex box is ideal here!), get the count, and then fill them in using ajax.
Here's a quick demo I whipped up. The actual JS is pretty simple, using jQuery.
var MARGIN = 10; //This should match your CSS
var itemContainerHeight = $(".foo").height();
var count = 0;
$(".item").each(function () {
if ($(this).position().top + $(this).height() + MARGIN > itemContainerHeight) {
$(this).hide();
} else {
count++;
}
});
$('.pagination').text("I can display "+count+" items!");
The important line is the one containing .position(). That'll get the location of each of the items top edge, add the height to find their bottom edge, and check if it's past the bounds of the item container.
After this you can just use the count to query the necessary items from the server. I'd also recommend using visbility: hidden; on all of the items so the user doesn't see them before they're ready.
I have simple page with an object that gets a "top" property from the javascript.
How do I run the function without getting things on my page to "jump" ?
<script type="text/javascript">
function changeHeight () {
//Gets height
var h = window.innerHeight;
//alert(h);
console.log(h);
var categories = document.getElementById("cat").offsetHeight;
//alert(categories);
var x = 0.32 * categories;
var catTop = h - x;
//Gets cats
document.getElementById("cat").style.top = catTop+"px";
}
</script>
</head>
<body onload="changeHeight()" onresize="changeHeight()">
<div class="main">
<div class="cat" id="cat"></div>
</div>
</body>
</html>
I used "onload" on the tag to run the function. Which I know that's not so good.
The object jumps because you move it after the DOM has been rendered. That's what onload does: Make sure the DOM is complete and all loading/rendering has happened.
There are two solutions:
Put the script element after the node.
Use CSS to position the element
The first solution looks like this:
<div class="main">
<div class="cat" id="cat"></div>
<script>...</script>
</div>
At the time when the script is executed, the necessary DOM nodes are there. Unless your layout is complex, the offsets should be correct at this time. Note that many browsers start rendering while the page is loading. So there still might be a jump but less often, depending on the complexity of the page, browser optimizations, etc.
The second solution is to wrap your element in a container where you set the margin/padding until the cat element is naturally positioned correctly. The 0.32 would be translated to 32%. You need another element around it which has the correct height but which isn't visible.
To final solution should give body height: 100%, then add two containers inside. One for the content and the other to position the cat element. You will need to play with position style. Then
#cat { top: 32% }
should do the trick.
I'm developing a pinboard-style blog (like Pinterest) using the tutorial by Ben Holland. Each pin has an absolute position and its location (top and left) is being calculated with jQuery script http://labs.benholland.me/pinterest/js/script-centered.js
Everything works perfectly (see demo), but the only thing that needs doing is adding footer. When I try to add footer (no matter how it is positioned: relatively or absolutely), it shows up either on the top of the page (position:relative) or it floats somewhere in the middle of the page (position:absolute;bottom:0). Footer never shows up underneath the blog.
I tried many CSS solutions (clearfixes, floats, a variety of different position combinations), after all this I came to the conclusion that it is impossible without JS.
The problem can be solved by placing the pinboard in the container, giving the container position:relative and adding the correct height. After this, footer can be placed below the container. And this is where I'm stuck.
I'm a beginner at JavaScript, can somebody help me to to this?
Just as you said,you may use a div to contain these absolute elements
The construct like:
<body onload="setupBlocks();">
<header>header</header>
<section id="container">
<div class="block">
<p>Lorem ipsum dolor sit amet....</p>
</div>
......
</section>
<footer>footer</footer>
</body>
and css code like:
header{height:30px;background-color:green;}
footer{height:20px;background-color:gray;}
section{position:relative;} //It's important,absolute element will calculate position depending on nearest parent which has sure position.
as to js code,Please look at array:block[],this array has the record of every column's height,you can print it in console.
so what you need to do is just set max value of block[] to section.
here I added two lines in function positionBlocks and a function to get max value
function positionBlocks() {
$('.block').each(function(i){
var min = Array.min(blocks);
var index = $.inArray(min, blocks);
var leftPos = margin+(index*(colWidth+margin));
$(this).css({
'left':(leftPos+spaceLeft)+'px',
'top':min+'px'
});
blocks[index] = min+$(this).outerHeight()+margin;
});
var max = Array.max(blocks); //you need to write a function to get max value of block
$('section').height(max); //set section(or div,as you wish)'s height
}
// Function to get the Min value in Array
Array.min = function(array) {
return Math.min.apply(Math, array);
};
// Function to get the Max value in Array
Array.max = function(array) {
return Math.max.apply(Math, array);
};
if you want to let your foot in the end if section's height too small,you need to calculate (scollheight-other's height)、compare with section's height and replace it in set seciton's height line.
I think I'm going mad!
I'm starting to write a little exercise for myself where I am going to have some divs that I can drag on the rightborder to increase or decrease the Div width. I also have a container Div that has a set width and I'm going to use this to determine a percentage - basically I'm going to be making some kind of bar-chart / histogram that you can edit.
I'm started writing my code and I thought I'd just make sure I could output the percentage.
Here's the perliminary code....
<style>
#container{width:500px;}
#dragDiv{border:1px solid #000;background-color:pink;width:100px;height:100px;}
</style>
</head>
<body>
<div id="container">
<div id="dragDiv"></div>
</div>
<script>
function dragOneSide(innDiv, outDiv){
if(document.getElementById(innDiv) && document.getElementById(outDiv)){
var iDiv = document.getElementById(innDiv),
oDiv = document.getElementById(outDiv);
// write out the width as a percentage
var iDivWidth = parseInt(iDiv.style.width),
oDivWidth = parseInt(oDiv.style.width);
//alert(document.getElementById("dragDiv").style.width);
iDiv.innerHTML = ((iDivWidth / oDivWidth) * 100);
}
}
window.onload = function(){
dragOneSide("dragDiv", "container");
}
</script>
Now the value in the iDiv was NaN? I found that rather odd. When trying to alert width I was getting a blank, literally an empty string! Rather odd I thought, especially as I wasn't trying to do anything complicated. I used firebug, set a breakpoint and observed the watch window. There was no value for the Div's width. I then put an inline style on the DIV like so...
<div id="container">
<div id="dragDiv" style="width:300px;">Hello World</div>
</div>
and low and behold I was now getting a value for the item! Now I don't like inline styles (who does) however I've never had this problem before and I've been using JavaScript and HTML for years - has anyone got an explaination for this? To retrieve the width not set by CSS do I have to use a different property like clientWidth?
Ps. I haven't included any of the dragging code yet so please don't point that out.
The call to style.width retrieves the style value, which isn't set.
http://jsfiddle.net/EC2HR/
See this example. Yes, you want to use clientWidth in this case.
The simplest way is to use offsetWidth property:
var iDivWidth = parseInt(iDiv.style.offsetWidth),
oDivWidth = parseInt(oDiv.style.offsetWidth);
style.width is a DOM api which returns the width of an element when it's set inline or via the element.style.width = n + "px";
So that it reacts the way you describe it is as designed.
The offsetWidth like ioseb refers to is a DOM api call which returns the amount of horizontal space an element takes up.
Beware of the many inconsistencies between browsers .
PM5544...
I have a page which has DIVs which contain short phrases (one-two words) of varying font sizes, which need to be positioned left-to-right according to a numerical parameter, and vertically so as not to overlap.
It's like a tag cloud, but there's information contained in the y-axis as well ("coolness" in this case - http://cool-wall.appspot.com)
How should I lay these out? I'm currently using a very messy series of DIVs like this:
<div style="position:absolute; top:150px;left:10px;right:10px;bottom:10px">
<!-- then, repeated, with different top, left and font-size values -->
<div style="align:center; margin:0; border:none; padding:0; float:left; visibility:visible; position:absolute; top:21%; left:56%; font-size:11px">
<div style="margin-top:0%; margin-right:50%; margin-bottom:0%; margin-left:-50%;">
<span style="display:inline"> ← </span>
<span style="display:inline"> Buzz </span>
<span style="display:inline"> → </span>
</div>
</div>
<!-- of course, followed by a close div -->
</div>
I use a stylesheet to extract some of those styles, and I realise that it's pretty poor CSS (and HTML)... but this was all I could hack together to do (almost) what I wanted to do. The main problem with the above (apart from it being confusing) is that I can't set the positioning so it doesn't overlap, because I don't know what size the font will be, nor how it will display onscreen.
Happy to use JavaScript to get it right. But I don't know where to start. Any tips?
There is a javascript property on the dom object that will tell you the height of the tag if you have the width set. I believe its called clientHeight
alert(document.getElementById('myElement').offsetHeight);
Try that (also see http://www.webdeveloper.com/forum/archive/index.php/t-121578.html)
OR
Try this
<span style="margin-top:${randomNumber}px;margin-bottom:${randomNumber}">randomtext</span>
<span style="margin-top:${randomNumber}px;margin-bottom:${randomNumber}">randomtext</span>
..
<span style="margin-top:${randomNumber}px;margin-bottom:${randomNumber}">randomtext</span>
Have all your element just display inline, output them in random order, and then set random margin's on them. This could all be done with server side code (or javascript if you want it client side).
The x-value is set on each one, you want to be as high on the page as possible (lowest y) as it can go without overlapping. Not too bad:
1) Render the container - position:relative; Render each item inside the container with "position:absolute; top:0; left:-1000; " - draw them all off screen.
2) One by one, move the element to it's needed x-coorinate and y=0; Check it with all previous render items to see if it collides, if it does, move it down one pixel until it doesn't collide:
var regions = [];
for(var i = 0; i < items.length; i++){
var item = items[i];
item.style.x = getX(item); // however you get this...
var region = YAHOO.util.Dom.getRegion(item);
var startingTop = region.top;
for(var iReg = 0; iReg < regions.length; iReg++){
var existingRegion = regions[iRegion];
while(region.intersect(existingRegion)){
region.top++;
region.bottom++;
}
item.style.y = (region.top - startingTop) + 'px';
}
}
It's important to just update the region and not actually move the dom node 1px at a time for performance reasons.
Put most important items first and they will render with more priority than items below them.
Don't position your elements absolutely. This is the reason they are falling on top of each other....