I want to make a smooth scrolling to a section of my page. In jQuery is done so:
$('html, body').animate({
scrollTop: $('#anchorOfMyTargetSection').offset().top
}, 'slow');
In Dart, I can make the scroll, but i have no idea of how to animate it:
int targetSection = querySelector('#anchorOfMyTargetSection').offsetTop;
window.scrollTo( 0, targetSection );
To be more specific, I'm doing a single page with links to sections in the self page.
Here are the links:
<nav>
<ul class="nav-list">
<li><a href="http://example.com/#title">Home</a></li>
<li><a href="http://example.com/#about">About us</a></li>
<li><a href="http://example.com/#products">Products</a></li>
<li><a href="http://example.com/#services">Services</a></li>
<li><a href="http://example.com/#contact">Contact</a></li>
</ul>
</nav>
Here is the full jQuery code:
// Generated by LiveScript 1.2.0
var smoothScrolling;
smoothScrolling = function(selector, offset){
return $(selector).click(function(click){
var link, anchor;
click.preventDefault();
link = $(this).attr('href');
anchor = link.substring(link.indexOf('#'));
return $('html ,body').animate({
scrollTop: $(anchor).offset().top + offset
}, 'slow');
});
};
smoothScrolling('.nav-list a', -45);
And here the Dart code (without the animation part of course):
import 'dart:html';
void main() {
smoothScrollingOffset = -45;
querySelectorAll('.nav-list a').onClick.listen(smoothScrolling);
}
int smoothScrollingOffset = 0;
void smoothScrolling(MouseEvent click) {
click.preventDefault();
String link = click.target.toString();
String anchor = link.substring( link.indexOf('#') );
int targetPosition = querySelector('$anchor').offsetTop;
window.scrollTo( 0 , targetPosition + smoothScrollingOffset );
}
Keep in mind than I'm new to Dart and new to programming in general. If you see something than can be improved in the Dart code tell it too.
Update: using only dart:html library.
These are the links
<nav>
<ul class="nav-list">
<li><a href="http://example.com/#title">Home</a></li>
<li><a href="http://example.com/#about">About us</a></li>
<li><a href="http://example.com/#products">Products</a></li>
<li><a href="http://example.com/#services">Services</a></li>
<li><a href="http://example.com/#contact">Contact</a></li>
</ul>
</nav>
In your Dart code import the dart:html library for accessing the DOM.
import 'dart:html';
Here is the function, and this is what it does:
.
void smoothScrolling(String selector, {int offset: 0, int duration: 500}) {
// The detection of the clicks and the selectors of the links are specified at the bottom of the function
// Let's suppose you click a link to visit 'http://example.com/#contact'
// When you click the link
void trigger(MouseEvent click) {
// Prevent to visit the resources, like normally does
click.preventDefault();
// Get the resource link of the clicked element. In this case: 'http://example.com/#contact'
String link = click.target.toString();
// Extract the anchor. In this case from 'http://example.com/#contact' will extract '#contact'
String anchor = link.substring( link.indexOf('#') );
// With the extracted anchor, search the corresponding element and get his position.
// In this case gets the position of the element with 'contact' in the 'id' attribute
int targetPosition = querySelector('$anchor').offsetTop;
// Before to translate to the element,
// you can specify if you want to translate some distance before or after the element
targetPosition += offset;
// Let's move in direction to the section
// We know than in Dart there are 60 frames per second, that means a frame duration is
// 1000 milliseconds divided in 60 frames = per frame is 16.66 milliseconds long.
// But 16.66 milliseconds multiplied by 60 = 999.99 milliseconds. That is ALMOST a second.
// And that means than there will be 59.99 frames in 999.99 milliseconds
// But we cannot handle frame fractions, we should round frames to integers
// So 59.99 frames will be rounded to 60 frames
// Calculate the total number of frames
int totalFrames = ( duration / (1000 / 60) ).round();
// The first animation frame will be the number 1, the number 0 will be the start point
int currentFrame = 0;
// In this case the start point will be the current position
int currentPosition = window.scrollY;
// The end point will be the target position, we should know how many distance there is between the start and end point.
// The positive and negative numbers represents the same distance, that means than 'y' and '-y' are the same.
// Example: 10 and -10 are the same distance.
// Calculate the distance between the start and end point.
int distanceBetween = targetPosition - currentPosition;
// Then calculate how many distance should move per frame
num distancePerFrame = distanceBetween / totalFrames;
// The animation function is triggered by first time more later in the code
// And when is triggered
void animation(num frame) {
// First we look the number of the frame we are going to run.
// When all the frames are complete the animation function will not be executed again
if ( totalFrames >= currentFrame ) {
// In every frame we are going to move some distance with direction to the target.
// The direction (in this case will be only up or down) depends of the 'distanceBetween' number.
// Let's explore this part with an example: You are 10 pixels from your target, your target is at the point 20,
// Remember, to calculate the distance between you and the target we do 'targetPosition - currentPosition'.
// If you are 10 pixels on from the target (at the point 10) the result will be: 20 - 10 = 10.
// If you are 10 pixels down from the target (at the point 30) the result will be: 20 - 30 = -10.
// You see how the number is the same but with different polarity?. And 10 and - 10 represent the same distance
// The direction depends of the number 0, if you move closer to the 0 you will go down, if you move away the 0 you will move up.
// Let's move 5 pixels:
// 10 + 5 = 15. You will move down, because you will be more away of the 0, your target is at the number 20.
// -10 + 5 = -5. You will move up, because you will be more closer to the 0, your target is at the number 0.
// Let's move to the point where we should be in this frame
window.scrollTo( 0, currentPosition );
// Calculate the point where we should be in the next frame
currentPosition += distancePerFrame;
// We get ready to execute the next frame
currentFrame++;
// When the time of this frame (16.66 milliseconds) is complete immediately starts the next frame.
window.animationFrame.then(animation);
}
}
// Here is triggered the animation by first time
window.animationFrame.then(animation);
}
// Here are the links' selectors and the detection of the clicks
querySelectorAll(selector).onClick.listen(trigger);
}
To use the function we should specify the links' selectors, and optionally an offset and/or the duration of the scrolling.
void main() {
// To use the function we should specify the links' selectors,
// and optionally an offset and/or the duration of the scrolling,
smoothScrolling('.nav-list a',
offset: -45,
duration: 2500);
}
I will explain the main points, all details are commented in the code.
Other thing to mark is than I been using Blender a long time, an open source 3D Animation software, thanks to Blender I entered to the world of programming. So I know what I am talking about animation.
Here is the first difficulty. If you search in the Dart docs something to handle an animation you will find animationFrame, that seems to be ok.
But first, what is a frame? Maybe you has heard something like 24 frames per second. That means than in this case a frame is 1 second divided by 24 = per frame is 0.0416 seconds long = a frame per 41.66 milliseconds.
Then let's handle frames as blocks of time, and this blocks of time are normally handle as integer. We usually say something like this: this screen is 24 frames per second, but not something like this screen is 24.6 frames per second.
But there is a problem in the docs.
The Future completes to a timestamp that represents a floating point value of the number of milliseconds that have elapsed since the page started to load (which is also the timestamp at this call to animationFrame).
Ok, that means than I can know how many time has been the user in the page, but there is not any reference of how many times per second I can know it, and that is what I expect to know when you talk about frames: How many frames there are in a second?
After some experiments I discovered than in Dart there are 60 frames per second
1000 milliseconds divided in 60 frames = per frame is 16.66 milliseconds long. But 16.66 milliseconds multiplied by 60 = 999.99 milliseconds. That is ALMOST a second. And that means than there will be 59.99 frames in 999.99 milliseconds But we cannot handle frame fractions, we should round frames to integers. So 59.99 frames will be rounded to 60 frames
Remember a frame is 16.66 milliseconds long.
// Set the duration of your animation in milliseconds
int duration = 1000;
// Calculate the total number of frames
int totalFrames = ( duration / (1000 / 60) ).round();
// The first animation frame will be the number 1, the number 0 will be the start point
int currentFrame = 0;
// The animation function is triggered by first time more later in the code
// And when is triggered
void animation(num frame) {
// First we look the number of the frame we are going to run.
// When all the frames are complete the animation function will not be executed again
if ( totalFrames >= currentFrame ) {
// ===========================================
// Here what we are going to do in every frame
// ===========================================
// We get ready to execute the next frame
currentFrame++;
// When the time of this frame (16.66 milliseconds) is complete immediately starts the next frame.
window.animationFrame.then(animation);
}
}
// Here is triggered the animation by first time
window.animationFrame.then(animation);
Note:
1. I found a bug writing the smoothScrolling function, but do not worry, only affects in the Dart Virtual Machine, the compiled JavaScript works as expected. I am trying to find what is exactly what causes the bug and so can report it.
What I found is than using the number distancePerFrame within the animation function make than the function do not loop.
2. Technically this is not a 'smooth scrolling', is a 'linear scrolling'.
You can use the package animation to do the work
here an example of use:
import 'dart:html';
import 'package:animation/animation.dart');
main() {
var el = query('#box');
var properties = {
'left': 1000,
'top': 350
};
animate(el, properties: properties, duration: 5000);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With