Scrollbar scroll 'size' - css

How would I, instead of 'scrolling' as much height as I want, a fixed height?
I.e a div is 50px high and each time I scroll down I want to go down 50px instead of just 'stopping' where you want.
Thanks in advance.

You can override scrolling of the div in such a way:
$("#scrollableContainer").scroll(function(e) {
//measure how far are you from the top of the scrollable container
var top = $("#scrollableContainer").scrollTop();
var scrollIncrement = 50; //50px
if (top % scrollIncrement!= 0) {
var delta;
//calculate delta you need to align the position with
if(e.detail > 0) {
//scroll down
delta = ((top / scrollIncrement) + 1) * scrollIncrement) - top;
}else {
//scroll up
delta = ((top / scrollIncrement) - 1) * scrollIncrement) - top;
}
$("#scrollableContainer").scrollTop(delta);
}
});

Related

Using CSS setProperty for top does not work well when implement GWT drag

I am implementing a GWT application, have a scroll panel, flow panel which contains image, mouse down/move/up to drag the flow panel in scroll panel.
Left part (x direction) works perfectly, however, the same code for top (y direction) does not work well, it seems it shake and move unstable.
Somehow the top value is much larger than left which cause the problem, but no idea how it happens and how to make the Y direction work smoothly.
public void mouseDown(MouseDownEvent event)
{
isMouseDown = true;
event.preventDefault();
xoffset = event.getX();
yoffset = event.getY();
Event.setCapture(panel.getElement());
}
public void mouseMove(MouseMoveEvent event) {
int = event.getX();
int y = event.getY();
float left = panel.getAbsoluteLeft();
float top = panel.getAbsoluteTop();
float offset_XX = x - xoffset;
float offset_YY = y - yoffset;
panel.getElement().getStyle().setProperty("position", "absolute");
float newLeft = left + offset_XX;
if (isMouseDown) {
if (newLeft < scrollPanel.getAbsoluteLeft() ) {
offset_XX = offset_XX - Math.abs(scrollPanel.getAbsoluteLeft() -panel.getAbsoluteLeft());
if (Math.abs(offset_XX) > Math.abs(scrollPanel.getOffsetWidth() - panel.getOffsetWidth())) {
if (offset_XX > 0 )
offset_XX = Math.abs(scrollPanel.getOffsetWidth() - panel.getOffsetWidth());
else
offset_XX = -Math.abs(scrollPanel.getOffsetWidth() - panel.getOffsetWidth());
}
panel.getElement().getStyle().setPropertyPx("left", (int)offset_XX);
}
float newtop = top + offset_YY;
if (newtop < scrollPanel.getAbsoluteTop()) {
offset_YY = offset_YY - Math.abs(scrollPanel.getAbsoluteTop() -panel.getAbsoluteTop());
if (Math.abs(offset_YY) > Math.abs(scrollPanel.getOffsetHeight() - panel.getOffsetHeight())) {
if (offset_YY > 0 )
offset_YY = Math.abs(scrollPanel.getOffsetHeight() - panel.getOffsetHeight());
else
offset_YY = -Math.abs(scrollPanel.getOffsetHeight() - panel.getOffsetHeight());
}
panel.getElement().getStyle().setPropertyPx("top", (int)offset_YY);
}
}
}
Long story short, there're too many computations and DOM calls going on in your drag code. I suggest you to incorporate GWT team's solution for draggable/resizable panels following the implementation of com.google.gwt.logging.client.LoggingPopup. It's very fast, elegant, easy to understand and use. You can get the code here https://github.com/stephenh/google-web-toolkit/blob/master/user/src/com/google/gwt/logging/client/LoggingPopup.java

Zoom breaks CSS

I the following javascript which creates a rectangle of 125 divs by 75 divs. As follows:
function createFlag() {
var flag;
var counter = 1;
var rowCounter = 1;
var divs = 10000;
flag = '<table cellspacing="0" cellpadding="0"><tr>';
for (var i = 0; i < divs; i++) {
if (i % 125 === 0) {
flag += '</ tr><tr>';
rowCounter++;
counter = rowCounter;
} else flag += '<td id="pixel_' + counter + '" class="pixel"></td>';
counter += 80;
}
flag += '</tr></table>';
$('#flag').append(flag);
}
And I have some CSS which works fine while no zoom is applied. The CSS uses % and em for sizes which I thought should mean that relative proportions would be kept. The problem is as soon as you zoom in or out the rectangle of divs distorts shape.
To see what I mean the url in question is here: link here
How can I keep the proportions when zooming? All help appreciated of course.
Your table can't expand any more because the #flag div's width is 45% of the #container div width, which itself is 50% of the <body>. The width of the <body> doesn't change when you zoom, so the width of your table can't.
So you can either change the layout so that the form and the flag won't be float side by side, or just change #container's width to em's or px's.

Background-size cover jumping when background-position switches to fixed

I am working on a Parallax/Scrolling Timeline project and I am having a problem with the CSS3 Background-size cover property.
The div has these properties:
background: url(../images/timeline/back-6.jpg) no-repeat top center black;
background-size: cover;
padding-top: 90px;
height: 1855px;
position: relative;
Using jQuery I switch the background-attachment to fixed. When I do this the background image jumps "in" (meaning that parts of the image that were past the edge of the screen are now visible). Which isn't the desired result.
In testing I can switch the div to use background-size: 100% cover but it is causing different vertical jumping issues when scrolling.
Any ideas of how to prevent it from jumping in when I switch the background to fixed? (It also happens in reverse when I set the background to scroll).
I sadly can't link to a demo of this code as the page isn't ready to be deployed yet.
I had the same issue, when setting background-size to cover or contain
Setting a fixed height, in example for smaller screens via #media prevents the background-image from jumping. After my tests I came to the conclusion, that the jumping is due to the orientation of the element after setting background-attachment to fixed
Setting it to fixed, the size is calculated by the size of the viewport, not the element containing the background-image. This is where the jumping comes from and why setting a fixed height or width for the background-size solves this issue.
I had the same problem while creating a one page layout i wanted to use with a scrollTo-Plugin and so on....
The page layout was devided in two parts:
Left side for the background image which should change/scroll with the content on the right side.
So i used to make a kind of jquery Plugin to combine both "background-position: fixed" and "background-size: cover".
you just need to define the element by class/id for aligning the background-images.
dont complain about the code. im relatively new to javascript/jquery. but its working ;)
there it is:
function fixedResize() {
var targetEl = $('element where bg-images are in');
var targetWidth = targetEl.width();
var targetHeight = targetEl.height();
var targetPosX = targetEl.offset().left;
var targetPosY = targetEl.offset().top;
var leftRatio = targetWidth / targetHeight;
//console.log('TargetWidth', targetWidth, 'TargetHeight', targetHeight, 'Offset', targetPosX, targetPosY, 'leftRatio', leftRatio);
targetEl.each(function(){
var imgTarget = $(this);
var url = $(this).css('background-image').replace('url(', '').replace(')', '').replace("'", '').replace('"', '');
var bgImg = $('<img />'); // make background-image as image tag for getting width and height of the image
imgTarget.css('background-attachment','fixed');
bgImg.hide();
bgImg.bind('load', function(){
var imgHeight = $(this).height();
var imgWidth = $(this).width();
var imgRatio = imgWidth / imgHeight;
$(this).remove(); // remove img Tags again
// Calculate resize dimensions
if (imgRatio > leftRatio) {
var currentWidth = imgRatio * targetHeight; // image width after resize
var currentHeight = (currentWidth/imgWidth)*imgHeight;
var setToLeft = ((currentWidth - targetWidth)/2);
var imgPosX = targetPosX - setToLeft;
var imgPosY = (currentHeight - targetPosY - currentHeight/2 - targetHeight/2)* -1;
var resizeImg = 'background-size: auto '+ targetHeight +'px;';
} else if (imgRatio < leftRatio){
var currentWidth = targetWidth;
var currentHeight = (currentWidth/imgWidth)*imgHeight;
var imgPosX = targetPosX;
var imgPosY = (currentHeight - targetPosY - currentHeight/2 - targetHeight/2)* -1;
var resizeImg = 'background-size: '+ targetWidth +'px auto;'; // resize background
}
imgTarget.attr('style','background-attachment: fixed; background-position: '+ imgPosX +'px '+ imgPosY +'px;' + resizeImg);
console.log('imgWidth', imgWidth, 'imgHeight', imgHeight, 'imgRatio', imgRatio, 'currentWidth', currentWidth, 'currentHeight', currentHeight, 'setToLeft', setToLeft);
console.log('imgPos', imgPosX, imgPosY, 'setToLeft', setToLeft, targetPosX);
});
$(this).append(bgImg);
bgImg.attr('src', url);
});
}
fixedResize(); // initiate function
$(window).resize(function() {
fixedResize(); // initiate function for window resize (Fluid behavior)
});
or
jsfiddle.net/rowphant/eXb6e/14/

What's the math behind CSS's background-size:cover

I'm creating an "image generator" where users can upload an image and add text and/or draw on it. The outputted image is a fixed size (698x450).
On the client side, when the user uploads their image it is set as the background of a div that's 698x450 with background-size:cover. This makes it fill the area nicely.
The final combined image is generated by PHP using GD functions. My question is, how can I get the image to scale in PHP the same way it does in CSS. I want the result of the PHP script to look the same as if the image was set in CSS as it was above.
Does anyone know how browsers using background-size:cover calculate how to scale the image appropriately? I want to translate this into PHP.
Thanks
Here's a logic behind cover calculations.
You have four base values :
imgWidth // your original img width
imgHeight
containerWidth // your container width (here 698px)
containerHeight
Two ratios derived from these values :
imgRatio = (imgHeight / imgWidth) // original img ratio
containerRatio = (containerHeight / containerWidth) // container ratio
You want to find two new values :
finalWidth // the scaled img width
finalHeight
So :
if (containerRatio > imgRatio)
{
finalHeight = containerHeight
finalWidth = (containerHeight / imgRatio)
}
else
{
finalWidth = containerWidth
finalHeight = (containerWidth / imgRatio)
}
... and you have the equivalent of a background-size : cover.
I know this is a very old question, but the answer I wrote is actually cleaner by using max and mins on the ratios between the images instead of each image with itself:
var originalRatios = {
width: containerWidth / imageNaturalWidth,
height: containerHeight / imageNaturalHeight
};
// formula for cover:
var coverRatio = Math.max(originalRatios.width, originalRatios.height);
// result:
var newImageWidth = imageNaturalWidth * coverRatio;
var newImageHeight = imageNaturalHeight * coverRatio;
I like this approach because it is very systematic — maybe it's the wrong word —. What I mean is you can get rid of the if statements and make it work in a more "math formula" kind of way (input = output, if that makes sense):
var ratios = {
cover: function(wRatio, hRatio) {
return Math.max(wRatio, hRatio);
},
contain: function(wRatio, hRatio) {
return Math.min(wRatio, hRatio);
},
// original size
"auto": function() {
return 1;
},
// stretch
"100% 100%": function(wRatio, hRatio) {
return { width:wRatio, height:hRatio };
}
};
function getImageSize(options) {
if(!ratios[options.size]) {
throw new Error(options.size + " not found in ratios");
}
var r = ratios[options.size](
options.container.width / options.image.width,
options.container.height / options.image.height
);
return {
width: options.image.width * (r.width || r),
height: options.image.height * (r.height || r)
};
}
Usage
const { width, height } = getImageSize({
container: {width: 100, height: 100},
image: {width: 200, height: 50},
size: 'cover' // 'contain' | 'auto' | '100% 100%'
});
Playground
I created a jsbin here if you want to take a look at what I mean with systematic (it also has a scale method that I thought was not needed in this answer but very useful for something other than the usual).
Thanks to mdi for pointing me in the right direction, but that didn't seem quite right.
This is the solution that worked for me:
$imgRatio = $imageHeight / $imageWidth;
$canvasRatio = $canvasHeight / $canvasWidth;
if ($canvasRatio > $imgRatio) {
$finalHeight = $canvasHeight;
$scale = $finalHeight / $imageHeight;
$finalWidth = round($imageWidth * $scale , 0);
} else {
$finalWidth = $canvasWidth;
$scale = $finalWidth / $imageWidth;
$finalHeight = round($imageHeight * $scale , 0);
}
I stumbled across this QA after a long search for a way how to scale and position a background image on a div to match an html background image while also supporting browser resizing and ad-hoc positioning of the div and I came up with this.
:root {
/* background image size (source) */
--bgw: 1920;
--bgh: 1080;
/* projected background image size and position */
--bgscale: max(calc(100vh / var(--bgh)), calc(100vw / var(--bgw)));
--pbgw: calc(var(--bgw) * var(--bgscale)); /* projected width */
--pbgh: calc(var(--bgh) * var(--bgscale)); /* projected height */
--bgLeftOverflow: calc((var(--pbgw) - 100vw) / 2);
--bgTopOverflow: calc((var(--pbgh) - 100vh) / 2);
}
JS equivalent
window.onresize = () => {
const vw100 = window.innerWidth
const vh100 = window.innerHeight
/* background image size (source) */
const bgw = 1920
const bgh = 1080
/* projected background image size and position */
const bgscale = Math.max(vh100 / bgh, vw100 / bgw)
const projectedWidth = bgw * bgscale | 0
const projectedHeight = bgh * bgscale | 0
const leftOverflow = (projectedWidth - vw100) / 2 | 0
const topOverflow = (projectedHeight - vh100) / 2 | 0
console.log(bgscale.toFixed(2), projectedWidth, projectedHeight, leftOverflow, topOverflow)
}
Try resizing a window with this snippet to see the result.
Best viewed in Full page view. tip: Open console.
window.onresize = () => {
const vw100 = window.innerWidth
const vh100 = window.innerHeight
const bgw = 1920
const bgh = 1080
const bgscale = Math.max(vh100 / bgh, vw100 / bgw)
const projectedWidth = bgw * bgscale | 0
const projectedHeight = bgh * bgscale | 0
const leftOverflow = (projectedWidth - vw100) / 2 | 0
const topOverflow = (projectedHeight - vh100) / 2 | 0
console.log(bgscale.toFixed(2), projectedWidth, projectedHeight, leftOverflow, topOverflow)
}
:root {
/* background image size */
--bgurl: url('https://i.stack.imgur.com/3iy4y.jpg');
--bgw: 1000;
--bgh: 600;
--bgscale: max(calc(100vh / var(--bgh)), calc(100vw / var(--bgw)));
--pbgw: calc(var(--bgw) * var(--bgscale));
--pbgh: calc(var(--bgh) * var(--bgscale));
--bgLeftOverflow: calc((var(--pbgw) - 100vw) / 2);
--bgTopOverflow: calc((var(--pbgh) - 100vh) / 2);
}
html {
background: #000 var(--bgurl) no-repeat center center fixed;
background-size: cover;
overflow: hidden;
}
#panel {
--x: 100px;
--y: 100px;
--w: 200px;
--h: 150px;
position: absolute;
left: var( --x);
top: var( --y);
width: var(--w);
height: var(--h);
background-image: var(--bgurl);
background-repeat: no-repeat;
background-position: calc(0px - var(--bgLeftOverflow) - var(--x)) calc(0px - var(--bgTopOverflow) - var(--y));
background-size: calc(var( --bgscale) * var(--bgw));
filter: invert(1);
}
<div id="panel"></div>
When using background-size: cover, it is scaled to the smallest size that covers the entire background.
So, where it is thinner than it is tall, scale it until its width is the same as the area. Where it is taller than it is thin, scale it until its height is the same as the area.
When it is larger than the area to cover, scale it down until it fits (if there is less overflow in height, scale until the same height, if there is less overflow in width, scale until the same width).

How do I allow a user to smoothly resize elements in Flex 3

I have a Flex 3 app that has elements that a user can add to the main canvas then resize and reposition.
There are 3 key functions I am using for the resize which are as follows:
When the resize begins:
private function startResize(event:MouseEvent):void
{
RESIZE_START_MOUSE_X = event.localX;
RESIZE_START_MOUSE_Y = event.localY;
RESIZE_START_WIDTH = this.width;
RESIZE_START_HEIGHT = this.height;
RESIZE_START_X = this.x;
RESIZE_START_Y = this.y;
RESIZE_BOUND = calculateResizeBound(event);
addEventListener(MouseEvent.MOUSE_MOVE, resizeMouseHandler);
isResizing = true;
}
When the resize is complete:
private function endResize():void
{
RESIZE_START_MOUSE_X = -1;
RESIZE_START_MOUSE_Y = -1;
RESIZE_START_WIDTH = this.width;
RESIZE_START_HEIGHT = this.height;
RESIZE_START_X = -1;
RESIZE_START_Y = -1;
RESIZE_BOUND = '';
removeEventListener(MouseEvent.MOUSE_MOVE, resizeMouseHandler);
isResizing = false;
}
Whilst the user is resizing:
private function resizeMouseHandler(event:MouseEvent):void
{
var deltaX:Number = event.localX - RESIZE_START_MOUSE_X;
var deltaY:Number = event.localY - RESIZE_START_MOUSE_Y;
if (RESIZE_BOUND.indexOf('T') > -1)
//We are fixing the top so move the bottom edge
{
this.height = RESIZE_START_HEIGHT + deltaY;
}
if (RESIZE_BOUND.indexOf('B') > -1)
//We are fixing the bottom so move the top edge
{
this.y = RESIZE_START_Y + deltaY;
this.height = RESIZE_START_HEIGHT - deltaY;
}
if (RESIZE_BOUND.indexOf('L') > -1)
//We are fixing the left so move the right edge
{
this.width = RESIZE_START_WIDTH + deltaX;
}
if (RESIZE_BOUND.indexOf('R') > -1)
//We are fixing the right so move the left edge
{
this.x = RESIZE_START_X + deltaX;
this.width = RESIZE_START_WIDTH - deltaX;
}
}
There is another function referenced in these called calculateResizeBound(). What this does is return a string indicating which edge / corner should remain fixed during the resize. Eg 'TL' means that the top left corner should stay fixed, 'BR' means bottom right, 'L' means just the left edge etc etc
When the resize starts from the 'normal' position, ie the top left corner stays fixed, everything works great. Similarly with the left or top edges fixed. However for the bottom and right cases, I need to reposition the element at the same time as resizing it since all the co-ordinates are calculated from the top left.
The problem that I have is that when it does this, the resize is not smooth, it keeps jumping up and down slightly as you resize it. Not only that but when you resize from the 'normal' edges the cursor position remains fixed relative to the fixed edge / corner however from one of the other edges, you can see it start to drift away from the edge / corner as you resize.
With this kind of thing, it is easy to get the + / - of the different bits of the calculation muddled but since the resize is working in the correct direction each time, I assume I have these correct.
So presumably the problem is coming from the simultaneous moving and resizing but I can't find a work-around for it. Any thoughts / suggestions would be much appreciated
Doug McCune has an awesome Resize wrapper that you can use to resize elements. Then you just need to add a mover on it. See the blog post for code/sample: http://dougmccune.com/blog/2007/08/17/my-360flex-slides-and-code/

Resources