mirror of
https://github.com/google/blockly.git
synced 2025-12-16 06:10:12 +01:00
Fix performance when opening mutator with many entries
This commit makes the following changes: 1. Improves the mutator code for use under the App Inventor blocks rendering algorithm which walks the blocks tree starting from a given node. Iterating over children resulted in an O(n^2) performance. 2. Prevents events from firing when the mutator is first opened, which prevents superfluous rerendering operations before any changes have been made by the user. 3. Defers resizing the mutator workspace on every block change to only occur once at the end of the current JavaScript execution context via setTimeout(). Fixes mit-cml/appinventor-sources#959
This commit is contained in:
committed by
Evan W. Patton
parent
c44909baa3
commit
5f6bfe0a92
@@ -90,6 +90,13 @@ Blockly.Events.UI = 'ui';
|
||||
*/
|
||||
Blockly.Events.FIRE_QUEUE_ = [];
|
||||
|
||||
/**
|
||||
* Pending timeout, if any, for event firing.
|
||||
* @type {?number}
|
||||
* @private
|
||||
*/
|
||||
Blockly.Events.FIRE_TIMER_ = undefined;
|
||||
|
||||
/**
|
||||
* Create a custom event and fire it.
|
||||
* @param {!Blockly.Events.Abstract} event Custom data for event.
|
||||
@@ -98,11 +105,14 @@ Blockly.Events.fire = function(event) {
|
||||
if (!Blockly.Events.isEnabled()) {
|
||||
return;
|
||||
}
|
||||
if (!Blockly.Events.FIRE_QUEUE_.length) {
|
||||
// First event added; schedule a firing of the event queue.
|
||||
setTimeout(Blockly.Events.fireNow_, 0);
|
||||
}
|
||||
Blockly.Events.FIRE_QUEUE_.push(event);
|
||||
if (!Blockly.Events.FIRE_TIMER_) {
|
||||
// First event added; schedule a firing of the event queue.
|
||||
Blockly.Events.FIRE_TIMER_ = setTimeout(function() {
|
||||
Blockly.Events.FIRE_TIMER_ = undefined;
|
||||
Blockly.Events.fireNow_();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -171,6 +171,16 @@ Blockly.Mutator.prototype.updateEditable = function() {
|
||||
Blockly.Icon.prototype.updateEditable.call(this);
|
||||
};
|
||||
|
||||
Blockly.Mutator.prototype.scheduleResizeBubble = function() {
|
||||
if (!this.pendingBubbleResize_) {
|
||||
var self = this;
|
||||
this.pendingBubbleResize_ = setTimeout(function() {
|
||||
self.workspace_ && self.resizeBubble_();
|
||||
self.pendingBubbleResize_ = undefined;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback function triggered when the bubble has resized.
|
||||
* Resize the workspace accordingly.
|
||||
@@ -224,6 +234,8 @@ Blockly.Mutator.prototype.setVisible = function(visible) {
|
||||
Blockly.Events.fire(
|
||||
new Blockly.Events.Ui(this.block_, 'mutatorOpen', !visible, visible));
|
||||
if (visible) {
|
||||
Blockly.Field.startCache();
|
||||
Blockly.Events.disable();
|
||||
// Create the bubble.
|
||||
this.bubble_ = new Blockly.Bubble(
|
||||
/** @type {!Blockly.WorkspaceSvg} */ (this.block_.workspace),
|
||||
@@ -235,10 +247,7 @@ Blockly.Mutator.prototype.setVisible = function(visible) {
|
||||
}
|
||||
|
||||
this.rootBlock_ = this.block_.decompose(this.workspace_);
|
||||
var blocks = this.rootBlock_.getDescendants();
|
||||
for (var i = 0, child; child = blocks[i]; i++) {
|
||||
child.render();
|
||||
}
|
||||
this.renderWorkspace();
|
||||
// The root block should not be dragable or deletable.
|
||||
this.rootBlock_.setMovable(false);
|
||||
this.rootBlock_.setDeletable(false);
|
||||
@@ -266,6 +275,8 @@ Blockly.Mutator.prototype.setVisible = function(visible) {
|
||||
// When the mutator's workspace changes, update the source block.
|
||||
this.workspace_.addChangeListener(this.workspaceChanged_.bind(this));
|
||||
this.updateColour();
|
||||
Blockly.Events.enable();
|
||||
Blockly.Field.stopCache();
|
||||
} else {
|
||||
// Dispose of the bubble.
|
||||
this.svgDialog_ = null;
|
||||
@@ -283,6 +294,16 @@ Blockly.Mutator.prototype.setVisible = function(visible) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders the mutator's workspace, starting from the root block.
|
||||
*/
|
||||
Blockly.Mutator.prototype.renderWorkspace = function() {
|
||||
var blocks = this.rootBlock_.getDescendants();
|
||||
for (var i = 0, child; child = blocks[i]; i++) {
|
||||
child.render();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the source block when the mutator's blocks are changed.
|
||||
* Bump down any block that's too high.
|
||||
@@ -305,6 +326,7 @@ Blockly.Mutator.prototype.workspaceChanged_ = function() {
|
||||
|
||||
// When the mutator's workspace changes, update the source block.
|
||||
if (this.rootBlock_.workspace == this.workspace_) {
|
||||
Blockly.Field.startCache();
|
||||
Blockly.Events.setGroup(true);
|
||||
var block = this.block_;
|
||||
var oldMutationDom = block.mutationToDom();
|
||||
@@ -334,8 +356,9 @@ Blockly.Mutator.prototype.workspaceChanged_ = function() {
|
||||
if (block.rendered) {
|
||||
block.render();
|
||||
}
|
||||
this.resizeBubble_();
|
||||
this.scheduleResizeBubble();
|
||||
Blockly.Events.setGroup(false);
|
||||
Blockly.Field.stopCache();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -521,16 +521,19 @@ Blockly.WorkspaceSvg.prototype.updateScreenCalculations_ = function() {
|
||||
* @package
|
||||
*/
|
||||
Blockly.WorkspaceSvg.prototype.resizeContents = function() {
|
||||
if (!this.resizesEnabled_ || !this.rendered) {
|
||||
if (!this.resizesEnabled_ || !this.rendered || this.pendingResize_) {
|
||||
return;
|
||||
}
|
||||
if (this.scrollbar) {
|
||||
// TODO(picklesrus): Once rachel-fenichel's scrollbar refactoring
|
||||
// is complete, call the method that only resizes scrollbar
|
||||
// based on contents.
|
||||
this.scrollbar.resize();
|
||||
}
|
||||
this.updateInverseScreenCTM();
|
||||
this.pendingResize_ = setTimeout((function() {
|
||||
if (this.scrollbar) {
|
||||
// TODO(picklesrus): Once rachel-fenichel's scrollbar refactoring
|
||||
// is complete, call the method that only resizes scrollbar
|
||||
// based on contents.
|
||||
this.scrollbar.resize();
|
||||
}
|
||||
this.updateInverseScreenCTM();
|
||||
this.pendingResize_ = undefined;
|
||||
}).bind(this));
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user