Calculate css translate property value on scale dynamically - javascript

I am trying to scale(X) the child div element to fit the parent div on window resize. I calculated the scale ratio by dividing the parent width and child width, and it works perfectly.
But alignment is not proper. Initially i set my child div margin-left 50 px from the parent div. Its not maintained on the scale.
This is the HTML/css code
#wrap {
margin-left:50px;
width:300px;
height:300px
}
#parentDiv {
width:500px
height:300px;
}
<body>
<div id="parentDiv">
<div id="wrap">
<img id="image" width="300px" src="http://placekitten.com/640/480" />
</div>
</div>
</body>
And this is the js code to scale on resize
window.onresize = function() {
scaleDiv();
};
scaleDiv = function() {
parentWidth = $('#parentDiv').width();
scale = (parentWidth) / $('#wrap').width();
new_width = $('#wrap').width() * scale;
$('#wrap').css('-webkit-transform', ' scaleX(' + scale + ')');
}
After some googling, i came to know that i can use translateX property to keep the alignment as original. But i am struck at how to calculate the translate value.
$('#wrap').css('-webkit-transform', 'translateX(20%)' + ' scaleX(' + scale + ')');
i put random value 20% on translate prop, its not proper. Can someone help me how to caclulate this value propery.
This is the jsfiddle test link

You need to specify the transform origin; by default this is set to 50% and 0%, but you can override it with the transform-origin property like so:
#wrap {
-webkit-transform-origin:0 0;
-moz-transform-origin:0 0;
-ms-transform-origin:0 0;
transform-origin:0 0;
}

Related

Finding where element meets top of scrollable div

I have a scrollable div container fits multiple "pages" (or div's) inside of it's container.
My goal is to, at any given moment, figure out where inside my red container does it reach the top of my scrollable container. So it can be a constant on scroll event, or a button that triggers this task.
So for example. If I have a absolute div element inside one of my red boxes at top:50px. And if I scroll to where that div element reaches the top of my scrollable container. The trigger should say that I am at 50px of my red container.
I'm having a hard time grasping how to accomplish this but I've tried things like:
$("#pageContent").scroll(function(e) {
console.log($(this).scrollTop());
});
But it doesn't take into account the separate pages and I don't believe it it completely accurate depending on the scale. Any guidance or help would be greatly appreciated.
Here is my code and a jsfiddle to better support my question.
Note: If necessary, I use scrollspy in my project so I could target which red container needs to be checked.
HTML
<div id="pageContent" class="slide" style="background-color: rgb(241, 242, 247); height: 465px;">
<div id="formBox" style="height: 9248.627450980393px;">
<div class="trimSpace" style="width: 1408px; height: 9248.627450980393px;">
<div id="formScale" style="width: 816px; -webkit-transform: scale(1.7254901960784315); display: block;">
<form action="#" id="XaoQjmc0L51z_form" autocomplete="off">
<div class="formContainer" style="width:816px;height:1056px" id="xzOwqphM4GGR_1">
<div class="formContent">
<div class="formBackground">
<div style="position:absolute;top:50px;left:100px;width:450px;height:25px;background-color:#fff;color:#000;">When this reaches the top, the "trigger" should say 50px"</div>
</div>
</div>
</div>
<div class="formContainer" style="width:816px;height:1056px" id="xzOwqphM4GGR_2">
<div class="formContent">
<div class="formBackground"><div style="position:absolute;top:50px;left:100px;width:450px;height:25px;background-color:#fff;color:#000;">This should still say 50px</div></div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
CSS
#pageContent {
position:relative;
padding-bottom:20px;
background-color:#fff;
z-index:2;
overflow:auto;
-webkit-overflow-scrolling: touch;
-webkit-transform: translate(0, 0);
-moz-transform: translate(0, 0);
-ms-transform: translate(0, 0);
transform: translate(0, 0);
}
#formBox {
display: block;
position: relative;
height: 100%;
padding: 15px;
}
.trimSpace {
display: block;
position: relative;
margin: 0 auto;
padding: 0;
height: 100%;
overflow: hidden;
}
#formScale::after {
display: block;
content:'';
padding-bottom:5px;
}
#formScale {
position:relative;
width:816px;
margin:0;
-webkit-transform-origin: 0 0;
-moz-transform-origin: 0 0;
transform-origin: 0 0;
-ms-transform-origin: 0 0;
}
.formContainer {
position:relative;
margin : 0 auto 15px auto;
padding:0;
}
.formContent {
position:absolute;
width:100%;
height:100%;
}
.formBackground {
width:100%;
height:100%;
background-color:red;
}
JS
var PAGEWIDTH = 816;
$(window).resize(function (e) {
zoomProject();
resize();
});
function resize() {
$("#pageContent").css('height', window.innerHeight - 45 + 'px');
}
function zoomProject() {
var maxWidth = $("#formBox").width(),
percent = maxWidth / PAGEWIDTH;
$("#formScale").css({
'transform': 'scale(' + percent + ')',
'-moz-transform': 'scale(' + percent + ')',
'-webkit-transform': 'scale(' + percent + ')',
'-ms-transform': 'scale(' + percent + ')'
});
$(".trimSpace").css('width', (PAGEWIDTH * percent) + 'px');
$("#formBox, .trimSpace").css('height', ($("#formScale").height() * percent) + 'px');
}
zoomProject();
resize();
EDIT:
I don't think I am conveying a good job at relaying what I want to accomplish.
At the moment there are two .formContainer's. When I scroll #pageContainer, the .formContainer divs move up through #pageContainer.
So what I want to accomplish is, when a user clicks the "ME" button or #click (as shown in the fiddle below), I'd like to know where in that particular .formContainer, is it touching the top of #pageContainer.
I do use scroll spy in my real world application so I know which .formContainer is closest to the top. So if you just want to target one .formContainer, that is fine.
I used these white div elements as an example. If I am scrolling #pageContainer, and that white div element is at the top of screen as I am scrolling and I click on "ME", the on click trigger should alert to me that .formContainer is touching the top of #pageContainer at 50px from the top. If, the the red container is just touching the top of #pageContainer, it should say it is 0px from the top.
I hope that helps clear up some misconception.
Here is an updated jsfiddle that shows the kind of action that I want to happen.
I am giving this a stab because I find these things interesting. It might just be a starting point since I have a headache today and am not thinking straight. I'd be willing to bet it can be cleaned up and simplified some.
I also might be over-complicating the approach I took, getting the first visible form, and the positioning. I didn't use the getBoundingClientRect function either.
Instead, I approached it trying to account for padding and margin, using a loop through parent objects up to the pageContent to get the offset relative to that element. Because the form is nested a couple levels deep inside the pageContent element you can't use position(). You also can't use offset() since that changes with scroll. The loop approach allowed me to factor the top margin/padding in. I haven't looked at the other solutions proposed fully so there might be a shorter way to accomplish this.
Keeping in mind that the scale will affect the ACTUAL location of the child elements, you have to divide by your scale percentage when getting the actual location. To do that I moved the scalePercentage to a global var so it was usable by the zoom function and the click.
Here's the core of what I did. The actual fiddle has more logging and junk:
var visForm = getVisibleForm();
var formTop = visForm.position().top;
var parents = visForm.parentsUntil('#pageContent');
var truOffset = 0;
parents.each(function() {
truOffset -= $(this).position().top;
});
// actual location of form relative to pageContent visible pane
var formLoc = truOffset - formTop;
var scaledLoc = formLoc / scalePercent;
Updated Fiddle (forgot to account for scale in get func): http://jsfiddle.net/e6vpq9c8/5/
If I understand your question correctly, what you want is to catch when certain descendant elements reach the top of the outer container, and then determine the position of the visible "page" (div with class formContainer) relative to the top.
If so, the first task is to mark the specific elements that could trigger this:
<div class='triggerElement' style="position:absolute;top:50px;left:100px;width:450px;height:25px;background-color:#fff;color:#000;">When this reaches the top, the "trigger" should say 50px"</div>
Then the code:
// arbitrary horizontal offset - customize for where your trigger elements are placed horizontally
var X_OFFSET = 100;
// determine once, at page load, where outer container is on the page
var outerContainerRect;
$(document).ready(function() {
outerContainerRect = $("#pageContent").get(0).getBoundingClientRect();
});
// when outer container is scrolled
$("#pageContent").scroll(function(e) {
// determine which element is at the top
var topElement = $(document.elementFromPoint(outerContainerRect.left+X_OFFSET, outerContainerRect.top));
/*
// if a trigger element
if (topElement.hasClass("triggerElement")) {
// get trigger element's position relative to page
console.log(topElement.position().top);
}
*/
var page = topElement.closest(".formContainer");
if (page.length > 0) {
console.log(-page.get(0).getBoundingClientRect().top);
}
});
EDIT: Changed code to check formContainer elements rather than descendant elements, as per your comment.
http://jsfiddle.net/j6ybgf58/23/
EDIT #2: A simpler approach, given that you know which formContainer to target:
$("#pageContent").scroll(function(e) {
console.log($(this).scrollTop() - $("#xzOwqphM4GGR_1").position().top);
});
http://jsfiddle.net/rL4Ly3yy/5/
However, it still gives different results based on the size of the window. This seems unavoidable - the zoomProject and resize functions are explicitly resizing the content, so you would have to apply the inverse transforms to the number you get from this code if you want it in the original coordinate system.
I do not fully understand what it is that you are needing, but if i am correct this should do the trick
$("#pageContent").scroll(function(e) {
// If more then 50 pixels from the top has been scrolled
// * if you want it to only happen at 50px, just execute this once by removing the scroll listener on pageContent
if((this.scrollHeight - this.scrollTop) < (this.scrollHeight - 50)) {
alert('it is');
}
});
ScrollHeight is the full height of the object including scrollable pixels.
ScrollTop is the amount of pixels scrolled from the top.
You can use waypoints to detect the position of divs based on where you're scrolling.
Here is a link to their official website's example: http://imakewebthings.com/waypoints/shortcuts/inview/

jQuery width does not include inner element padding

When an element contains inline-blocks which contain padding it doesn't get included in the width calculations of the element.
Essentially the same issue as jQuery outerWidth on a parent element which has child elements with padding.
This page should have text that lines up along the right side of the green box,
however the text will always grow larger than it's container, because width never includes the padding of any of it's children.
Is there a way to find the width of an element correctly without manually enumerating all child elements and re-adding the padding of each child? Same results when using .css('width'), .width() or .outerWidth().
<html>
<head>
<script src="http://code.jquery.com/jquery-2.1.0.min.js"></script>
<script>
jQuery(document).ready(function() {
var e = jQuery('#BLAH');
var pw = e.parent().width();
e.css('font-size','1px');
if (e.outerWidth() < pw) {
while ( e.outerWidth() < pw) {
alert('width ' + e.outerWidth() + ' < ' + pw);
e.css('font-size','+=1px');
}
e.css('font-size','-=1px');
}
});
</script>
<style>
#BLAH {
background-color: red;
white-space: nowrap;
}
.BLAH {
//padding: 0 10%;
background-color: blue;
display: inline;
}
</style>
</head>
<body>
<div style="background-color: green; width: 50%; height: 50%">
<div id="BLAH" style="display: inline-block;">
<div class="BLAH">BLAH</div>
<div class="BLAH">BLAH</div>
<div class="BLAH">BLAH</div>
<div class="BLAH">BLAH</div>
</div>
</div>
</body>
</html>
As the issue only occurs with percentage padding, you can instead use fixed pixel padding and increase that along with your font-size in the javascript. Something like this:
jQuery(document).ready(function () {
var e = jQuery('#BLAH');
var pw = e.parent().width();
e.css('font-size', '1px');
if (e.outerWidth() < pw) {
while (e.outerWidth() < pw) {
console.log('width ' + e.outerWidth() + ' < ' + pw);
e.css('font-size', '+=1px');
jQuery(".BLAH").css({
'padding-right': '+=1px',
'padding-left': '+=1px'
});
}
e.css('font-size', '-=1px');
jQuery(".BLAH").css({
'padding-right': '-=1px',
'padding-left': '-=1px'
});
}
});
http://jsfiddle.net/5Gufk/
If you wanted to get more sophisticated with it, you could calculate the padding as a percentage of the parent element's previous width and apply that rather than just increasing by one, or any other formula.
As for why it works this way, I was unable to find the part of the CSS spec that defines this behavior. However, it is important to understand that a percentage padding is based on the width of the containing block. Consider how it would work if you had 6 elements, all with 10% padding on both sides. That would be 120% padding, how could that even be possible for the padding of the elements to be 120% of the width of the parent element and still fit inside the parent?

How to calculate the origin that starting zoom using jQuery?

Currently the zooming action is illustrate like the top graph. I would like to achieve the zoom action in bottom graph. The point is the zoom origin .Currently the codes are:
$("#popup").css("width",ui.value+"%");
$("#largeText").css("width",ui.value+"%");
$("#largeImg").css("width",ui.value+"%");
Where UI value is the width in percantage (eg. width : 100% , width : 200%) The height is set as auto.
Thanks
I don't know if that will give you answer but heres an exemple of an animation
Here's the exemple: http://jsfiddle.net/pRccr/6/
<div class="global">
<div class="item"></div>
​
CSS ::::::
.global {
width:600px;
height:600px;
background-color:#ff00ff;
position:relative;
}
.item{
position:absolute;
width:3px;
height:3px;
background-color:#000;
}
JAVASCRIPT :::::
var start_size = 20;
var timer=setInterval(function(){
start_size ++;
$('.item').css('height',start_size+'px');
$('.item').css('width',start_size+'px');
$('.item').css('top', ($('.global').height()/2 - $('.item').height()/2) +'px');
$('.item').css('left', ($('.global').width()/2 - $('.item').width()/2)+'px');
}, 50);​
This will depend on your elements' positioning on the page.
I expect, to get the result you want in your image, you will have to center the element on your page both vertically and horizontally.
margin:auto auto;
width:?px;
height:?px;

How to color an image based on a dynamically changing percentage value?

I have an image which i want to fill with some color based on a dynamically changing value that represents percentage, e.g. if the value is 50% half of the image should be colored.
How to achieve that using JavaScript (jQuery can be used)?
You can accomplish that by utilizing the clip CSS property, and a little bit of added markup to serve an underlaying container for the unrevealing background color.
Abstract
Place an element underneath the image for the faux color fill, and set its dimensions and position to match the images'. Then use JavaScript to clip the image dynamically - thus revealing the underlying color - by altering the clip value of the image element according to your needs (you can, of course, control each offset separately, e.g. left, bottom).
Note: To achieve specifically what you desire you can alter the underlying element to contain another image that suits your needs (i.e. a top image of an empty barrel, and a bottom image of a full one).
Implementation
In this example a slider is used to trigger the value change.
Markup
<input type="range" min="0" max="100" id="slider" value="100" />
<div id="underlay"></div>
<img src="http://placekitten.com/500/207" id="image" />
Styles
#slider,
#image,
#underlay {
/* absolute positioning is mandatory for clipped elements (#image) */
position: absolute;
left: 50px;
width: 500px;
}
#image,
#underlay {
top: 100px;
height: 207px;
}
#image {
/* initial clip state */
clip: rect(auto, auto, auto, 500px);
}
#slider {
top: 50px;
}
#underlay {
background-color: #4C76A5;
}
Functionality
var img = document.getElementById('image');
var sld = document.getElementById('slider');
sld.addEventListener('change', function(e) {
// get the slider value
var val = e.srcElement.value;
// calc the percentage to pass an absolute length value to the clip property
var perc = img.width / 100 * val;
// set the images' left offset clip accordingly
img.style.clip = 'rect(auto, auto, auto, ' + perc + 'px)';
});
Live Demo
On jsFiddle
References
clip on Mozilla Developer Network
Browser support

Proportional image scaling

I have a div of known size and a link to some image with random size, which i want to show inside this div. I would like an image to have proportional scaling, to be as big as posible, but no bigger than div (either the image width should equal the div's width or the image height should equal the div's height, but i dont exactly know which case).
How could i do it using only html, css, javascript and jquery?
And it would be great not to read the image size.
You can do this with pure CSS by setting max-width and max-height to 100%. This is a great article to read on the subject: http://unstoppablerobotninja.com/entry/fluid-images. The article also discusses how to deal with older versions of IE.
Here's an example of the CSS in action - http://jsfiddle.net/JamesHill/R7bAA/
HTML
<div id='div1'>
<img class='myImageClass' src='http://www.google.com/intl/en_com/images/srpr/logo3w.png' />
</div>
<br />
<div id='div2'>
<img class='myImageClass' src='http://www.google.com/intl/en_com/images/srpr/logo3w.png' />
</div>
CSS
#div1
{
height:100px;
width:200px;
background-color:Gray;
border: 1px solid Black;
}
#div2
{
height:500px;
width:100px;
background-color:Gray;
border: 1px solid Black;
}
.myImageClass
{
max-height:100%;
max-width:100%;
}
Here's a javascript method that computes the aspect ratio of image and container and sets the corresponding height or width value that will first hit the edge and the image then scales the other dimension proportionally:
// pre-cache image
var img1 = new Image();
img1.src = "http://photos.smugmug.com/photos/344291068_HdnTo-L.jpg";
var img2 = new Image();
img2.src = "http://photos.smugmug.com/photos/344291068_HdnTo-L.jpg";
function placeImage(imgObj, containerID) {
var container = $(containerID);
var imageAspectRatio = imgObj.height / imgObj.width;
var containerAspectRatio = container.height() / container.width();
// figure out which dimension hits first and set that to match
if (imageAspectRatio > containerAspectRatio) {
imgObj.style.height = container.height() + "px";
} else {
imgObj.style.width = container.width() + "px";
}
container.append(imgObj);
}
$("#go").click(function() {
placeImage(img1, "#container1");
placeImage(img2, "#container2");
});
You can see it here in this jsFiddle: http://jsfiddle.net/jfriend00/5K3Zf/

Categories

Resources