I'm quite new to HTML/CSS/Javascript and I have been following this example to create an interactive zoom of another image. The code works fine for me. It also works if the size of the input image is not absolute, but given in percentages. You can see this here by changing the line
<img id="myimage" src="img_girl.jpg" width="300" height="240">
to
<img id="myimage" src="img_girl.jpg" width="50%" height="50%">
However, switching to percentage-based image size introduces a problem. If the browser window is resized, the zoomed image no longer aligns with the lens. This problem goes away if I refresh the window.
So, how can I tell my JavaScript imageZoom() function that the browser window has been resized, the target image has changed dimensions, and therefore the function variables have changed?
At the end of the main function, add:
window.addEventListener("resize", updateVars)
and define the function
function updateVars(e) {
/* Recalculate ratios. */
cx = result.offsetWidth / lens.offsetWidth;
cy = result.offsetHeight / lens.offsetHeight;
result.style.backgroundSize = (img.width * cx) + "px " + (img.height * cy) + "px";
}
Related
I am working on a project with very specific criteria. I have a button that will open a random image from an array when clicked, into a new window located randomly on the screen, and size the window/image height relative to the size of the monitor while maintaining the original image's aspect ratio.
The issue is all of the images in the array are different resolutions and aspect ratios, and I would like the window they open into to fit nicely to the image.
Here is the code I am working with so far:
function openWin() {
var myWindow;
var rand = Math.random();
var l = screen.width * Math.floor(Math.random());
var t = screen.height * Math.floor(Math.random());
var w = screen.width / 5;
var h = screen.height / 3;
var arr = [
"images/testpic.png",
"images/testpic2.png",
"images/testpic3.png",
"images/testpic4.png",
"images/testpic5.png"];
var value = arr[Math.floor(Math.random() * arr.length)];
myWindow = window.open(value, "", "left= "+ l +", top= "+ t +", width= " + w +", height=" + h +" ");
}
At this point I can open the random image from an array, place it randomly on screen, with the height of the new window scaled to the height of the monitor.
BUT the width of the new window is also scaled to the width of the monitor and not the width of the image. This either gives black bars or cuts off parts of the image.
I have been trying to get an answer for a while and will preempt a couple of things:
This is for a personal project, not a customer or any other users so it doesn't matter if it is annoying
When I say the images are different aspect ratios I mean VERY different. Some are 3:1, 16:9, 1:1, 1:2, etc.
There are 1,500 images so I am not keen on brute force sizing each one
I realize this is very niche but any help is appreciated and sorry if my code is a mess
EDIT: Here is a gif visualizing the kind of functionality I am looking for. Note: Some of the images are HD but resized relative to the screen size
See Here
As I couldn't get it work here, I mage a JSFiddle for you:
Sample
Here my idea. Get all the images on the page in imagesArr. Then for each of them make an object Image() with its features. Add an event listener to each image to open the openWindow function.
I have a canvas with an image that fills the canvas. This works fine but I would like to have the canvas be full width of the window. At the moment the canvas is the width of the image I put in it.
I've tried the following at the bottom of my script:
function resizeCanvas() {
canvas.setHeight(img.height);
canvas.setWidth(window.innerWidth);
canvas.renderAll();
}
resizeCanvas();
But this does not work.
I've also tried giving the canvas element 100% width in its paramaters and with css, both with no success.
Codepen with working example:
https://codepen.io/twan2020/pen/YzpeEEr
If you increase your screen size the image stops after a while instead of keeping full width of the browser window.
Is this possible? With keeping all objects in their place?
It was not easy to fix but i found some documentation that could make it work.
First edit the code to realWidth and add var realWidth = window.innerWidth;
and then for setting the background remove your current code and add
fabric.Object.NUM_FRACTION_DIGITS = 10;
fabric.Image.fromURL(source, function(img) {
img.scaleToWidth(canvas.width);
canvas.setBackgroundImage(img);
canvas.requestRenderAll();
});
this should fix the problem, and the backgound will take the full size of the screen.
Update for the new calculation of the circle position.
is equal to Newposition= oldPosition * (newWidth / oldWidth)
Here you can see that it work https://codepen.io/AlenToma/pen/ExNEooX
var print = document.createElement('button');
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
canvas.width = 300;
canvas.height = 100;
ctx.fillStyle = '#000';
ctx.font = '15px sans-serif';
ctx.fillText('Fill Text, 18px, sans-serif', 10, 20);
print.innerHTML = 'Print';
document.body.appendChild(print);
document.body.appendChild(canvas);
print.addEventListener('click', function () {
window.print();
});
http://jsfiddle.net/vpetrychuk/LWup5/.
As you can see text in the canvas displays ok, but after clicking "Print" button (and saving page as PDF) output image becomes ugly.
Any chance to print the canvas contents without blur?
You need to make the actual canvas at print size then scale it on screen using CSS rules.
The browser will always use the internal bitmap size first and adjust that to the print or screen. If the bitmap is then of high resolution you will get better result on the print.
But mind you though, you will need to scale every coordinate and size when you print to the canvas. You will also need to prioritize screen versus print as one of them will look worse (if you prioritize print it will not look super on screen and vica verse).
Here is a modified example of your canvas which is now equivalent of 300 DPI (versus default 96 DPI). You can see it looks about the same on screen but will be much sharper when you print it.
/// conversion factor for scale, we want 300 DPI in this example
var dpiFactor = 300 / 96,
width = 400,
height = 100;
/// set canvas size representing 300 DPI
canvas.width = width * dpiFactor;
canvas.height = height * dpiFactor;
/// scale all content to fit the 96 DPI display (DPI doesn't really matter here)
canvas.style.width = width + 'px';
canvas.style.height = height + 'px';
/// scale all sizes incl. font size
ctx.font = (15 * dpiFactor).toFixed(0) + 'px sans-serif';
/// scale all positions
ctx.fillText('Fill Text, 18px, sans-serif', 10 * dpiFactor, 20 * dpiFactor);
Simply use wrapper functions to do all the math for you:
function fillText(txt, x, y) {
ctx.fillText(txt, x * dpiFactor, y * dpiFactor);
}
You can try to detect when printing is going to happen (e.g. using Webkit window.matchMedia) but the actual printing is done using a scaling that is not under your control so creating a perfect 1x1 scaled canvas for sharp graphics is impossible.
You can replace the canvas with an high-enough resolution version when you detect printing, but the exact real size of the output is unknown. It's like if the user has a zoomed view of the page... even if canvas has been drawn sharply the browser can zoom it making the result blurry anyway.
Probably for text the best quality option is using a regular text div overimposed on the canvas instead of using fillText (of course this won't work for all use cases).
I had in css width: 100% for canvas, which caused wrong scaling
Fixed by changing from 100% to 210mm
A better solution is to use the canvas.toDataURL() method and then set the resulting string to the src of an img. When doing this, generate the canvas through Javascript and never actually append it to the body of the page.
Daniel's answer works great. Printing images instead of canvases is better. You don't need to write any JS hacks.
I'm building a phonegap app (with jquery mobile) and trying to insert an image in my DOM with width relative to the window.outerWidth and height auto.
I've already tried placing the image in a div with relative width like so:
<div style="width:myRelativeWidth">
<img style"width:100%; height:100%" src="somePath>
</div>
This works great, except on the iPhone where it sets the height of the image (auto) too late. It will be the correct width, but it is stretched heightwise to its original size before it is sized to the correct aspect ratio.
To counteract this, I've tried to scale it in relation to the size of the original image. The only way I know to get this is by preloading the image and setting the size before it is inserted in the DOM by the following function
imageElement = new Image();
imageElement.src = path;
setImageSize(widthPercentage);
function setImageSize(widthPercentage) {
var pageWidth = window.outerWidth;
var pageHeight = window.outerHeight;
var imageWidth = imageElement.width;
var imageHeight = imageElement.height;
var calculatedImageWidth;
var calculatedImageHeight;
var scaleFactor;
if(widthPercentage) {
calculatedImageWidth = pageWidth * (widthPercentage / 100);
scaleFactor = calculatedImageWidth / imageWidth;
calculatedImageHeight = imageHeight * scaleFactor;
imageElement.width = calculatedImageWidth;
imageElement.height = calculatedImageHeight;
}
}
document.body.appendChild(imageElement);
But testing in the browser i don't get the image when loading the page, but i get it when refreshing it.
Some googling told me that I have a problem with the image being loaded in the cache, but not drawn.
How can i force the image to be drawn?
Found my answer!
Assign the onload method to setImageSize as mentioned by #CBroe, and place it before imageElement.src=.
I have some complicated, problem to be solved. Now I need to write such a function in javascript that supports object canvas in html5, which will cut out the portion of the picture and show it in the preview. I need to do than with diffrent resolution of images. I use the jQuery library for this, especially jquery.Jcrop.js .. The visible part of the picture in the preview I'm gona use later for further purposes, it must be writable in the cut form to file - so I use the opportunities of canvas. This script is working well, but the problem is when I try to scale a photo from the larger to the smaller one ( I want that each image will be fixed in the browser window to height 500 px). I present below the current figure of a script:
function updatePreview(c)
{
if (parseInt(c.w) > 0)
{
var rx = 200 / c.w;
var ry = 300 / c.h;
// Show canvas image preview2
var imageObj = $("#target")[0];
var canvas = $("#preview2")[0];
var context = canvas.getContext("2d");
canvas.setAttribute('width', '200');
canvas.setAttribute('height', '300');
//context.scale(2, 2);
context.drawImage(imageObj, c.x, c.y, c.w, c.h, 0, 0,
canvas.width, canvas.height);
$('#preview').css({
width: Math.round(rx * boundx) + 'px',
height: Math.round(ry * boundy) + 'px',
marginLeft: '-' + Math.round(rx * c.x) + 'px',
marginTop: '-' + Math.round(ry * c.y) + 'px'
});
}
};
And here's a simplified html code that is for the script to be processing
<table>
<tr>
<td>
<img src="http://imgon.net/di-M7Z9.jpg" id="target"
alt="obrazek" height="450"/>
</td>
<td>
<div style="width:200px;height:300px;overflow:hidden;">
<img src="http://imgon.net/di-M7Z9.jpg" id="preview" alt="Preview" />
</div>
<br />
<div>
<canvas id="preview2" style="width:200px;height:300px;"></canvas>
</div>
</td>
</tr>
</table>
The first preview is based on css and it works correctly but css covers only part of the picture and not actually cut it. Contrast, canvas sees a picture in high resolution and preview does not reflect the segment of the scaled images (I have enlarged section only). This happens in Firefox. For Internet Explorer is a special library, and there result for the canvas is the same as for CSS. My final question is. How I can say to the function to create a preview for the scaled image and not the preview for the original resolution? I tried to put substitute for the variable c.y like Math.round (rx * boundx) and for cx Math.round (ry * boundy) but it is not right.
I give here a page where you can see the script live: agd-brita.pl/mobile2/tutorial.html
I ask you for help. Thanks for advance.
I had to understand a little bit how jCrop works to answer you.
I made a fiddle to show how my solution works: http://jsfiddle.net/maitrekaio/Wre8w/
The main point is that working with CSS and working with canvas are really different and that you have to make different computations.
Nevertheless, the starting is the same: you have an image element, target and a crop within. The details of the crop are given by jCrop, and the dimensions of the image element are stored in my displayedImg variable.
The CSS preview
The preview-container is like a window that let's us see a portion of the contained image. The contained image element has not been resized, so its dimensions are those of the picture realImg. When the crop is resized and moved, we have to give the feeling that the window does the same. In fact, it's the contained image that is resized and moved. How to compute that ?
It's easy to see that the ratio (crop / displayedImg) must be equal to the ratio (preview / realImg). That gives us the formula:
realImg = (displayedImg * preview) / crop
With this, it's easy to calculate width, height, x (marginLeft) and y (marginTop) which are applied to the CSS preview.
The canvas preview
For the canvas, we know that we'll use the most complex version of context.drawImage(), the one that allows us to crop and resize. The first parameter of this method is a JS image object, we'll use the target image. This time we want to compute the crop in the real image, knowing the crop in the displayed image. (crop / displayedImg) must be equal to (realImgCrop / realImg). It gives us the formula:
realImgCrop = (crop * realImg) / displayedImg
Done !