mirror of
https://github.com/scratchfoundation/scratch-blocks.git
synced 2025-08-12 05:59:06 -04:00
192 lines
6.6 KiB
JavaScript
192 lines
6.6 KiB
JavaScript
|
/**
|
||
|
* @license
|
||
|
* Visual Blocks Editor
|
||
|
*
|
||
|
* Copyright 2016 Google Inc.
|
||
|
* https://developers.google.com/blockly/
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @fileoverview An SVG that floats on top of the workspace.
|
||
|
* Blocks are moved into this SVG during a drag, improving performance.
|
||
|
* The entire SVG is translated using css translation instead of SVG so the
|
||
|
* blocks are never repainted during drag improving performance.
|
||
|
* @author katelyn@google.com (Katelyn Mann)
|
||
|
*/
|
||
|
|
||
|
'use strict';
|
||
|
|
||
|
goog.provide('Blockly.WorkspaceDragSurfaceSvg');
|
||
|
|
||
|
goog.require('Blockly.utils');
|
||
|
|
||
|
goog.require('goog.asserts');
|
||
|
goog.require('goog.math.Coordinate');
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Blocks are moved into this SVG during a drag, improving performance.
|
||
|
* The entire SVG is translated using css transforms instead of SVG so the
|
||
|
* blocks are never repainted during drag improving performance.
|
||
|
* @param {!Element} container Containing element.
|
||
|
* @constructor
|
||
|
*/
|
||
|
Blockly.workspaceDragSurfaceSvg = function(container) {
|
||
|
this.container_ = container;
|
||
|
this.createDom();
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* The SVG drag surface. Set once by Blockly.workspaceDragSurfaceSvg.createDom.
|
||
|
* @type {Element}
|
||
|
* @private
|
||
|
*/
|
||
|
Blockly.workspaceDragSurfaceSvg.prototype.SVG_ = null;
|
||
|
|
||
|
/**
|
||
|
* SVG group inside the drag surface that holds blocks while a drag is in
|
||
|
* progress. Blocks are moved here by the workspace at start of a drag and moved
|
||
|
* back into the main SVG at the end of a drag.
|
||
|
*
|
||
|
* @type {Element}
|
||
|
* @private
|
||
|
*/
|
||
|
Blockly.workspaceDragSurfaceSvg.prototype.dragGroup_ = null;
|
||
|
|
||
|
/**
|
||
|
* Containing HTML element; parent of the workspace and the drag surface.
|
||
|
* @type {Element}
|
||
|
* @private
|
||
|
*/
|
||
|
Blockly.workspaceDragSurfaceSvg.prototype.container_ = null;
|
||
|
|
||
|
/**
|
||
|
* Create the drag surface and inject it into the container.
|
||
|
*/
|
||
|
Blockly.workspaceDragSurfaceSvg.prototype.createDom = function() {
|
||
|
if (this.SVG_) {
|
||
|
return; // Already created.
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Dom structure when the workspace is being dragged. If there is no drag in
|
||
|
* progress, the SVG is empty and display: none.
|
||
|
* <svg class="blocklyWsDragSurface" style=transform:translate3d(...)>
|
||
|
* <g class="blocklyBlockCanvas"></g>
|
||
|
* <g class="blocklyBubbleCanvas">/g>
|
||
|
* </svg>
|
||
|
*/
|
||
|
this.SVG_ = Blockly.utils.createSvgElement('svg', {
|
||
|
'xmlns': Blockly.SVG_NS,
|
||
|
'xmlns:html': Blockly.HTML_NS,
|
||
|
'xmlns:xlink': 'http://www.w3.org/1999/xlink',
|
||
|
'version': '1.1',
|
||
|
'class': 'blocklyWsDragSurface'
|
||
|
}, null);
|
||
|
this.container_.appendChild(this.SVG_);
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Translate the entire drag surface during a drag.
|
||
|
* We translate the drag surface instead of the blocks inside the surface
|
||
|
* so that the browser avoids repainting the SVG.
|
||
|
* Because of this, the drag coordinates must be adjusted by scale.
|
||
|
* @param {number} x X translation for the entire surface
|
||
|
* @param {number} y Y translation for the entire surface
|
||
|
* @package
|
||
|
*/
|
||
|
Blockly.workspaceDragSurfaceSvg.prototype.translateSurface = function(x, y) {
|
||
|
// This is a work-around to prevent a the blocks from rendering
|
||
|
// fuzzy while they are being moved on the drag surface.
|
||
|
x = x.toFixed(0);
|
||
|
y = y.toFixed(0);
|
||
|
|
||
|
var transform =
|
||
|
'transform: translate3d(' + x + 'px, ' + y + 'px, 0px); display: block;';
|
||
|
this.SVG_.setAttribute('style', transform);
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Reports the surface translation in scaled workspace coordinates.
|
||
|
* Use this when finishing a drag to return blocks to the correct position.
|
||
|
* @return {!goog.math.Coordinate} Current translation of the surface
|
||
|
* @package
|
||
|
*/
|
||
|
Blockly.workspaceDragSurfaceSvg.prototype.getSurfaceTranslation = function() {
|
||
|
return Blockly.utils.getRelativeXY(this.SVG_);
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Move the blockCanvas and bubbleCanvas out of the surface SVG and on to
|
||
|
* newSurface.
|
||
|
* @param {!SVGElement} newSurface The element to put the drag surface contents
|
||
|
* into.
|
||
|
* @package
|
||
|
*/
|
||
|
Blockly.workspaceDragSurfaceSvg.prototype.clearAndHide = function(newSurface) {
|
||
|
var blockCanvas = this.SVG_.childNodes[0];
|
||
|
var bubbleCanvas = this.SVG_.childNodes[1];
|
||
|
if (!blockCanvas || !bubbleCanvas ||
|
||
|
!Blockly.utils.hasClass(blockCanvas, 'blocklyBlockCanvas') ||
|
||
|
!Blockly.utils.hasClass(bubbleCanvas, 'blocklyBubbleCanvas')) {
|
||
|
throw 'Couldn\'t clear and hide the drag surface. A node was missing.';
|
||
|
}
|
||
|
|
||
|
// If there is a previous sibling, put the blockCanvas back right afterwards,
|
||
|
// otherwise insert it as the first child node in newSurface.
|
||
|
if (this.previousSibling_ != null) {
|
||
|
Blockly.utils.insertAfter_(blockCanvas, this.previousSibling_);
|
||
|
} else {
|
||
|
newSurface.insertBefore(blockCanvas, newSurface.firstChild);
|
||
|
}
|
||
|
|
||
|
// Reattach the bubble canvas after the blockCanvas.
|
||
|
Blockly.utils.insertAfter_(bubbleCanvas, blockCanvas);
|
||
|
// Hide the drag surface.
|
||
|
this.SVG_.style.display = 'none';
|
||
|
goog.asserts.assert(this.SVG_.childNodes.length == 0,
|
||
|
'Drag surface was not cleared.');
|
||
|
this.SVG_.style.transform = '';
|
||
|
this.previousSibling_ = null;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Set the SVG to have the block canvas and bubble canvas in it and then
|
||
|
* show the surface.
|
||
|
* @param {!Element} blockCanvas The block canvas <g> element from the workspace.
|
||
|
* @param {!Element} bubbleCanvas The <g> element that contains the bubbles.
|
||
|
* @param {?Element} previousSibling The element to insert the block canvas &
|
||
|
bubble canvas after when it goes back in the dom at the end of a drag.
|
||
|
* @param {number} width The width of the workspace svg element.
|
||
|
* @param {number} height The height of the workspace svg element.
|
||
|
* @param {number} scale The scale of the workspace being dragged.
|
||
|
* @package
|
||
|
*/
|
||
|
Blockly.workspaceDragSurfaceSvg.prototype.setContentsAndShow = function(
|
||
|
blockCanvas, bubbleCanvas, previousSibling, width, height, scale) {
|
||
|
goog.asserts.assert(this.SVG_.childNodes.length == 0,
|
||
|
'Already dragging a block.');
|
||
|
this.previousSibling_ = previousSibling;
|
||
|
// Make sure the blocks and bubble canvas are scaled appropriately.
|
||
|
blockCanvas.setAttribute('transform', 'translate(0, 0) scale(' + scale + ')');
|
||
|
bubbleCanvas.setAttribute('transform',
|
||
|
'translate(0, 0) scale(' + scale + ')');
|
||
|
this.SVG_.setAttribute('width', width);
|
||
|
this.SVG_.setAttribute('height', height);
|
||
|
this.SVG_.appendChild(blockCanvas);
|
||
|
this.SVG_.appendChild(bubbleCanvas);
|
||
|
this.SVG_.style.display = 'block';
|
||
|
};
|