mirror of
https://github.com/google/blockly.git
synced 2026-01-10 18:37:09 +01:00
Movement Updates (#2247)
This is a squash and merge of a large set of changes by @BeksOmega * Added functionality to scrolling, dragging, and zooming. * Fixed incorrect changes to workspaceChanged function. * Fixed comment. * Fixed typo. * Removed scrollbar.set calls from workspace_svg. * Removed scrollbar.resize() call. * Added move options to playground. * Fixed scroll_ calls that replaced scrollbar.set calls. * Removed this.scrollbar checks. * Changed zoom so that it always zooms towards the coordinates. Changed isContentBounded_ to be separate from isMovable_ (b/c of the previous change zoomControls had to be added to the bounded check). Fixed scroll_() calls... again. * Changed procedures so the Highlight definition option is only available if the workspace is moveable. * Fixed scrollCenter so that it works with flyout toolboxes. * Fixed zoomToFit so that it works with horizontal flyout toolboxes. * Fixed Typo. * Fixed bumping blocks when the workspace is not movable. * Fixed bumping not working with left and top toolbox positions. * Re-Added not allowing scrollCenter if the workspace is not movable. Disabled scrollCenter button for this case. * Cleaned up formatting. * Fixed bumping... again. Reformatted workspaceChanged a bit. * Changed blocks to be completely bumped into the workspace. * Reorganized metrics-getting for workspaceChanged. * Added bumping workspace comments. Moved event checking. * Renamed workspaceChanged to bumpObjects. * Added a bumpObjects developer reminder. * Added warning to zoomToFit. * Cleaned up some text. * Added better inline documentation. * Fixed up inline docs. * Cleaned up comments. * Fixed zoomCenter not actually zooming towards the center. * Fixed zoomControls error on unmovable bottom-toolbox workspaces * Fixed programatically placing blocks in an unmovable workspace. * Removed unnecessary translate call in inject. * Reversed removal of translate. (apparently it was necessary) * Cleaned up code in response to first round of reviews. * Added unit comments to the zoom function. * Removed bumpObjectsEventChecker. Added BUMP_EVENTS list to Blockly.Events. * Changed getWorkspaceObjectMetrics call to getBoundingRectangle(). * Fixed utils.mouseToSvg (was causing problems with zoom on wheel if the page was scrolled). * Fixed zoom when page is scrolled (actually this time). Reverted changes to utils.mouseToSvg. * Fixed centerOnBlock. * Added unit docs to translate. Moved setting the grid position to the translate function. * Added TODO's.
This commit is contained in:
committed by
Rachel Fenichel
parent
c2447e7e8b
commit
9dec2da5c5
176
core/inject.js
176
core/inject.js
@@ -232,71 +232,112 @@ Blockly.createMainWorkspace_ = function(svg, options, blockDragSurface,
|
||||
mainWorkspace.translate(0, 0);
|
||||
Blockly.mainWorkspace = mainWorkspace;
|
||||
|
||||
if (!options.readOnly && !options.hasScrollbars) {
|
||||
var workspaceChanged = function(e) {
|
||||
if (!mainWorkspace.isDragging()) {
|
||||
var metrics = mainWorkspace.getMetrics();
|
||||
var edgeLeft = metrics.viewLeft + metrics.absoluteLeft;
|
||||
var edgeTop = metrics.viewTop + metrics.absoluteTop;
|
||||
if (metrics.contentTop < edgeTop ||
|
||||
metrics.contentTop + metrics.contentHeight >
|
||||
metrics.viewHeight + edgeTop ||
|
||||
metrics.contentLeft <
|
||||
(options.RTL ? metrics.viewLeft : edgeLeft) ||
|
||||
metrics.contentLeft + metrics.contentWidth > (options.RTL ?
|
||||
metrics.viewWidth : metrics.viewWidth + edgeLeft)) {
|
||||
// One or more blocks may be out of bounds. Bump them back in.
|
||||
var MARGIN = 25;
|
||||
var blocks = mainWorkspace.getTopBlocks(false);
|
||||
if (!options.readOnly && !mainWorkspace.isMovable()) {
|
||||
// Helper function for the workspaceChanged callback.
|
||||
// TODO (#2300): Move metrics math back to the WorkspaceSvg.
|
||||
var getWorkspaceMetrics = function() {
|
||||
var workspaceMetrics = Object.create(null);
|
||||
var defaultMetrics = mainWorkspace.getMetrics();
|
||||
var scale = mainWorkspace.scale;
|
||||
|
||||
// Get the view metrics in workspace units.
|
||||
workspaceMetrics.viewLeft = defaultMetrics.viewLeft / scale;
|
||||
workspaceMetrics.viewTop = defaultMetrics.viewTop / scale;
|
||||
workspaceMetrics.viewRight =
|
||||
(defaultMetrics.viewLeft + defaultMetrics.viewWidth) / scale;
|
||||
workspaceMetrics.viewBottom =
|
||||
(defaultMetrics.viewTop + defaultMetrics.viewHeight) / scale;
|
||||
|
||||
// Get the exact content metrics (in workspace units), even if the
|
||||
// content is bounded.
|
||||
if (mainWorkspace.isContentBounded()) {
|
||||
// Already in workspace units, no need to divide by scale.
|
||||
var blocksBoundingBox = mainWorkspace.getBlocksBoundingBox();
|
||||
workspaceMetrics.contentLeft = blocksBoundingBox.x;
|
||||
workspaceMetrics.contentTop = blocksBoundingBox.y;
|
||||
workspaceMetrics.contentRight =
|
||||
blocksBoundingBox.x + blocksBoundingBox.width;
|
||||
workspaceMetrics.contentBottom =
|
||||
blocksBoundingBox.y + blocksBoundingBox.height;
|
||||
} else {
|
||||
workspaceMetrics.contentLeft = defaultMetrics.contentLeft / scale;
|
||||
workspaceMetrics.contentTop = defaultMetrics.contentTop / scale;
|
||||
workspaceMetrics.contentRight =
|
||||
(defaultMetrics.contentLeft + defaultMetrics.contentWidth) / scale;
|
||||
workspaceMetrics.contentBottom =
|
||||
(defaultMetrics.contentTop + defaultMetrics.contentHeight) / scale;
|
||||
}
|
||||
|
||||
return workspaceMetrics;
|
||||
};
|
||||
|
||||
var bumpObjects = function(e) {
|
||||
// We always check isMovable_ again because the original
|
||||
// "not movable" state of isMovable_ could have been changed.
|
||||
if (!mainWorkspace.isDragging() && !mainWorkspace.isMovable() &&
|
||||
(Blockly.Events.BUMP_EVENTS.indexOf(e.type) != -1)) {
|
||||
var metrics = getWorkspaceMetrics();
|
||||
if (metrics.contentTop < metrics.viewTop ||
|
||||
metrics.contentBottom > metrics.viewBottom ||
|
||||
metrics.contentLeft < metrics.viewLeft ||
|
||||
metrics.contentRight > metrics.viewRight) {
|
||||
|
||||
// Handle undo.
|
||||
var oldGroup = null;
|
||||
if (e) {
|
||||
oldGroup = Blockly.Events.getGroup();
|
||||
Blockly.Events.setGroup(e.group);
|
||||
}
|
||||
var movedBlocks = false;
|
||||
for (var b = 0, block; block = blocks[b]; b++) {
|
||||
var blockXY = block.getRelativeToSurfaceXY();
|
||||
var blockHW = block.getHeightWidth();
|
||||
// Bump any block that's above the top back inside.
|
||||
var overflowTop = edgeTop + MARGIN - blockHW.height - blockXY.y;
|
||||
if (overflowTop > 0) {
|
||||
block.moveBy(0, overflowTop);
|
||||
movedBlocks = true;
|
||||
}
|
||||
// Bump any block that's below the bottom back inside.
|
||||
var overflowBottom =
|
||||
edgeTop + metrics.viewHeight - MARGIN - blockXY.y;
|
||||
if (overflowBottom < 0) {
|
||||
block.moveBy(0, overflowBottom);
|
||||
movedBlocks = true;
|
||||
}
|
||||
// Bump any block that's off the left back inside.
|
||||
var overflowLeft = MARGIN + edgeLeft -
|
||||
blockXY.x - (options.RTL ? 0 : blockHW.width);
|
||||
if (overflowLeft > 0) {
|
||||
block.moveBy(overflowLeft, 0);
|
||||
movedBlocks = true;
|
||||
}
|
||||
// Bump any block that's off the right back inside.
|
||||
var overflowRight = edgeLeft + metrics.viewWidth - MARGIN -
|
||||
blockXY.x + (options.RTL ? blockHW.width : 0);
|
||||
if (overflowRight < 0) {
|
||||
block.moveBy(overflowRight, 0);
|
||||
movedBlocks = true;
|
||||
}
|
||||
|
||||
switch (e.type) {
|
||||
case Blockly.Events.BLOCK_CREATE:
|
||||
case Blockly.Events.BLOCK_MOVE:
|
||||
var object = mainWorkspace.getBlockById(e.blockId);
|
||||
break;
|
||||
case Blockly.Events.COMMENT_CREATE:
|
||||
case Blockly.Events.COMMENT_MOVE:
|
||||
var object = mainWorkspace.getCommentById(e.commentId);
|
||||
break;
|
||||
}
|
||||
var objectMetrics = object.getBoundingRectangle();
|
||||
|
||||
// Bump any object that's above the top back inside.
|
||||
var overflowTop = metrics.viewTop - objectMetrics.topLeft.y;
|
||||
if (overflowTop > 0) {
|
||||
object.moveBy(0, overflowTop);
|
||||
}
|
||||
|
||||
// Bump any object that's below the bottom back inside.
|
||||
var overflowBottom = metrics.viewBottom - objectMetrics.bottomRight.y;
|
||||
if (overflowBottom < 0) {
|
||||
object.moveBy(0, overflowBottom);
|
||||
}
|
||||
|
||||
// Bump any object that's off the left back inside.
|
||||
var overflowLeft = metrics.viewLeft - objectMetrics.topLeft.x;
|
||||
if (overflowLeft > 0) {
|
||||
object.moveBy(overflowLeft, 0);
|
||||
}
|
||||
|
||||
// Bump any object that's off the right back inside.
|
||||
var overflowRight = metrics.viewRight - objectMetrics.bottomRight.x;
|
||||
if (overflowRight < 0) {
|
||||
object.moveBy(overflowRight, 0);
|
||||
}
|
||||
|
||||
if (e) {
|
||||
if (!e.group && movedBlocks) {
|
||||
console.log('WARNING: Moved blocks in bounds but there was no event group.'
|
||||
+ ' This may break undo.');
|
||||
if (!e.group) {
|
||||
console.log('WARNING: Moved object in bounds but there was no' +
|
||||
' event group. This may break undo.');
|
||||
}
|
||||
Blockly.Events.setGroup(oldGroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
mainWorkspace.addChangeListener(workspaceChanged);
|
||||
mainWorkspace.addChangeListener(bumpObjects);
|
||||
}
|
||||
|
||||
// The SVG is now fully assembled.
|
||||
Blockly.svgResize(mainWorkspace);
|
||||
Blockly.WidgetDiv.createDom();
|
||||
@@ -339,12 +380,6 @@ Blockly.init_ = function(mainWorkspace) {
|
||||
mainWorkspace.flyout_.init(mainWorkspace);
|
||||
mainWorkspace.flyout_.show(options.languageTree.childNodes);
|
||||
mainWorkspace.flyout_.scrollToStart();
|
||||
// Translate the workspace sideways to avoid the fixed flyout.
|
||||
mainWorkspace.scrollX = mainWorkspace.flyout_.width_;
|
||||
if (options.toolboxPosition == Blockly.TOOLBOX_AT_RIGHT) {
|
||||
mainWorkspace.scrollX *= -1;
|
||||
}
|
||||
mainWorkspace.translate(mainWorkspace.scrollX, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -356,9 +391,31 @@ Blockly.init_ = function(mainWorkspace) {
|
||||
mainWorkspace.zoomControls_.init(verticalSpacing);
|
||||
}
|
||||
|
||||
if (options.hasScrollbars) {
|
||||
if (options.moveOptions && options.moveOptions.scrollbars) {
|
||||
mainWorkspace.scrollbar = new Blockly.ScrollbarPair(mainWorkspace);
|
||||
mainWorkspace.scrollbar.resize();
|
||||
} else {
|
||||
mainWorkspace.setMetrics({x: .5, y: .5});
|
||||
}
|
||||
|
||||
if (mainWorkspace.flyout_) {
|
||||
// Translate the workspace sideways to avoid the fixed flyout.
|
||||
switch (mainWorkspace.toolboxPosition) {
|
||||
case Blockly.TOOLBOX_AT_LEFT:
|
||||
mainWorkspace.scrollX =
|
||||
mainWorkspace.RTL ? 0 : mainWorkspace.flyout_.width_;
|
||||
break;
|
||||
case Blockly.TOOLBOX_AT_RIGHT:
|
||||
mainWorkspace.scrollX =
|
||||
mainWorkspace.RTL ? -mainWorkspace.flyout_.width_ : 0;
|
||||
break;
|
||||
case Blockly.TOOLBOX_AT_TOP:
|
||||
mainWorkspace.scrollY = mainWorkspace.flyout_.height_;
|
||||
break;
|
||||
// If the toolbox is at the top left (workspace origin) is untouched,
|
||||
// so no need to include it.
|
||||
}
|
||||
mainWorkspace.translate(mainWorkspace.scrollX, mainWorkspace.scrollY);
|
||||
}
|
||||
|
||||
// Load the sounds.
|
||||
@@ -380,6 +437,9 @@ Blockly.init_ = function(mainWorkspace) {
|
||||
*/
|
||||
Blockly.inject.bindDocumentEvents_ = function() {
|
||||
if (!Blockly.documentEventsBound_) {
|
||||
Blockly.bindEventWithChecks_(document, 'scroll', null,
|
||||
Blockly.mainWorkspace.updateInverseScreenCTM
|
||||
.bind(Blockly.mainWorkspace));
|
||||
Blockly.bindEventWithChecks_(document, 'keydown', null, Blockly.onKeyDown_);
|
||||
// longStop needs to run to stop the context menu from showing up. It
|
||||
// should run regardless of what other touch event handlers have run.
|
||||
|
||||
Reference in New Issue
Block a user