mirror of
https://github.com/scratchfoundation/scratch-paint.git
synced 2024-12-22 13:32:28 -05:00
add comments and clean up
This commit is contained in:
parent
060ff0ab15
commit
fd9a4af83f
12 changed files with 109 additions and 90 deletions
|
@ -4,5 +4,7 @@
|
|||
margin: auto;
|
||||
position: relative;
|
||||
background-color: #fff;
|
||||
/* Turn off anti-aliasing for the drawing canvas. Each time it's updated it switches
|
||||
back and forth from aliased to unaliased and that looks bad */
|
||||
image-rendering: pixelated;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ import React from 'react';
|
|||
import {connect} from 'react-redux';
|
||||
import paper from 'paper';
|
||||
|
||||
const SelectionHOV = function (WrappedComponent) {
|
||||
const SelectionHOC = function (WrappedComponent) {
|
||||
class SelectionComponent extends React.Component {
|
||||
componentDidMount () {
|
||||
if (this.props.hoveredItem) {
|
||||
|
@ -43,4 +43,4 @@ const SelectionHOV = function (WrappedComponent) {
|
|||
)(SelectionComponent);
|
||||
};
|
||||
|
||||
export default SelectionHOV;
|
||||
export default SelectionHOC;
|
|
@ -1,6 +1,6 @@
|
|||
import paper from 'paper';
|
||||
import {getGuideLayer} from './layer';
|
||||
import {removePaperItemsByTags, removePaperItemsByDataTags} from './helper';
|
||||
import {getAllPaperItems} from './selection';
|
||||
|
||||
const GUIDE_BLUE = '#009dec';
|
||||
const GUIDE_GREY = '#aaaaaa';
|
||||
|
@ -65,12 +65,34 @@ const getGuideColor = function (colorName) {
|
|||
}
|
||||
};
|
||||
|
||||
const _removePaperItemsByDataTags = function (tags) {
|
||||
const allItems = getAllPaperItems(true);
|
||||
for (const item of allItems) {
|
||||
for (const tag of tags) {
|
||||
if (item.data && item.data[tag]) {
|
||||
item.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const _removePaperItemsByTags = function (tags) {
|
||||
const allItems = getAllPaperItems(true);
|
||||
for (const item of allItems) {
|
||||
for (const tag of tags) {
|
||||
if (item[tag]) {
|
||||
item.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const removeHelperItems = function () {
|
||||
removePaperItemsByDataTags(['isHelperItem']);
|
||||
_removePaperItemsByDataTags(['isHelperItem']);
|
||||
};
|
||||
|
||||
const removeAllGuides = function () {
|
||||
removePaperItemsByTags(['guide']);
|
||||
_removePaperItemsByTags(['guide']);
|
||||
};
|
||||
|
||||
export {
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
import paper from 'paper';
|
||||
|
||||
/**
|
||||
* @param {boolean} includeGuides True if guide layer items like the bounding box should
|
||||
* be included in the returned items.
|
||||
* @return {Array<paper.item>} all top-level (direct descendants of a paper.Layer) items
|
||||
*/
|
||||
const getAllPaperItems = function (includeGuides) {
|
||||
includeGuides = includeGuides || false;
|
||||
const allItems = [];
|
||||
for (const layer of paper.project.layers) {
|
||||
for (const child of layer.children) {
|
||||
// don't give guides back
|
||||
if (!includeGuides && child.guide) {
|
||||
continue;
|
||||
}
|
||||
allItems.push(child);
|
||||
}
|
||||
}
|
||||
return allItems;
|
||||
};
|
||||
|
||||
const getPaperItemsByTags = function (tags) {
|
||||
const allItems = getAllPaperItems(true);
|
||||
const foundItems = [];
|
||||
for (const item of allItems) {
|
||||
for (const tag of tags) {
|
||||
if (item[tag] && foundItems.indexOf(item) === -1) {
|
||||
foundItems.push(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
return foundItems;
|
||||
};
|
||||
|
||||
const removePaperItemsByDataTags = function (tags) {
|
||||
const allItems = getAllPaperItems(true);
|
||||
for (const item of allItems) {
|
||||
for (const tag of tags) {
|
||||
if (item.data && item.data[tag]) {
|
||||
item.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const removePaperItemsByTags = function (tags) {
|
||||
const allItems = getAllPaperItems(true);
|
||||
for (const item of allItems) {
|
||||
for (const tag of tags) {
|
||||
if (item[tag]) {
|
||||
item.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export {
|
||||
getAllPaperItems,
|
||||
getPaperItemsByTags,
|
||||
removePaperItemsByDataTags,
|
||||
removePaperItemsByTags
|
||||
};
|
|
@ -24,7 +24,7 @@ const Modes = keyMirror({
|
|||
});
|
||||
|
||||
/**
|
||||
* A paper.Tool that handles transforming the selection and drawing a bounding box with handles.
|
||||
* Tool that handles transforming the selection and drawing a bounding box with handles.
|
||||
* On mouse down, the type of function (move, scale, rotate) is determined based on what is clicked
|
||||
* (scale handle, rotate handle, the object itself). This determines the mode of the tool, which then
|
||||
* delegates actions to the MoveTool, RotateTool or ScaleTool accordingly.
|
||||
|
|
|
@ -3,6 +3,9 @@ import {isCompoundPathItem, getRootItem} from '../item';
|
|||
import {snapDeltaToAngle} from '../math';
|
||||
import {clearSelection, cloneSelection, getSelectedItems, setItemSelection} from '../selection';
|
||||
|
||||
/**
|
||||
* Tool to handle dragging an item to reposition it in a selection mode.
|
||||
*/
|
||||
class MoveTool {
|
||||
/**
|
||||
* @param {!function} onUpdateSvg A callback to call when the image visibly changes
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
import paper from 'paper';
|
||||
|
||||
/**
|
||||
* Tool to handle rotation when dragging the rotation handle in the bounding box tool.
|
||||
*/
|
||||
class RotateTool {
|
||||
/**
|
||||
* @param {!function} onUpdateSvg A callback to call when the image visibly changes
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
import paper from 'paper';
|
||||
|
||||
/**
|
||||
* Tool to handle scaling items by pulling on the handles around the edges of the bounding
|
||||
* box when in the bounding box tool.
|
||||
*/
|
||||
class ScaleTool {
|
||||
/**
|
||||
* @param {!function} onUpdateSvg A callback to call when the image visibly changes
|
||||
|
@ -34,9 +38,9 @@ class ScaleTool {
|
|||
this.boundsPath = boundsPath;
|
||||
this.boundsScaleHandles = boundsScaleHandles;
|
||||
this.boundsRotHandles = boundsRotHandles;
|
||||
this.pivot = this.boundsPath.bounds[this.getOpposingRectCornerNameByIndex(index)].clone();
|
||||
this.origPivot = this.boundsPath.bounds[this.getOpposingRectCornerNameByIndex(index)].clone();
|
||||
this.corner = this.boundsPath.bounds[this.getRectCornerNameByIndex(index)].clone();
|
||||
this.pivot = this.boundsPath.bounds[this._getOpposingRectCornerNameByIndex(index)].clone();
|
||||
this.origPivot = this.boundsPath.bounds[this._getOpposingRectCornerNameByIndex(index)].clone();
|
||||
this.corner = this.boundsPath.bounds[this._getRectCornerNameByIndex(index)].clone();
|
||||
this.origSize = this.corner.subtract(this.pivot);
|
||||
this.origCenter = this.boundsPath.bounds.center;
|
||||
for (const item of selectedItems) {
|
||||
|
@ -105,14 +109,14 @@ class ScaleTool {
|
|||
|
||||
for (let i = 0; i < this.boundsScaleHandles.length; i++) {
|
||||
const handle = this.boundsScaleHandles[i];
|
||||
handle.position = this.itemGroup.bounds[this.getRectCornerNameByIndex(i)];
|
||||
handle.position = this.itemGroup.bounds[this._getRectCornerNameByIndex(i)];
|
||||
handle.bringToFront();
|
||||
}
|
||||
|
||||
for (let i = 0; i < this.boundsRotHandles.length; i++) {
|
||||
const handle = this.boundsRotHandles[i];
|
||||
if (handle) {
|
||||
handle.position = this.itemGroup.bounds[this.getRectCornerNameByIndex(i)] + handle.data.offset;
|
||||
handle.position = this.itemGroup.bounds[this._getRectCornerNameByIndex(i)] + handle.data.offset;
|
||||
handle.bringToFront();
|
||||
}
|
||||
}
|
||||
|
@ -156,7 +160,7 @@ class ScaleTool {
|
|||
// @todo add back undo
|
||||
this.onUpdateSvg();
|
||||
}
|
||||
getRectCornerNameByIndex (index) {
|
||||
_getRectCornerNameByIndex (index) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
return 'bottomLeft';
|
||||
|
@ -176,7 +180,7 @@ class ScaleTool {
|
|||
return 'bottomCenter';
|
||||
}
|
||||
}
|
||||
getOpposingRectCornerNameByIndex (index) {
|
||||
_getOpposingRectCornerNameByIndex (index) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
return 'topRight';
|
||||
|
|
|
@ -6,10 +6,23 @@ import BoundingBoxTool from './bounding-box-tool';
|
|||
import SelectionBoxTool from './selection-box-tool';
|
||||
import paper from 'paper';
|
||||
|
||||
/**
|
||||
* paper.Tool that handles select mode. This is made up of 2 subtools.
|
||||
* - The selection box tool is active when the user clicks an empty space and drags.
|
||||
* It selects all items in the rectangle.
|
||||
* - The bounding box tool is active if the user clicks on a non-empty space. It handles
|
||||
* reshaping the item that was clicked.
|
||||
*/
|
||||
class SelectTool extends paper.Tool {
|
||||
/** The distance within which mouse events count as a hit against an item */
|
||||
static get TOLERANCE () {
|
||||
return 6;
|
||||
}
|
||||
/**
|
||||
* @param {function} setHoveredItem Callback to set the hovered item
|
||||
* @param {function} clearHoveredItem Callback to clear the hovered item
|
||||
* @param {!function} onUpdateSvg A callback to call when the image visibly changes
|
||||
*/
|
||||
constructor (setHoveredItem, clearHoveredItem, onUpdateSvg) {
|
||||
super();
|
||||
this.setHoveredItem = setHoveredItem;
|
||||
|
@ -18,13 +31,6 @@ class SelectTool extends paper.Tool {
|
|||
this.boundingBoxTool = new BoundingBoxTool(onUpdateSvg);
|
||||
this.selectionBoxTool = new SelectionBoxTool(Modes.SELECT);
|
||||
this.selectionBoxMode = false;
|
||||
this._hitOptions = {
|
||||
segments: true,
|
||||
stroke: true,
|
||||
curves: true,
|
||||
fill: true,
|
||||
guide: false
|
||||
};
|
||||
|
||||
// We have to set these functions instead of just declaring them because
|
||||
// paper.js tools hook up the listeners in the setter functions.
|
||||
|
@ -37,21 +43,42 @@ class SelectTool extends paper.Tool {
|
|||
selectRootItem();
|
||||
this.boundingBoxTool.setSelectionBounds();
|
||||
}
|
||||
/**
|
||||
* To be called when the hovered item changes. When the select tool hovers over a
|
||||
* new item, it compares against this to see if a hover item change event needs to
|
||||
* be fired.
|
||||
* @param {paper.Item} prevHoveredItem The highlight that indicates the mouse is over
|
||||
* a given item currently
|
||||
*/
|
||||
setPrevHoveredItem (prevHoveredItem) {
|
||||
this.prevHoveredItem = prevHoveredItem;
|
||||
}
|
||||
/**
|
||||
* Returns the hit options to use when conducting hit tests.
|
||||
* @param {boolean} preselectedOnly True if we should only return results that are already
|
||||
* selected.
|
||||
* @return {object} See paper.Item.hitTest for definition of options
|
||||
*/
|
||||
getHitOptions (preselectedOnly) {
|
||||
this._hitOptions.tolerance = SelectTool.TOLERANCE / paper.view.zoom;
|
||||
// Tolerance needs to be scaled when the view is zoomed in in order to represent the same
|
||||
// distance for the user to move the mouse.
|
||||
const hitOptions = {
|
||||
segments: true,
|
||||
stroke: true,
|
||||
curves: true,
|
||||
fill: true,
|
||||
guide: false,
|
||||
tolerance: SelectTool.TOLERANCE / paper.view.zoom
|
||||
};
|
||||
if (preselectedOnly) {
|
||||
this._hitOptions.selected = true;
|
||||
} else {
|
||||
delete this._hitOptions.selected;
|
||||
hitOptions.selected = true;
|
||||
}
|
||||
return this._hitOptions;
|
||||
return hitOptions;
|
||||
}
|
||||
handleMouseDown (event) {
|
||||
if (event.event.button > 0) return; // only first mouse button
|
||||
|
||||
// If bounding box tool does not find an item that was hit, use selection box tool.
|
||||
this.clearHoveredItem();
|
||||
if (!this.boundingBoxTool
|
||||
.onMouseDown(
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import {rectSelect} from '../guides';
|
||||
import {clearSelection, processRectangularSelection} from '../selection';
|
||||
|
||||
/** Tool to handle drag selection. A dotted line box appears and everything enclosed is selected. */
|
||||
class SelectionBoxTool {
|
||||
constructor (mode) {
|
||||
this.selectionRect = null;
|
||||
|
|
|
@ -1,11 +1,30 @@
|
|||
import paper from 'paper';
|
||||
import Modes from '../modes/modes';
|
||||
|
||||
import {getAllPaperItems} from './helper';
|
||||
import {getItemsGroup, isGroup} from './group';
|
||||
import {getRootItem, isBoundsItem, isCompoundPathItem, isPathItem, isPGTextItem} from './item';
|
||||
import {getItemsCompoundPath, isCompoundPath, isCompoundPathChild} from './compound-path';
|
||||
|
||||
/**
|
||||
* @param {boolean} includeGuides True if guide layer items like the bounding box should
|
||||
* be included in the returned items.
|
||||
* @return {Array<paper.item>} all top-level (direct descendants of a paper.Layer) items
|
||||
*/
|
||||
const getAllPaperItems = function (includeGuides) {
|
||||
includeGuides = includeGuides || false;
|
||||
const allItems = [];
|
||||
for (const layer of paper.project.layers) {
|
||||
for (const child of layer.children) {
|
||||
// don't give guides back
|
||||
if (!includeGuides && child.guide) {
|
||||
continue;
|
||||
}
|
||||
allItems.push(child);
|
||||
}
|
||||
}
|
||||
return allItems;
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {Array<paper.item>} all top-level (direct descendants of a paper.Layer) items
|
||||
* that aren't guide items or helper items.
|
||||
|
@ -489,6 +508,7 @@ const shouldShowSelectAll = function () {
|
|||
};
|
||||
|
||||
export {
|
||||
getAllPaperItems,
|
||||
selectAllItems,
|
||||
selectAllSegments,
|
||||
clearSelection,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import PaintEditor from './containers/paint-editor.jsx';
|
||||
import SelectionHOV from './containers/selection-hov.jsx';
|
||||
import SelectionHOV from './containers/selection-hoc.jsx';
|
||||
import ScratchPaintReducer from './reducers/scratch-paint-reducer';
|
||||
|
||||
const Wrapped = SelectionHOV(PaintEditor);
|
||||
|
|
Loading…
Reference in a new issue