Improve syncscroll performance and accuracy with few UX tweaks
This commit is contained in:
		
							parent
							
								
									20fbc9957f
								
							
						
					
					
						commit
						2c60f0dd67
					
				| @ -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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user