+
{{ proj.started_at | short_date }}
@@ -115,7 +115,7 @@
return pluralize(diff/month, 'month');
}
return pluralize(diff/year, 'year');
- }
+ },
}
})
export default class Timeline extends Vue {
diff --git a/src/service/scroller.ts b/src/service/scroller.ts
new file mode 100644
index 0000000..d3498bf
--- /dev/null
+++ b/src/service/scroller.ts
@@ -0,0 +1,57 @@
+
+let scroll_interval: number;
+
+// scroll time in milliseconds
+const SCROLL_MS = 500;
+const SCROLL_MS_STEP = 5;
+
+// go() scrolls to the element with the specified id with an optional offset.
+// It achieves a smooth scrolling compared to the direct default one.
+export function go(id: string, offset: number|undefined): void {
+ // find item with id
+ const item = document.querySelector(`#${id}`) as HTMLElement;
+ if( item == null ){
+ console.warn(`item with id '${id}' not found`);
+ return;
+ }
+
+ // get item absolute y coordinates
+ let targety = absY(item, 0);
+ if( offset != null ){
+ targety += offset;
+ }
+
+ clearInterval(scroll_interval);
+ const step = (targety - document.body.scrollTop) / (SCROLL_MS / SCROLL_MS_STEP);
+ scroll_interval = setInterval(
+ () => smooth_scroll(targety, step),
+ SCROLL_MS_STEP
+ );
+
+}
+
+function absY(item: HTMLElement|null, children_y: number): number {
+ if( item == null || item == document.body ){
+ return children_y;
+ }
+ return absY(item.parentElement, children_y + item.offsetTop);
+}
+
+// incremental smooth scroll
+function smooth_scroll(target: number, step: number) {
+ const cur = document.body.scrollTop;
+ const max = (document.body as any).scrollTopMax;
+
+ // moving up & reached top or target -> stop
+ const upLimit = ( step < 0 && (cur <= 0 || cur <= target) );
+ // moving down & reached bottom or target -> stop
+ const downLimit = ( step > 0 && (cur >= max || cur >= target) );
+
+ if( upLimit || downLimit ){
+ clearInterval(scroll_interval);
+ document.body.scroll(0, target);
+ return
+ }
+
+ document.body.scroll(0, cur + step);
+}
\ No newline at end of file