scheduleZoom = function(delay)
	{
		if (updateZoomTimeout != null)
		{
			window.clearTimeout(updateZoomTimeout);
		}

		window.setTimeout(function()
		{
			if (!graph.isMouseDown)
			{
				updateZoomTimeout = window.setTimeout(mxUtils.bind(this, function()
		        {
		        	if (graph.isFastZoomEnabled())
		    		{
		            	// Transforms background page
		  				if (graph.view.backgroundPageShape != null && graph.view.backgroundPageShape.node != null)
		  				{
		  					mxUtils.setPrefixedStyle(graph.view.backgroundPageShape.node.style, 'transform-origin', null);
		  					mxUtils.setPrefixedStyle(graph.view.backgroundPageShape.node.style, 'transform', null);
		  				}
		  				
		  				// Transforms graph and background image
		  				mainGroup.style.transformOrigin = '';
		  				bgGroup.style.transformOrigin = '';

		  				// Workaround for no reset of transform in Safari
		  				if (mxClient.IS_SF)
		  				{
			  				mainGroup.style.transform = 'scale(1)';
			  				bgGroup.style.transform = 'scale(1)';
			  				
			  				window.setTimeout(function()
	  						{
			  					mainGroup.style.transform = '';
	  							bgGroup.style.transform = '';
	  						}, 0)
		  				}
		  				else
		  				{
			  				mainGroup.style.transform = '';
			  				bgGroup.style.transform = '';
		  				}
		  				
		            	// Shows interactive elements
		            	graph.view.getDecoratorPane().style.opacity = '';
		            	graph.view.getOverlayPane().style.opacity = '';
		    		}
		        	
		        	var sp = new mxPoint(graph.container.scrollLeft, graph.container.scrollTop);
		            var offset = mxUtils.getOffset(graph.container);
		        	var prev = graph.view.scale;
		            var dx = 0;
		            var dy = 0;
		            
		            if (cursorPosition != null)
		            {
		                dx = graph.container.offsetWidth / 2 - cursorPosition.x + offset.x;
		                dy = graph.container.offsetHeight / 2 - cursorPosition.y + offset.y;
		            }
	
		            graph.zoom(graph.cumulativeZoomFactor);
		            var s = graph.view.scale;
		            
		            if (s != prev)
		            {
			            if (scrollPosition != null)
			            {
			            	dx += sp.x - scrollPosition.x;
			            	dy += sp.y - scrollPosition.y;
			            }
			            
		                if (resize != null)
		                {
		                	ui.chromelessResize(false, null, dx * (graph.cumulativeZoomFactor - 1),
		                		dy * (graph.cumulativeZoomFactor - 1));
		                }
		                
		                if (mxUtils.hasScrollbars(graph.container) && (dx != 0 || dy != 0))
		                {
		                    graph.container.scrollLeft -= dx * (graph.cumulativeZoomFactor - 1);
		                    graph.container.scrollTop -= dy * (graph.cumulativeZoomFactor - 1);
		                }
		            }
		            
					if (filter != null)
					{
						mainGroup.setAttribute('filter', filter);
					}
					
		            graph.cumulativeZoomFactor = 1;
		            updateZoomTimeout = null;
		            scrollPosition = null;
		            cursorPosition = null;
		            filter = null;
		        }), (delay != null) ? delay : ((graph.isFastZoomEnabled()) ? ui.wheelZoomDelay : ui.lazyZoomDelay));
			}
		}, 0);
	}
Guesses autoTranslate to avoid another repaint (see below).
Works if only the scale of the graph changes or if pages
are visible and the visible pages do not change.