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