From 2c60f0dd671b63885ffcbc494025ef037fdf34fd Mon Sep 17 00:00:00 2001
From: Cheng-Han, Wu
Date: Sun, 29 May 2016 13:58:32 +0800
Subject: Improve syncscroll performance and accuracy with few UX tweaks

---
 public/js/index.js      | 34 +++++++++----------
 public/js/syncscroll.js | 90 +++++++++++++++++++++++++++----------------------
 2 files changed, 64 insertions(+), 60 deletions(-)

(limited to 'public')

diff --git a/public/js/index.js b/public/js/index.js
index 92a06a53..22652d0e 100644
--- a/public/js/index.js
+++ b/public/js/index.js
@@ -713,6 +713,14 @@ $(window).error(function () {
     //setNeedRefresh();
 });
 
+function autoSyncscroll() {
+    if (editorHasFocus()) {
+        syncScrollToView();
+    } else {
+        syncScrollToEdit();
+    }
+}
+
 var windowResizeDebounce = 200;
 var windowResize = _.debounce(windowResizeInner, windowResizeDebounce);
 
@@ -727,11 +735,7 @@ function windowResizeInner(callback) {
         if (editor.getOption('scrollbarStyle') === 'native') {
             setTimeout(function () {
                 clearMap();
-                if (editorHasFocus()) {
-                    syncScrollToView();
-                } else {
-                    syncScrollToEdit();
-                }
+                autoSyncscroll();
                 updateScrollspy();
                 if (callback && typeof callback === 'function')
                     callback();
@@ -741,11 +745,7 @@ function windowResizeInner(callback) {
             editor.setOption('viewportMargin', Infinity);
             setTimeout(function () {
                 clearMap();
-                if (editorHasFocus()) {
-                    syncScrollToView();
-                } else {
-                    syncScrollToEdit();
-                }
+                autoSyncscroll();
                 editor.setOption('viewportMargin', viewportMargin);
                 //add or update user cursors
                 for (var i = 0; i < onlineUsers.length; i++) {
@@ -1029,12 +1029,12 @@ function changeMode(type) {
 
     if (lastMode == modeType.view && currentMode == modeType.both) {
         preventSyncScrollToView = 2;
-        syncScrollToEdit();
+        syncScrollToEdit(null, true);
     }
     
     if (lastMode == modeType.edit && currentMode == modeType.both) {
         preventSyncScrollToEdit = 2;
-        syncScrollToView();
+        syncScrollToView(null, true);
     }
     
     if (lastMode == modeType.both && currentMode != modeType.both) {
@@ -2458,10 +2458,10 @@ editor.on('beforeChange', function (cm, change) {
         cmClient.editorAdapter.ignoreNextChange = true;
 });
 editor.on('cut', function () {
-    windowResize(); //workaround for scrollMap
+    //na
 });
 editor.on('paste', function () {
-    windowResize(); //workaround for scrollMap
+    //na
 });
 editor.on('changes', function (cm, changes) {
     updateHistory();
@@ -2630,11 +2630,7 @@ function updateViewInner() {
     clearMap();
     //buildMap();
     updateTitleReminder();
-    if (editorHasFocus()) {
-        syncScrollToView();
-    } else {
-        syncScrollToEdit();
-    }
+    autoSyncscroll();
 }
 
 var updateHistoryDebounce = 600;
diff --git a/public/js/syncscroll.js b/public/js/syncscroll.js
index c8b45e7f..83c9a69c 100644
--- a/public/js/syncscroll.js
+++ b/public/js/syncscroll.js
@@ -110,7 +110,7 @@ var syncscroll = true;
 var preventSyncScrollToEdit = false;
 var preventSyncScrollToView = false;
 
-var editScrollThrottle = 2;
+var editScrollThrottle = 10;
 var viewScrollThrottle = 10;
 var buildMapThrottle = 100;
 
@@ -214,7 +214,7 @@ function buildMapInner(callback) {
 // sync view scroll progress to edit
 var viewScrollingTimer = null;
 
-function syncScrollToEdit(e) {
+function syncScrollToEdit(event, preventAnimate) {
     if (currentMode != modeType.both || !syncscroll) return;
     if (preventSyncScrollToEdit) {
         if (typeof preventSyncScrollToEdit === 'number') {
@@ -225,7 +225,9 @@ function syncScrollToEdit(e) {
         return;
     }
     if (!scrollMap || !lineHeightMap) {
-        buildMap(syncScrollToEdit);
+        buildMap(function () {
+            syncScrollToEdit(event, preventAnimate);
+        });
         return;
     }
     if (editScrolling) return;
@@ -263,24 +265,28 @@ function syncScrollToEdit(e) {
         posTo = preLastLineHeight;
         topDiffPercent = (scrollTop - preLastLinePos) / (viewBottom - preLastLinePos);
         posToNextDiff = textHeight * topDiffPercent;
-        posTo += Math.floor(posToNextDiff);
+        posTo += Math.ceil(posToNextDiff);
     } else {
         posTo = lineNo * textHeight;
         topDiffPercent = (scrollTop - scrollMap[lineNo]) / (scrollMap[lineNo + lineDiff] - scrollMap[lineNo]);
         posToNextDiff = textHeight * lineDiff * topDiffPercent;
-        posTo += Math.floor(posToNextDiff);
+        posTo += Math.ceil(posToNextDiff);
     }
     
-    var posDiff = Math.abs(scrollInfo.top - posTo);
-    var duration = posDiff / 50;
-    duration = duration >= 100 ? duration : 100;
-    ui.area.codemirrorScroll.stop(true, true).animate({
-        scrollTop: posTo
-    }, duration, "linear");
+    if (preventAnimate) {
+        ui.area.codemirrorScroll.scrollTop(posTo);
+    } else {
+        var posDiff = Math.abs(scrollInfo.top - posTo);
+        var duration = posDiff / 50;
+        duration = duration >= 100 ? duration : 100;
+        ui.area.codemirrorScroll.stop(true, true).animate({
+            scrollTop: posTo
+        }, duration, "linear");
+    }
     
     viewScrolling = true;
     clearTimeout(viewScrollingTimer);
-    viewScrollingTimer = setTimeout(viewScrollingTimeoutInner, duration * 1.2);
+    viewScrollingTimer = setTimeout(viewScrollingTimeoutInner, duration * 1.5);
 }
 
 function viewScrollingTimeoutInner() {
@@ -290,7 +296,7 @@ function viewScrollingTimeoutInner() {
 // sync edit scroll progress to view
 var editScrollingTimer = null;
 
-function syncScrollToView(event, _lineNo) {
+function syncScrollToView(event, preventAnimate) {
     if (currentMode != modeType.both || !syncscroll) return;
     if (preventSyncScrollToView) {
         if (typeof preventSyncScrollToView === 'number') {
@@ -301,44 +307,46 @@ function syncScrollToView(event, _lineNo) {
         return;
     }
     if (!scrollMap || !lineHeightMap) {
-        buildMap(syncScrollToView);
+        buildMap(function () {
+            syncScrollToView(event, preventAnimate);
+        });
         return;
     }
     if (viewScrolling) return;
     
-    if (!_lineNo) {
-        var lineNo, posTo;
-        var topDiffPercent, posToNextDiff;
-        var scrollInfo = editor.getScrollInfo();
-        var textHeight = editor.defaultTextHeight();
-        lineNo = Math.floor(scrollInfo.top / textHeight);
-        // if reach the last line, will start lerp to the bottom
-        var diffToBottom = (scrollInfo.top + scrollInfo.clientHeight) - (scrollInfo.height - textHeight);
-        if (scrollInfo.height > scrollInfo.clientHeight && diffToBottom > 0) {
-            topDiffPercent = diffToBottom / textHeight;
-            posTo = scrollMap[lineNo + 1];
-            posToNextDiff = (viewBottom - posTo) * topDiffPercent;
-            posTo += Math.floor(posToNextDiff);
-        } else {
-            topDiffPercent = (scrollInfo.top % textHeight) / textHeight;
-            posTo = scrollMap[lineNo];
-            posToNextDiff = (scrollMap[lineNo + 1] - posTo) * topDiffPercent;
-            posTo += Math.floor(posToNextDiff);
-        }
+    var lineNo, posTo;
+    var topDiffPercent, posToNextDiff;
+    var scrollInfo = editor.getScrollInfo();
+    var textHeight = editor.defaultTextHeight();
+    lineNo = Math.floor(scrollInfo.top / textHeight);
+    // if reach the last line, will start lerp to the bottom
+    var diffToBottom = (scrollInfo.top + scrollInfo.clientHeight) - (scrollInfo.height - textHeight);
+    if (scrollInfo.height > scrollInfo.clientHeight && diffToBottom > 0) {
+        topDiffPercent = diffToBottom / textHeight;
+        posTo = scrollMap[lineNo + 1];
+        posToNextDiff = (viewBottom - posTo) * topDiffPercent;
+        posTo += Math.floor(posToNextDiff);
     } else {
-        posTo = scrollMap[lineHeightMap[_lineNo]];
+        topDiffPercent = (scrollInfo.top % textHeight) / textHeight;
+        posTo = scrollMap[lineNo];
+        posToNextDiff = (scrollMap[lineNo + 1] - posTo) * topDiffPercent;
+        posTo += Math.floor(posToNextDiff);
     }
     
-    var posDiff = Math.abs(ui.area.view.scrollTop() - posTo);
-    var duration = posDiff / 50;
-    duration = duration >= 100 ? duration : 100;
-    ui.area.view.stop(true, true).animate({
-        scrollTop: posTo
-    }, duration, "linear");
+    if (preventAnimate) {
+        ui.area.view.scrollTop(posTo);
+    } else {
+        var posDiff = Math.abs(ui.area.view.scrollTop() - posTo);
+        var duration = posDiff / 50;
+        duration = duration >= 100 ? duration : 100;
+        ui.area.view.stop(true, true).animate({
+            scrollTop: posTo
+        }, duration, "linear");
+    }
     
     editScrolling = true;
     clearTimeout(editScrollingTimer);
-    editScrollingTimer = setTimeout(editScrollingTimeoutInner, duration * 1.2);
+    editScrollingTimer = setTimeout(editScrollingTimeoutInner, duration * 1.5);
 }
 
 function editScrollingTimeoutInner() {
-- 
cgit v1.2.3