I use images created on the fly to maintain the aspect ratio of boxes with a fixed height. Image sources are set as data-urls provided from a canvas with a given width and height, the images are then attached to divs which can contain any content, have any height, and still maintain a fixed aspect ratio.
This works well, however, on slower phones with less memory the large number of data-urls on the page can start to be a little bit of a drag. Some of the ratios can't be reduced below a certain point resulting in relatively large canvases.
Is there any way to set the ratio of an img element without setting its source? Is there any way to set the source to a format that is an truly empty image with only a width and height?
EDIT: The snippet below throws an error - iframe restrictions, probably having to do with making images. You can see an error free version over at this CodePen.
const wrapper = document.querySelector(".wrapper");
function addRatioBox(width, height = 1) {
const cvs = document.createElement("canvas");
const img = new Image(width, height);
const box = document.createElement("div");
cvs.width = width;
cvs.height = height;
img.src = cvs.toDataURL("image/png");
box.appendChild(img);
box.className = "ratioBox";
wrapper.appendChild(box);
}
addRatioBox(1);
addRatioBox(4, 3);
addRatioBox(16, 9);
addRatioBox(2, 1);
.ratioBox {
background: orange;
display: inline-block;
height: 100%;
margin-right: 10px;
}
.ratioBox img {
height: 100%;
width: auto;
display: block;
}
/* just a whole bunch of stuff to make things prettier from here on down */
.wrapper {
background: #556;
padding: 10px;
position: absolute;
height: 20%;
top: 50%;
left: 50%;
white-space: nowrap;
transform: translate(-50%, -50%);
}
body {
background: #334;
}
.ratioBox:last-of-type {
margin-right: 0;
}
<div class="wrapper"></div>
Related
I'm using a full screen canvas as background of the first section of my page. But as soon as I add the second section and vertical scrollbar appears, the height of canvas reduces a little bit and a gap appears. here's my code:
P.S: Sorry, my code contained bugs, I fixed them. now you can see the red gap.
var canvas = document.getElementById('canvas')
var c = canvas.getContext('2d')
scaleCanvas()
window.addEventListener("resize", scaleCanvas)
function scaleCanvas() {
canvas.width = window.innerWidth
canvas.height = window.innerHeight
c.fillStyle = 'black'
c.fillRect(0, 0, canvas.width, canvas.height)
}
* {
box-sizing: border-box;
max-width: 100%;
}
body {
margin: 0;
padding: 0;
}
#first-section {
position: relative;
min-height: 100vh;
background-color: red; /* to see the gap */
}
#content {
position: relative;
z-index: 2;
}
#second-section {
min-height: 100vh;
background-color: blue;
}
#canvas {
display: block;
padding: 0;
margin: 0;
border: none;
position: absolute;
top: 0;
left: 0;
z-index: 1;
}
<div id="first-section">
<canvas id="canvas"></canvas>
<div id="content">content</div>
</div>
<div id="second-section"></div>
Assuming you mean full screen, and not full page. The two are very different.
If you mean full page then the link to the Screen API will also give you details on obtaining the page size.
Size full screen canvas.
The problem is that you have content that extends outside the page width and height (innerWidth, innerHeight)
The elements with ids first-section, content, and second-section must be inside the display area or else you will get a scroll bar. The scroll bar will change the innerWidth, innerHeight values subtracting the scrollbar width or height depending on which is visible.
To prevent scroll bars the best option is to keep all content inside innerWidth, and innerHeight
Full screen with scroll bars.
If you want have the scroll bars and you are using full screen you can use the Screen API to get the width and height of the display in pixels. You can set the canvas size to match the screen without the scroll bars effecting its size.
Note Do read the provided link to Screen as what defines the screen may not be as expected. EG more than one monitor, or device orientation will effect how you use the API.
Basic example
Thus when in full-screen mode you can set the canvas size and ignore scroll bars with
function sizeFullScreenCanvas() {
canvas.width = screen.width;
canvas.height= screen.height;
}
I have an animation from Lottiefiles (in JSON format), which is then converted into an animated SVG document by the Lottie framwork. However, I can't seem to position the SVG document with the header tag. I'd like it to be beside the text.
I tried to search existing threads for similar things, but none of these worked, except for one (sort of). This included adding the SVG into a div, inside the header itself. However, when I tried this, the SVG document is fixed in place, so while it worked for shorter text (less than 6 characters), if the text was longer, the SVG would appear underneath, instead of moving to the end of the text.
I also have to manually assign the style to the SVG file through Javascript in a timeout, because the SVG document doesn't exist initially.
This is the actual header code (in PugJS).
h1(class="channel-header" style="margin-bottom: 36px; width: 96px; margin: auto;") #{channel}
if premium
div(id="bodyanim" class="badge baseline")
Here is the SASS for the header and inner div tag:
.badge
display: inline-flex
align-self: center
height: 70%
.badge svg, .badge img
height: 1em
width: 1em
fill: currentColor
z-index: -1
position: absolute
left: 0
top: 0
.badge.baseline svg, .badge img
top: .125em
position: relative
.channel-header
margin: 0 0 16px 0
padding: 0
line-height: 1
font-weight: normal
position: relative
height: 45px
And here's the JS setting the SVG object, and setting its CSS after a timeout.
var animData = {
wrapper: document.getElementById('bodyanim'),
animType: 'svg',
loop: true,
prerender: true,
autoplay: true,
path: '/anims/4768-trophy.json'
};
var anim = bodymovin.loadAnimation(animData);
setTimeout(function () {
var svg = animData.wrapper.getElementsByTagName("svg")[0];
svg.style.position = "absolute";
svg.style.left = "0";
svg.style.top = "0";
svg.style.zIndex = -1;
svg.style.marginLeft = "65%";
}, 100);
When I run the site with this code, the header works for any text shorter than 7 characters, but if there's more, the header tries to "push" itself above the SVG document, and the SVG remains in position behind it instead of moving along with the text.
You can see an example of this on this site (you can either edit the endpoint, i.e. /channel/anythinghere or edit the tag client-side):
http://themadgamers.co.uk:3000/channel/ItsMike
Why do you set a fixed width for your h1?
h1(class="channel-header" style="margin-bottom: 36px; width: 96px; margin: auto;")
If you remove the 96px width restriction, longer strings no longer push the trophy below the user names.
As for the manual need to style the SVG via JavaScript...
setTimeout(function () {
var svg = animData.wrapper.getElementsByTagName("svg")[0];
svg.style.position = "absolute";
svg.style.left = "0";
svg.style.top = "0";
svg.style.zIndex = -1;
svg.style.marginLeft = "65%";
}, 100);
Consider adding a new class to your CSS.
.mySvg {
position: absolute;
left: 0;
top: 0;
z-index: -1;
margin-left: 65%;
}
Then you should be able to simplify the JavaScript to:
setTimeout(function () {
var svg = animData.wrapper.getElementsByTagName("svg")[0];
svg.className = "mySvg";
}, 100);
I am currently trying to make a pictionary application in HTML/CSS/PHP and after making the application I am trying to make it mobile friendly/responsive.
The way I am displaying the canvas that is being drawn on on the other players' screen is this:
javascript
let canvas = document.querySelector("canvas");
let base64dotpng = canvas.toDataURL();
ws.send("canvas:" + base64dotpng);
Which I am sending over a websocket. This works perfectly fine and when I read the data back in like this:
let ctx = document.querySelector("canvas").getContext('2d');
let canvasImage = new Image();
canvasImage.src = msg;
if (newRound) {
ctx.clearRect(0, 0, window.innerWidth * 0.525, window.innerHeight * 0.90);
}
ctx.drawImage(canvasImage, 0, 0);
However now that I'm implementing a mobile version whenever I load in a canvas on mobile the ratio of the canvas is a bit different and it does not load the full image.
css
This is my css on general vs mobile:
general:
#drawingCanvas {
display: inline-block;
background-color: white;
border-width: 0.3vh;
border-color: black;
border-style: solid;
position: absolute;
height: 90vh;
top: 5vh;
left: 20vw;
width: 52.5vw;
}
mobile:
canvas#drawingCanvas {
z-index: 1;
top: 0;
margin-left: -20%;
display: inline-block;
width: 52.5%;
height: 99%;
}
If the canvas was to be stretched on mobile that would be fine, but right now this is the difference:
how it is being drawn on a computer browser
vs
how it is getting displayed on mobile
(the phone is in landscape mode)
So the canvas appears to be loading in at full size
Thanks in advance,
Aap.
I have found an answer in the .drawImage method of context.
The 4th and 5th parameters can be used to rescale the canvas like so:
if (isMobile){
ctx.drawImage(canvasImage, 0,0,canvasImage.width*(window.innerWidth / (canvasImage.width/0.525)),canvasImage.height*(window.innerHeight/(canvasImage.height/0.9)));
} else {
ctx.drawImage(canvasImage, 0, 0);
}
I am trying to get the dimensions of images on a page for further use with a custom 'lightbox' or sorts. However, when trying both a pure js method, and a jquery method, I get the output undefined on my variables. Why is this? Is it because of jquery load event? I tried both onload and ready.
Basically I need the full dimensions of the image to justify whether it should be loaded in a lightbox with a click event or not.
Update I am now able to get console feedback from the function now, however it's not providing me a dimension of the image.
$('.postbody').find('img').each(function() {
var img = new Image(), width, height;
$(img).load(function() {
width = $(this).width();
height = $(this).height();
console.log('Width: '+width+' Height: '+height);
});
console.log($(this).attr('src'));
img.src = $(this).attr('src');
});
#theater-box {
display: none;
position: fixed;
width: auto;
height: auto;
min-width: 1005px;
max-width: 1428px;
padding: 10px;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(0,0,0,0.90);
border: 2px solid rgba(255,255,255,0.4);
}
.postbody {
width: 90%;
height: 90%;
background: rgba(100,50,50,0.5);
}
.postbody * img {
width: 100%;
max-width: 1168px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="theater-box"></div>
<div class="postbody">
<div id="someclass"><img src="https://e8zzxa.bl3301.livefilestore.com/storageservice/passport/auth.aspx?sru=https:%2f%2fe8zzxa.bl3301.livefilestore.com%2fy2pDapooeiISgUV7-ugpyADuRULJ_stpkiALbypYJHjNxrhUqcvRsZ6eRk4PiJlClABLOfByjulDSDLOMCEpHhggVkgvM4z5Gdq0Jo-C0e1pCU%2fMajipoorHighlands2.jpg&wa=wsignin1.0" /></div>
</div>
You are setting the variables asynchronously and getting it directly.
In pseudocode it is a bit like this:
Set the function to retrieve the width and height when the images loads
Display the width and height variables (not set yet)
The functions set in step 1 runs and sets the varaibles.
So your code that uses the width and height should be inside the image.load function.
I hope it helps, if you have any further questions dont hesitate to comment :-)
Perhaps you can just put the console.log line as the last line in the $(img).load function.
Try this...
$(img).load = function() {
var $this = $(this);
width = $this.width();
height = $this.height();
}
I'm not exactly sure why the original method (which works in a lot of examples) was not working here. So I found some awesome code by GregL from right here at Stackoverflow.
Essentially, the method loads a new, and hidden image into the body, and then captures the width and height before removing it.
$('.postbody').find('img').each(function() {
var img = $(this), width, height,
hiddenImg = img.clone().css('visibility', 'hidden').removeAttr('height').removeAttr('width').appendTo('body');
width = hiddenImg.height();
height = hiddenImg.width();
hiddenImg.remove();
console.log('Width: '+width+' Height: '+height);
});
Check out the Fiddle
So this is what I want to do :
I have a regular rectangle image, and I want to be displayed as a rounded image. How can I do this?
(Image credit)
I hope I got this right:
you have a rectangular non-square image, something like this
(width > height) or like this
(height > width)
and you want to display it in a circle without distorting it,
probably as much as you can display of it and the central part,
something like this:
Solutions:
When you know the size of the image it is really simple: you put it in a wrapper, give a wrapper a width and a height that are both equal to the minimum between the width and the height of the image itself. You then give the wrapper border-radius: 50%; and overflow: hidden;.
Next, you position the image such that the central part is visible.
if the width of the image is greater than its height (landscape
image), then you set its left margin to be (height-width)/2
otherwise, if the height of the image id greater than its width
(portrait image), then you set its top margin to be (width-height)/2
demo
Relevant HTML:
<a href='#' class='circle-wrap'>
<img src='image.jpg'>
</a>
Relevant CSS for landscape image (dimensions: 468px x 159px):
.circle-wrap {
overflow: hidden;
width: 159px; height: 159px; /* height of img */
border-radius: 50%;
}
.circle-wrap img {
margin: 0 0 0 -154px; /* (height-width)/2 */
}
Alternatively, you could use a JavaScript solution (I'm suggesting this because you list javascript among the tags) if you don't know anything about the orientation (portrait or landscape) of your image or about its dimensions.
demo
I've used a few images of different orientations sizes for testing. The HTML for one:
<a class='circle-wrap' href='#'>
<img src='image.jpg'>
</a>
Relevant CSS:
.circle-wrap {
overflow: hidden;
padding: 0;
border-radius: 50%;
}
.circle-wrap img { display: block; }
JavaScript:
var wrps = document.querySelectorAll('.circle-wrap'),
toCircle = function(a) {
var style, w, h, img;
for(var i = 0; i < a.length; i++) {
style = window.getComputedStyle(a[i]);
w = parseInt(style.width.split('px')[0],10);
h = parseInt(style.height.split('px')[0],10);
/* part that makes the wrapper circular */
a[i].style.width = a[i].style.height = Math.min(w,h)+'px';
/* part that takes care of centering imgs */
img = a[i].querySelector('img');
if(w > h)
img.style.marginLeft = ((h - w)/2) + 'px';
else if(w < h)
img.style.marginTop = ((w - h)/2) + 'px';
}
};
toCircle(wrps);
Try
img { border-radius:50%; }
Note that the image must have equal width and height for this to work. If the image doesn't, you can set the width and height with CSS as well.
img { border-radius:50%; width:200px; height:200px; }
Fiddle
All you need is CSS to do this:
<img class='circle' src='/my/img/path/img.jpg' />
<style type="text/css">
img.circle {
-ie-border-radius: 50%; /* IE */
-khtml-border-radius: 50%; /* KHTML */
-o-border-radius: 50%; /* Opera */
-moz-border-radius: 50%; /* Mozilla / FF */
-webkit-border-radius: 50%;/* Chrome / Safari */
border-radius: 50%; /* CSS Compliant */
}
</style>
Have a white square image with a transparent circle in the middle and overlay on the image.