Includes scratch-gui, scratch-vm, scratch-blocks, scratch-render, scratch-l10n, and deployment config. Co-authored-by: Cursor <cursoragent@cursor.com>
103 lines
3.0 KiB
JavaScript
103 lines
3.0 KiB
JavaScript
'use strict';
|
|
|
|
goog.provide('Blockly.IntersectionObserver');
|
|
|
|
Blockly.IntersectionObserver = function(workspace) {
|
|
this.workspace = workspace;
|
|
this.observing = [];
|
|
this.intersectionCheckQueued = false;
|
|
this.checkForIntersections = this.checkForIntersections.bind(this);
|
|
};
|
|
|
|
Blockly.IntersectionObserver.prototype.observe = function(block) {
|
|
var index = this.observing.indexOf(block);
|
|
if (index === -1) {
|
|
this.observing.push(block);
|
|
}
|
|
};
|
|
|
|
Blockly.IntersectionObserver.prototype.unobserve = function(block) {
|
|
var index = this.observing.indexOf(block);
|
|
if (index !== -1) {
|
|
this.observing = this.observing.filter(function(i) {
|
|
return i !== block;
|
|
});
|
|
}
|
|
};
|
|
|
|
Blockly.IntersectionObserver.prototype.dispose = function() {
|
|
this.observing = [];
|
|
this.workspace = null;
|
|
};
|
|
|
|
Blockly.IntersectionObserver.prototype.queueIntersectionCheck = function() {
|
|
if (this.intersectionCheckQueued) {
|
|
return;
|
|
}
|
|
this.intersectionCheckQueued = true;
|
|
// Check for intersections on the next microtick
|
|
// Prefer to use the native method when available, otherwise fallback to a Promise-based polyfill
|
|
if (window.queueMicrotask) {
|
|
window.queueMicrotask(this.checkForIntersections);
|
|
} else {
|
|
// eslint-disable-next-line no-undef
|
|
Promise.resolve().then(this.checkForIntersections);
|
|
}
|
|
};
|
|
|
|
Blockly.IntersectionObserver.prototype.checkForIntersections = function() {
|
|
this.intersectionCheckQueued = false;
|
|
|
|
if (!this.workspace) {
|
|
return;
|
|
}
|
|
|
|
var workspace = this.workspace;
|
|
var workspaceScale = workspace.scale;
|
|
var RTL = workspace.RTL;
|
|
var workspaceHeight = workspace.getParentSvg().height.baseVal.value;
|
|
var workspaceWidth = workspace.getParentSvg().width.baseVal.value;
|
|
if (workspace.isDragSurfaceActive_) {
|
|
var canvasPos = Blockly.utils.getRelativeXY(workspace.workspaceDragSurface_.SVG_);
|
|
} else {
|
|
var canvasPos = Blockly.utils.getRelativeXY(workspace.getCanvas());
|
|
}
|
|
|
|
// Allow blocks to go slightly offscreen so that effects such as glow do not get cut off.
|
|
var margin = 12 * workspaceScale;
|
|
|
|
for (var i = 0; i < this.observing.length; i++) {
|
|
var block = this.observing[i];
|
|
var blockPos = block.getRelativeToSurfaceXY();
|
|
var blockSize = null;
|
|
if (RTL) {
|
|
blockSize = block.getHeightWidth();
|
|
blockPos.x -= blockSize.width;
|
|
blockSize.width *= workspaceScale;
|
|
blockSize.height *= workspaceScale;
|
|
}
|
|
blockPos.x *= workspaceScale;
|
|
blockPos.y *= workspaceScale;
|
|
|
|
var visible = true;
|
|
if (canvasPos.y + blockPos.y - margin > workspaceHeight) {
|
|
visible = false;
|
|
} else if (canvasPos.x + blockPos.x - margin > workspaceWidth) {
|
|
visible = false;
|
|
} else {
|
|
if (!blockSize) {
|
|
blockSize = block.getHeightWidth();
|
|
blockSize.width *= workspaceScale;
|
|
blockSize.height *= workspaceScale;
|
|
}
|
|
if (canvasPos.x + blockPos.x + blockSize.width + margin < 0) {
|
|
visible = false;
|
|
} else if (canvasPos.y + blockPos.y + blockSize.height + margin < 0) {
|
|
visible = false;
|
|
}
|
|
}
|
|
|
|
block.setIntersects(visible);
|
|
}
|
|
};
|