How to Scroll Draw only for the length of a div? - javascript

Hi I'm looking at the Scroll Drawing examples over on W3Schools and CSS Tricks. Both examples use Javascript and an SVG path to "draw" an element on scroll. They also both base the length of the drawn path according to how much the document body has been scrolled (scroll percentage). Here's how they calculate their scroll percentage:
var scrollpercent = (document.body.scrollTop + document.documentElement.scrollTop) / (document.documentElement.scrollHeight - document.documentElement.clientHeight);
Does anyone know how I can change the scroll percentage so that it calculates based on how far down a div has been scrolled?
Here's a Fiddle where I tried using the y of the div's boundingClientRect() divided by the window.innerHeight. This probably doesn't make sense because it seems to be drawn over and over again, but I'm trying to figure out the math. The SVG in this case is sticky to the div (instead of fixed). This only kind of works in that the SVG path is drawn on scroll, but it's drawn over and over again until you've scrolled past the height of the div.
My desired outcome is for it to be drawn once completely when scrolled 50% down the div and stay drawn for scrolling the remaining 50% of the div.
I hope this makes sense. Thanks for your help in advance! Any references would help too in terms of JS math and logic!
Also, for the SVG itself, do you know which end of the path is the one that starts?

Okay, I figured this out. Here's the complete fiddle
The math for calculating the scroll percentage: get the amount that the window has scrolled and divide by the height of the div (that the SVG is in). You then want to divide this in half so that the drawing completes halfway before div finishes scrolling:
var svgContainer = document.getElementById("svg-container");
var svgContainerRect = svgContainer.getBoundingClientRect();
var svgDivHeight = svgContainerRect.height;
var windowScroll = window.pageYOffset;
var scrollPercent = windowScroll / svgDivHeight *2;
Then, for the drawing to remain "drawn" after scrolling halfway through the div, throw the "drawing function" into an "if". This stops drawing once the scroll percentage reaches 1 (reaching halfway down the page):
if (scrollPercent < 1) {
//draw the length of SVG path according to the scroll
var draw = length * scrollPercent;
// Reverse the drawing (when scrolling upwards)
triangle.style.strokeDashoffset = length - draw;
} else {
var still = length;
}
The only quirk is that when the drawing is reversed (when you scroll up and then scroll back down), it seems to not complete all the way, like there's a bit of length missing. More to figure out, but the main function is there.
I guess it just took me a while to figure out the simple math. Hope this can help someone in the future.

Related

How To space out photoshop Layers in a group horizontally with scripting v2019 [duplicate]

I'm working on a script that will move a layer, right, left, up, or down. This depends upon which edge of the layer is inside the canvas.
I've managed to get the layer moving left and right (x-axis) using bounds[0] and bounds[2].
But when I try to get it to move up or down, it still moves left/right. Is it the bounds number I've got wrong?
var Y1 = bounds[3].as('px');
var Height = app.activeDocument.height.as('px');
//move down
if (Y1 < Height) {
activeDocument.activeLayer.translate(Height-Y1);
}
The first thing you probably want to do in a situation like this is to check the documentation. For .translate() we can find the following:
so to move horizontally we would use deltaX and to move vertically deltaY, in your code you're giving to .translate() only deltaX, so as expected your layer is being moved horizontally. To fix this pass 0 as a first argument and your Height-Y1 as a second one:
activeDocument.activeLayer.translate(0, Height - Y1);

How do you calculate the number of times to call $( '#el'' ).scrollTop( 1 ) to traverse a div height of 759?

Update:
I've created this Code Page demo to show what I'm talking about. This demo shows two methods, the first is the brute-force method and the second is Robert McKee's method.
With the first method, press the Scroll to End button to derive the vertical (y) scaling value, which is then shown next to the button that was just pushed. The list of values below the buttons, you will also see the number of 1px scrolls horizontally and vertically needed to fully scroll to the lower-left corner of the scroll-area, shown in the Scroll Y Count and Scroll X Count fields. With the scaling value now showing and the adjacent checkbox checked, pressing the Scroll to End button shows that the same number of 1px horizontal and scaled vertical scrolls now get to the lower-right end of the scroll-area.
With the second method, press the Calculate Y Scale button to calculate the y scale value without needing to actually scroll. After the value is calculated the second dive is scrolled to show that it works.
The first method finds a y scale value that allow scrolling so that the horizontal and vertical scrolls over and down such that they both get to the left side and bottom with exactly the same number of scrolls. I'm not sure why there is a difference, but the second method is very close, only one scroll different, so its good enough.
Original Question:
I need to calculate the scaling values needed to scroll the horizontal and vertical scrollbars of a div so that when the horizontal scrolling completely traverses the width of the div, the vertical scrolling also completely traverses the height of the same div.
I do this now by first manually counting the number of of calls of the $( '#div' ).scrollLeft( ++x ) jQuery function and, separately, the number of calls of the $( '#div' ).scrollTop( ++y ) function, with the x and y values starting at 0, and increasing by 1 per call, that are needed to scroll over the div's width and height, respectively. In my case the div is 540 px wide by 759 px high, and it take 342 times to cover the width and 660 for the height. From this I can calculate the y scaling value to put in the vertical scroll function call, $( '#div' ).scrollTop( ++y * yScale ), to be 660/342 for my div. The issue is that the div's width and height aren't always the same so I can't use a pre-calculated value for the y scaling value for all possible contents that the scrolling div needs to display.
Why with a 1 pixel x and y increment isn't the number of each scroll calls not 540 and 759 rather than 342 and 660 for my specific case?
Before trying to automate the calculations, I tried calling the scrollTop function multiple times with a parameter value starting with 0, and incrementing by 1 pixel in each successive call (0, 1, 2, ... 10, 11, .., 20, etc.), and I found that the amount scrolled by each scroll call was not consistent.
I include this because with the inconsistency I found that I couldn't rely on the average scrolled amount by a few scroll calls to calculate the total number of calls needed to traverse the full distance of each div axis direction.
I can automate this with a loop that counts the number of repeated calls for each dimension, stopping counting for each direction when the respective scrollbar stops scrolling, and stopping looping when both scrollbars stop scrolling, but I'd rather not have to do this if there is a purely mathematical way to calculate the scaling values. Besides, this would look odd to the user as the div contents jumped around each time it is loaded, especially for larger contents and slow the display.
Does anyone know how to do this?
Thanks.
If you are trying to calculate yScaling, here you go:
var elem = $('#div2a').parent()[0]; // same as divScroller[0]
var yScaling = (elem.scrollHeight-elem.clientHeight) / (elem.scrollWidth-elem.clientWidth);
which for your divs, comes out to 1.9298245614035088.
If you want the values you are trying to calculate in "Ave Scroll Y" and "Ave Scroll X", then those values are 1 and 1/1.9298245614035088 which is 0.5181818181818182.
This is why the formula works:
Assume you have a viewport of 100px width, and the content inside that viewport is 400px. When fully scrolled left, the scrollLeft will be 300px (400px - 100px). 300px of the 400px will be off the screen, and the last 100px will be visible inside the viewport. That is why when you are trying to calculate the maximum value for scrollLeft, you use scrollWidth - clientWidth of the viewport (.scroller). Do the same thing to calculate the maximum scrollTop, and the Y-Scaling is the ratio between those two numbers.
Use currentScrollX and currentScrollY for setting current position of scrollbar and destinationScrollX and destinationScrollY for where you want to go
Then each animation loop runs the following to recalculate currentScrollX and currentScrollY
var speed = 20; // adjust accordingly
// Home into destination
currentScrollX += (destinationScrollX - currentScrollX) / speed;
currentScrollY += (destinationScrollY - currentScrollY) / speed;
To end scrolling simply do something like
if (Math.abs(destinationScrollX - currentScrollX) < 0.05 && Math.abs(destinationScrollY - currentScrollY) < 0.05) {
currentScrollX = destinationScrollX;
currentScrollY = destinationScrollY;
// stop scrolling flag / code goes here
}
// At this point set scrollTop(currentScrollY) and scrollLeft(currentScrollX)
Update
If you want to scroll x and y a certain number of pixels in 30 frames based on their width / height then
var scaleX = widthOfScrollingDiv / 30;
var scaleY = heightOfScrollingDiv / 30;
You then animate for 30 frames and you'll reach the destination at the same time even if width and height aren't the same.

Photoshop move layer along y-axis

I'm working on a script that will move a layer, right, left, up, or down. This depends upon which edge of the layer is inside the canvas.
I've managed to get the layer moving left and right (x-axis) using bounds[0] and bounds[2].
But when I try to get it to move up or down, it still moves left/right. Is it the bounds number I've got wrong?
var Y1 = bounds[3].as('px');
var Height = app.activeDocument.height.as('px');
//move down
if (Y1 < Height) {
activeDocument.activeLayer.translate(Height-Y1);
}
The first thing you probably want to do in a situation like this is to check the documentation. For .translate() we can find the following:
so to move horizontally we would use deltaX and to move vertically deltaY, in your code you're giving to .translate() only deltaX, so as expected your layer is being moved horizontally. To fix this pass 0 as a first argument and your Height-Y1 as a second one:
activeDocument.activeLayer.translate(0, Height - Y1);

Resizing and rotation on svg (Raphael.js) creates jumping

I've been working on this problem for days. I am trying to implement a "free transform" tool for svgs. Similar to that of Raphael.FreeTransform or how you would move/rotate/scale images in MS Word. (Yes, I am aware there are libraries) The following jSFiddle displays my problem: https://jsfiddle.net/hLjvrep7/12/
There are 5 functions in the jsFiddle: rotate-t. shrink-t, grow-t, shrink, grow. The functions suffixed with '-t' also apply the current rotation transformation. e.g.:
grow-t
rect.attr({height : height * 1.25, width : width * 1.25}).transform('r' + degree);
grow
rect.attr({height : height * 1.25, width : width * 1.25});
Once an svg is rotated, then scaled. If you try to rotate the svg again (after scale), the svg jumps. To see this, go top the fiddle:
Hit rotate-t twice. Svg should rotate a total of 30 degrees from the rectangles origin.
Hit grow (not grow-t) twice. Note the top left position of the svg stays the same.
Hit rotate-t once. Note the svg jumps to a different position, then rotates.
Note hitting rotate-t subsequent times will continue to rotate the image around the origin (which is what I want the first time rotate-t is clicked)
One solution I had was to apply the current rotation transformation whenever changing the height and width. This fixes my previous problem, but introduces another problem. To see an example of this, go to the fiddle, and:
Hit rotate-t twice.
Hit grow-t a couple times. Notice the svg grows, but the top left position of the rectangle moves. That's a problem for me. I want the svg to grow without the top left corner to move.
Notes on using the jsFiddle:
Any combination of rotate-t, grow-t, shrink-t will exhibit the ideal rotation behavior (about the origin, no jumping). But this also demonstrates the undesired growing and shrinking (top left position moved when svg is on angle).
Any combination pf rotate-t, grow, shrink will exhibit the ideal scaling behavior (top left corner of svg doesn't move). But this also demonstrates the undesired rotation property (will jump around after different rotations and scales).
Bottom line: I want to be able to the svg rotate around the origin. Then grow the image, while the top left position remains the same. Then rotate the svg again, around the origin without any jumping.
I am aware the how the transform function impacts the local coordinate system of the svg. I'm leaning towards using rotate-t, grow, shrink combo and simply apply some x-y offsets to remove the "jumping" effect. I would imagine there must be some sort of offset I could apply to avoid jumping or shifting during rotation or scaling, but its not clear to me how to calculate such offsets. Any help would be appreciated.
Please don't hesitate to ask anymore questions. Like I said, I've been digging into this for days. Clearly, I don't understand it all, but am somewhat intimate with what's happening and happy to explain anything in more detail.
My solutions for scale, rotate, move back and front etc:
$scope.back = function () {
if($scope.currentImage !==null) {
if($scope.currentImage.prev!=undefined) {
var bot = $scope.currentImage.prev;
$scope.currentImage.insertBefore(bot);
ft.apply();
}
}
};
//Function for moving front
$scope.front = function () {
if($scope.currentImage !==null) {
if($scope.currentImage.next!=undefined) {
var top = $scope.currentImage.next;
if($scope.currentImage.next.node.localName == "image")
$scope.currentImage.insertAfter(top);
ft.apply();
}
}
};
//ZOOM
$scope.zoomIn = function () {
if ($scope.currentImage!= null) {
var ft = paper.freeTransform($scope.currentImage);
if(ft.attrs.scale.y<4) {
$scope.currentImage.toFront();
ft.attrs.scale.y = ft.attrs.scale.y *(1.1);
ft.attrs.scale.x = ft.attrs.scale.x *(1.1);
ft.apply();
ft.updateHandles();
}
}
};

Zoom-in and Zoom-out image when Mouse Scroll

I want to zoom-in and zoom-out image on mouse scroll in HTML. There are multiple img tag without ID. So how can I do it using JavaScript or Ajax?
Just throwing the answer for the ones that will search for an answer to this question.
First, you will need to find a system to detect the mouse scroll.
If you are courageous, you can develop it yourself.
If you're not, you can find some pretty good libraries (ex : MouseWheel with JQuery).
Next, you will find another two ways to zoom in and out.
Easy way
First, let's cheat a bit.
When you will have to zoom, just multiply the height and width of your image by a factor you will decide.
To have height and width into a variable (JQuery)
var height = $('#image').height();
var width = $('#image').width();
For each scroll you will receive, you will only have 2 choices.
Once you are able to know if the mousewheel goes up or down, you will just have to do something like this (JQuery)
height *= 2;
width *= 2;
This way, by doubling the size of your image, you will have the impression to zoom in.
Less easy way
If you want to zoom in as you would do in a GMap object, you can do something like that.
var firstHeight = $('#image').height();
height *= 2;
width *= 2;
scalechange = (actualHeight / firstHeight) - 1;
offsetX = -(coordX * scalechange);
offsetY = -(coordY * scalechange);
$("#image").css('top', offsetY + 'px');
$("#image").css('left', offsetX + 'px');
First, you have to have the first height of your image.
Next, you will double the size of your image (zoom effect).
Next step is to calculate the scalechange. You will be able to find multiple explanations and many way to calculate it, my method is as good as another.
The two offsets presented are the new positions that your image will adopt (simple factor calculation, it's like making x percent on a price).
Last part is to set the new values of your image.
In the end, you will be able to zoom and unzoom with ou without centering the image at your mouse position.
Be careful : The calculation above in only to zoom-in. You will have to do some maths to get the zoom-out!
Go further ?
Another way to go further would be to place your image in a div.
<div id="imageContainer" style="overflow:hidden;">
<img id="image" src="YourImage">
</div>
By setting
"overflow:hidden;"
to your div, your image will zoom.
But everything that will overflow your div will be hidden.
If you set your div to the original size of your image, like this (JQuery)
$("#imageContainer").css('height', $('#image').height());
$("#imageContainer").css('width', $('#image').width());
Then you will have an image displayed that will always be at the same size, but your zoom will be effective.
If you combine this to a drag'n'drop method, you have a GMap object-like (zoom in-out, moove the zoomed image, ...)
Hope it will help someone!

Categories

Resources