add comments and clean up

This commit is contained in:
DD 2017-09-22 12:12:07 -04:00
parent 060ff0ab15
commit fd9a4af83f
12 changed files with 109 additions and 90 deletions

View file

@ -4,5 +4,7 @@
margin: auto; margin: auto;
position: relative; position: relative;
background-color: #fff; 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; image-rendering: pixelated;
} }

View file

@ -3,7 +3,7 @@ import React from 'react';
import {connect} from 'react-redux'; import {connect} from 'react-redux';
import paper from 'paper'; import paper from 'paper';
const SelectionHOV = function (WrappedComponent) { const SelectionHOC = function (WrappedComponent) {
class SelectionComponent extends React.Component { class SelectionComponent extends React.Component {
componentDidMount () { componentDidMount () {
if (this.props.hoveredItem) { if (this.props.hoveredItem) {
@ -43,4 +43,4 @@ const SelectionHOV = function (WrappedComponent) {
)(SelectionComponent); )(SelectionComponent);
}; };
export default SelectionHOV; export default SelectionHOC;

View file

@ -1,6 +1,6 @@
import paper from 'paper'; import paper from 'paper';
import {getGuideLayer} from './layer'; import {getGuideLayer} from './layer';
import {removePaperItemsByTags, removePaperItemsByDataTags} from './helper'; import {getAllPaperItems} from './selection';
const GUIDE_BLUE = '#009dec'; const GUIDE_BLUE = '#009dec';
const GUIDE_GREY = '#aaaaaa'; 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 () { const removeHelperItems = function () {
removePaperItemsByDataTags(['isHelperItem']); _removePaperItemsByDataTags(['isHelperItem']);
}; };
const removeAllGuides = function () { const removeAllGuides = function () {
removePaperItemsByTags(['guide']); _removePaperItemsByTags(['guide']);
}; };
export { export {

View file

@ -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
};

View file

@ -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 * 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 * (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. * delegates actions to the MoveTool, RotateTool or ScaleTool accordingly.

View file

@ -3,6 +3,9 @@ import {isCompoundPathItem, getRootItem} from '../item';
import {snapDeltaToAngle} from '../math'; import {snapDeltaToAngle} from '../math';
import {clearSelection, cloneSelection, getSelectedItems, setItemSelection} from '../selection'; import {clearSelection, cloneSelection, getSelectedItems, setItemSelection} from '../selection';
/**
* Tool to handle dragging an item to reposition it in a selection mode.
*/
class MoveTool { class MoveTool {
/** /**
* @param {!function} onUpdateSvg A callback to call when the image visibly changes * @param {!function} onUpdateSvg A callback to call when the image visibly changes

View file

@ -1,5 +1,8 @@
import paper from 'paper'; import paper from 'paper';
/**
* Tool to handle rotation when dragging the rotation handle in the bounding box tool.
*/
class RotateTool { class RotateTool {
/** /**
* @param {!function} onUpdateSvg A callback to call when the image visibly changes * @param {!function} onUpdateSvg A callback to call when the image visibly changes

View file

@ -1,5 +1,9 @@
import paper from 'paper'; 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 { class ScaleTool {
/** /**
* @param {!function} onUpdateSvg A callback to call when the image visibly changes * @param {!function} onUpdateSvg A callback to call when the image visibly changes
@ -34,9 +38,9 @@ class ScaleTool {
this.boundsPath = boundsPath; this.boundsPath = boundsPath;
this.boundsScaleHandles = boundsScaleHandles; this.boundsScaleHandles = boundsScaleHandles;
this.boundsRotHandles = boundsRotHandles; this.boundsRotHandles = boundsRotHandles;
this.pivot = this.boundsPath.bounds[this.getOpposingRectCornerNameByIndex(index)].clone(); this.pivot = this.boundsPath.bounds[this._getOpposingRectCornerNameByIndex(index)].clone();
this.origPivot = 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.corner = this.boundsPath.bounds[this._getRectCornerNameByIndex(index)].clone();
this.origSize = this.corner.subtract(this.pivot); this.origSize = this.corner.subtract(this.pivot);
this.origCenter = this.boundsPath.bounds.center; this.origCenter = this.boundsPath.bounds.center;
for (const item of selectedItems) { for (const item of selectedItems) {
@ -105,14 +109,14 @@ class ScaleTool {
for (let i = 0; i < this.boundsScaleHandles.length; i++) { for (let i = 0; i < this.boundsScaleHandles.length; i++) {
const handle = this.boundsScaleHandles[i]; const handle = this.boundsScaleHandles[i];
handle.position = this.itemGroup.bounds[this.getRectCornerNameByIndex(i)]; handle.position = this.itemGroup.bounds[this._getRectCornerNameByIndex(i)];
handle.bringToFront(); handle.bringToFront();
} }
for (let i = 0; i < this.boundsRotHandles.length; i++) { for (let i = 0; i < this.boundsRotHandles.length; i++) {
const handle = this.boundsRotHandles[i]; const handle = this.boundsRotHandles[i];
if (handle) { 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(); handle.bringToFront();
} }
} }
@ -156,7 +160,7 @@ class ScaleTool {
// @todo add back undo // @todo add back undo
this.onUpdateSvg(); this.onUpdateSvg();
} }
getRectCornerNameByIndex (index) { _getRectCornerNameByIndex (index) {
switch (index) { switch (index) {
case 0: case 0:
return 'bottomLeft'; return 'bottomLeft';
@ -176,7 +180,7 @@ class ScaleTool {
return 'bottomCenter'; return 'bottomCenter';
} }
} }
getOpposingRectCornerNameByIndex (index) { _getOpposingRectCornerNameByIndex (index) {
switch (index) { switch (index) {
case 0: case 0:
return 'topRight'; return 'topRight';

View file

@ -6,10 +6,23 @@ import BoundingBoxTool from './bounding-box-tool';
import SelectionBoxTool from './selection-box-tool'; import SelectionBoxTool from './selection-box-tool';
import paper from 'paper'; 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 { class SelectTool extends paper.Tool {
/** The distance within which mouse events count as a hit against an item */
static get TOLERANCE () { static get TOLERANCE () {
return 6; 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) { constructor (setHoveredItem, clearHoveredItem, onUpdateSvg) {
super(); super();
this.setHoveredItem = setHoveredItem; this.setHoveredItem = setHoveredItem;
@ -18,13 +31,6 @@ class SelectTool extends paper.Tool {
this.boundingBoxTool = new BoundingBoxTool(onUpdateSvg); this.boundingBoxTool = new BoundingBoxTool(onUpdateSvg);
this.selectionBoxTool = new SelectionBoxTool(Modes.SELECT); this.selectionBoxTool = new SelectionBoxTool(Modes.SELECT);
this.selectionBoxMode = false; 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 // We have to set these functions instead of just declaring them because
// paper.js tools hook up the listeners in the setter functions. // paper.js tools hook up the listeners in the setter functions.
@ -37,21 +43,42 @@ class SelectTool extends paper.Tool {
selectRootItem(); selectRootItem();
this.boundingBoxTool.setSelectionBounds(); 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) { setPrevHoveredItem (prevHoveredItem) {
this.prevHoveredItem = 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) { 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) { if (preselectedOnly) {
this._hitOptions.selected = true; hitOptions.selected = true;
} else {
delete this._hitOptions.selected;
} }
return this._hitOptions; return hitOptions;
} }
handleMouseDown (event) { handleMouseDown (event) {
if (event.event.button > 0) return; // only first mouse button 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(); this.clearHoveredItem();
if (!this.boundingBoxTool if (!this.boundingBoxTool
.onMouseDown( .onMouseDown(

View file

@ -1,6 +1,7 @@
import {rectSelect} from '../guides'; import {rectSelect} from '../guides';
import {clearSelection, processRectangularSelection} from '../selection'; import {clearSelection, processRectangularSelection} from '../selection';
/** Tool to handle drag selection. A dotted line box appears and everything enclosed is selected. */
class SelectionBoxTool { class SelectionBoxTool {
constructor (mode) { constructor (mode) {
this.selectionRect = null; this.selectionRect = null;

View file

@ -1,11 +1,30 @@
import paper from 'paper'; import paper from 'paper';
import Modes from '../modes/modes'; import Modes from '../modes/modes';
import {getAllPaperItems} from './helper';
import {getItemsGroup, isGroup} from './group'; import {getItemsGroup, isGroup} from './group';
import {getRootItem, isBoundsItem, isCompoundPathItem, isPathItem, isPGTextItem} from './item'; import {getRootItem, isBoundsItem, isCompoundPathItem, isPathItem, isPGTextItem} from './item';
import {getItemsCompoundPath, isCompoundPath, isCompoundPathChild} from './compound-path'; 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 * @return {Array<paper.item>} all top-level (direct descendants of a paper.Layer) items
* that aren't guide items or helper items. * that aren't guide items or helper items.
@ -489,6 +508,7 @@ const shouldShowSelectAll = function () {
}; };
export { export {
getAllPaperItems,
selectAllItems, selectAllItems,
selectAllSegments, selectAllSegments,
clearSelection, clearSelection,

View file

@ -1,5 +1,5 @@
import PaintEditor from './containers/paint-editor.jsx'; 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'; import ScratchPaintReducer from './reducers/scratch-paint-reducer';
const Wrapped = SelectionHOV(PaintEditor); const Wrapped = SelectionHOV(PaintEditor);