Skip to content

Commit e9b0ce8

Browse files
committed
Update to improve sync scroll to edit performance and fix sync scroll behavior on many situations
1 parent 954137b commit e9b0ce8

2 files changed

Lines changed: 70 additions & 33 deletions

File tree

public/js/index.js

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -722,8 +722,11 @@ function windowResizeInner(callback) {
722722
if (loaded) {
723723
if (editor.getOption('scrollbarStyle') === 'native') {
724724
clearMap();
725-
syncScrollToView();
726-
syncScrollToEdit();
725+
if (editorHasFocus()) {
726+
syncScrollToView();
727+
} else {
728+
syncScrollToEdit();
729+
}
727730
updateScrollspy();
728731
if (callback && typeof callback === 'function')
729732
callback();
@@ -732,8 +735,11 @@ function windowResizeInner(callback) {
732735
editor.setOption('viewportMargin', Infinity);
733736
setTimeout(function () {
734737
clearMap();
735-
syncScrollToView();
736-
syncScrollToEdit();
738+
if (editorHasFocus()) {
739+
syncScrollToView();
740+
} else {
741+
syncScrollToEdit();
742+
}
737743
editor.setOption('viewportMargin', viewportMargin);
738744
//add or update user cursors
739745
for (var i = 0; i < onlineUsers.length; i++) {
@@ -774,6 +780,7 @@ function checkResponsive() {
774780
}
775781

776782
var lastEditorWidth = 0;
783+
var previousFocusOnEditor = null;
777784

778785
function checkEditorStyle() {
779786
var desireHeight = statusBar ? (ui.area.edit.height() - statusBar.outerHeight()) : ui.area.edit.height();
@@ -806,6 +813,11 @@ function checkEditorStyle() {
806813
}
807814
if (!ui.area.resize.syncToggle.length) {
808815
ui.area.resize.syncToggle = $('<button class="btn btn-lg btn-default ui-sync-toggle" title="Toggle sync scrolling"><i class="fa fa-link fa-fw"></i></button>');
816+
ui.area.resize.syncToggle.hover(function () {
817+
previousFocusOnEditor = editorHasFocus();
818+
}, function () {
819+
previousFocusOnEditor = null;
820+
});
809821
ui.area.resize.syncToggle.click(function () {
810822
syncscroll = !syncscroll;
811823
checkSyncToggle();
@@ -822,6 +834,13 @@ function checkEditorStyle() {
822834

823835
function checkSyncToggle() {
824836
if (syncscroll) {
837+
if (previousFocusOnEditor) {
838+
preventSyncScrollToView = false;
839+
syncScrollToView();
840+
} else {
841+
preventSyncScrollToEdit = false;
842+
syncScrollToEdit();
843+
}
825844
ui.area.resize.syncToggle.find('i').removeClass('fa-unlink').addClass('fa-link');
826845
} else {
827846
ui.area.resize.syncToggle.find('i').removeClass('fa-link').addClass('fa-unlink');
@@ -1003,9 +1022,14 @@ function changeMode(type) {
10031022
restoreInfo();
10041023

10051024
if (lastMode == modeType.view && currentMode == modeType.both) {
1006-
preventSyncScrollToView = true;
1025+
preventSyncScrollToView = 2;
10071026
syncScrollToEdit();
10081027
}
1028+
1029+
if (lastMode == modeType.edit && currentMode == modeType.both) {
1030+
preventSyncScrollToEdit = 2;
1031+
syncScrollToView();
1032+
}
10091033

10101034
if (lastMode != modeType.edit && currentMode == modeType.edit) {
10111035
editor.refresh();
@@ -2595,8 +2619,11 @@ function updateViewInner() {
25952619
clearMap();
25962620
//buildMap();
25972621
updateTitleReminder();
2598-
syncScrollToView();
2599-
syncScrollToEdit();
2622+
if (editorHasFocus()) {
2623+
syncScrollToView();
2624+
} else {
2625+
syncScrollToEdit();
2626+
}
26002627
}
26012628

26022629
var updateHistoryDebounce = 600;

public/js/syncscroll.js

Lines changed: 36 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -110,17 +110,15 @@ var syncscroll = true;
110110
var preventSyncScrollToEdit = false;
111111
var preventSyncScrollToView = false;
112112

113-
var editScrollThrottle = 1;
113+
var editScrollThrottle = 2;
114114
var viewScrollThrottle = 10;
115115
var buildMapThrottle = 100;
116116

117117
var viewScrolling = false;
118-
var viewScrollingDelay = 200;
119-
var viewScrollingTimer = null;
118+
var viewScrollingDebounce = 200;
120119

121120
var editScrolling = false;
122-
var editScrollingDelay = 100;
123-
var editScrollingTimer = null;
121+
var editScrollingDebounce = 200;
124122

125123
if (editor.getOption('scrollbarStyle') === 'native') {
126124
ui.area.codemirrorScroll.on('scroll', _.throttle(syncScrollToView, editScrollThrottle));
@@ -145,7 +143,7 @@ var buildMap = _.throttle(buildMapInner, buildMapThrottle);
145143
// Build offsets for each line (lines can be wrapped)
146144
// That's a bit dirty to process each line everytime, but ok for demo.
147145
// Optimizations are required only for big texts.
148-
function buildMapInner(syncBack) {
146+
function buildMapInner(callback) {
149147
var i, offset, nonEmptyList, pos, a, b, _lineHeightMap, linesCount,
150148
acc, _scrollMap;
151149

@@ -217,12 +215,15 @@ function buildMapInner(syncBack) {
217215
scrollMap = _scrollMap;
218216
lineHeightMap = _lineHeightMap;
219217

220-
if (loaded && syncBack) {
221-
syncScrollToView();
222-
syncScrollToEdit();
223-
}
218+
if (loaded && callback) callback();
224219
}
225220

221+
// sync view scroll progress to edit
222+
var viewScrollingTimeout = _.debounce(viewScrollingTimeoutInner, viewScrollingDebounce);
223+
224+
function viewScrollingTimeoutInner() {
225+
viewScrolling = false;
226+
}
226227

227228
function syncScrollToEdit(e) {
228229
if (currentMode != modeType.both || !syncscroll) return;
@@ -235,7 +236,7 @@ function syncScrollToEdit(e) {
235236
return;
236237
}
237238
if (!scrollMap || !lineHeightMap) {
238-
buildMap(true);
239+
buildMap(syncScrollToEdit);
239240
return;
240241
}
241242
if (editScrolling) return;
@@ -272,21 +273,30 @@ function syncScrollToEdit(e) {
272273
if (scrollInfo.height > scrollInfo.clientHeight && scrollTop >= preLastLinePos) {
273274
posTo = preLastLineHeight;
274275
topDiffPercent = (scrollTop - preLastLinePos) / (viewBottom - preLastLinePos);
275-
posToNextDiff = Math.ceil(textHeight * topDiffPercent);
276+
posToNextDiff = textHeight * topDiffPercent;
277+
posTo += Math.floor(posToNextDiff);
276278
} else {
277279
posTo = lineNo * textHeight;
278280
topDiffPercent = (scrollTop - scrollMap[lineNo]) / (scrollMap[lineNo + lineDiff] - scrollMap[lineNo]);
279-
posToNextDiff = Math.ceil(textHeight * lineDiff * topDiffPercent);
281+
posToNextDiff = textHeight * lineDiff * topDiffPercent;
282+
posTo += Math.floor(posToNextDiff);
280283
}
281284

282-
editor.scrollTo(0, posTo + posToNextDiff);
283-
preventSyncScrollToView = true;
285+
var posDiff = Math.abs(scrollInfo.top - posTo);
286+
var duration = posDiff / 50;
287+
ui.area.codemirrorScroll.stop(true, true).animate({
288+
scrollTop: posTo
289+
}, duration >= 100 ? duration : 100, "linear");
284290

285291
viewScrolling = true;
286-
clearTimeout(viewScrollingTimer);
287-
viewScrollingTimer = setTimeout(function () {
288-
viewScrolling = false;
289-
}, viewScrollingDelay);
292+
viewScrollingTimeout();
293+
}
294+
295+
// sync edit scroll progress to view
296+
var editScrollingTimeout = _.debounce(editScrollingTimeoutInner, editScrollingDebounce);
297+
298+
function editScrollingTimeoutInner() {
299+
editScrolling = false;
290300
}
291301

292302
function syncScrollToView(event, _lineNo) {
@@ -300,7 +310,7 @@ function syncScrollToView(event, _lineNo) {
300310
return;
301311
}
302312
if (!scrollMap || !lineHeightMap) {
303-
buildMap(true);
313+
buildMap(syncScrollToView);
304314
return;
305315
}
306316
if (viewScrolling) return;
@@ -328,12 +338,12 @@ function syncScrollToView(event, _lineNo) {
328338
posTo = scrollMap[lineHeightMap[_lineNo]];
329339
}
330340

331-
ui.area.view.stop(true, true).scrollTop(posTo);
332-
preventSyncScrollToEdit = true;
341+
var posDiff = Math.abs(ui.area.view.scrollTop() - posTo);
342+
var duration = posDiff / 50;
343+
ui.area.view.stop(true, true).animate({
344+
scrollTop: posTo
345+
}, duration >= 100 ? duration : 100, "linear");
333346

334347
editScrolling = true;
335-
clearTimeout(editScrollingTimer);
336-
editScrollingTimer = setTimeout(function () {
337-
editScrolling = false;
338-
}, editScrollingDelay);
348+
editScrollingTimeout();
339349
}

0 commit comments

Comments
 (0)