I've been trying to make use of html2canvas to take a screenshot of a element
I noticed an image inside the div element that uses the object-fit property becomes stretched after the html2canvas screenshot
Is there a walk around for this. Here is my code
<script>window.addEventListener('load', function () {
var bigCanvas = $("<div>").appendTo('body');
var scaledElement = $("#Element").clone()
.css({
'transform': 'scale(1,1)',
'transform-origin': '0 0'
})
.appendTo(bigCanvas);
var oldWidth = scaledElement.width();
var oldHeight = scaledElement.height();
var newWidth = oldWidth * 1;
var newHeight = oldHeight * 1;
bigCanvas.css({
'width': newWidth,
'height': newHeight
})
html2canvas(bigCanvas, {
onrendered: function(canvasq) {
var image = document.getElementById('image');
image.style.width='300px';
image.src = canvasq.toDataURL();
bigCanvas.remove() ;
}
});}) </script>
While html goes as
<div id="Element" class="container">
<div class="bg-light p-3 text-center">
<h3>iPhone 12 Pro Max</h3>
<div class="m-2 shadow" style="height:400px;width:100%;">
<img src="img/agency.jpeg" style="object-fit:cover;height:100%;width:100%;" />
</div>
<h4>Now available for free</h4>
</div>
</div>
<div class="container" style="width:100%;border:2px solid black;overflow:hidden">
<img src="" id="image" style="max-width:100%;"/>
</div>
I had the same issue, unfortunally it seems that html2cavas doesn't support the object-fit property but i resolve with flexbox and the result it's good, it's important to set the width and height for parent node:
.logo-preview-inner {
height: 200px;
width: 200px;
border-radius: 50%;
border: solid 1px #e6e6e6;
margin: 0 auto;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
position: relative;
img {
width: 100%;
}
where the class .logo-preview-inner is the parent node and the image is the child
i hope to help you!
Related
I have an image gallery with a main image and some thumbnail images on the right side of the main image.
I want to set the height of the thumbnails div the same as the main image. The problem is, this image is always different so it doesn't have a static height. Tried to use javascript to get it's height then give it to the thumbnails div, but it doesn't do anything.
<div class="gallery">
<a href="images/1.jpg">
<div class="main-image">
<img class="card-img-top" id="modal-img-top" src="images/1.jpg" alt="Fő kép">
</div>
<div class="image-container" id="image-thumbnails">
<img src="images/1.jpg" alt="Egy kép a hirdetésről">
<img src="images/motor.jpg" alt="Egy kép a hirdetésről">
<img src="images/motor2.jpg" alt="Egy kép a hirdetésről">
<img src="images/2.jpg" alt="Egy kép a hirdetésről">
<img src="images/1.jpg" alt="Egy kép a hirdetésről">
<img src="images/motor.jpg" alt="Egy kép a hirdetésről">
<img src="images/motor2.jpg" alt="Egy kép a hirdetésről">
<img src="images/2.jpg" alt="Egy kép a hirdetésről">
</div>
</a>
</div>
<script type="text/javascript">
const img = new Image();
img.onload = function() {
alert(this.width + 'x' + this.height);
document.getElementById("image-thumbnails").style.height = this.height;
}
img.src = document.getElementById("modal-img-top").getElementsByTagName('img');
</script>
Edit: Ok let's have another try.
The main issue is to size your main image which should stay in its ratio and be wrapped in its parent. After trial and error there seems to be no easy method to archive this. I also tried object-fit property, but event this is not working as you want to. So here are my two solutions.
Solution 1:
The most easy way is to use a div with the background-image property instead of an img. As you see in the solution below, the main-image is a div now. You could also use the element .image-wrapper as the background image. But I wrapped a main-image into it to get some padding between these two elements.
Solution 2: Instead of using the background-image property you can still use a img, but you'll need some javascript and calculations. The calculation is done by the function calculateMainImage. It is not too complex, but it needs some lines. The strategy is this:
Get the dimensions of the main image and its parent element
Assume that the image fits into its parent (in css: width: 100%). So calculate the image dimensions for this assumption.
If the calculated height is greater than the height of the parent, the image won't fit into the parent. So now set the image's height to the height of its parent and recalculate the width.
This function is also called when the document is ready (initialization) and when the window resizes (window.onresize).
let mainImage = document.querySelector('.main-image');
let thumbnails = document.querySelectorAll('.thumbnail');
thumbnails.forEach(thumbnail => {
thumbnail.addEventListener('click', () => {
let backgroundImage = 'url(' + thumbnail.src +')';
mainImage.style.backgroundImage = backgroundImage;
});
});
.gallery{
position: relative;
width: 100%;
height: 400px;
background: #dedede;
display: grid;
grid-template-columns: 70% 30%;
}
.image-wrapper{
position: relative;
width: 100%;
height: 100%;
background: #aaa;
padding: 12px;
box-sizing: border-box;
}
.main-image{
position: relative;
width: 100%;
height: 100%;
background-image: url("https://via.placeholder.com/350x150");
background-size: contain;
background-repeat: no-repeat;
background-position: center;
}
.thumbnail-wrapper{
position: relative;
width: 100%;
height: 100%;
overflow-y: auto;
padding: 12px;
box-sizing: border-box;
}
.thumbnail-wrapper > .thumbnail:not(:last-child){
margin-bottom: 12px;
}
.thumbnail{
position: relative;
display: block;
width: 100%;
height: auto;
margin-left: auto;
margin-right: auto;
cursor: pointer;
}
<section class="gallery">
<!-- Main image -->
<div class="image-wrapper">
<div class="main-image">
</div>
</div>
<!-- Thumbnails -->
<div class="thumbnail-wrapper">
<img class="thumbnail" src="https://via.placeholder.com/350x150">
<img class="thumbnail" src="https://via.placeholder.com/200x100">
<img class="thumbnail" src="https://via.placeholder.com/140x100">
<img class="thumbnail" src="https://via.placeholder.com/350x65">
<img class="thumbnail" src="https://via.placeholder.com/350x150">
<img class="thumbnail" src="https://via.placeholder.com/200x100">
<img class="thumbnail" src="https://via.placeholder.com/140x100">
</div>
</section>
let gallery = document.querySelector('.gallery');
let container = document.querySelector('.container');
let mainImage = document.querySelector('.main-image');
let thumbnails = document.querySelectorAll('.thumbnail');
(function(){
// Document ready
calculateMainImage();
// When window resizes
window.addEventListener('resize', () => {
calculateMainImage();
});
})();
thumbnails.forEach(thumbnail => {
thumbnail.addEventListener('click', () => {
mainImage.src = thumbnail.src;
// Fit image to container
calculateMainImage();
});
});
function calculateMainImage(){
// Reset current dimensions
mainImage.style.width = 'initial';
mainImage.style.height = 'initial';
// Container dimensions
let containerWidth = container.getBoundingClientRect().width;
let containerHeight = container.getBoundingClientRect().height;
// Image dimensions
let width = mainImage.getBoundingClientRect().width;
let height = mainImage.getBoundingClientRect().height;
let ratio = width / height;
// Calculate image dimensions when width: 100%
let maxWidth = containerWidth;
let maxHeight = maxWidth / ratio;
// Check if image fits in parent
if(maxHeight > containerHeight){
// Scale image down. Recalculate image's width
let newHeight = containerHeight;
let newWidth = newHeight * ratio;
setMainImageSize(newWidth, newHeight);
}else{
setMainImageSize(maxWidth, maxHeight);
}
}
function setMainImageSize(width, height){
mainImage.style.width = width + 'px';
mainImage.style.height = height + 'px';
}
.gallery{
position: relative;
width: 100%;
height: 400px;
background: #dedede;
display: grid;
grid-template-columns: 70% 30%;
}
.image-wrapper{
position: relative;
width: 100%;
height: 100%;
background: #aaa;
padding: 12px;
box-sizing: border-box;
}
.container{
position: relative;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.main-image{
position: relative;
flex-grow: 0;
flex-shrink: 0;
}
.thumbnail-wrapper{
position: relative;
width: 100%;
height: 100%;
overflow-y: auto;
padding: 12px;
box-sizing: border-box;
}
.thumbnail-wrapper > .thumbnail:not(:last-child){
margin-bottom: 12px;
}
.thumbnail{
position: relative;
display: block;
width: 100%;
height: auto;
margin-left: auto;
margin-right: auto;
cursor: pointer;
}
<section class="gallery">
<!-- Main image -->
<div class="image-wrapper">
<div class="container">
<img class="main-image" src="https://via.placeholder.com/200x100">
</div>
</div>
<!-- Thumbnails -->
<div class="thumbnail-wrapper">
<img class="thumbnail" src="https://via.placeholder.com/350x150">
<img class="thumbnail" src="https://via.placeholder.com/200x100">
<img class="thumbnail" src="https://via.placeholder.com/140x100">
<img class="thumbnail" src="https://via.placeholder.com/350x65">
<img class="thumbnail" src="https://via.placeholder.com/350x150">
</div>
</section>
Update
When you have several gallerys on your page and use use solution #1, then you need to add this JS snipped.
let gallerys = document.querySelectorAll('.gallery');
gallerys.forEach(gallery => {
updateGalleryPictures(gallery)
});
function updateGalleryPictures(gallery) {
// Get gallery's main image
let mainImage = gallery.querySelector('.main-image');
if (mainImage === null) return;
// Get gallery's thumbnail images
let thumbnails = gallery.querySelectorAll('.thumbnail');
// Change the background-image property on click
thumbnails.forEach(thumbnail => {
thumbnail.addEventListener('click', () => {
let backgroundImage = 'url(' + thumbnail.src + ')';
mainImage.style.backgroundImage = backgroundImage;
});
});
// Initialize background-image property using the 1st thumbnail image
let firstThumbnail = thumbnails[0];
if (firstThumbnail === null || firstThumbnail === undefined) return;
let initialBackgroundImage = 'url(' + firstThumbnail.src + ')';
mainImage.style.backgroundImage = initialBackgroundImage;
}
Update 2: Usage of baguetteBox
Step 1: Add the property overflow: hidden; to the class .image-wrapper and create a new class
.baguettebox-image{
opacity: 0 !important;
}
Step 2: Change the structure of the main-image setup.
<div class="image-wrapper">
<div class="main-image"> <!-- THis is the baguette box -->
<a class="baguettebox-link" href="">
<img class="baguettebox-image" src=""></a>
</a>
</div>
</div>
Step 3: Change the JS snipped of the 1st update to:
Note that the baguette boxes are also initialized in this script. According to the documentation querySelectorAll is used, so all boxes (.main-image) should be initialized.
let gallerys = document.querySelectorAll('.gallery');
gallerys.forEach(gallery => {
updateGalleryPictures(gallery);
});
// Initialize all baguette boxes
baguetteBox.run('.main-image');
function updateGalleryPictures(gallery) {
// Get gallery's thumbnail images
let thumbnails = gallery.querySelectorAll('.thumbnail');
// Change the background-image property on click
thumbnails.forEach(thumbnail => {
thumbnail.addEventListener('click', () => {
updateMainImage(gallery, thumbnail.src)
});
});
// Initialize background-image property using the 1st thumbnail image
let firstThumbnail = thumbnails[0];
if (firstThumbnail === null || firstThumbnail === undefined) return;
updateMainImage(gallery, firstThumbnail.src)
// Initialize baguette
}
function updateMainImage(gallery, src) {
// Get main image and check if it exists
let mainImage = gallery.querySelector('.main-image');
if (mainImage === null) return;
mainImage.style.backgroundImage = 'url(' + src + ')';
// Get baguette elements
let boxLink = gallery.querySelector('.baguettebox-link');
let boxImage = gallery.querySelector('.baguettebox-image');
// Update baguette elements href and src
if (boxLink !== null && boxLink !== undefined) boxLink.href = src;
if (boxImage !== null && boxImage !== undefined) boxImage.src = src;
}
document.getElementById("image-thumbnails").style.height = '300px';
I am using CSS Flex in order to display three DIVs consequential in a wrapper.
The width dimension for the first DIV (item0) is to 50px.
I need to change the height of the wrapper and keep the original width for item0 and item1 DIVs inside the wrapper.
My current problem is that:
When re-sizing the wrapper, item for flex (item0) get a different width. size
Please click the two buttons in the example to see the change in dimension.
I would like to know:
Why the width size change?
How to maintain the width size for item0 and item2same as my original CSS settings?
Notes:
I understand scroll-bar appears taking space. How I could I keep item0 and item2 at a fix width and item1 stretching to fill up the remaining space? (I have tried to use % but I cannot get the result wanted).
var btn0 = document.getElementById('btn0');
var btn1 = document.getElementById('btn1');
var item0 = document.getElementById('item0');
var result = document.getElementById('result');
var wrapper = document.getElementById('wrapper');
btn0.addEventListener('click', function(event) {
wrapper.style.height = '25px';
result.value = item0.getBoundingClientRect().width;
});
btn1.addEventListener('click', function(event) {
wrapper.style.height = '350px';
result.value = item0.getBoundingClientRect().width;
});
#wrapper {
width: 250px;
height: 350px;
background-color: gray;
overflow: auto;
}
#flex-container {
display: flex;
}
#item0 {
width: 50px;
background-color: red;
height: 150px;
}
#item1 {
width: 150px;
background-color: orange;
height: 150px;
}
#item2 {
width: 50px;
background-color: pink;
height: 150px;
}
<div id="wrapper">
<div id="flex-container">
<div id="item0" class="item">a
</div>
<div id="item1" class="item">b
</div>
<div id="item2" class="item">c
</div>
</div>
</div>
<button id='btn0' type="button">Smaller wrapper</button>
<button id='btn1' type="button">Bigger wrapper</button>
item0 width is: <input id="result"type="text">
Use flex: 0 0 50px for the item0 style.
See jsfiddle
It tells the flexbox layout don't grow and don't shrink and give it a width of 50px.
It is always good to use the flex: property for flexbox items because the default value for it may be different from browser to browser.
(Actually your problem doesn't happen in firefox for example)
When the width of the container is reduced, all child elements are reduced proportionally too.
Add flex: 0 0 auto; to item0 and item2. It disallows element to shrink to its minimum when there is not enough space.
var btn0 = document.getElementById('btn0');
var btn1 = document.getElementById('btn1');
var item0 = document.getElementById('item0');
var result = document.getElementById('result');
var wrapper = document.getElementById('wrapper');
btn0.addEventListener('click', function(event) {
wrapper.style.height = '25px';
result.value = item0.getBoundingClientRect().width;
});
btn1.addEventListener('click', function(event) {
wrapper.style.height = '350px';
result.value = item0.getBoundingClientRect().width;
});
#wrapper {
width: 250px;
height: 350px;
background-color: gray;
overflow: auto;
}
#flex-container {
display: flex;
}
#item0 {
flex: 0 0 auto;
width: 50px;
background-color: red;
height: 150px;
}
#item1 {
width: 150px;
background-color: orange;
height: 150px;
}
#item2 {
flex: 0 0 auto;
width: 50px;
background-color: pink;
height: 150px;
}
<div id="wrapper">
<div id="flex-container">
<div id="item0" class="item">a
</div>
<div id="item1" class="item">b
</div>
<div id="item2" class="item">c
</div>
</div>
</div>
<button id='btn0' type="button">Smaller wrapper</button>
<button id='btn1' type="button">Bigger wrapper</button>
item0 width is: <input id="result"type="text">
according to this question
i want div to be float up not just fix dynamic height!
jquery masonry use float left and right but i want it look like newspaper columns!
any idea?
its my html:
`<div class="paper">
<div class="ticket" style="height: 116px;background-color: rgb(121,89,118);">1</div>
<div class="ticket" style="height: 75px;background-color: rgb(121,89,118);">2</div>
....
</div>`
and js is:
var $grid = $('.paper').masonry({
// options
itemSelector: '.ticket',
columnWidth: '.ticket',
percentPosition: true,
isOriginLeft: false
});
$grid.imagesLoaded().progress( function() {
$grid.masonry('layout');
});
and it's final result:
You could work with display: flex; note that older browsers do not support this completly
<div class="box">
<div class="stuff" style="background-color: cyan; height: 100px;">1</div>
<div class="stuff" style="background-color: red; height: 200px;">2</div>
<div class="stuff" style="background-color: lime; height: 150px;">3</div>
<div class="stuff" style="background-color: orange; height: 50px;">4</div>
<div class="stuff" style="background-color: yellow; height: 300px;">5</div>
<div class="stuff" style="background-color: pink; height: 200px;">6</div>
</div>
.box{
display: flex;
flex-flow: column wrap;
width: 220px;
height: 600px;
}
.stuff{
width: 100px;
margin: 4px;
}
Fiddle
You could calculate the heights using jQuery, and then set the appropriate margins: https://jsfiddle.net/6u8jypmr/1/
It works for a dynamic width and height.
var heightdiv1 = $("#div1").css("height");
var heightdiv2 = $("#div2").css("height");
var margindiv2 = parseInt(heightdiv1) + parseInt(8);
var margindiv3 = parseInt(margindiv2) + parseInt(heightdiv2) + parseInt(8);
var heightdiv4 = $("#div4").css("height");
var heightdiv5 = $("#div5").css("height");
var margindiv5 = parseInt(heightdiv4) + parseInt(8);
var margindiv6 = parseInt(margindiv5) + parseInt(heightdiv5) + parseInt(8);
var widthdiv = $("#div1").css("width");
var marginleftdiv = parseInt(widthdiv) + parseInt(8);
$("#div2").css("margin-top", margindiv2);
$("#div3").css("margin-top", margindiv3);
$("#div5").css("margin-top", margindiv5);
$("#div6").css("margin-top", margindiv6);
$("#div4").css("margin-left", marginleftdiv);
$("#div5").css("margin-left", marginleftdiv);
$("#div6").css("margin-left", marginleftdiv);
I want to automatically scroll a div based on mouse position using jQuery.
If you see this fiddle here, you can see a number of images that are horizontally ordered in a div that is scrollable:
<div id="parent">
<div id="propertyThumbnails">
<img src="http://www.millport.org/wp-content/uploads/2013/05/Flower-festival.jpg" />
<img src="http://www.millport.org/wp-content/uploads/2013/05/Flower-festival.jpg" />
<img src="http://www.millport.org/wp-content/uploads/2013/05/Flower-festival.jpg" />
<img src="http://www.millport.org/wp-content/uploads/2013/05/Flower-festival.jpg" />
<img src="http://www.millport.org/wp-content/uploads/2013/05/Flower-festival.jpg" />
</div>
</div>
CSS:
#parent {
height: 300px;
width: 100%;
background: #ddd;
}
#propertyThumbnails {
background: #666;
height: 80px;
white-space: nowrap;
overflow: scroll;
}
#propertyThumbnails img {
width: 125px;
height: 80px;
display: inline-block;
margin: 3px;
margin-right: 0;
opacity: 0.6;
}
I found out that you can use $("#container").scrollLeft(position) to set the position of the scroller but I want to do it based on the mouse position of the parent. So that when the mouse is fully to the right hand side, the right most image displays, and when the mouse is fully left, the left most image displays.
How can I do this?
A slightly different way to achieve what you need:
jQuery(function($) {
$(window).load(function() {
var $gal = $("#propertyThumbnails"),
galW = $gal.outerWidth(true),
galSW = $gal[0].scrollWidth,
wDiff = (galSW / galW) - 1, // widths difference ratio
mPadd = 60, // Mousemove Padding
damp = 20, // Mousemove response softness
mX = 0, // Real mouse position
mX2 = 0, // Modified mouse position
posX = 0,
mmAA = galW - (mPadd * 2), // The mousemove available area
mmAAr = (galW / mmAA); // get available mousemove fidderence ratio
$gal.mousemove(function(e) {
mX = e.pageX - $(this).offset().left;
mX2 = Math.min(Math.max(0, mX - mPadd), mmAA) * mmAAr;
});
setInterval(function() {
posX += (mX2 - posX) / damp; // zeno's paradox equation "catching delay"
$gal.scrollLeft(posX * wDiff);
}, 10);
});
});
#parent {
position: relative;
margin: 0 auto;
width: 60%;
height: 260px;
}
#propertyThumbnails {
position: relative;
overflow: hidden;
background: #444;
width: 100%;
height: 262px;
white-space: nowrap;
}
#propertyThumbnails img {
vertical-align: middle;
height: 100%;
display: inline;
margin-left: -4px;
}
<div id="parent">
<div id="propertyThumbnails">
<img src="//placehold.it/600x400/0bf" />
<img src="//placehold.it/600x400/f0b" />
<img src="//placehold.it/600x400/0fb" />
<img src="//placehold.it/600x400/b0f" />
<img src="//placehold.it/600x400/bf0" />
</div>
</div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
where mPadd is the area (in PX, at the left and right border zone) without any sensitivity to prevent user frustrations :)
this should at least get you headed in the right direction.
var parent = $('#parent');
var img = $('img:first-child');
parent.on('mousemove', function(e) {
mouseX = e.pageX
img.css('margin-left',-mouseX/parent.width()*100);
});
http://jsfiddle.net/xWcXt/4/
I'm making something similar to an iphone layout (a bunch of tiles with pictures/numbers that you can click on to get more information). After the layout has been set, I'd like a click-event to expand one of the tiles to be full screen. Right now, it moves the tiles so that the layout is re-adjusted. Is it possible to get masonry to stop rendering so that one tile get's enlarged over the other tiles?
The following is what I've tried (but unsuccessfully). Note: It uses d3.js to generate the div's for masonry to use.
function drawGrid(divname,orders)
{
var mydiv = d3.select(divname);
$(divname).masonry({
itemSelector: '.g1',
isAnimated: true,
//isResizable: true
});
var myd = mydiv.selectAll("div");
var mygs = myd.data(orders,function(d){ return d.orderid;})
.enter().append("div")
.attr("class","g1")
.append("g");
var x1 = mygs.append("div")
.attr("class","tickerdiv")
.text(function(d){ return d.ticker; });
var ActiveOrder = "1";
$(divname+' .g1').click(function() {
//$(this).show('maximised');
console.log("clicked")
$(this).animate({"display":"none","position": "absolute",
"top": "0",
"left": "0",
"width": "100%",
"height": "100%",
"z-index": 1000 }, 1000);
});
var x = [];
x.redraw = function(o)
{
x1.text(function(d){ return d.ticker; });
}
return x;
}
and from the css file:
.g1 { min-height:80px; width: 100px; margin: 15px; float: left; background-color: RGB(223,224,224); border-radius: 10px; vertical-align: middle; text-align: center; padding-top: 20px;}
EDIT Ok, my first answer was not useful here - absolute positioning won't work in case of masonry's/Isotope's relatively positioned container with absolute positioned elemens contained therein; the solution is rather to take the content of a masonry/Isotope element out of the DOM on click and append it temporarily to the body. You can see the basic idea in my dirty swedish sandbox
<!-- masonry/Isotope item large -->
<div class="item large">
<div class="header">
<p>Click here</p>
</div>
<div class="minimised">
<p>Preview</p>
</div>
<div class="maximised">
<p>Content</p>
<button id="screen-overlay-on">Screen overlay on</button>
<div id="screen-overlay-background"></div>
<div id="screen-overlay-content">
<p>Content</p>
<button id="screen-overlay-off">Screen overlay off</button>
</div>
</div>
</div>
<script type="text/javascript">
$(document).ready(function(){
$('#screen-overlay-on').click(function(){
var sob = $('#screen-overlay-background').detach();
var soc = $('#screen-overlay-content').detach();
sob.appendTo('body');
soc.appendTo('body');
$('#screen-overlay-background').toggleClass("active");
$('#screen-overlay-content').toggleClass("active");
});
$('#screen-overlay-background, #screen-overlay-off').click(function(){
$('#screen-overlay-background').toggleClass("active");
$('#screen-overlay-content').toggleClass("active");
});
});
</script>
With CSS like
#screen-overlay-background {
display: none;
position: fixed;
top: 0;
left: 0;
height: 100%;
width: 100%;
background-color: #333;
zoom: 1;
filter: alpha(opacity=50);
opacity: 0.5;
z-index: 1000;
}
#screen-overlay-content {
display: none;
position: absolute;
top: 50%;
left: 50%;
height: 240px;
width: 320px;
margin: -120px 0 0 -160px;
background-color: #FFF;
z-index: 1000;
}
#screen-overlay-background.active, #screen-overlay-content.active {
display: block;
}
You can add a :hover to the element in css and change the z-index. You could easily change this on click with a class as well...
.item {
z-index:1
}
.item:hover{
z-index:2500;
}