mirror of
https://github.com/scratchfoundation/scratch-paint.git
synced 2024-12-22 21:42:30 -05:00
Revert "Revert "Wait for other callbacks before load SVG code"" (#772)
* Add back bitmap jumping fix * Cancel previous async action if a new one is queued, and move zoomToFit call until after import * Make bitmap load cancellable too
This commit is contained in:
parent
6d69e7c65f
commit
badc549fdc
1 changed files with 79 additions and 50 deletions
|
@ -25,8 +25,10 @@ class PaperCanvas extends React.Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
super(props);
|
super(props);
|
||||||
bindAll(this, [
|
bindAll(this, [
|
||||||
|
'clearQueuedImport',
|
||||||
'setCanvas',
|
'setCanvas',
|
||||||
'importSvg',
|
'importSvg',
|
||||||
|
'initializeSvg',
|
||||||
'maybeZoomToFit',
|
'maybeZoomToFit',
|
||||||
'switchCostume'
|
'switchCostume'
|
||||||
]);
|
]);
|
||||||
|
@ -65,9 +67,21 @@ class PaperCanvas extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
componentWillUnmount () {
|
componentWillUnmount () {
|
||||||
|
this.clearQueuedImport();
|
||||||
this.props.saveZoomLevel();
|
this.props.saveZoomLevel();
|
||||||
paper.remove();
|
paper.remove();
|
||||||
}
|
}
|
||||||
|
clearQueuedImport () {
|
||||||
|
if (this.queuedImport) {
|
||||||
|
window.clearTimeout(this.queuedImport);
|
||||||
|
this.queuedImport = null;
|
||||||
|
}
|
||||||
|
if (this.queuedImageToLoad) {
|
||||||
|
this.queuedImageToLoad.src = '';
|
||||||
|
this.queuedImageToLoad.onload = null;
|
||||||
|
this.queuedImageToLoad = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
switchCostume (format, image, rotationCenterX, rotationCenterY, oldZoomLevelId, newZoomLevelId) {
|
switchCostume (format, image, rotationCenterX, rotationCenterY, oldZoomLevelId, newZoomLevelId) {
|
||||||
if (oldZoomLevelId && oldZoomLevelId !== newZoomLevelId) {
|
if (oldZoomLevelId && oldZoomLevelId !== newZoomLevelId) {
|
||||||
this.props.saveZoomLevel();
|
this.props.saveZoomLevel();
|
||||||
|
@ -94,6 +108,9 @@ class PaperCanvas extends React.Component {
|
||||||
this.importImage(format, image, rotationCenterX, rotationCenterY);
|
this.importImage(format, image, rotationCenterX, rotationCenterY);
|
||||||
}
|
}
|
||||||
importImage (format, image, rotationCenterX, rotationCenterY) {
|
importImage (format, image, rotationCenterX, rotationCenterY) {
|
||||||
|
// Stop any in-progress imports
|
||||||
|
this.clearQueuedImport();
|
||||||
|
|
||||||
if (!image) {
|
if (!image) {
|
||||||
this.props.changeFormat(Formats.VECTOR_SKIP_CONVERT);
|
this.props.changeFormat(Formats.VECTOR_SKIP_CONVERT);
|
||||||
performSnapshot(this.props.undoSnapshot, Formats.VECTOR_SKIP_CONVERT);
|
performSnapshot(this.props.undoSnapshot, Formats.VECTOR_SKIP_CONVERT);
|
||||||
|
@ -104,7 +121,11 @@ class PaperCanvas extends React.Component {
|
||||||
// import bitmap
|
// import bitmap
|
||||||
this.props.changeFormat(Formats.BITMAP_SKIP_CONVERT);
|
this.props.changeFormat(Formats.BITMAP_SKIP_CONVERT);
|
||||||
const imgElement = new Image();
|
const imgElement = new Image();
|
||||||
|
this.queuedImageToLoad = imgElement;
|
||||||
imgElement.onload = () => {
|
imgElement.onload = () => {
|
||||||
|
if (!this.queuedImageToLoad) return;
|
||||||
|
this.queuedImageToLoad = null;
|
||||||
|
|
||||||
getRaster().drawImage(
|
getRaster().drawImage(
|
||||||
imgElement,
|
imgElement,
|
||||||
(ART_BOARD_WIDTH / 2) - rotationCenterX,
|
(ART_BOARD_WIDTH / 2) - rotationCenterX,
|
||||||
|
@ -120,7 +141,6 @@ class PaperCanvas extends React.Component {
|
||||||
} else if (format === 'svg') {
|
} else if (format === 'svg') {
|
||||||
this.props.changeFormat(Formats.VECTOR_SKIP_CONVERT);
|
this.props.changeFormat(Formats.VECTOR_SKIP_CONVERT);
|
||||||
this.importSvg(image, rotationCenterX, rotationCenterY);
|
this.importSvg(image, rotationCenterX, rotationCenterY);
|
||||||
this.maybeZoomToFit();
|
|
||||||
} else {
|
} else {
|
||||||
log.error(`Didn't recognize format: ${format}. Use 'jpg', 'png' or 'svg'.`);
|
log.error(`Didn't recognize format: ${format}. Use 'jpg', 'png' or 'svg'.`);
|
||||||
this.props.changeFormat(Formats.VECTOR_SKIP_CONVERT);
|
this.props.changeFormat(Formats.VECTOR_SKIP_CONVERT);
|
||||||
|
@ -171,59 +191,68 @@ class PaperCanvas extends React.Component {
|
||||||
performSnapshot(paperCanvas.props.undoSnapshot, Formats.VECTOR_SKIP_CONVERT);
|
performSnapshot(paperCanvas.props.undoSnapshot, Formats.VECTOR_SKIP_CONVERT);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const itemWidth = item.bounds.width;
|
item.remove();
|
||||||
const itemHeight = item.bounds.height;
|
|
||||||
|
|
||||||
// Remove viewbox
|
// Without the callback, rasters' load function has not been called yet, and they are
|
||||||
if (item.clipped) {
|
// positioned incorrectly
|
||||||
let mask;
|
paperCanvas.queuedImport =
|
||||||
for (const child of item.children) {
|
window.setTimeout(() => {
|
||||||
if (child.isClipMask()) {
|
paperCanvas.initializeSvg(item, rotationCenterX, rotationCenterY, viewBox);
|
||||||
mask = child;
|
}, 0);
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
item.clipped = false;
|
|
||||||
mask.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reduce single item nested in groups
|
|
||||||
if (item instanceof paper.Group && item.children.length === 1) {
|
|
||||||
item = item.reduce();
|
|
||||||
}
|
|
||||||
|
|
||||||
ensureClockwise(item);
|
|
||||||
scaleWithStrokes(item, 2, new paper.Point()); // Import at 2x
|
|
||||||
|
|
||||||
if (typeof rotationCenterX !== 'undefined' && typeof rotationCenterY !== 'undefined') {
|
|
||||||
let rotationPoint = new paper.Point(rotationCenterX, rotationCenterY);
|
|
||||||
if (viewBox && viewBox.length >= 2 && !isNaN(viewBox[0]) && !isNaN(viewBox[1])) {
|
|
||||||
rotationPoint = rotationPoint.subtract(viewBox[0], viewBox[1]);
|
|
||||||
}
|
|
||||||
item.translate(new paper.Point(ART_BOARD_WIDTH / 2, ART_BOARD_HEIGHT / 2)
|
|
||||||
.subtract(rotationPoint.multiply(2)));
|
|
||||||
} else {
|
|
||||||
// Center
|
|
||||||
item.translate(new paper.Point(ART_BOARD_WIDTH / 2, ART_BOARD_HEIGHT / 2)
|
|
||||||
.subtract(itemWidth, itemHeight));
|
|
||||||
}
|
|
||||||
if (isGroup(item)) {
|
|
||||||
// Fixes an issue where we may export empty groups
|
|
||||||
for (const child of item.children) {
|
|
||||||
if (isGroup(child) && child.children.length === 0) {
|
|
||||||
child.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ungroupItems([item]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Without the callback, the transforms sometimes don't finish applying before the
|
|
||||||
// snapshot is taken.
|
|
||||||
window.setTimeout(
|
|
||||||
() => performSnapshot(paperCanvas.props.undoSnapshot, Formats.VECTOR_SKIP_CONVERT), 0);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
initializeSvg (item, rotationCenterX, rotationCenterY, viewBox) {
|
||||||
|
if (this.queuedImport) this.queuedImport = null;
|
||||||
|
const itemWidth = item.bounds.width;
|
||||||
|
const itemHeight = item.bounds.height;
|
||||||
|
|
||||||
|
// Remove viewbox
|
||||||
|
if (item.clipped) {
|
||||||
|
let mask;
|
||||||
|
for (const child of item.children) {
|
||||||
|
if (child.isClipMask()) {
|
||||||
|
mask = child;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
item.clipped = false;
|
||||||
|
mask.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reduce single item nested in groups
|
||||||
|
if (item instanceof paper.Group && item.children.length === 1) {
|
||||||
|
item = item.reduce();
|
||||||
|
}
|
||||||
|
|
||||||
|
ensureClockwise(item);
|
||||||
|
scaleWithStrokes(item, 2, new paper.Point()); // Import at 2x
|
||||||
|
|
||||||
|
if (typeof rotationCenterX !== 'undefined' && typeof rotationCenterY !== 'undefined') {
|
||||||
|
let rotationPoint = new paper.Point(rotationCenterX, rotationCenterY);
|
||||||
|
if (viewBox && viewBox.length >= 2 && !isNaN(viewBox[0]) && !isNaN(viewBox[1])) {
|
||||||
|
rotationPoint = rotationPoint.subtract(viewBox[0], viewBox[1]);
|
||||||
|
}
|
||||||
|
item.translate(new paper.Point(ART_BOARD_WIDTH / 2, ART_BOARD_HEIGHT / 2)
|
||||||
|
.subtract(rotationPoint.multiply(2)));
|
||||||
|
} else {
|
||||||
|
// Center
|
||||||
|
item.translate(new paper.Point(ART_BOARD_WIDTH / 2, ART_BOARD_HEIGHT / 2)
|
||||||
|
.subtract(itemWidth, itemHeight));
|
||||||
|
}
|
||||||
|
paper.project.activeLayer.insertChild(0, item);
|
||||||
|
if (isGroup(item)) {
|
||||||
|
// Fixes an issue where we may export empty groups
|
||||||
|
for (const child of item.children) {
|
||||||
|
if (isGroup(child) && child.children.length === 0) {
|
||||||
|
child.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ungroupItems([item]);
|
||||||
|
}
|
||||||
|
performSnapshot(this.props.undoSnapshot, Formats.VECTOR_SKIP_CONVERT);
|
||||||
|
this.maybeZoomToFit();
|
||||||
|
}
|
||||||
setCanvas (canvas) {
|
setCanvas (canvas) {
|
||||||
this.canvas = canvas;
|
this.canvas = canvas;
|
||||||
if (this.props.canvasRef) {
|
if (this.props.canvasRef) {
|
||||||
|
|
Loading…
Reference in a new issue