CSS + jQuery: scale, center and rotate images inside container - javascript

If you take a look at https://jsfiddle.net/0spv56uk/1/
I am creating something on a website that has a container.
This container cannot get any wider (it may be able to get lightly taller - to fir the size of the screen)
Inside this container I will be setting images. They all vary in size.
These Images/SVGs have ability to rotate on click of a button (As shown in code).
I'm using 90 degrees at the moment but may need it at 45 degrees later.
The issue I have is that the image overflows the container when rotated.
I need it to scale inside the container when rotated. (The bottom of the container should be expandable but not the top).
I've looked over other threads here, and they either hard-code the scale(which only works if you have single image) or the code does not really apply to me so well.
Thank you all in advance.
This has been giving me nightmares for some time.
Here is my code
var myArray = ['0deg', '90deg', '45deg','180deg','270deg']; var myIndex = 1;
function nextRotation() { return 'rotate('+myArray[myIndex++%myArray.length];+')' };
$('#btn1').click(function(){
$('#testImg').css('transform', nextRotation() );
$('#testImg').css('-webkit-transform', nextRotation() );
$('#testImg').css('-moz-transform', nextRotation() );
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button onclick=document.getElementById('testImg').src='https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/smile.svg'>Img1</button>
<button onclick=document.getElementById('testImg').src='https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/juanmontoya_lingerie.svg'>Img2</button>
<button onclick=document.getElementById('testImg').src='https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/php.svg'>Img3</button>
<button type="button" id="btn1" >Rotate Div</button>
<DIV id="container" style=" wid th:60%;border-style:dotted;">
<DIV id="outer" width="100%">
<img id ="testImg" src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/smile.svg" style="width:100%;height:100%;">
</DIV>
</DIV>

You might be able to get it working by matching the height of the image to the width of the container. I also made container's position relative.
Note that you're also working with transparency in the image, so that is making it look like it's leaving a bunch of empty space.
I just added :
$('#testImg').css('height', $('#container').width() );
This looks to be working, but may stretch the image

Related

Determine scrolled distance on the webpage for Paper.js synchronized scrolling of the view

I have an absolutely positioned canvas laid over a webpage. The canvas has some items created using Paper.js. I want the canvas (or the view) to move in sync with the scrolling of the webpage.
The canvas covers the entire screen (1920 x 1080) not the webpage (1920 x variable length). So, just shifting the canvas's fixed position does not work. It is no longer overlaid on the entire screen.
Later, I found about views in Paper.js and I can use the following line to scroll the view:
project.view.scrollBy(new Point(0, 450));
The problem is that I cannot figure out the value I need to put in place for 450 so that the scrolling is always synchronized.
I do use the following JavaScript to animate the scrolling action on the webpage whenver up and down keys are pressed:
$("section.scrollable").animate({scrollTop : $("section.scrollable").scrollTop() + 300 })
However, putting 300 in the scrollBy values doesn't move the canvas and the webpage in proper synchronization either.
This pen is a very minimal example to show my problem. You might prefer to see it in debug mode.
You can drag over the canvas to create orange lines.
There are three heading and three corresponding lines drawn on an overlaid canvas. The canvas is 1920px wide and 1080px high.
The third heading falls below 1080px so its line is not visible on the canvas. However, it becomes visible when I scroll inside the Paper view by using the following line:
project.view.scrollBy(new Point(0, 600));
Here is my problem with following constraints:
The canvas position has to stay fixed. So, it won't scroll with the rest of the document.
However, the view for Paper.js has to shift in sync with the document so that the lines, paths and other items don't change their relative positions with respect to the webpage. For example, the lines still stay under the same headings.
You need to listen to scroll event and every time it happens, update your paper.js scene y position.
Rather than using the view, I found that using the active layer was more convenient but you could theoretically do the same with the view.
Here's a simple fiddle that should get you on the track.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Debug Paper.js</title>
<script src="https://unpkg.com/acorn"></script>
<script src="https://unpkg.com/paper"></script>
<style>
html,
body {
margin : 0;
height : 100%;
}
canvas {
position : fixed;
top : 0;
left : 0;
width : 100vw;
height : 100vh;
}
section {
max-width : 500px;
margin : auto;
}
</style>
</head>
<body>
<section>
<div>
<h1>title 1</h1>
<p>...</p>
</div>
<div>
<h1>title 2</h1>
<p>...</p>
</div>
</section>
<canvas id="canvas" resize></canvas>
<script>
paper.setup('canvas');
new paper.Path.Circle({
center: paper.view.center,
radius: 50,
fillColor: 'orange'
});
const originalY = paper.view.center.y;
const update = () => {
const yOffset = document.scrollingElement.scrollTop;
paper.view.center.y = originalY - yOffset;
};
window.addEventListener('scroll', update);
</script>
</body>
</html>

change slides div width to image width

<div data-u="slides" style="cursor:default;position:relative;top:0px;left:0px;width:980px;height:380px;overflow:hidden; ">
<div data-p="170.00" >
<img data-u="image" src="../../../Admin/Products and Services/images/<?php echo $img1 ;?>" />
</div>
<div>
In this Jssor slider how can I change sliders div max width to image width. Link to the jssor slider is given belowJssor Slider. Thank You!
Assuming you might have more sliders on the page and more images in each slider, this is the way to go:
document.querySelectorAll("[data-u=slides]").forEach(slider=>{
var maxWidth=0;
slider.querySelectorAll("img")
.forEach( image => {
maxWidth=Math.max(maxWidth,image.width)
});
slider.style.maxWidth=maxWidth+"px";
})
Here is a quick demo how you can do it:
var imageFrame = document.querySelector("div[data-u='slides']");
var imagediv= imageFrame.querySelector("div[data-p='170.00'] > img");
console.log("before: " + imageFrame.offsetWidth, imagediv.offsetWidth);
imageFrame.style.width = imagediv.offsetWidth+"px";
console.log("after: " + imageFrame.offsetWidth, imagediv.offsetWidth);
I assumed you wanna stretch the outer div holding the inner div to the size of the inner image of inner div. I also assumed no libs, vanilla only. I also assumed you want it compatible with older browsers so no fancy stuff like arrows.
If you got multiple photos you are gonna need to add their sizes up with possible margins, borders and paddings in between. That one would require me to see your entire HTML with CSS that styles it so I know what I need to take into account.
Here is a demo with photo off the internet:
fiddlejs
Ofc, remove the console logs, they are there in for demo only.

How to create randomly laid out grid with divs of random sizes

I'm trying to create a site layout similar to this -
http://www.mondieu.nu/mishmash/fashion/
How can I get the divs in the "grid" to be of different sizes and to appear in a layout similar to that? So far I have this bit of jQuery:
$('.post-image img').each(function(){
$(this).css('width', (50+(Math.random()*700)))
})
Any help will be appreciated.
There is a little bit of built in order to the site you reference. The first two images look more fixed, both aligned to the top and taking up about half the page (centered). After that it looks like the images are in divs which are floated left and maybe have a random margin to offset them from where they should be. The images within the div then have a random width as you have attempted above.
So if I were you I would start with placing some images (say 10) in a container div and floating them left. I would then play around with adding random offsets to them (random margins or random top/bottom in px's (with position relative or absolute)). You can then try randomly changing the image size.
Finally, once you've got this working you can look at something more ordered at the top to make it look like it's shifting from ordered to random as you scroll down, rather than just starting off random.
One other thing to keep in mind is how this scales on smaller vs larger devices. Float left will just wrap images under each other as you scale down which is cool, if your images can be a % of the page width you could also scale those down to work on smaller pages.
Try this:
$('.post-image img').each(function(){
$(this).css('width', (50+(Math.random()*700)) + 'px');
});
Within .each()
the keyword this refers to the element
you could use this.width = 50 + (Math.random() * 700) to set <img> element width attribute
$(function() {
$(".post-image img").each(function() {
this.width = 50 + (Math.random() * 700)
})
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
<div class="post-image">
<img src="http://lorempixel.com/100/100?=1" />
<img src="http://lorempixel.com/100/100?=2" />
<img src="http://lorempixel.com/100/100?=3" />
</div>

Lazy loading with "responsive" images (unknown height)

I'm using a CSS grid system which is based upon percentages. I have a grid with 4 columns, each 25% of the page's total width. I output my image tags inside of each "25% cell" like this:
<img src="foo.jpg" style="max-width:100%" />
As the browser resizes, the images also resize to fill in 100% of each 25% cell. The browser picks a height, as if I had put "height:auto" (which is implicit when omitted).
Now I want to add lazy loading capability to this. The problem is that before the images are loaded, their height on the page is unknown. The browser has to download the image & observe its aspect ratio, and calculate a height for it. Prior to this, all the images have a height of 1px. Since every image has a height of 1px, they are all considered as "within the viewport" and are immediately loaded.
Currently I have a proof of concept where prior to outputting the img tag, I calculate the images aspect ratio on the server, and output in a data attribute:
<img src="foo.jpg" style="max-width:100%" data-aspect="1.7742" />
Then, upon the event "document ready", I loop through every image and set a fixed 'height' value in pixels prior to lazy loading:
$('img').each(function() {
var img = $(this);
var width = img.width();
var ratio = img.data('aspectratio');
var height = width / ratio;
$(this).css('height', height+'px');
});
This seems to be working, in the sense that it no longer loads all the images at the same time, but only loads images as I scroll.
However, it seems like it could cause new problems, like the images becoming stretched as the user resizes the browser. I would have to switch the 'height' back to 'auto' when a callback fires for lazy loading having completed. That would take care of images the user sees - but the images below the fold would still have an improper 'height' value upon the browser being resized. Every time the browser is resized, I would have to iterate all images that were previously below the fold, measure their updated width, read their aspect ratio, and update the new height, and then retrigger lazy loading to handle anything that is now above the fold. If I don't do this, loading could be triggered too early or too late due to those images having the wrong height value.
My question is, is there any other ways to lazy load images with unknown heights, other than the exact method I've described here, and what ramifications would this have? Is there any downside to my method, other than it being a pain to program?
I had a similar problem recently, combining Isotope with Lazy Load in a responsive layout. Isotope determines the layout based upon the width and height of the images when the page is loaded, so initially, the items were all overlapping because Isotope wasn't calculating the correct size.
To make sure the placeholder items were saving the space, I used the padding-bottom trick you mentioned: http://thisisthat.co.uk/notebook/2013-10-07-lazy-loading-responsive-images (Though it may have not been that exact post.) Here's my markup:
<article class="portfolio-item">
<a class="portfolio-link" href="img/gallery/thumb90.jpg" style="padding-bottom: 66.2%">
<div class="portfolio-image-wrapper">
<img class="portfolio-image" data-original="img/gallery/thumb90.jpg" width="1000" height="662">
</div>
<div class="portfolio-text">
<h1 class="portfolio-item-name">
<span href="#" class="icon" data-icon="e"></span>
<span class="portfolio-item-tags">Bridals</span>
</h1>
</div>
</a>
</article>
That's probably more involved than you need (as the entire .portfolio-text div is an overlay which has quite a bit of styling going on). The real key was just in calculating the bottom padding based upon the width and height of the image (which I did in the template with PHP) and setting that as the padding-bottom of the item that I wanted to save the space.
Here's the more elegant solution, from the comments. It still requires writing the aspect ratio server side, but with a wrapper div:
<div class="lazy"><img src="foo.jpg" style="max-width:100%" data-aspect="0.75" /></div>
Then with JS I give the wrapper div a padding-bottom:
$('div.lazy').livequery(function() {
var c = $(this);
var r = c.data('ar');
c.css('padding-bottom', r * 100 + '%');
});
This gives the div the exact dimensions that the img will eventually consume. I then use the following LESS to load the image within the area the padding consumes:
div.lazy {
max-width:100%;
position:relative;
img {
position:absolute;
width:100%;
height:100%;
}
}
Even cleaner:
Set height and width of images to an arbitrarily-large number (like 2000px x 1000px)
Apply the following CSS to each of the desired images (perhaps via a shared class):
max-width: 100% and height: auto
Smile wide :)
Credit for this approach goes to Github user dryabove, given in this Github issue
if you have images with height and width props (WordPress's default) with loaded 1x1px gif in src - by default in some plugins (looking at you - wp-smush) then just plug this little beast on docready event in your script and it will auto-fix nasty vertical jumping of image when lazy loading ,, I know this is old post, but this is I believe modern js solution:
$('.lazyload').each(function(i,j){
var h = $(j).attr( 'height' );
var w = $(j).attr( 'width' );
var at = `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 ${w} ${h}'%3E%3C/svg%3E`;
$(j).attr('src', at);
});

Rotating Div using javascript

Here is a link: http://www.avineon.com/
Open this link see on the top. Four images are rotating.
I need something similiar using Javascript.
Is it possible by using Javascript.
I don't think you'll have much luck if you try to do that in pure javascript. It might be possible using the emerging canvas and SVG libraries such as Raphael, but you'll still have cross-browser issues. That site used Flash, and I'd recommend using that if you wanted such an effect.
...why you'd want that on your website is another story though...
You could so something similar, but not exact.
Transparency = Supported in FF, Safari, IE7+
Changing image width = Place image in div with this Css
.class img {
display: block;
width: 100%;
height: 100%
}
This will make the image stretch to fill the .class div. You can then use JS to make this div narrower like the carousel does, and the image contained will animate within the div.
You would then need to track the mouse locations to determine how fast it spins.
You can use an equation using cosine for smooth acceleration from the far ends (IIRC)
You will not however be able to get the images in reverse, unless you create a copy in a server side language or use canvas.
Your best bet would not be to attempt to render something in actual 3D, but rather to use visual tricks to approximate a 3D effect. That is, use perspective / image deformation to make it look like a cube is rotating, similar to what is implemented at this page, which has a better explanation of the math involved.
Really, though, you're probably better off just using Flash.
That effect is possible in JavaScript simply by modifying each of the images width, height, and left styles over time. It's an involved script, but only needs to interpolate those three styles on the each of the image elements.
To get the rotation effect, decrement the width style of the image in a setInterval function while moving the left style property. There is a slight decrement on the height also.
You'll need two images for each side, a front and reverse. When the width decrements to zero, swap the image with it's flipped version and start incrementing the width.
Alternatively use Webkit's, and Firefox's transform css properties.
Or try one of these coverflow components that look similar:
Protoflow,
ImageFlow
<html>
<head>
<title></title>
</head>
<body>
<script type="text/javascript">
if (document.all || document.getElementById){ //if IE4 or NS6+
document.write('<style type="text/css">\n');
document.write('.dyncontent{display: none; width: 728px; height: 90px;}\n');
document.write('</style>');
}
var curcontentindex=0;
var messages=new Array();
function getElementByClass(classname){
var inc=0;
var alltags=document.all? document.all : document.getElementsByTagName("*");
for (i=0; i<alltags.length; i++){
if (alltags[i].className==classname)
messages[inc++]=alltags[i];
}
}
function rotatecontent(){
//get current message index (to show it):
curcontentindex=(curcontentindex<messages.length-1)? curcontentindex+1 : 0;
//get previous message index (to hide it):
prevcontentindex=(curcontentindex==0)? messages.length-1 : curcontentindex-1;
messages[prevcontentindex].style.display="none"; //hide previous message
messages[curcontentindex].style.display="block"; //show current message
}
window.onload=function(){
if (document.all || document.getElementById){
getElementByClass("dyncontent");
setInterval("rotatecontent()", 5000);
}
}
</script>
<table width="100%">
<tr align="center">
<td>
<div class="dyncontent" style="display: block">
first
</div>
<div class="dyncontent">
second
</div>
<div class="dyncontent">
Third
</div>
</td>
</tr>
</table>
</body>
</html>

Categories