Javascript Arranging Images as Pile of Cards - javascript

Im new to javascript so im sure there is a lot i am missing in its understanding.
What i am trying to do it create a layer of images so that it looks like a pile of cards.
have seen similar codes and have tried to follow their idea but i just cant get the images to position properly. All 10 or so images are place in the exact same location.
Can any help to see why they not positioning? Also what is "em". I cant find any literature on it but assume it is the measurement em like px ?? Why is it in "" ?
function Display() {
var el;
var left = 0;
var top = 0;
var i=0;
var n = deck.length;
var cardNode;
var img = document.createElement("IMG");
img.src = "wendell7_back.png";
el = document.getElementById('deck');
el.appendChild(img);
while (el.firstChild != null) el.removeChild(el.firstChild);
for (i = 0; i < Math.round(n / 5); i++)
{
cardNode = document.createElement("DIV");
cardNode.appendChild(img);
cardNode.style.left = left + "em";
cardNode.style.top = top + "em";
el.appendChild(cardNode);
left += 0.1;
top += 0.1;
}
}

"em" is the width of an "M" in whichever font is being used (or browser's default font if nothing overrides it).
There are at least two things wrong in your code:
left and top have no meaning unless the element to which they are applied also has position:absolute or position:relative (or position:fixed I think). Your safest approach is to apply position:relative (but no left: or top:) to the container and position:absolute to each of the cards.
There's only one img. For multiple cards, you need multiple imgs otherwise the same img gets repositioned over and over.
A more economical approach is probably to show a separate "stack" image for multiple cards and single card images for a single cards.
An even more economical approach is only to show single card images with a "tooltip" to indicate the number of cards in a stack. I have successfully employed this technique in an implementation of a game of patients.
Of course, these alternative techniques don't work if you want to show multiple cards as a "fanned out" stack of upturned cards.
Create a class and modify the position of that for the deck. Here is the working code:
function Display() {
var el;
var left = 0;
var top = 0;
var i=0;
var n = deck.length;
var cardNode;
el = document.getElementById('deck');
while (el.firstChild != null) el.removeChild(el.firstChild);
for (i = 0; i < Math.round(n / 5); i++)
{
cardNode = document.createElement("DIV");
cardNode.className = "card2";
var img = document.createElement("IMG");
img.src = "wendell7_back.png";
cardNode.appendChild(img);
cardNode.style.left = left + "em";
cardNode.style.top = top + "em";
el.appendChild(cardNode);
left += .1;
top -= 6.2;
}
}
Hope this will help.

There are a couple of problems with that code.
You're only using one img, and then you're appending it to each div you create. When you append an element to another element, if it's already in the DOM tree, you end up moving it. What you need is to create a separate img element for each card.
You haven't shown us your CSS, but unless you're using CSS to make all div elements under the #deck element absolutely or relatively positioned, the left and top style attributes will be ignored, as the div will be subject to normal flow.
Also what is "em". I cant find any literature on it but assume it is the measurement em like px ??
Yes, it's a term from typography. An "em" is the width of a capital letter M.
Why is it in "" ?
Because it's a string. You'd also have to have "px" in quotes. What you're doing with this code:
cardNode.style.left = left + "em";
...is using JavaScript to set a style property. Style properties are always strings, in this case you're creating strings like "0.1em" and "0.2em", etc.
Some reading:
DOM2 Core specification
DOM2 HTML specification
DOM3 Core specification
HTML5 specification
Various CSS specifications
A good book on JavaScript, I quite liked JavaScript: The Definitive Guide by David Flanagan
A good book on CSS and HTML authoring

My guess is that your offset is too small: if you replace the "em" with "px" for test's sake, and increase the left and top variables by 10 instead of 0.1, I bet you'll see some results.
To explain the em: 1em is equal to the current font-size of the element. If you haven't set the font size it uses the browser default. If you set the font-size to be e.g. 20px on the body tag, then 1em will equal 20px.

Make sure that your 'cards' have the css property 'position' set - either to 'absolute' or 'relative'.

Related

Modify CSS classes using Javascript

I was wondering if there is an easy way to change the CSS classes in JavaScript.
I have gone through all other similar questions here and I couldn't find an straight-forward and simple solution.
what I'm trying to do is to set the width and height of a <div> to match an image that I have on my site (upon loading). I already know the picture dimensions and I can set my CSS to that - but I want my script to figure this out on its own.
After hours of r&d (I'm a beginner), this is what I came up with:
var myImg = new Image();
myImg.src = "img/default.jpg";
myImg.onload = function(){
var imgWidth = this.width;
var imgHeight = this.height;
document.getElementById("myBg").setAttribute('style', "height :"+ imgHeight + "px");
document.getElementById("myBg").setAttribute('style', "width :"+ imgWidth + "px");
};
However, this only sets the width of the element with id "myBg". If I reverse the order of the height and width, then it only sets the height to the image's height.
It seems like first it sets the height of the element to the image height but right after it moves to the next statement to set the width, the height value goes back to what it what defined originally in css.
I did further research online and seems like changing the css (inserting new attributes, removing, etc.) using JavaScript is not an easy task. It is done through
document.styleSheets[i].cssRules[i] or document.styleSheets[i].addRule
type of commands, but all the tutorials online and here on stackoverflow were confusing and complicated.
I was wondering if anyone familiar with document.styleSheets can explain this to me simply?
Imagine I have this class in my separate css file:
.container
{
height: 600px;
width: 500px;
}
I want the height and width to change to the dimension of the picture upon loading. How do I do this?
I don't want to define a new "style" element in my html file, I want to change the css file.
I'm not supposed to know the image dimension before it loads to the page.
no jquery please, I want to do this using only standard JavaScript.
Thank you.
The reason only one or the other works is because in your second line of code, you destroy the whole style attribute, and recreate it. Note that setAttribute() overwrites the whole attribute.
A better solution would be to use the element.style property, not the attribute;
var bg = document.getElementById("myBg");
bg.style.width = imgWidth + "px";
bg.style.height = imgHeight + "px";
You can grab all elements with class container and apply it to each of them like this:
var elements = document.querySelectorAll('.container');
for(var i=0; i<elements.length; i++){
elements[i].style.width = imgWidth + "px";
elements[i].style.height = imgHeight + "px";
}
Note querySelectorAll isn't supported by IE7 or lower, if you need those then there are shims for getElementsByClassName() here on SO.
If your rules start incrementing you could extract your css to a new class and switch classes:
CSS:
.container-1{
/* A set of rules */
}
.container-2{
/* A set of rules */
}
JavaScript:
element.className = element.className.replace(/container-1/, 'container-2')
var object = document.createElement('container');
object.style.width= "500px";
object.style.height= "600px";
You can also add values to this if you hold the dimensions in variables
var height = 600;
var width = 500;
You can increment when needed
height += 5;
Here is something you might find useful. It may offer you some insight on how you can solve a problem with many different approaches, seeing as though you are new to js.

Javascript/jQuery get true width and position of float affected element?

Is it possible to get the width (using javascript or jQuery) of a float-affected element? When text is being pushed over due to a floating image is it possible to get its position and true width? I have attached an image to explain better.
Code example,
<div>
<img style="...float: left"/>
<h1>A title!</h1>
<p>Text!</p>
<h1>New header added.</h1>
</div>
Picture
I need to find the width starting from the arrow, (the gray box is the image)(the dotted line is the width according to Firefox inspect mode).
I would like to avoid changing all the elements display types if possible.
Thank you!
I'm a little late to the party, but I had a similar problem and came up with a solution which (so far) seems to work in all instances of this issue. I like this solution because as far as I can tell, it works independent of the floating element - all you need is the element whose true width/position you want to get, nothing more. I've done it in pure Javascript for speed purposes, but it can easily be streamlined with jQuery and a separate CSS Stylesheet if you so choose.
//Get the rendered bounding box for the content of any HTMLElement "el"
var getLimits = function(el) {
//Set a universal style for both tester spans; use "!important" to make sure other styles don't mess things up!
var testerStyle = 'width: 0px!important; overflow: hidden!important; color: transparent!important;';
//Create a 'tester' span and place it BEFORE the content
var testerStart = document.createElement('SPAN');
testerStart.innerHTML = '|';
var testerFloat = ' float: left!important;';
testerStart.setAttribute('style', testerStyle + testerFloat);
//Insert testerStart before the first child of our element
if (el.firstChild) {
el.insertBefore(testerStart, el.firstChild);
} else {
el.appendChild(testerStart);
}
//Create a 'tester' span and place it AFTER the content
var testerEnd = document.createElement('SPAN');
testerEnd.innerHTML = '|';
testerFloat = ' float: right!important;';
testerEnd.setAttribute('style', testerStyle + testerFloat);
el.appendChild(testerEnd);
//Measure the testers
var limits = {
top: testerStart.offsetTop,
bottom: testerEnd.offsetTop + testerEnd.offsetHeight,
left: testerStart.offsetLeft,
right: testerEnd.offsetLeft
}
//Remove the testers and return
el.removeChild(testerStart);
el.removeChild(testerEnd);
return limits;
};
So, in your case, the code would just be:
var paragraphBoundingBox = getLimits($('div>p').get(0));
A couple things to note:
1) The float direction would be reversed if you are using an RTL language
2) All of the four edge positions in the output object are relative to the el.offsetParent - use this handy function can find their positions relative to the document.
First of all, the "full width" is exactly the true width.
You can watch this picture, it can help you understand why the true width and true position of the affected element is the way firefox tells you.
http://i.stack.imgur.com/mB5Ds.png
To get the width of inline text where it's pushed right by the float image, there's no good way except using the full width minus the float image's width.
var w = $('p').width()
- $('img').width()
- $('img').css('margin-left').replace("px", "")
- $('img').css('margin-right').replace("px", "")
- $('img').css('padding-left').replace("px", "")
- $('img').css('padding-right').replace("px", "")
- $('img').css('border-left-width').replace("px", "")
- $('img').css('border-right-width').replace("px", "");

How to position elements for auto overlap

I have a variable amount of elements in a fixed sized div. As long as there <= 5 elements they have enough space to sit side by side. But as soon as there are more, I want them to slightly overlap each other more and more, so they all stay inside the div. Think of it as holding a variable amount of cards in a game. I can't think of any way to do this, aside from controlling it "manually" with JavaScript on adding/removing elements. Is there a way to let the browser handle this effect for me?
http://jsfiddle.net/mFP9E/
$(document).ready(function(){
$("ul").each(function(){
var total = $(this).find("li").length;
var elWidth = 100; //Element width
if(total > 5) {
var space = Math.ceil((((elWidth * total)-(elWidth * 5))/total)/2);
$(this).children("li").css("margin","0 -"+space+"px");
}
});
});​

Truncating html text appropriately into a fixed size area

In a generated html page, we have a fixed size area (lets say 200 x 300) in which we need to fit in as much text as possible (like a regular paragraph of text), and if it doesn't fit, remove an appropriate number of characters and append "..." to the end.
The text is NOT in a fixed sized font, and although we are using one specific font for this text, a "generic" solution would obviously be preferred.
This looked interesting, but I'm thinking it would be very slow with this function being called for several items on a page - http://bytes.com/topic/javascript/answers/93847-neatly-truncating-text-fit-physical-dimension
The solution can use an intermix of html, css, js, and php as needed.
Suggestions on approaches are more than welcome!
I'd say that the solution you found is the best. It is, for instance, used for this jQuery plugin which autoresizes textareas as you enter text into it. I took the concept and rewrote it with jQuery for this simple test here: http://jsfiddle.net/ZDr5K/
var para = $('#para');
var height = 200;
while(para.height() >= height){
var text = para.text();
para.text(text.substring(0, text.length - 4) + '...');
}
Possible improvements would include right trimming and removing the period if the last character is a full stop. Removing word by word would also be more readable/slightly faster.
As for the function running multiple times, that would be unavoidable. The only thing you can really do with CSS here is to use :after to append the ellipses, but even that should be avoided for cross-compatibility problems.
Set the element dimensions via CSS and its overflow to "hidden".
Then, find out with this function, if the element's content is overflowing (via):
// Determines if the passed element is overflowing its bounds,
// either vertically or horizontally.
// Will temporarily modify the "overflow" style to detect this
// if necessary.
function checkOverflow(el)
{
var curOverflow = el.style.overflow;
if ( !curOverflow || curOverflow === "visible" )
el.style.overflow = "hidden";
var isOverflowing = el.clientWidth < el.scrollWidth
|| el.clientHeight < el.scrollHeight;
el.style.overflow = curOverflow;
return isOverflowing;
}
Now, in a loop remove text and check until it is not overflowing anymore. Append an ellipsis character (String.fromCharCode(8230)) to the end, but only if it was overflowing.
To avoid any flickering effects during that operation, you can try working on a hidden copy of the element, but I'm not sure if the browsers do the necessary layout calculations on an element that's not visible. (Can anyone clarify that?)

Div absolute position relative to static elements

I have a div element which I'm using as a pop-over search field which I want to have appear under the element which is being filtered. However, it seems that I cannot use the style.bottom and style.left of the element I want the field to be relative to as this element is static.
Example is here: http://www.is-epic.co.uk/example/example.html
Clicking the Header 2 link will have the input box appear, in the top-left corner of the table. I would like it to appear roughly where Data 1.2 is. How do I achieve this?
(Code in example.html is on one page, in live dev CSS and JS are in separate files)
Set the element you wish to position the other element with respect to to position: relative.
This will make it the containing block for any descendants that are position: absolute (unless an element between the two is also position: not static).
this works in FF and Google-Chrome
var head = document.getElementById("header_2");
var filter = document.getElementById("search_filter");
filter.style.display = "";
filter.style.left = head.offsetLeft + 'px';
filter.style.top = head.offsetTop + head.offsetHeight + 'px';
it should work with IE as well..
i used variables filter and head to cut down on typing :)
The problem is that for header_2 both style.left and style.bottom are 0, so that
document.getElementById("search_filter").style.left =
document.getElementById("header_2").style.left;
document.getElementById("search_filter").style.top =
document.getElementById("header_2").style.bottom;
is equivalent to
document.getElementById("search_filter").style.left = 0;
document.getElementById("search_filter").style.top = 0;
which is exactly what happens. You have to find out header_2's actual position, e.g. using jQuery.

Categories

Resources