Fit (contain) <img> of unknown size to parent, keeping aspect ratio WITHOUT img-element having same w/h as parent [duplicate] - html

I realise this has been asked many times under many guises, but most solutions seem to not care about the resulting image height, or only scale in one direction. This:
min-width: 100%;
height: auto;
isn't a solution.
I'm trying to fit an image to the height and width so that it can be dynamically injected into a number of places in different systems and sites, so I don't necessarily know what the parent object is going to be - might be a div with or without overflow set, or a p, or the body - or its dimensions; The parent container mustn't change size just by injecting my image/script .. jQuery is NOT available.
I can't see how the css3 background technique would work.
Proportional scaling is as easy as using a ratio:
<img onload="scale(this)" src="screenshot.png">
<script type="text/javascript">
function scale(img){
var p = img.parentNode,
x = p.offsetWidth,
y = p.offsetHeight,
w = img.naturalWidth,
h = img.naturalHeight;
ratio = h / w;
if (h >= y) {
h = y;
w = h / ratio;
img.style.width = w + "px";
img.style.height = h + "px";
} else if(w >= x) { //} && ratio <= 1){
w = x;
h = w * ratio;
img.style.width = w + "px";
img.style.height = h + "px";
}
}
</script>
but this only scales in one plane - I need it to continue to scale both width and height until it fits into the parent container space neatly in both dimensions. If the image is smaller than the parent container, it should scale UP to fill proportionally.

Adapt image to fit parent container (of unknown size) without stretching image
Instead of messing with JS, let CSS do the job!
Set your image to 100%; height and width;
Replace your image's src with a transparent pixel and set it's background to the actual src.
Use CSS's background-size on your (now) full-sized image:
contain (image will cover the parent completely)
cover (image will respect image proportions instead)
Example using contain
function scale( img ) {
if(img.isScaled) return;
img.style.background="no-repeat url("+ img.src +") 50%";
img.style.backgroundSize="contain"; // Use "contain", "cover" or a % value
img.style.width="100%";
img.style.height="100%";
img.isScaled=true; // Prevent triggering another onload on src change
img.src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
}
<div style="width:300px; height:300px; background:#000; margin:10px;">
<img onload="scale(this);" src="//placehold.it/1200x600/f0f">
</div>
<div style="width:300px; height:300px; background:#000; margin:10px;">
<img onload="scale(this);" src="//placehold.it/400x600/cf5">
</div>
Tested in: FF, CH, E, IE(11), SA
NB: The transparent pixel data is used solely to prevent the browser's Missing Iimage Icon that would be otherwise caused by doing img.src = "";
http://caniuse.com/#search=background-size

I used this code to fit a video to its parent:
var parent = vid.parentNode,
vw = vid.videoWidth,
vh = vid.videoHeight,
vr = vh / vw, // video ratio
pw = parent.offsetWidth,
ph = parent.offsetHeight,
pr = ph / pw; // parent ratio
if(pr > vr) {
vid.style.width = 'unset';
vid.style.height = `${ph}px`;
} else {
vid.style.height = 'unset';
vid.style.width = `${pw}px`;
}

Related

Pixi.js - Unable to set sprite width to full width of canvas

Ultimately I want to have a canvas that fills the entire viewport width of the browser and have an image on the canvas fill the entire width of that canvas. I'm taking advantage of pixi.js's displacement filter so that I can create a pseudo 3d effect using a depth map underneath it. The code I'm currently using is
let app = new PIXI.Application();
var w = window.innerWidth;
var h = w / ratio;
app.view.style.width = w + 'px';
app.view.style.height = h + 'px';
document.body.appendChild(app.view);
let img = new PIXI.Sprite.from("images/horses.png");
img.width = w;
img.height = h;
app.stage.addChild(img);
depthMap = new PIXI.Sprite.from("images/horses-depth.png");
depthMap.renderable = false;
depthMap.width = img.width;
depthMap.height = img.height;
img.addChild(depthMap);
app.stage.addChild(depthMap);
displacementFilter = new PIXI.filters.DisplacementFilter(depthMap, 0);
app.stage.filters = [displacementFilter];
Here's a screenshot of it in action.
I even tried manually setting the width to the viewport pixel width on the canvas and the sprite to the actual pixel width of the viewport width and it still wasn't the right size. Manually setting the width for the viewport and sprite to the exact same number also doesn't work; the sprite is inexplicably smaller than the canvas.
I tried to look at the documentation of the sprite class and see if there is something unusual about how sprites handle widths but I couldn't find anything https://pixijs.download/dev/docs/PIXI.Sprite.html
How can I create a pixi.js sprite that fills the entire width of the canvas in order to make both the canvas and the sprite fill the entire viewport width?
pixijs.download
PixiJS API Documentation
Documentation for PixiJS library

Calculate aspect ratio of an image to get equal heights with flexbox

I was taking a look at:
this code pen about equal responsive height images
I want images to have the same height, despite their width/height differences.
As can be seen in the CSS below, there is usage of flexbox with flex to get the images as this:
/* Important stuff for this demo. */
img {
width: 100%;
height: auto;
vertical-align: middle;
}
.pics_in_a_row {
display: flex;
}
.img1 { flex: 1.3344; } /* <-- how can I calculate this part? */
.img2 { flex: 1.3345; }
.img3 { flex: 0.7505; }
.img4 { flex: 1.5023; }
.img5 { flex: 0.75; }
How can I calculate the part of the flex : number. I guess this is the aspect ratio?
The aspect ratio is X/Y of the image size.
So if the image is 600 pixels wide and 800 pixels high, the aspect ratio would be 600/800=0.75
When knowing this, you can choose one of the methods proposed in the article you referenced:
With the CSS methods, you do have a few options for specifying the
aspect ratio:
Work out the aspect ratio yourself and hard-code it into the CSS (as done in this demo)
Use CSS's calc() to calculate the aspect ratio (e.g. flex: calc(600/800);)
Use a preprocessor to calculate the aspect ratio at build time
I was struggling with this myself. You get the image ratio by dividing its width and height. If you don't use JavaScript just open your calculator and divide image width with the height. If you use JavaScript then to get the flex value you need to divide image width/height. Like this:
const imageRatio = img.naturalWidth / img.naturalHeight;
When getting the value you can use naturalWidth and naturalHeight values that return the original size of the image. I used only height and width in the beginning but it is from the browser and might return incorrect values in some cases (loading image etc).
https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/naturalWidth
What I ended up doing is that I calculate the column widths with JavaScript instead of the flex because it doesn't work if there is text inside the column. Then the math becomes more complex. You have to get the ratio of all images, sum them and you get the total ratio. Then you divide the image ratio with this full ratio to get the percentage.
Here is some pseudocode:
const getFullRatio = (images) => images.reduce((acc, curr) => (curr.naturalWidth / curr.naturalHeight) + acc, 0);
const containerWidth = 740;
const columnAmount = images.length;
const columnMargin = 15;
const marginPercentageToAdd = ((columnAmount * columnMargin) / containerWidth) + 1;
const fullRatio = getFullRatio(images);
const fullRatioWithMargins = fullRatio * marginPercentageToAdd;
images.forEach((img) => {
const imageRatio = img.naturalWidth / img.naturalHeight;
const columnRatio = (imageRatio / fullRatioWithMargins) * 100;
const imageParentDiv = img.closest('.COLUMNCLASS');
imageParentDiv.style.width = `${columnRatio}%`;
const image = img;
image.style.width = '100%';
});

HTML5: Canvas width and height

Consider:
<canvas id="myCanvas" width="200" height="300" />
Are those units in pixels? If not, is there a workaround to change it?
Yes, those units are always in pixels and applies to the bitmap the canvas element uses. However, if there is no size defined on the element using CSS (ie. style attribute or using a style sheet) the element will automatically adopt to the size of its bitmap.
There is no other way of setting the size of the bitmap than by number of pixels. Using CSS will only change the size of the element itself, not the bitmap, stretching whatever is drawn to the bitmap to fit the element.
To use other units you will have to manually calculate these using JavaScript, for example:
// using % of viewport for canvas bitmap (pixel ratio not considered)
var canvas = document.getElementById("myCanvas"),
vwWidth = window.innerWidth,
vwHeight = window.innerHeight,
percent = 60;
canvas.width = Math.round(vwWidth * percent / 100); // integer pixels
canvas.height = Math.round(vwHeight * percent / 100);
// not to be confused with the style property which affects CSS, ie:
// canvas.style.width = "60%"; // CSS only, does not affect bitmap
If you want to support retina then you need to use the window.devicePixelRatio and multiply it with the sizes. In this case CSS would be necessary as well (combine with code above):
var pxRatio = window.devicePixelRatio || 1,
width = Math.round(vwWidth * percent / 100),
height = Math.round(vwHeight * percent / 100);
canvas.width = width * pxRatio;
canvas.height = height * pxRatio;
canvas.style.width = width + "px";
canvas.style.height = height + "px";
Almost all size parameters in HTML5 are going to be in pixels. If you're experiencing issues drawing the canvas with your current code, try taking out the self-closing block at the end:
<canvas id="myCanvas" width="200" height="300"></canvas>
You may also consider viewing the properties of the canvas element as defined by W3 Schools: http://www.w3schools.com/html/html5_canvas.asp
use css to setup your canvas styles
<canvas id="el"></canvas>
<style>
#el{
display: block;
width:100%;
height: 100%;
}
</style>

Moving background with my cursor

My website's landing page (http://www.chrisamaddeo.com/) has a full screen background. I want to make it move like an example of this website's header (http://www.kaiserair.com/) I have this code, HTML, which goes in the head of my website:
<!DOCTYPE html>
<html>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>
<script>
$(document).ready(function() {
var movementStrength = 25;
var height = movementStrength / $(window).height();
var width = movementStrength / $(window).width();
$("#top-image").mousemove(function(e){
var pageX = e.pageX - ($(window).width() / 2);
var pageY = e.pageY - ($(window).height() / 2);
var newvalueX = width * pageX * -1 - 50;
var newvalueY = height * pageY * -1 - 25;
$('#top-image').css("background-position", newvalueX+"px "+newvalueY+"px");
});
I have this code, css and it doesn't work:
#top-image {
background:url('https://d3ui957tjb5bqd.cloudfront.net/images/screenshots/products/0/8/8905/red-rocks-park-o.jpg' -50px -25px;
position:fixed ;
top:0;
width:100%;
z-index:0;
}
My website is hosted with weebly and their html is a little different
Actually, i've just tried copying your code:
http://codepen.io/chrisboon27/pen/rEDIC
It does work, in that it moves the image.
I did have to add some some closing braces to your jQuery but maybe you just missed those when you pasted the code into this question.
Also, I looked at your site and noticed you are currently using background-size:cover. This takes your bg image and makes it fit within the div - you dont want that as you want some bg extending beyond the div - so i'n the css in the example I linked to you can see I used calc to make the bg-image size to 100% width + 50px. I used 50px as your code currently moves the background image position by up to 25px left or right, therefore you need it to be 50px total wider than the div.
EDIT:
If you use calc you should include a -webkit prefixed version too (unless you are using prefix-free or prefixr to add prefixes. Here is browser support: http://caniuse.com/calc
If you need to support more browsers you will need to set background-size via javascript
I'm finding that quite hard to follow without recreating it and seeing where those numbers come from. However I recently made something very similar with jQuery for someone else except it moves an img within a div. It probably wouldn't take much to switch it to move a background image though (though finding out the bg-image dimensions would be tricky - you might be better hard coding them in that instance).
html:
<div class="container"><img src="foo.jpg" class="draggable"/>
</div>
jQuery:
//for each item
$(".container").each(function(){
//get the container width
var conWidth = $(this).width();
//and its height
var imgHeight = $(this).find("img").height();
//get the nested img width
var conHeight = $(this).height();
//and its height
var imgWidth = $(this).find("img").width();
//figure out how much of the image is not visible horizontally
var excessWidth = imgWidth - conWidth;
//and how much is not visible vertically
var excessHeight = imgHeight - conHeight;
//how far is this container from the left of the page
var containerPositionLeft = this.offsetLeft;
//and from the top
var containerPositionTop = this.offsetTop;
//when moving mouse over container
$(this).mousemove(function(e){
//figure out how many pixels the mouse is from the left edge of the page
var mouseoffLeftPage = e.pageX;
//and how many from the top edge of the page
var mouseoffTopPage = e.pageY;
//figure out how many pixels the mouse is from the left edge of the page
var mouseoffLeftPx = mouseoffLeftPage - containerPositionLeft;
//and how many from the top edge of the page
var mouseoffTopPx = mouseoffTopPage - containerPositionTop;
//figure out the distance the mouse is from the left edge as a percentage (kind of - all the way to the right equals 1 not 100)
var mouseoffLeftPercent = mouseoffLeftPx/conWidth;
//do the same for height
var mouseoffTopPercent = mouseoffTopPx/conHeight;
//times the 'percentage' value by the amount of image hidden - so if your conatiner is 200px wide, your image 300px wide nd your mouse is half way across this value would be 0.5*100 which would give you 50 - which is exactly half the amount of image that is missing.
//note this gets set as a minus value as we will be using a minus number to shift the image around.
var setnewWidth = -(mouseoffLeftPercent * excessWidth);
//do the same for the height
var setnewHeight = -(mouseoffTopPercent * excessHeight);
//add the values as css (using transform(translate) as it's more performant and does subpixel rendering so looks smoother [or does it? it does in animations but seems as my js is not technically animating it it might not make a difference in that respect] - could set the top,left version as fallback for unsupporting browsers but ie9 supports transforms anyway so i dont care.)
$(this).find("img").css({"transform" : "translate("+ setnewWidth+"px ,"+setnewHeight+"px)" });
//$(this).find("img").css({"left" : setnewWidth+"px", "top" : setnewHeight+"px" });
});
});
Not a direct answer to what isn't working in your code, but shows an example (with comments on what is happening) of how it can be done - note that my version doesn't rely on you knowing any of the widths or heights of objects and can run on multiple items on one page - also it doesn't have to be placed at the very top of the page. It does assume the image is larger than its container though - if it isn't larger the image just moves around within it.
You could reduce the number of variables by doing more calculations in a row, I just wanted it to be as easy to read the logic as possible.
DEMO:
http://codepen.io/chrisboon27/pen/BhkJq
Simpler than that, you can just make sure the CSS position is set to "fixed" so wherever you are on the page it's always 0px from the top.

How to rotate an image on the canvas and expand the parent so that the image is not cut away?

How to rotate an image on an HTML5 Canvas, without loosing any image data? I mean if rotation causes the image dimensions to increase, I want to expand the Canvas container as well, so that the image is not cut off. The following image might say better:
The brown colored box is actually the container that wraps the Canvas. I want to expand it (and the Canvas to fit the image) when the Canvas is rotated, so that the image is not cut off.
Update:
The image could be larger than the Canvas hence I'm using a bounding box method to calculate proportional sizes with the parent container to fit the image. So the Canvas's style dimensions will be the calculated ones whereas it's height and width attributes will be the image dimensions.
Any help is appreciated!
This function will resize your canvas to exactly fit the rotated image. You must supply the width and height of the image and it's current rotation angle in degrees.
[Edited: OOPS! I should have converted the angle to radians ... And ... the canvas width/height should be changed, not the css width/height]
function resizeCanvasContainer(w,h,a){
var newWidth,newHeight;
var rads=a*Math.PI/180;
var c = Math.cos(rads);
var s = Math.sin(rads);
if (s < 0) { s = -s; }
if (c < 0) { c = -c; }
newWidth = h * s + w * c;
newHeight = h * c + w * s ;
var canvas = document.getElementById('canvas');
canvas.width = newWidth + 'px';
canvas.height = newHeight + 'px';
}