Modify CSS classes using Javascript - 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.

Related

Wrong width and height when reusing FileReader

I am currently developing a simple interface allowing users to upload a picture, have a preview of it, and then be able to crop it as a square.
I'm using FileReader to get the preview of the image, and jCrop to crop it.
Here is the code I'm using (a part of it):
var jcrop = null;
var reader = new FileReader();
reader.onload = function (e) {
$('#upload-picture-sample').attr('src', e.target.result).load(function(){
var img = this;
var imageWidth = img.width;
var imageHeight = img.height;
console.log(img.width+'-- WIDTH --'+$(this).width());
console.log(img.height+'-- HEIGHT --'+$(this).height());
if(imageWidth != imageHeight){
var selectArray = [];
if(imageWidth > imageHeight){
selectArray = [(imageWidth-imageHeight)/2, 0, (imageWidth-imageHeight)/2 + imageHeight, imageHeight];
}else{
selectArray = [0, (imageHeight - imageWidth)/2, imageWidth, (imageHeight - imageWidth)/2 + imageWidth];
}
if(!jcrop){
$('#upload-picture-sample').Jcrop({
aspectRatio: 1,
keySupport: false,
addClass: 'jcrop-centered',
setSelect: selectArray
}, function(){
jcrop = this;
});
}else{
jcrop.setImage(e.target.result);
jcrop.setSelect(selectArray);
}
}
$(this).unbind('load');
});
}
$('#upload-picture-file').change(function(){
$('#upload-picture-send').removeClass('disabled');
$('#upload-picture-error').hide();
console.log('changed!');
reader.readAsDataURL(this.files[0]);
})
I think the only part that really matters is the part when I calculate the width and height.
To illustrate the problem, I'm uploading:
1/ Picture1 (600x450)
2/ Picture2 (94x125)
3/ Picture1 again (600x450)
The first upload is working fine, the second is working fine as well, but I guess it's more luck than something else, since the height is incorrectly calculated as 0.
The third upload is not working (the size is not correctly set).
It means that the cropzone is not correctly displayed.
Regarding css, I have this:
#upload-picture-sample{
display:block;
margin-left: auto;
margin-right: auto;
margin-bottom: 30px;
max-height:125px;
height:auto;
width:auto;
max-width:300px;
}
Do you have any idea of how I could solve my problem?
UPDATE: After having added setTimeout as recommended by #initialxy
So it's much better, but still, the first image doesn't have the same dimensions than the last (and it should, since it's exactly the same image)
Thanks.
All of your numbers look inconsistent. In first image, width end up being 167 with img.width but 167 with jQuery. One thing to note is that jQuery gets computed style while img.width and img.height are DOM properties that sets desired width and height. (FYI there's also naturalWidth and naturalHeight, which are read-only DOM properties that gets you the original dimensions of img.)
it's more luck than something else
If your code depends on luck, then we got a problem.
It looks like browser emitted load event slightly too early, such that layout engine hasn't finished updating the DOM. load just means data is loaded, doesn't necessarily mean layout engine has to be completed. So try to queue your code block inside your load function later in the task queue. By which, I mean wrap all that in a setTimeout(..., 0); Watch out for this, as it has changed.
eg.
$('#upload-picture-sample').attr('src', e.target.result).load(function(){
var img = this;
setTimeout(function() {
var imageWidth = img.width;
var imageHeight = img.height;
console.log(img.width+'-- WIDTH --'+$(img).width());
console.log(img.height+'-- HEIGHT --'+$(img).height());
// TODO: Crop
...
}, 0);
$(this).unbind('load');
});
EDIT: In response to #Vico's update. Looks like layout engine has settled this time. Let's make some observations on these numbers. The first image's dimensions were originally 600x450, but it ended up being 167x125. This makes sense, because it was resized by max-height: 125px; CSS property. The second image has both of its dimensions less than max-width and max-height so it didn't get resized. The third image has dimensions of 600x450, and it ended up having these dimensions, so at this point max-width and max-height is no longer taking effect. Why is that? Perhaps jcrop screwed around with style and overridden your style. Fire up your Chrome debugger, inspect your img element and use its JavaScript console to play around with it. (To give you a short answer, yes, jcrop does screw around with style and applies inline styles to the element, which overrides your style. But hey, it's more fun to play with debugger.) Also, I'm not sure why your dimensions on the right all ended up with 1440x514. You can find out by screwing around in debugger.
For more information, I suggest all the potential readers to have a look at this issue:
https://github.com/tapmodo/Jcrop/issues/46
The workarounds work fine.

Get image dimensions after resizing

I have encountered a problem that other people had in this website before but none of the solutions helped me slightly.
I have a method that updates an image inside a div (read: user uploads a new image) where the image is resized to fit the set proportions (max-height and max-width are 45x45). I have to resize the div that holds the image to 2* it's dimensions such as the example below:
Original image is 180x180.
It is resized to 45x45. Div has to be 90x90.
Code is as follows:
function uploadThumbnail(id, xCoord, yCoord) {
var oFReader = new FileReader();
oFReader.readAsDataURL(document.getElementById("thumbnailLoader"+id).files[0]);
oFReader.onload = function(oFREvent) {
var mapThumbnail = updateMapThumbnail(oFREvent.target.result, id);
var mapContainer = document.getElementById("thumbnail"+id);
var informationContainer = document.getElementById("container"+id);
console.log(mapThumbnail.width);
mapContainer.removeChild(document.getElementById("mapThumbnail"+id));
informationContainer.removeChild(document.getElementById("infoThumbnail"+id));
informationContainer.insertBefore(updateInfoThumbnail(oFREvent.target.result, id), informationContainer.firstChild);
mapContainer.appendChild(mapThumbnail);
};
};
function updateMapThumbnail(result, id){
var newThumbnail = document.createElement("img");
newThumbnail.src = result;
newThumbnail.style.maxWidth = "45px";
newThumbnail.style.maxHeight = "45px";
newThumbnail.id = "mapThumbnail" + id;
return newThumbnail;
}
As you can see I added a console.log method there for test purposes. The problem I am facing is that generating mapThumbnail with set max dimensions (45x45) still has the height and width attributes set with the original image size. I tried reading image.height/width and image.style.height/width as well as naturalHeight/width and clientHeight/width.
None of these solutions return the height and width after resizing.
Thanks for your time.
Also, please refrain from offering solutions that require JavaScript libraries.
Edit: forgot to mention that the image placed inside the div is re-sized to the dimensions that I do want it to be. It's just the attributes that seem to be wrong.
There are four different and undependant widths on an image:
1) img.naturalWidth is the width in px the original image file has. It doesn't change when you set the other widths to some value. This value is rendered when the others are not defined.
2) img.width is an attribute of img. You find it inside the html img tag and can set it with img.setAttribute('width', 'value'). It doesn't change when the others are set to some value. This value is rendered when 3) is not defined and 4) is >= img.width or not defined.
3) img.style.width is a css-property of the images style. You can set it in your css or into the style-attribute in the img tag with img.style.width = 'value';. It doesn't change when the others are set to some value. This value is rendered when it is <= 4) or 4) is not defined.
4) img.style.max-width is another css-property of images style. You can set it in your css or into the style-attribute in the img tag with img.style.maxWidth = 'value';. It doesn't change when the others are set to some value. This is rendered when 2) or 3) are not defined or have values > 4).
So you have to decide by yourself which value you want to receive or set.
Its the same with height, there are also four heights.
EDIT According to your comment:
Inside your function updateMapThumbnail you create a new img. A newly created img has no .width unless you define it with newThumbnail.setAttribute('width', 'value). Same with img.style.width: unless you set it explicitely somewhere it's simply not there.
Did you try:
console.log(getComputedStyle(mapThumbnail).width);

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", "");

Javascript Arranging Images as Pile of Cards

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'.

Programmatically Clip/Cut image using Javascript

Are there any documents/tutorials on how to clip or cut a large image so that the user only sees a small portion of this image? Let's say the source image is 10 frames of animation, stacked end-on-end so that it's really wide. What could I do with Javascript to only display 1 arbitrary frame of animation at a time?
I've looked into this "CSS Spriting" technique but I don't think I can use that here. The source image is produced dynamically from the server; I won't know the total length, or the size of each frame, until it comes back from the server. I'm hoping that I can do something like:
var image = getElementByID('some-id');
image.src = pathToReallyLongImage;
// Any way to do this?!
image.width = cellWidth;
image.offset = cellWidth * imageNumber;
This can be done by enclosing your image in a "viewport" div. Set a width and height on the div (according to your needs), then set position: relative and overflow: hidden on it. Absolutely position your image inside of it and change the position to change which portions are displayed.
To display a 30x40 section of an image starting at (10,20):
<style type="text/css">
div.viewport {
overflow: hidden;
position: relative;
}
img.clipped {
display: block;
position: absolute;
}
</style>
<script type="text/javascript">
function setViewport(img, x, y, width, height) {
img.style.left = "-" + x + "px";
img.style.top = "-" + y + "px";
if (width !== undefined) {
img.parentNode.style.width = width + "px";
img.parentNode.style.height = height + "px";
}
}
setViewport(document.getElementsByTagName("img")[0], 10, 20, 30, 40);
</script>
<div class="viewport">
<img class="clipped" src="/images/clipped.png" alt="Clipped image"/>
</div>
The common CSS properties are associated with classes so that you can have multiple viewports / clipped images on your page. The setViewport(…) function can be called at any time to change what part of the image is displayed.
In answer to :
Alas, JavaScript simply isn't capable of extracting the properties of the image you'd require to do something like this. However, there may be salvation in the form of the HTML element combined with a bit of server-side scripting.
...
< ? (open php)
$large_image = 'path/to/large_image';
$full_w = imagesx($large_image);
$full_h = imagesy($large_image);
(close php) ? >
This can be done in Javascript, just google a bit :
var newimage = new Image();
newimage.src = document.getElementById('background').src;
var height = newimage.height;
var width = newimage.width;
This generates a new image from an existing one and captures this way in java script the original height and width properties of the original image (not the one id'ed as background.
In answer to :
The width/height properties of the document's image object are read only. If you could change them, however, you would only squish the frames, not cut the frames up like you desire. The kind of image manipulation you want can not be done with client-side javascript. I suggest cutting the images up on the server, or overlay a div on the image to hide the parts you do not wish to display.
...
var newimage = new Image();
newimage.src = document.getElementById('background').src;
var height = newimage.height;
var width = newimage.width;
newimage.style.height = '200px';
newimage.style.width = '200px';
newimage.height = '200px';
newimage.width = '200px';
and if wanted :
newimage.setAttribute('height','200px');
The doubled newimage.style.height and newimage.height is needed in certain circumstances in order to make sure that a IE will understand in time that the image is resized (you are going to render the thing immediately after, and the internal IE processing is too slow for that.)
Thanks for the above script I altered and implemented on http://morethanvoice.net/m1/reader13.php (right click menu... mouseover zoom lent) correct even in IE , but as you will notice the on mousemove image processing is too fast for the old styled IE, renders the position but only once the image. In any case any good idea is welcome.
Thanks to all for your attention, hope that the above codes can help someone...
Claudio Klemp
http://morethanvoice.net/m1/reader13.php
CSS also defines a style for clipping. See the clip property in the CSS specs.
The width/height properties of the document's image object are read only. If you could change them, however, you would only squish the frames, not cut the frames up like you desire. The kind of image manipulation you want can not be done with client-side javascript. I suggest cutting the images up on the server, or overlay a div on the image to hide the parts you do not wish to display.
What spriting does is essentially position a absolutely-positioned DIV inside another DIV that has overflow:hidden. You can do the same, all you need to do is resize the outer DIV depending on the size of each frame of the larger image. You can do that in code easily.
You can just set the inner DIV's style:
left: (your x-position = 0 or a negative integer * frame width)px
Most JavaScript Frameworks make this quite easy.
Alas, JavaScript simply isn't capable of extracting the properties of the image you'd require to do something like this. However, there may be salvation in the form of the HTML <canvas> element combined with a bit of server-side scripting.
PHP code to go about extracting the width and height of the really large image:
<?php
$large_image = 'path/to/large_image';
$full_w = imagesx($large_image);
$full_h = imagesy($large_image);
?>
From here, you'd then load the image into a <canvas> element, an example of which is documented here. Now, my theory was that you may be able to extract pixel data from a <canvas> element; assuming that you can, you would simply make sure to have some form of definite divider between the frames of the large image and then search for it within the canvas. Let's say you found the divider 110 pixels from the left of the image; you would then know that each "frame" was 110 pixels wide, and you've already got the full width stored in a PHP variable, so deciphering how much image you're working with would be a breeze.
The only speculative aspect to this method is whether or not JavaScript is capable of extracting color data from a specified location within an image loaded into a <canvas> element; if this is possible, then what you're trying to accomplish is entirely feasible.
I suppose you want to take a thumbnail for your image. You can use ImageThumbnail.js that created from prototype library in this way:
<script type="text/javascript" src="prototype.js"></script>
<script type="text/javascript" src="ImageThumbnail.js"></script>
<input type="file" id="photo">
<img src="empty.gif" id="thumbnail" width="80" height="0">
<script type="text/javascript">
<!--
new Image.Thumbnail('thumbnail', 'photo');
//-->
</script>
for more information
try use haxcv library haxcv js by simple functions
go to https://docs.haxcv.org/Methods/cutImage to read more about his library
var Pixels = _("img").cutImage (x , y , width , height );
_("img").src (Pixels.src);
// return cut image
but try to include library first

Categories

Resources