I have an image and I want to draw on it. To do that, I use jQuery to hide the image:
$("img").hide();
And then I create a canvas and put it in the same div with id drawing in the html. I then set the background of the canvas to be the same as the img src for the image I hid. This makes it look like an image but now it is actually a canvas with the image as it's background. I do this by:
$('#drawing > canvas').css('background-image','url('+$(".image img").attr('src')+')');
context.canvas.width = $("img").width();
context.canvas.height = $("img").height();
The issue I am having is that sometimes, the image isn't displayed in the canvas and the canvas is not the size of the image. I think it's probably because of some loading issue. How can I wait for the canvas to have the image displayed in the background for sure? Thank you
Edit: Note that in the DOM, the canvas always has the right src. It just doesn't display it
Edit 2: Here's the JSfiddle. Here, everything seems fine but I have a lot more going on in my code including fetching stuff from the server so it's slower there. Hope this helps you guys to understand the problem: http://jsfiddle.net/wL3ezLke/2/
Thanks again
You need to use:
$(function(){
// Code executed once the DOM is loaded.
});
Official documentation:
https://api.jquery.com/ready/
If I understand correctly your problem is knowing when the image loaded (from what you describe it could be a lot of other problems though).
To test if an image has loaded it's pretty simple.
var $img = $('#hiddenImg');
if ($img[0].complete) doCanvasStuff();
else {
$img.on('load', function(e) {
var $canvas = $('#drawCanvas');
$canvas.css({width: $img.width(), height: $img.height()});
//you can go ahead with the background image, but this is preferable
var ctx = $canvas[0].getContext("2d");
ctx.drawImage(img,0,0);
}
}
This should make sure you canvas loads an image only after it was loaded, or do canvas stuff right away if image was loaded, fiddle
Change
$('#drawing > canvas').css('background-image','url('+$(".image img").attr('src')+')');
context.canvas.width = $("img").width();
context.canvas.height = $("img").height();
to
context.canvas.width = $("img").width();
context.canvas.height = $("img").height();
$('#drawing > canvas').css('background-image','url('+$(".image img").attr('src')+')');
so the height and width are set before the image goes into the background.
Related
Okay so I've successfully managed after a couple of hours to call over an image using HTML localStorage system but I now have one problem with the called over image.... I can't dictate where it goes..... It just sits at the bottom of the page as the code is purely javascript..... I've tried putting it in a div and changing its position but it won't budge any suggestions.... heres the code thats calling the image across:
window.onload = function() {
var picture = localStorage.getItem('img');
var image = document.createElement('img');
image.src = picture;
document.body.appendChild(image);
};
How can I edit the position on the page as well as the hight etc......................? Any help appreciated!
You're appending the image to the document body, so likewise, it's going to be added to the bottom of the page.
You can set the properties of image.style to change the image's CSS properties such as height (image.style.height) and width (image.style.width).
To position it elsewhere on the page, you can change it's display properties
image.style.position = "absolute"; //(for example)
image.style.top = "50px"; //drops the image down 50px from the top of the page
Or, you can add it to a different part of the DOM altogether:
document.getElementById('ID_OF_YOUR_DIV').appendChild(image);
Hope this helps.
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.
Here is my code
javascript: (function() {
var canvas = document.getElementById("app-view").children[1];
var img = canvas.toDataURL("image/png");
window.open(img);
})();
and here is the app element where I wish to target the second canvas element "children1" but it's not working for some reason and always gets stuck at the first element. A solution will be much appreciated, thanks in advance!
In the picture it always targets the first canvas in yellow but I need the one displayed in blue. You can test the code by saving the script as a bookmark in your browser.
Haven't worked out why toDataURL gets the data of the left canvas, but if you wanted to save the canvas, you can isolate it with
var can = document.getElementById("app-view").children[1];
jQuery("body > *").remove();
jQuery("body").append(can) ;
and then now you can right click and save the canvas
This works for me:
document.getElementById('app-view').childNodes[1]
I've got a web application that loads some content from an external source to the dom via an ajax call, one of the things that comes back is a set of images (different sizes and aspect ratios) to be displayed in an profile photo section. I'd like for each of the images to be resized to fit within a 64px x 64px area and I'd like to maintain aspect ratio. I was able to do this in firefox, chrome, and safari, but I've no luck getting this to work in IE 7 or 8. The problem I've had is finding a jquery event that reliably gets triggered after the image loads since the image was added after the page load. Here's what works in the listed browsers:
$(window).load(function () {
$('.profileThumbnail').each(function (i) {
var divHeight = $(this).height();
var divWidth = $(this).width();
if (divHeight > divWidth) {
$(this).css('height', '64px');
$(this).css('width', 'auto');
}
else {
$(this).css('height', 'auto');
$(this).css('width', '64px');
}
divHeight = $(this).height();
var divParentHeight = $(this).parent().parent().height();
var divNewHeight = (divParentHeight - divHeight) / 2;
$(this).parent().css('top', divNewHeight);
divWidth = $(this).width();
var divParentWidth = $(this).parent().parent().width();
var divNewWidth = (divParentWidth - divWidth) / 2;
$(this).parent().css('left', divNewWidth);
});
});
I'm also trying to center (horizontally and vertically) them which is what the rest of that code does, but I think I've got all of that working if I can find a way to trigger this code after the image loads in IE.
keep in mind this needs to work both on the first visit (not cached) and subsequent visits (cached). I'm looking for a jquery, javascript, or css solution as I want to avoid the roundtrip/bandwidth for each image.
Have you tired to add a load event to the images yourself which triggers when the image is loaded? This is how image preloaders work.
var img = document.createElement("img");
img.onload = function(){ alert('loaded'); }
img.onerror = function(){ alert('error'); }
img.src = "foo.png";
You can add the onload to the image elements themselves if you are not doing the preload approach.
The problem I've had is finding a jquery event that reliably gets triggered after the image loads since the image was added after the page load.
Instead of setting an onload listener for the window, set an onload listener for the images you are loading remotely. Set the listener after you create the image object and before you insert it into the body. The listener can basically be all the stuff insife of the .each() in the code you posted,
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