Don't reset cache while zooming using a gesture (#1103)
* Don't reset cache while zooming using a gesture This reuses the cached canvas while the gesture is happening. Once it has stop updating, then recompute the cache with the proper zoom. This should massively improve performance when panning on big scenes on mobile Fixes #1056 * update snapshot tests
This commit is contained in:
		
							parent
							
								
									95eaadeb85
								
							
						
					
					
						commit
						24fa657093
					
				|  | @ -0,0 +1 @@ | |||
| {} | ||||
|  | @ -35,6 +35,7 @@ export function getDefaultAppState(): AppState { | |||
|     lastPointerDownWith: "mouse", | ||||
|     selectedElementIds: {}, | ||||
|     collaborators: new Map(), | ||||
|     shouldCacheIgnoreZoom: false, | ||||
|   }; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -481,6 +481,7 @@ export class App extends React.Component<any, AppState> { | |||
|         viewBackgroundColor: this.state.viewBackgroundColor, | ||||
|         zoom: this.state.zoom, | ||||
|         remotePointerViewportCoords: pointerViewportCoords, | ||||
|         shouldCacheIgnoreZoom: this.state.shouldCacheIgnoreZoom, | ||||
|       }, | ||||
|       { | ||||
|         renderOptimizations: true, | ||||
|  | @ -1247,7 +1248,9 @@ export class App extends React.Component<any, AppState> { | |||
|         scrollX: normalizeScroll(this.state.scrollX + deltaX / this.state.zoom), | ||||
|         scrollY: normalizeScroll(this.state.scrollY + deltaY / this.state.zoom), | ||||
|         zoom: getNormalizedZoom(gesture.initialScale! * scaleFactor), | ||||
|         shouldCacheIgnoreZoom: true, | ||||
|       }); | ||||
|       this.resetShouldCacheIgnoreZoomDebounced(); | ||||
|     } else { | ||||
|       gesture.lastCenter = gesture.initialDistance = gesture.initialScale = null; | ||||
|     } | ||||
|  | @ -2553,6 +2556,10 @@ export class App extends React.Component<any, AppState> { | |||
|     this.socket && this.broadcastMouseLocation({ pointerCoords }); | ||||
|   }; | ||||
| 
 | ||||
|   private resetShouldCacheIgnoreZoomDebounced = debounce(() => { | ||||
|     this.setState({ shouldCacheIgnoreZoom: false }); | ||||
|   }, 1000); | ||||
| 
 | ||||
|   private saveDebounced = debounce(() => { | ||||
|     saveToLocalStorage(globalSceneState.getAllElements(), this.state); | ||||
|   }, 300); | ||||
|  |  | |||
|  | @ -245,7 +245,11 @@ function generateElement( | |||
|   } | ||||
|   const zoom = sceneState ? sceneState.zoom : 1; | ||||
|   const prevElementWithCanvas = elementWithCanvasCache.get(element); | ||||
|   if (!prevElementWithCanvas || prevElementWithCanvas.canvasZoom !== zoom) { | ||||
|   const shouldRegenerateBecauseZoom = | ||||
|     prevElementWithCanvas && | ||||
|     prevElementWithCanvas.canvasZoom !== zoom && | ||||
|     !sceneState?.shouldCacheIgnoreZoom; | ||||
|   if (!prevElementWithCanvas || shouldRegenerateBecauseZoom) { | ||||
|     const elementWithCanvas = generateElementCanvas(element, zoom); | ||||
|     elementWithCanvasCache.set(element, elementWithCanvas); | ||||
|     return elementWithCanvas; | ||||
|  | @ -261,8 +265,8 @@ function drawElementFromCanvas( | |||
| ) { | ||||
|   context.scale(1 / window.devicePixelRatio, 1 / window.devicePixelRatio); | ||||
|   context.translate( | ||||
|     -CANVAS_PADDING / sceneState.zoom, | ||||
|     -CANVAS_PADDING / sceneState.zoom, | ||||
|     -CANVAS_PADDING / elementWithCanvas.canvasZoom, | ||||
|     -CANVAS_PADDING / elementWithCanvas.canvasZoom, | ||||
|   ); | ||||
|   context.drawImage( | ||||
|     elementWithCanvas.canvas!, | ||||
|  | @ -276,12 +280,12 @@ function drawElementFromCanvas( | |||
|         (Math.floor(elementWithCanvas.element.y) + sceneState.scrollY) * | ||||
|           window.devicePixelRatio, | ||||
|     ), | ||||
|     elementWithCanvas.canvas!.width / sceneState.zoom, | ||||
|     elementWithCanvas.canvas!.height / sceneState.zoom, | ||||
|     elementWithCanvas.canvas!.width / elementWithCanvas.canvasZoom, | ||||
|     elementWithCanvas.canvas!.height / elementWithCanvas.canvasZoom, | ||||
|   ); | ||||
|   context.translate( | ||||
|     CANVAS_PADDING / sceneState.zoom, | ||||
|     CANVAS_PADDING / sceneState.zoom, | ||||
|     CANVAS_PADDING / elementWithCanvas.canvasZoom, | ||||
|     CANVAS_PADDING / elementWithCanvas.canvasZoom, | ||||
|   ); | ||||
|   context.scale(window.devicePixelRatio, window.devicePixelRatio); | ||||
| } | ||||
|  |  | |||
|  | @ -50,6 +50,7 @@ export function exportToCanvas( | |||
|       scrollY: normalizeScroll(-minY + exportPadding), | ||||
|       zoom: 1, | ||||
|       remotePointerViewportCoords: {}, | ||||
|       shouldCacheIgnoreZoom: false, | ||||
|     }, | ||||
|     { | ||||
|       renderScrollbars: false, | ||||
|  |  | |||
|  | @ -7,6 +7,7 @@ export type SceneState = { | |||
|   // null indicates transparent bg
 | ||||
|   viewBackgroundColor: string | null; | ||||
|   zoom: number; | ||||
|   shouldCacheIgnoreZoom: boolean; | ||||
|   remotePointerViewportCoords: { [id: string]: { x: number; y: number } }; | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -33,6 +33,7 @@ Object { | |||
|     "id2": true, | ||||
|   }, | ||||
|   "selectionElement": null, | ||||
|   "shouldCacheIgnoreZoom": false, | ||||
|   "viewBackgroundColor": "#ffffff", | ||||
|   "zoom": 1, | ||||
| } | ||||
|  | @ -211,6 +212,7 @@ Object { | |||
|     "id0": true, | ||||
|   }, | ||||
|   "selectionElement": null, | ||||
|   "shouldCacheIgnoreZoom": false, | ||||
|   "viewBackgroundColor": "#ffffff", | ||||
|   "zoom": 1, | ||||
| } | ||||
|  | @ -316,6 +318,7 @@ Object { | |||
|     "id0": true, | ||||
|   }, | ||||
|   "selectionElement": null, | ||||
|   "shouldCacheIgnoreZoom": false, | ||||
|   "viewBackgroundColor": "#ffffff", | ||||
|   "zoom": 1, | ||||
| } | ||||
|  | @ -558,6 +561,7 @@ Object { | |||
|     "id1": true, | ||||
|   }, | ||||
|   "selectionElement": null, | ||||
|   "shouldCacheIgnoreZoom": false, | ||||
|   "viewBackgroundColor": "#ffffff", | ||||
|   "zoom": 1, | ||||
| } | ||||
|  | @ -699,6 +703,7 @@ Object { | |||
|     "id2": true, | ||||
|   }, | ||||
|   "selectionElement": null, | ||||
|   "shouldCacheIgnoreZoom": false, | ||||
|   "viewBackgroundColor": "#ffffff", | ||||
|   "zoom": 1, | ||||
| } | ||||
|  | @ -873,6 +878,7 @@ Object { | |||
|     "id2": true, | ||||
|   }, | ||||
|   "selectionElement": null, | ||||
|   "shouldCacheIgnoreZoom": false, | ||||
|   "viewBackgroundColor": "#ffffff", | ||||
|   "zoom": 1, | ||||
| } | ||||
|  | @ -1053,6 +1059,7 @@ Object { | |||
|     "id3": true, | ||||
|   }, | ||||
|   "selectionElement": null, | ||||
|   "shouldCacheIgnoreZoom": false, | ||||
|   "viewBackgroundColor": "#ffffff", | ||||
|   "zoom": 1, | ||||
| } | ||||
|  | @ -1320,6 +1327,7 @@ Object { | |||
|   "scrolledOutside": false, | ||||
|   "selectedElementIds": Object {}, | ||||
|   "selectionElement": null, | ||||
|   "shouldCacheIgnoreZoom": false, | ||||
|   "viewBackgroundColor": "#ffffff", | ||||
|   "zoom": 1, | ||||
| } | ||||
|  | @ -1895,6 +1903,7 @@ Object { | |||
|     "id0": true, | ||||
|   }, | ||||
|   "selectionElement": null, | ||||
|   "shouldCacheIgnoreZoom": false, | ||||
|   "viewBackgroundColor": "#ffffff", | ||||
|   "zoom": 1, | ||||
| } | ||||
|  | @ -2000,6 +2009,7 @@ Object { | |||
|     "id0": true, | ||||
|   }, | ||||
|   "selectionElement": null, | ||||
|   "shouldCacheIgnoreZoom": false, | ||||
|   "viewBackgroundColor": "#ffffff", | ||||
|   "zoom": 1, | ||||
| } | ||||
|  | @ -2105,6 +2115,7 @@ Object { | |||
|     "id0": true, | ||||
|   }, | ||||
|   "selectionElement": null, | ||||
|   "shouldCacheIgnoreZoom": false, | ||||
|   "viewBackgroundColor": "#ffffff", | ||||
|   "zoom": 1, | ||||
| } | ||||
|  | @ -2210,6 +2221,7 @@ Object { | |||
|     "id0": true, | ||||
|   }, | ||||
|   "selectionElement": null, | ||||
|   "shouldCacheIgnoreZoom": false, | ||||
|   "viewBackgroundColor": "#ffffff", | ||||
|   "zoom": 1, | ||||
| } | ||||
|  | @ -2337,6 +2349,7 @@ Object { | |||
|     "id0": true, | ||||
|   }, | ||||
|   "selectionElement": null, | ||||
|   "shouldCacheIgnoreZoom": false, | ||||
|   "viewBackgroundColor": "#ffffff", | ||||
|   "zoom": 1, | ||||
| } | ||||
|  | @ -2464,6 +2477,7 @@ Object { | |||
|     "id0": true, | ||||
|   }, | ||||
|   "selectionElement": null, | ||||
|   "shouldCacheIgnoreZoom": false, | ||||
|   "viewBackgroundColor": "#ffffff", | ||||
|   "zoom": 1, | ||||
| } | ||||
|  | @ -2591,6 +2605,7 @@ Object { | |||
|     "id0": true, | ||||
|   }, | ||||
|   "selectionElement": null, | ||||
|   "shouldCacheIgnoreZoom": false, | ||||
|   "viewBackgroundColor": "#ffffff", | ||||
|   "zoom": 1, | ||||
| } | ||||
|  | @ -2696,6 +2711,7 @@ Object { | |||
|     "id0": true, | ||||
|   }, | ||||
|   "selectionElement": null, | ||||
|   "shouldCacheIgnoreZoom": false, | ||||
|   "viewBackgroundColor": "#ffffff", | ||||
|   "zoom": 1, | ||||
| } | ||||
|  | @ -2801,6 +2817,7 @@ Object { | |||
|     "id0": true, | ||||
|   }, | ||||
|   "selectionElement": null, | ||||
|   "shouldCacheIgnoreZoom": false, | ||||
|   "viewBackgroundColor": "#ffffff", | ||||
|   "zoom": 1, | ||||
| } | ||||
|  | @ -2928,6 +2945,7 @@ Object { | |||
|     "id0": true, | ||||
|   }, | ||||
|   "selectionElement": null, | ||||
|   "shouldCacheIgnoreZoom": false, | ||||
|   "viewBackgroundColor": "#ffffff", | ||||
|   "zoom": 1, | ||||
| } | ||||
|  | @ -3033,6 +3051,7 @@ Object { | |||
|     "id0": true, | ||||
|   }, | ||||
|   "selectionElement": null, | ||||
|   "shouldCacheIgnoreZoom": true, | ||||
|   "viewBackgroundColor": "#ffffff", | ||||
|   "zoom": 1, | ||||
| } | ||||
|  | @ -3098,6 +3117,7 @@ Object { | |||
|     "id9": true, | ||||
|   }, | ||||
|   "selectionElement": null, | ||||
|   "shouldCacheIgnoreZoom": false, | ||||
|   "viewBackgroundColor": "#ffffff", | ||||
|   "zoom": 1, | ||||
| } | ||||
|  | @ -3754,6 +3774,7 @@ Object { | |||
|     "id7": true, | ||||
|   }, | ||||
|   "selectionElement": null, | ||||
|   "shouldCacheIgnoreZoom": false, | ||||
|   "viewBackgroundColor": "#ffffff", | ||||
|   "zoom": 1, | ||||
| } | ||||
|  | @ -4102,6 +4123,7 @@ Object { | |||
|     "id5": true, | ||||
|   }, | ||||
|   "selectionElement": null, | ||||
|   "shouldCacheIgnoreZoom": false, | ||||
|   "viewBackgroundColor": "#ffffff", | ||||
|   "zoom": 1, | ||||
| } | ||||
|  | @ -4380,6 +4402,7 @@ Object { | |||
|     "id3": true, | ||||
|   }, | ||||
|   "selectionElement": null, | ||||
|   "shouldCacheIgnoreZoom": false, | ||||
|   "viewBackgroundColor": "#ffffff", | ||||
|   "zoom": 1, | ||||
| } | ||||
|  | @ -4588,6 +4611,7 @@ Object { | |||
|     "id1": true, | ||||
|   }, | ||||
|   "selectionElement": null, | ||||
|   "shouldCacheIgnoreZoom": false, | ||||
|   "viewBackgroundColor": "#ffffff", | ||||
|   "zoom": 1, | ||||
| } | ||||
|  | @ -4742,6 +4766,7 @@ Object { | |||
|     "id9": true, | ||||
|   }, | ||||
|   "selectionElement": null, | ||||
|   "shouldCacheIgnoreZoom": false, | ||||
|   "viewBackgroundColor": "#ffffff", | ||||
|   "zoom": 1, | ||||
| } | ||||
|  | @ -5370,6 +5395,7 @@ Object { | |||
|     "id9": true, | ||||
|   }, | ||||
|   "selectionElement": null, | ||||
|   "shouldCacheIgnoreZoom": false, | ||||
|   "viewBackgroundColor": "#ffffff", | ||||
|   "zoom": 1, | ||||
| } | ||||
|  | @ -5928,6 +5954,7 @@ Object { | |||
|     "id9": true, | ||||
|   }, | ||||
|   "selectionElement": null, | ||||
|   "shouldCacheIgnoreZoom": false, | ||||
|   "viewBackgroundColor": "#ffffff", | ||||
|   "zoom": 1, | ||||
| } | ||||
|  | @ -6416,6 +6443,7 @@ Object { | |||
|     "id9": true, | ||||
|   }, | ||||
|   "selectionElement": null, | ||||
|   "shouldCacheIgnoreZoom": false, | ||||
|   "viewBackgroundColor": "#ffffff", | ||||
|   "zoom": 1, | ||||
| } | ||||
|  | @ -6835,6 +6863,7 @@ Object { | |||
|     "id8": true, | ||||
|   }, | ||||
|   "selectionElement": null, | ||||
|   "shouldCacheIgnoreZoom": false, | ||||
|   "viewBackgroundColor": "#ffffff", | ||||
|   "zoom": 1, | ||||
| } | ||||
|  | @ -7218,6 +7247,7 @@ Object { | |||
|     "id6": true, | ||||
|   }, | ||||
|   "selectionElement": null, | ||||
|   "shouldCacheIgnoreZoom": false, | ||||
|   "viewBackgroundColor": "#ffffff", | ||||
|   "zoom": 1, | ||||
| } | ||||
|  | @ -7531,6 +7561,7 @@ Object { | |||
|     "id4": true, | ||||
|   }, | ||||
|   "selectionElement": null, | ||||
|   "shouldCacheIgnoreZoom": false, | ||||
|   "viewBackgroundColor": "#ffffff", | ||||
|   "zoom": 1, | ||||
| } | ||||
|  | @ -7774,6 +7805,7 @@ Object { | |||
|     "id2": true, | ||||
|   }, | ||||
|   "selectionElement": null, | ||||
|   "shouldCacheIgnoreZoom": false, | ||||
|   "viewBackgroundColor": "#ffffff", | ||||
|   "zoom": 1, | ||||
| } | ||||
|  | @ -7963,6 +7995,7 @@ Object { | |||
|     "id9": true, | ||||
|   }, | ||||
|   "selectionElement": null, | ||||
|   "shouldCacheIgnoreZoom": false, | ||||
|   "viewBackgroundColor": "#ffffff", | ||||
|   "zoom": 1, | ||||
| } | ||||
|  | @ -8626,6 +8659,7 @@ Object { | |||
|     "id9": true, | ||||
|   }, | ||||
|   "selectionElement": null, | ||||
|   "shouldCacheIgnoreZoom": false, | ||||
|   "viewBackgroundColor": "#ffffff", | ||||
|   "zoom": 1, | ||||
| } | ||||
|  | @ -9219,6 +9253,7 @@ Object { | |||
|     "id9": true, | ||||
|   }, | ||||
|   "selectionElement": null, | ||||
|   "shouldCacheIgnoreZoom": false, | ||||
|   "viewBackgroundColor": "#ffffff", | ||||
|   "zoom": 1, | ||||
| } | ||||
|  | @ -9742,6 +9777,7 @@ Object { | |||
|     "id9": true, | ||||
|   }, | ||||
|   "selectionElement": null, | ||||
|   "shouldCacheIgnoreZoom": false, | ||||
|   "viewBackgroundColor": "#ffffff", | ||||
|   "zoom": 1, | ||||
| } | ||||
|  | @ -10191,6 +10227,7 @@ Object { | |||
|     "id4": true, | ||||
|   }, | ||||
|   "selectionElement": null, | ||||
|   "shouldCacheIgnoreZoom": false, | ||||
|   "viewBackgroundColor": "#ffffff", | ||||
|   "zoom": 1, | ||||
| } | ||||
|  | @ -10419,6 +10456,7 @@ Object { | |||
|   "scrolledOutside": false, | ||||
|   "selectedElementIds": Object {}, | ||||
|   "selectionElement": null, | ||||
|   "shouldCacheIgnoreZoom": false, | ||||
|   "viewBackgroundColor": "#ffffff", | ||||
|   "zoom": 1, | ||||
| } | ||||
|  | @ -10468,6 +10506,7 @@ Object { | |||
|     "id1": true, | ||||
|   }, | ||||
|   "selectionElement": null, | ||||
|   "shouldCacheIgnoreZoom": true, | ||||
|   "viewBackgroundColor": "#ffffff", | ||||
|   "zoom": 1, | ||||
| } | ||||
|  | @ -10517,6 +10556,7 @@ Object { | |||
|     "id2": true, | ||||
|   }, | ||||
|   "selectionElement": null, | ||||
|   "shouldCacheIgnoreZoom": false, | ||||
|   "viewBackgroundColor": "#ffffff", | ||||
|   "zoom": 1, | ||||
| } | ||||
|  | @ -10785,6 +10825,7 @@ Object { | |||
|   "scrolledOutside": false, | ||||
|   "selectedElementIds": Object {}, | ||||
|   "selectionElement": null, | ||||
|   "shouldCacheIgnoreZoom": false, | ||||
|   "viewBackgroundColor": "#ffffff", | ||||
|   "zoom": 1, | ||||
| } | ||||
|  |  | |||
|  | @ -42,6 +42,7 @@ export type AppState = { | |||
|   lastPointerDownWith: PointerType; | ||||
|   selectedElementIds: { [id: string]: boolean }; | ||||
|   collaborators: Map<string, { pointer?: { x: number; y: number } }>; | ||||
|   shouldCacheIgnoreZoom: boolean; | ||||
| }; | ||||
| 
 | ||||
| export type PointerCoords = Readonly<{ | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue