Why is image stretched on canvas? [duplicate] - javascript

This question already has answers here:
Canvas is stretched when using CSS but normal with "width" / "height" properties
(10 answers)
Closed 6 months ago.
I specified the image dimensions to be 50px by 50px but it is stretched on the y axis like this.
Stretched Image
I think it may have something to do with the css styling so here is my css code.
canvas {
background-color: green;
padding: 0;
margin: auto;
display: block;
height: 700px;
width: 700px;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
Please tell me why the image is stretched.

css width and height doesn't update the initial aspect ratio of canvas, which is introduced to the element by the attributes like this: <canvas width="X" height="Y">
If the size of your canvas is fixed, you should change the width and height of the canvas tag attributes.
If it's not constant, you may need to use Javascript to update it, like this:
const canvasDom = document.getElementById('mycanvas');
canvasDom.setAttribute('width', '700');
canvasDom.setAttribute('height', '700');

Related

Pixel not the right size on canvas [duplicate]

This question already has answers here:
Canvas is stretched when using CSS but normal with "width" / "height" properties
(10 answers)
Closed 3 years ago.
So my rectangle i want to draw on a canvas are, i think scaled to the size of the canvas. I i want them to be 8x8 they dont come out as 8x8.
Here's my code:
function draw() {
var canvas = document.getElementById('karte');
var ctx = canvas.getContext("2d");
Stuttgart = ctx.fillRect(10,10,8,8);
}
.map {
height: 799px;
width: 591px;
margin: auto;
margin-top: 50px;
background-image: url('../img/Karte_Deutschland.svg');
background-repeat: no-repeat;
background-size: contain;
background-position: center;
}
.map canvas {
height: 799px;
width: 591px;
}
<canvas id="karte">
</canvas>
Here's a screenshot how it looks like in the end: https://prnt.sc/r58bvl
For now you set the canvas width and height on the screen different then the canvas actual width and height (which is 300/150 by default) it is why anything scaled for you. so :
Eather add the height and width to the canvas:
<canvas id="karte" height="799" width="591"><canvas>
Or add it manually in the js:
canvas.width = canvas.offsetWidth;
canvas.height = canvas.offsetHeight

Proportional width div with 100% height (without JS?) [duplicate]

I need to maintain the width of an element as a percentage of its height. So as the height changes, the width is updated.
The opposite is achievable by using a % value for padding-top, but padding-left as a percentage will be a percentage of the width of an object, not its height.
So with markup like this:
<div class="box">
<div class="inner"></div>
</div>
I'd like to use something like this:
.box {
position: absolute;
margin-top: 50%;
bottom: 0;
}
.inner {
padding-left: 200%;
}
To ensure the box's aspect ratio is maintained according to it's height. The height is fluid because of it's % margin - as the window's height changes, the box's height will too.
I know how to achieve this with JavaScript, just wondering if there's a clean CSS-only solution?
You can use an image that has the desired proportions as to help with proportional sizing (images can be scaled proportionally by setting one dimension to some value and other to auto). The image does not have to be visible, but it must occupy space.
.box {
position: absolute;
bottom: 0;
left: 0;
height: 50%;
}
.size-helper {
display: block;
width: auto;
height: 100%;
}
.inner {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: rgba(255, 255, 153, .8);
}
<div class="box">
<img class="size-helper" src="//dummyimage.com/200x100/999/000" width="200" height="100">
<div class="inner">
1. box has fluid height<br>
2. img has 2:1 aspect ratio, 100% height, auto width, static position<br>
2.1 it thus maintains width = 200% of height<br>
2.2 it defines the dimensions of the box<br>
3. inner expands as much as box
</div>
</div>
In the above example, box, inner and helper are all same size.
You can use vh units for both height and width of your element so they both change according to the viewport height.
vh
1/100th of the height of the viewport. (MDN)
DEMO
.box {
position: absolute;
height:50vh;
width:100vh;
bottom: 0;
background:teal;
}
<div class="box"></div>
There is another, more efficient way to achieve constant aspect ratio according to height.
You can place an empty svg so you dont have to load an external image.
HTML code:
<svg xmlns="http://www.w3.org/2000/svg"
height="100"
width="200"
class='placeholder-svg'
/>
CSS code:
.placeholder-svg {
width: auto;
height: 100%;
}
Change width/height to achieve desired aspect ratio.
Keep in mind, the svg might overflow.
http://www.w3.org/2000/svg is just a namespace. It doesn't load anything.
If you change placeholder-svg class to:
.placeholder-svg {
width: 100%;
height: auto;
}
then height is adjusted according to width.
Demo 1 Width is adjusted according to height and 2:1 aspect ratio.
Demo 2 same as above, but you can resize easily (uses React)
The CSS trick you wrote, works pretty well to keep ratio width / height on an element.
It is based on the padding property that, when its value is in percent, is proportional to parent width, even for padding-top and padding-bottom.
There is no CSS property that could set an horizontal sizing proportionally to the parent height.
So I think there is no clean CSS solution.
As of 2021 there is a property called aspect-ratio.
Most browsers support it
div {
border: 1px solid;
margin: 8px;
}
.box {
width: 100px;
min-height: 100px;
resize: horizontal;
overflow: auto;
}
.inner1 {
aspect-ratio: 1/1;
}
.inner2 {
aspect-ratio: 3/1;
}
<div class="box">
<div class="inner1"></div>
<div class="inner2"></div>
</div>
Run this snippet and resize the outer div manually to see the inner divs behavior
I can't find a pure CSS solution. Here's a solution using CSS Element Queries JavaScript library.
var aspectRatio = 16/9;
var element = document.querySelector('.center');
function update() {
element.style.width = (element.clientHeight * aspectRatio) + 'px';
}
new ResizeSensor(element, update);
update();
CodePen demo!

CSS width in % and height in px and both same length [duplicate]

This question already has answers here:
Height equal to dynamic width (CSS fluid layout) [duplicate]
(9 answers)
css width same as height
(4 answers)
Closed 8 years ago.
What I try to make is square that change size with the size of the screen.
So I have the width set to 25%.
How do I make sure that the height keeps the same length in px as the width?
Thanks in advance.
You could use top/bottom padding property in percentage, to achieve the result.
Example Here.
.box {
width: 25%;
padding-bottom: 25%;
}
A percentage value on top/bottom padding or margins is relative to the width of the box's containing block.
8.4 Padding properties: 'padding-top', 'padding-right', 'padding-bottom', 'padding-left', and 'padding'
<percentage>
The percentage is calculated with respect to the width of
the generated box's containing block, even for 'padding-top' and
'padding-bottom'.
Adding the content
Since the the height of the box grows by adding content, we could wrap the content by an element .wrapper and position that absolutely relative to the box, and then use top, right, left and bottom properties to fill the entire space of the box.
Example Here
<div class="box">
<div class="wrapper">
<!-- content goes here... -->
</div>
</div>
.box {
width: 25%;
position: relative;
}
.box:after {
content: "";
display: block;
padding-top: 100%; /* 1:1 square */
}
.box > .wrapper {
position: absolute;
top: 0; right: 0; bottom: 0; left: 0;
}
For further information you could refer my answer here (Responsive Container section).
you may set the width value as a percentage, then grab it with jquery then let it to be the height value. see this
var box = $(".box");
var width = box.css("width");
box.css("height", width);
http://jsfiddle.net/DPYcg/1/
To be able to add contents, you may use pseudo element and floats behavior : http://codepen.io/anon/pen/fklAr/
div {
width:25%;
background:red;
margin:auto;
}
div:before, div:after {
content:'';
}
div:before {
float:left;
padding-top:100%;
}
div:after {
display:block;
clear:both;
}
maybe a duplicate if you want to center content : Center content in the middle of div container

Vertically align 50% of the viewport [duplicate]

This question already has answers here:
Vertically center in viewport using CSS
(4 answers)
Closed 9 years ago.
I am trying to vertically align a div to 50% of the viewport, no matter how long the document is.
You can see an example here http://fancyapps.com/fancybox/#examples
Box offsets properties can be used to obtain this effect.
This property specifies how far an absolutely positioned box's top
margin edge is offset below the top edge of the box's containing
block.
Source: http://www.w3.org/TR/CSS2/visuren.html#position-props
jsfiddle
CSS
#centered {
position: fixed;
top: 0;
bottom: 0;
right: 0;
left: 0;
margin: auto;
height: 200px; /* arbitrary */
width: 600px; /* arbitrary */
background-color: grey;
}
Here is a jQuery example that will center a div regardless of it's height and width.
DEMO http://jsfiddle.net/kevinPHPkevin/dzSPN/120/
function animateHight(newHeight){
$('div#centered').animate({'height': newHeight, 'margin-top': -newHeight/2}, 600, function(){animateWidth(100);animateHight(100);});
}
function animateWidth(newWidth){
$('div#centered').animate({'width': newWidth, 'margin-left': -newWidth/2}, 600);
}

Scale a div to fit in window but preserve aspect ratio

How can I scale a div to fit inside the browser view port but preserve the aspect ratio of the div. How can I do this using CSS and/or JQuery?
Thanks!
You don't need javascript for this. You can use pure CSS.
A padding-top percentage is interpreted relative to the containing block width. Combine it with position: absolute on a child element, and you can put pretty much anything in a box that retains its aspect ratio.
HTML:
<div class="aspectwrapper">
<div class="content">
</div>
</div>
CSS:
.aspectwrapper {
display: inline-block; /* shrink to fit */
width: 100%; /* whatever width you like */
position: relative; /* so .content can use position: absolute */
}
.aspectwrapper::after {
padding-top: 56.25%; /* percentage of containing block _width_ */
display: block;
content: '';
}
.content {
position: absolute;
top: 0; bottom: 0; right: 0; left: 0; /* follow the parent's edges */
outline: thin dashed green; /* just so you can see the box */
}
The display: inline-block leaves a little extra space below the bottom edge of the .aspectwrapper box, so another element below it won't run flush against it. Using display: block will get rid of it.
Thanks to this post for the tip!
Another approach relies on the fact that browsers respect an image's aspect ratio when you resize only its width or height. (I'll let google generate a 16x9 transparent image for demonstration purposes, but in practice you would use your own static image.)
HTML:
<div class="aspectwrapper">
<img class="aspectspacer" src="http://chart.googleapis.com/chart?cht=p3&chs=160x90" />
<div class="content">
</div>
</div>
CSS:
.aspectwrapper {
width: 100%;
position: relative;
}
.aspectspacer {
width: 100%; /* let the enlarged image height push .aspectwrapper's bottom edge */
}
.content {
position: absolute;
top: 0; bottom: 0; right: 0; left: 0;
outline: thin dashed green;
}
Thanks to Geoff for the tip on how to structure the math and logic. Here's my jQuery implementation, which I'm using to size a lightbox so it fills the window:
var height = originalHeight;
var width = originalWidth;
aspect = width / height;
if($(window).height() < $(window).width()) {
var resizedHeight = $(window).height();
var resizedWidth = resizedHeight * aspect;
}
else { // screen width is smaller than height (mobile, etc)
var resizedWidth = $(window).width();
var resizedHeight = resizedWidth / aspect;
}
This is working well for me right now across laptop and mobile screen sizes.
I have a different pure HTML/CSS approach which does not rely on padding or absolute positioning. Instead it uses em units and relies on the CSS min() function plus a little bit of math.
Imagine that we want a viewport div with 16:9 aspect ratio which always fits the browser window and is centered in the axis with excess space. Here's how we can accomplish that:
HTML
<body>
<div class="viewport">
<p>
This should be a 16:9 viewport that fits the window.
</p>
</div>
</body>
CSS
body {
width: 100vw;
height: 100vh;
margin: 0;
display: flex;
justify-content: center;
align-items: center;
background-color: white;
font-size: min(1vw, 1.778vh);
}
div.viewport {
width: 100em;
height: 56.25em;
background-color: lightblue;
}
div.viewport > p {
font-size: 3em;
text-align: center;
}
You can experiment with this in a sample JSFiddle here.
The secret sauce is in the body font-size. It should be set to min(1vw, Avh), where A is the aspect ratio you want the div to have, i.e. width / height. In the example above we're using 1.778, which is approximately 16 / 9.
In CSS, em units are based on the font-size of the element, which is inherited from parent element if not explicitly set. For your viewport div, set the width to 100em (NOT rem) and the height to Iem, where I is the inverse of the aspect ratio expressed as a percentage, i.e. 100 / A or 100 * height / width. In the example above we're using 56.25, which is 100 * 9 / 16.
One bonus of this approach is that all of your nested elements may also use em units so that they always scale precisely with the size of the viewport. You can see this used on the p element in the example.
Note that as an alternative to the above, you may set the font-size on your html element and use rem units everywhere. CSS rem units are similar to em units but always relative to the root element's font-size.
Javascipt:
//Responsive Scaling
let outer = document.getElementById('outer'),
wrapper = document.getElementById('wrap'),
maxWidth = outer.clientWidth,
maxHeight = outer.clientHeight;
window.addEventListener("resize", resize);
resize();
function resize(){
let scale,
width = window.innerWidth,
height = window.innerHeight,
isMax = width >= maxWidth && height >= maxHeight;
scale = Math.min(width/maxWidth, height/maxHeight);
outer.style.transform = isMax?'':'scale(' + scale + ')';
wrapper.style.width = isMax?'':maxWidth * scale;
wrapper.style.height = isMax?'':maxHeight * scale;
}
HTML:
<div id="wrap">
<div id="outer">
{{ fixed content here }}
</div>
</div>
Styling:
/* Responsive Scaling */
#wrap {
position: relative;
width: 1024px;
height: 590px;
margin: 0 auto;
}
#outer {
position: relative;
width: 1024px;
height: 590px;
transform-origin: 0% 0%;
overflow: hidden;
}
This is possible with JQuery and a bit of maths.
Use JQuery to get the view ports width and height as well as the divs current dimensions.
$(document).width();
Calculate the divs current aspect ratio. eg width/height
You need a bit of logic to determine whether to set the width or height first, then use the initial ratio to calculate the other side.
jQuery has a plugin that grows an object until one of it's sides reaches a certain px-value. Coupling this will the viewport's height, you could expand any element to that size: jQuery MaxSide.

Categories

Resources