mirror of
https://github.com/scratchfoundation/scratch-paint.git
synced 2025-06-08 11:14:51 -04:00
Import and export bitmaps (#404)
* Rename svg to image * Import/export bitmap * Fix playground and readme * Fix lint * Assume strings are svgs
This commit is contained in:
parent
af29e606d8
commit
3d99044ccf
44 changed files with 350 additions and 301 deletions
README.md
src
components/paint-editor
containers
bit-brush-mode.jsxbit-line-mode.jsxbrush-mode.jsxeraser-mode.jsxfill-color-indicator.jsxfill-mode.jsxline-mode.jsxmode-tools.jsxoval-mode.jsxpaint-editor.jsxpaper-canvas.jsxrect-mode.jsxreshape-mode.jsxrounded-rect-mode.jsxselect-mode.jsxstroke-color-indicator.jsxstroke-width-indicator.jsxtext-mode.jsx
helper
bit-tools
blob-tools
group.jsorder.jsselection-tools
bounding-box-tool.jshandle-tool.jsmove-tool.jsnudge-tool.jspoint-tool.jsreshape-tool.jsrotate-tool.jsscale-tool.jsselect-tool.js
selection.jstools
undo.jsplayground
reducers
test/unit
15
README.md
15
README.md
|
@ -60,17 +60,22 @@ Then go to [http://localhost:8601](http://localhost:8601). 601 is supposed to lo
|
||||||
|
|
||||||
### How to include in your own Node.js App
|
### How to include in your own Node.js App
|
||||||
For an example of how to use scratch-paint as a library, check out the `scratch-paint/src/playground` directory.
|
For an example of how to use scratch-paint as a library, check out the `scratch-paint/src/playground` directory.
|
||||||
In `playground.jsx`, you can change the SVG vector that is passed in, and edit the handler `onUpdateSvg`, which is called with the new SVG each time the vector drawing is edited.
|
In `playground.jsx`, you can change the image that is passed in (which may either be nothing, an SVG string or an HTMLImageElement) and edit the handler `onUpdateImage`, which is called with the new image (either an SVG string or an HTMLCanvasElement) each time the vector drawing is edited.
|
||||||
|
|
||||||
|
If the `imageId` parameter changes, then the paint editor will be cleared, the undo stack reset, and the image re-imported.
|
||||||
|
|
||||||
|
SVGs of up to size 480 x 360 will fit into the view window of the paint editor, while bitmaps of size up to 960 x 720 will fit into the paint editor. One unit of an SVG will appear twice as tall and wide as one unit of a bitmap. This quirky import behavior comes from needing to support legacy projects in Scratch.
|
||||||
|
|
||||||
In your parent component:
|
In your parent component:
|
||||||
```
|
```
|
||||||
import PaintEditor from 'scratch-paint';
|
import PaintEditor from 'scratch-paint';
|
||||||
...
|
...
|
||||||
<PaintEditor
|
<PaintEditor
|
||||||
svg={optionalSvg}
|
image={optionalImage}
|
||||||
rotationCenterX={optionalCenterPointXRelativeToSvgTopLeft}
|
imageId={optionalId}
|
||||||
rotationCenterY={optionalCenterPointYRelativeToSvgTopLeft}
|
rotationCenterX={optionalCenterPointXRelativeToTopLeft}
|
||||||
onUpdateSvg={handleUpdateSvgFunction}
|
rotationCenterY={optionalCenterPointYRelativeToTopLeft}
|
||||||
|
onUpdateImage={handleUpdateImageFunction}
|
||||||
/>
|
/>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -329,43 +329,44 @@ const PaintEditorComponent = props => {
|
||||||
{/* fill */}
|
{/* fill */}
|
||||||
<FillColorIndicatorComponent
|
<FillColorIndicatorComponent
|
||||||
className={styles.modMarginRight}
|
className={styles.modMarginRight}
|
||||||
onUpdateSvg={props.onUpdateSvg}
|
onUpdateImage={props.onUpdateImage}
|
||||||
/>
|
/>
|
||||||
{/* stroke */}
|
{/* stroke */}
|
||||||
<StrokeColorIndicatorComponent
|
<StrokeColorIndicatorComponent
|
||||||
onUpdateSvg={props.onUpdateSvg}
|
onUpdateImage={props.onUpdateImage}
|
||||||
/>
|
/>
|
||||||
{/* stroke width */}
|
{/* stroke width */}
|
||||||
<StrokeWidthIndicatorComponent
|
<StrokeWidthIndicatorComponent
|
||||||
onUpdateSvg={props.onUpdateSvg}
|
onUpdateImage={props.onUpdateImage}
|
||||||
/>
|
/>
|
||||||
</InputGroup>
|
</InputGroup>
|
||||||
<InputGroup className={styles.modModeTools}>
|
<InputGroup className={styles.modModeTools}>
|
||||||
<ModeToolsContainer
|
<ModeToolsContainer
|
||||||
onUpdateSvg={props.onUpdateSvg}
|
onUpdateImage={props.onUpdateImage}
|
||||||
/>
|
/>
|
||||||
</InputGroup>
|
</InputGroup>
|
||||||
</div> :
|
</div> :
|
||||||
<div className={styles.row}>
|
isBitmap(props.format) ?
|
||||||
<InputGroup
|
<div className={styles.row}>
|
||||||
className={classNames(
|
<InputGroup
|
||||||
styles.row,
|
className={classNames(
|
||||||
styles.modDashedBorder,
|
styles.row,
|
||||||
styles.modLabeledIconHeight
|
styles.modDashedBorder,
|
||||||
)}
|
styles.modLabeledIconHeight
|
||||||
>
|
)}
|
||||||
{/* fill */}
|
>
|
||||||
<FillColorIndicatorComponent
|
{/* fill */}
|
||||||
className={styles.modMarginRight}
|
<FillColorIndicatorComponent
|
||||||
onUpdateSvg={props.onUpdateSvg}
|
className={styles.modMarginRight}
|
||||||
/>
|
onUpdateImage={props.onUpdateImage}
|
||||||
</InputGroup>
|
/>
|
||||||
<InputGroup className={styles.modModeTools}>
|
</InputGroup>
|
||||||
<ModeToolsContainer
|
<InputGroup className={styles.modModeTools}>
|
||||||
onUpdateSvg={props.onUpdateSvg}
|
<ModeToolsContainer
|
||||||
/>
|
onUpdateImage={props.onUpdateImage}
|
||||||
</InputGroup>
|
/>
|
||||||
</div>
|
</InputGroup>
|
||||||
|
</div> : null
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
@ -375,32 +376,32 @@ const PaintEditorComponent = props => {
|
||||||
{props.canvas !== null ? ( // eslint-disable-line no-negated-condition
|
{props.canvas !== null ? ( // eslint-disable-line no-negated-condition
|
||||||
<div className={isVector(props.format) ? styles.modeSelector : styles.hidden}>
|
<div className={isVector(props.format) ? styles.modeSelector : styles.hidden}>
|
||||||
<SelectMode
|
<SelectMode
|
||||||
onUpdateSvg={props.onUpdateSvg}
|
onUpdateImage={props.onUpdateImage}
|
||||||
/>
|
/>
|
||||||
<ReshapeMode
|
<ReshapeMode
|
||||||
onUpdateSvg={props.onUpdateSvg}
|
onUpdateImage={props.onUpdateImage}
|
||||||
/>
|
/>
|
||||||
<BrushMode
|
<BrushMode
|
||||||
onUpdateSvg={props.onUpdateSvg}
|
onUpdateImage={props.onUpdateImage}
|
||||||
/>
|
/>
|
||||||
<EraserMode
|
<EraserMode
|
||||||
onUpdateSvg={props.onUpdateSvg}
|
onUpdateImage={props.onUpdateImage}
|
||||||
/>
|
/>
|
||||||
<FillMode
|
<FillMode
|
||||||
onUpdateSvg={props.onUpdateSvg}
|
onUpdateImage={props.onUpdateImage}
|
||||||
/>
|
/>
|
||||||
<TextMode
|
<TextMode
|
||||||
textArea={props.textArea}
|
textArea={props.textArea}
|
||||||
onUpdateSvg={props.onUpdateSvg}
|
onUpdateImage={props.onUpdateImage}
|
||||||
/>
|
/>
|
||||||
<LineMode
|
<LineMode
|
||||||
onUpdateSvg={props.onUpdateSvg}
|
onUpdateImage={props.onUpdateImage}
|
||||||
/>
|
/>
|
||||||
<OvalMode
|
<OvalMode
|
||||||
onUpdateSvg={props.onUpdateSvg}
|
onUpdateImage={props.onUpdateImage}
|
||||||
/>
|
/>
|
||||||
<RectMode
|
<RectMode
|
||||||
onUpdateSvg={props.onUpdateSvg}
|
onUpdateImage={props.onUpdateImage}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
@ -408,10 +409,10 @@ const PaintEditorComponent = props => {
|
||||||
{props.canvas !== null ? ( // eslint-disable-line no-negated-condition
|
{props.canvas !== null ? ( // eslint-disable-line no-negated-condition
|
||||||
<div className={isBitmap(props.format) ? styles.modeSelector : styles.hidden}>
|
<div className={isBitmap(props.format) ? styles.modeSelector : styles.hidden}>
|
||||||
<BitBrushMode
|
<BitBrushMode
|
||||||
onUpdateSvg={props.onUpdateSvg}
|
onUpdateImage={props.onUpdateImage}
|
||||||
/>
|
/>
|
||||||
<BitLineMode
|
<BitLineMode
|
||||||
onUpdateSvg={props.onUpdateSvg}
|
onUpdateImage={props.onUpdateImage}
|
||||||
/>
|
/>
|
||||||
<BitOvalMode />
|
<BitOvalMode />
|
||||||
<BitRectMode />
|
<BitRectMode />
|
||||||
|
@ -432,11 +433,11 @@ const PaintEditorComponent = props => {
|
||||||
>
|
>
|
||||||
<PaperCanvas
|
<PaperCanvas
|
||||||
canvasRef={props.setCanvas}
|
canvasRef={props.setCanvas}
|
||||||
|
image={props.image}
|
||||||
|
imageId={props.imageId}
|
||||||
rotationCenterX={props.rotationCenterX}
|
rotationCenterX={props.rotationCenterX}
|
||||||
rotationCenterY={props.rotationCenterY}
|
rotationCenterY={props.rotationCenterY}
|
||||||
svg={props.svg}
|
onUpdateImage={props.onUpdateImage}
|
||||||
svgId={props.svgId}
|
|
||||||
onUpdateSvg={props.onUpdateSvg}
|
|
||||||
/>
|
/>
|
||||||
<textarea
|
<textarea
|
||||||
className={styles.textArea}
|
className={styles.textArea}
|
||||||
|
@ -470,19 +471,20 @@ const PaintEditorComponent = props => {
|
||||||
{props.intl.formatMessage(messages.bitmap)}
|
{props.intl.formatMessage(messages.bitmap)}
|
||||||
</span>
|
</span>
|
||||||
</Button> :
|
</Button> :
|
||||||
<Button
|
isBitmap(props.format) ?
|
||||||
className={styles.bitmapButton}
|
<Button
|
||||||
onClick={props.onSwitchToVector}
|
className={styles.bitmapButton}
|
||||||
>
|
onClick={props.onSwitchToVector}
|
||||||
<img
|
>
|
||||||
className={styles.bitmapButtonIcon}
|
<img
|
||||||
draggable={false}
|
className={styles.bitmapButtonIcon}
|
||||||
src={bitmapIcon}
|
draggable={false}
|
||||||
/>
|
src={bitmapIcon}
|
||||||
<span>
|
/>
|
||||||
{props.intl.formatMessage(messages.vector)}
|
<span>
|
||||||
</span>
|
{props.intl.formatMessage(messages.vector)}
|
||||||
</Button>
|
</span>
|
||||||
|
</Button> : null
|
||||||
}
|
}
|
||||||
{/* Zoom controls */}
|
{/* Zoom controls */}
|
||||||
<InputGroup className={styles.zoomControls}>
|
<InputGroup className={styles.zoomControls}>
|
||||||
|
@ -534,7 +536,12 @@ PaintEditorComponent.propTypes = {
|
||||||
canUndo: PropTypes.func.isRequired,
|
canUndo: PropTypes.func.isRequired,
|
||||||
canvas: PropTypes.instanceOf(Element),
|
canvas: PropTypes.instanceOf(Element),
|
||||||
colorInfo: Loupe.propTypes.colorInfo,
|
colorInfo: Loupe.propTypes.colorInfo,
|
||||||
format: PropTypes.oneOf(Object.keys(Formats)).isRequired,
|
format: PropTypes.oneOf(Object.keys(Formats)),
|
||||||
|
image: PropTypes.oneOfType([
|
||||||
|
PropTypes.string,
|
||||||
|
PropTypes.instanceOf(HTMLImageElement)
|
||||||
|
]),
|
||||||
|
imageId: PropTypes.string,
|
||||||
intl: intlShape,
|
intl: intlShape,
|
||||||
isEyeDropping: PropTypes.bool,
|
isEyeDropping: PropTypes.bool,
|
||||||
name: PropTypes.string,
|
name: PropTypes.string,
|
||||||
|
@ -548,8 +555,8 @@ PaintEditorComponent.propTypes = {
|
||||||
onSwitchToVector: PropTypes.func.isRequired,
|
onSwitchToVector: PropTypes.func.isRequired,
|
||||||
onUndo: PropTypes.func.isRequired,
|
onUndo: PropTypes.func.isRequired,
|
||||||
onUngroup: PropTypes.func.isRequired,
|
onUngroup: PropTypes.func.isRequired,
|
||||||
|
onUpdateImage: PropTypes.func.isRequired,
|
||||||
onUpdateName: PropTypes.func.isRequired,
|
onUpdateName: PropTypes.func.isRequired,
|
||||||
onUpdateSvg: PropTypes.func.isRequired,
|
|
||||||
onZoomIn: PropTypes.func.isRequired,
|
onZoomIn: PropTypes.func.isRequired,
|
||||||
onZoomOut: PropTypes.func.isRequired,
|
onZoomOut: PropTypes.func.isRequired,
|
||||||
onZoomReset: PropTypes.func.isRequired,
|
onZoomReset: PropTypes.func.isRequired,
|
||||||
|
@ -557,8 +564,6 @@ PaintEditorComponent.propTypes = {
|
||||||
rotationCenterY: PropTypes.number,
|
rotationCenterY: PropTypes.number,
|
||||||
setCanvas: PropTypes.func.isRequired,
|
setCanvas: PropTypes.func.isRequired,
|
||||||
setTextArea: PropTypes.func.isRequired,
|
setTextArea: PropTypes.func.isRequired,
|
||||||
svg: PropTypes.string,
|
|
||||||
svgId: PropTypes.string,
|
|
||||||
textArea: PropTypes.instanceOf(Element)
|
textArea: PropTypes.instanceOf(Element)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,7 @@ class BitBrushMode extends React.Component {
|
||||||
color = DEFAULT_COLOR;
|
color = DEFAULT_COLOR;
|
||||||
}
|
}
|
||||||
this.tool = new BitBrushTool(
|
this.tool = new BitBrushTool(
|
||||||
this.props.onUpdateSvg
|
this.props.onUpdateImage
|
||||||
);
|
);
|
||||||
this.tool.setColor(color);
|
this.tool.setColor(color);
|
||||||
this.tool.setBrushSize(this.props.bitBrushSize);
|
this.tool.setBrushSize(this.props.bitBrushSize);
|
||||||
|
@ -81,7 +81,7 @@ BitBrushMode.propTypes = {
|
||||||
handleMouseDown: PropTypes.func.isRequired,
|
handleMouseDown: PropTypes.func.isRequired,
|
||||||
isBitBrushModeActive: PropTypes.bool.isRequired,
|
isBitBrushModeActive: PropTypes.bool.isRequired,
|
||||||
onChangeFillColor: PropTypes.func.isRequired,
|
onChangeFillColor: PropTypes.func.isRequired,
|
||||||
onUpdateSvg: PropTypes.func.isRequired
|
onUpdateImage: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
|
|
|
@ -52,7 +52,7 @@ class BitLineMode extends React.Component {
|
||||||
color = DEFAULT_COLOR;
|
color = DEFAULT_COLOR;
|
||||||
}
|
}
|
||||||
this.tool = new BitLineTool(
|
this.tool = new BitLineTool(
|
||||||
this.props.onUpdateSvg
|
this.props.onUpdateImage
|
||||||
);
|
);
|
||||||
this.tool.setColor(color);
|
this.tool.setColor(color);
|
||||||
this.tool.setLineSize(this.props.bitBrushSize);
|
this.tool.setLineSize(this.props.bitBrushSize);
|
||||||
|
@ -81,7 +81,7 @@ BitLineMode.propTypes = {
|
||||||
handleMouseDown: PropTypes.func.isRequired,
|
handleMouseDown: PropTypes.func.isRequired,
|
||||||
isBitLineModeActive: PropTypes.bool.isRequired,
|
isBitLineModeActive: PropTypes.bool.isRequired,
|
||||||
onChangeFillColor: PropTypes.func.isRequired,
|
onChangeFillColor: PropTypes.func.isRequired,
|
||||||
onUpdateSvg: PropTypes.func.isRequired
|
onUpdateImage: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
|
|
|
@ -21,7 +21,7 @@ class BrushMode extends React.Component {
|
||||||
'deactivateTool'
|
'deactivateTool'
|
||||||
]);
|
]);
|
||||||
this.blob = new Blobbiness(
|
this.blob = new Blobbiness(
|
||||||
this.props.onUpdateSvg, this.props.clearSelectedItems);
|
this.props.onUpdateImage, this.props.clearSelectedItems);
|
||||||
}
|
}
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
if (this.props.isBrushModeActive) {
|
if (this.props.isBrushModeActive) {
|
||||||
|
@ -85,7 +85,7 @@ BrushMode.propTypes = {
|
||||||
handleMouseDown: PropTypes.func.isRequired,
|
handleMouseDown: PropTypes.func.isRequired,
|
||||||
isBrushModeActive: PropTypes.bool.isRequired,
|
isBrushModeActive: PropTypes.bool.isRequired,
|
||||||
onChangeFillColor: PropTypes.func.isRequired,
|
onChangeFillColor: PropTypes.func.isRequired,
|
||||||
onUpdateSvg: PropTypes.func.isRequired
|
onUpdateImage: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
|
|
|
@ -17,7 +17,7 @@ class EraserMode extends React.Component {
|
||||||
'deactivateTool'
|
'deactivateTool'
|
||||||
]);
|
]);
|
||||||
this.blob = new Blobbiness(
|
this.blob = new Blobbiness(
|
||||||
this.props.onUpdateSvg, this.props.clearSelectedItems);
|
this.props.onUpdateImage, this.props.clearSelectedItems);
|
||||||
}
|
}
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
if (this.props.isEraserModeActive) {
|
if (this.props.isEraserModeActive) {
|
||||||
|
@ -62,7 +62,7 @@ EraserMode.propTypes = {
|
||||||
}),
|
}),
|
||||||
handleMouseDown: PropTypes.func.isRequired,
|
handleMouseDown: PropTypes.func.isRequired,
|
||||||
isEraserModeActive: PropTypes.bool.isRequired,
|
isEraserModeActive: PropTypes.bool.isRequired,
|
||||||
onUpdateSvg: PropTypes.func.isRequired
|
onUpdateImage: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
|
|
|
@ -21,10 +21,10 @@ class FillColorIndicator extends React.Component {
|
||||||
this._hasChanged = false;
|
this._hasChanged = false;
|
||||||
}
|
}
|
||||||
componentWillReceiveProps (newProps) {
|
componentWillReceiveProps (newProps) {
|
||||||
const {fillColorModalVisible, onUpdateSvg} = this.props;
|
const {fillColorModalVisible, onUpdateImage} = this.props;
|
||||||
if (fillColorModalVisible && !newProps.fillColorModalVisible) {
|
if (fillColorModalVisible && !newProps.fillColorModalVisible) {
|
||||||
// Submit the new SVG, which also stores a single undo/redo action.
|
// Submit the new SVG, which also stores a single undo/redo action.
|
||||||
if (this._hasChanged) onUpdateSvg();
|
if (this._hasChanged) onUpdateImage();
|
||||||
this._hasChanged = false;
|
this._hasChanged = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,7 @@ FillColorIndicator.propTypes = {
|
||||||
isEyeDropping: PropTypes.bool.isRequired,
|
isEyeDropping: PropTypes.bool.isRequired,
|
||||||
onChangeFillColor: PropTypes.func.isRequired,
|
onChangeFillColor: PropTypes.func.isRequired,
|
||||||
onCloseFillColor: PropTypes.func.isRequired,
|
onCloseFillColor: PropTypes.func.isRequired,
|
||||||
onUpdateSvg: PropTypes.func.isRequired,
|
onUpdateImage: PropTypes.func.isRequired,
|
||||||
textEditTarget: PropTypes.number
|
textEditTarget: PropTypes.number
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ class FillMode extends React.Component {
|
||||||
this.tool = new FillTool(
|
this.tool = new FillTool(
|
||||||
this.props.setHoveredItem,
|
this.props.setHoveredItem,
|
||||||
this.props.clearHoveredItem,
|
this.props.clearHoveredItem,
|
||||||
this.props.onUpdateSvg
|
this.props.onUpdateImage
|
||||||
);
|
);
|
||||||
this.tool.setFillColor(this.props.fillColor === MIXED ? DEFAULT_COLOR : this.props.fillColor);
|
this.tool.setFillColor(this.props.fillColor === MIXED ? DEFAULT_COLOR : this.props.fillColor);
|
||||||
this.tool.setPrevHoveredItemId(this.props.hoveredItemId);
|
this.tool.setPrevHoveredItemId(this.props.hoveredItemId);
|
||||||
|
@ -82,7 +82,7 @@ FillMode.propTypes = {
|
||||||
hoveredItemId: PropTypes.number,
|
hoveredItemId: PropTypes.number,
|
||||||
isFillModeActive: PropTypes.bool.isRequired,
|
isFillModeActive: PropTypes.bool.isRequired,
|
||||||
onChangeFillColor: PropTypes.func.isRequired,
|
onChangeFillColor: PropTypes.func.isRequired,
|
||||||
onUpdateSvg: PropTypes.func.isRequired,
|
onUpdateImage: PropTypes.func.isRequired,
|
||||||
setHoveredItem: PropTypes.func.isRequired
|
setHoveredItem: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -220,7 +220,7 @@ class LineMode extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.path) {
|
if (this.path) {
|
||||||
this.props.onUpdateSvg();
|
this.props.onUpdateImage();
|
||||||
this.path = null;
|
this.path = null;
|
||||||
}
|
}
|
||||||
this.active = false;
|
this.active = false;
|
||||||
|
@ -257,7 +257,7 @@ LineMode.propTypes = {
|
||||||
isLineModeActive: PropTypes.bool.isRequired,
|
isLineModeActive: PropTypes.bool.isRequired,
|
||||||
onChangeStrokeColor: PropTypes.func.isRequired,
|
onChangeStrokeColor: PropTypes.func.isRequired,
|
||||||
onChangeStrokeWidth: PropTypes.func.isRequired,
|
onChangeStrokeWidth: PropTypes.func.isRequired,
|
||||||
onUpdateSvg: PropTypes.func.isRequired
|
onUpdateImage: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
|
|
|
@ -117,7 +117,7 @@ class ModeTools extends React.Component {
|
||||||
}
|
}
|
||||||
if (changed) {
|
if (changed) {
|
||||||
this.props.setSelectedItems();
|
this.props.setSelectedItems();
|
||||||
this.props.onUpdateSvg();
|
this.props.onUpdateImage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
handlePointPoints () {
|
handlePointPoints () {
|
||||||
|
@ -133,7 +133,7 @@ class ModeTools extends React.Component {
|
||||||
}
|
}
|
||||||
if (changed) {
|
if (changed) {
|
||||||
this.props.setSelectedItems();
|
this.props.setSelectedItems();
|
||||||
this.props.onUpdateSvg();
|
this.props.onUpdateImage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_handleFlip (horizontalScale, verticalScale) {
|
_handleFlip (horizontalScale, verticalScale) {
|
||||||
|
@ -160,7 +160,7 @@ class ModeTools extends React.Component {
|
||||||
}
|
}
|
||||||
itemGroup.remove();
|
itemGroup.remove();
|
||||||
|
|
||||||
this.props.onUpdateSvg();
|
this.props.onUpdateImage();
|
||||||
}
|
}
|
||||||
handleFlipHorizontal () {
|
handleFlipHorizontal () {
|
||||||
this._handleFlip(-1, 1);
|
this._handleFlip(-1, 1);
|
||||||
|
@ -194,7 +194,7 @@ class ModeTools extends React.Component {
|
||||||
}
|
}
|
||||||
this.props.incrementPasteOffset();
|
this.props.incrementPasteOffset();
|
||||||
this.props.setSelectedItems();
|
this.props.setSelectedItems();
|
||||||
this.props.onUpdateSvg();
|
this.props.onUpdateImage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
render () {
|
render () {
|
||||||
|
@ -217,7 +217,7 @@ ModeTools.propTypes = {
|
||||||
clearSelectedItems: PropTypes.func.isRequired,
|
clearSelectedItems: PropTypes.func.isRequired,
|
||||||
clipboardItems: PropTypes.arrayOf(PropTypes.array),
|
clipboardItems: PropTypes.arrayOf(PropTypes.array),
|
||||||
incrementPasteOffset: PropTypes.func.isRequired,
|
incrementPasteOffset: PropTypes.func.isRequired,
|
||||||
onUpdateSvg: PropTypes.func.isRequired,
|
onUpdateImage: PropTypes.func.isRequired,
|
||||||
pasteOffset: PropTypes.number,
|
pasteOffset: PropTypes.number,
|
||||||
// Listen on selected items to update hasSelectedPoints
|
// Listen on selected items to update hasSelectedPoints
|
||||||
selectedItems:
|
selectedItems:
|
||||||
|
|
|
@ -65,7 +65,7 @@ class OvalMode extends React.Component {
|
||||||
this.tool = new OvalTool(
|
this.tool = new OvalTool(
|
||||||
this.props.setSelectedItems,
|
this.props.setSelectedItems,
|
||||||
this.props.clearSelectedItems,
|
this.props.clearSelectedItems,
|
||||||
this.props.onUpdateSvg
|
this.props.onUpdateImage
|
||||||
);
|
);
|
||||||
this.tool.setColorState(this.props.colorState);
|
this.tool.setColorState(this.props.colorState);
|
||||||
this.tool.activate();
|
this.tool.activate();
|
||||||
|
@ -96,7 +96,7 @@ OvalMode.propTypes = {
|
||||||
isOvalModeActive: PropTypes.bool.isRequired,
|
isOvalModeActive: PropTypes.bool.isRequired,
|
||||||
onChangeFillColor: PropTypes.func.isRequired,
|
onChangeFillColor: PropTypes.func.isRequired,
|
||||||
onChangeStrokeColor: PropTypes.func.isRequired,
|
onChangeStrokeColor: PropTypes.func.isRequired,
|
||||||
onUpdateSvg: PropTypes.func.isRequired,
|
onUpdateImage: PropTypes.func.isRequired,
|
||||||
selectedItems: PropTypes.arrayOf(PropTypes.instanceOf(paper.Item)),
|
selectedItems: PropTypes.arrayOf(PropTypes.instanceOf(paper.Item)),
|
||||||
setSelectedItems: PropTypes.func.isRequired
|
setSelectedItems: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
|
@ -35,7 +35,7 @@ class PaintEditor extends React.Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
super(props);
|
super(props);
|
||||||
bindAll(this, [
|
bindAll(this, [
|
||||||
'handleUpdateSvg',
|
'handleUpdateImage',
|
||||||
'handleUndo',
|
'handleUndo',
|
||||||
'handleRedo',
|
'handleRedo',
|
||||||
'handleSendBackward',
|
'handleSendBackward',
|
||||||
|
@ -118,7 +118,7 @@ class PaintEditor extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
handleUpdateSvg (skipSnapshot) {
|
handleUpdateImage (skipSnapshot) {
|
||||||
// Store the zoom/pan and restore it after snapshotting
|
// Store the zoom/pan and restore it after snapshotting
|
||||||
// TODO Only doing this because snapshotting at zoom/pan makes export wrong
|
// TODO Only doing this because snapshotting at zoom/pan makes export wrong
|
||||||
const oldZoom = paper.project.view.zoom;
|
const oldZoom = paper.project.view.zoom;
|
||||||
|
@ -127,35 +127,36 @@ class PaintEditor extends React.Component {
|
||||||
|
|
||||||
let raster;
|
let raster;
|
||||||
if (isBitmap(this.props.format)) {
|
if (isBitmap(this.props.format)) {
|
||||||
// @todo export bitmap here
|
|
||||||
raster = trim(getRaster());
|
raster = trim(getRaster());
|
||||||
if (raster.width === 0 || raster.height === 0) {
|
raster.remove();
|
||||||
raster.remove();
|
|
||||||
} else {
|
this.props.onUpdateImage(
|
||||||
paper.project.activeLayer.addChild(raster);
|
false /* isVector */,
|
||||||
}
|
raster.canvas,
|
||||||
|
paper.project.view.center.x - raster.bounds.x,
|
||||||
|
paper.project.view.center.y - raster.bounds.y);
|
||||||
|
} else if (isVector(this.props.format)) {
|
||||||
|
const guideLayers = hideGuideLayers(true /* includeRaster */);
|
||||||
|
|
||||||
|
// Export at 0.5x
|
||||||
|
scaleWithStrokes(paper.project.activeLayer, .5, new paper.Point());
|
||||||
|
const bounds = paper.project.activeLayer.bounds;
|
||||||
|
|
||||||
|
this.props.onUpdateImage(
|
||||||
|
true /* isVector */,
|
||||||
|
paper.project.exportSVG({
|
||||||
|
asString: true,
|
||||||
|
bounds: 'content',
|
||||||
|
matrix: new paper.Matrix().translate(-bounds.x, -bounds.y)
|
||||||
|
}),
|
||||||
|
(paper.project.view.center.x / 2) - bounds.x,
|
||||||
|
(paper.project.view.center.y / 2) - bounds.y);
|
||||||
|
|
||||||
|
scaleWithStrokes(paper.project.activeLayer, 2, new paper.Point());
|
||||||
|
paper.project.activeLayer.applyMatrix = true;
|
||||||
|
|
||||||
|
showGuideLayers(guideLayers);
|
||||||
}
|
}
|
||||||
|
|
||||||
const guideLayers = hideGuideLayers(true /* includeRaster */);
|
|
||||||
|
|
||||||
// Export at 0.5x
|
|
||||||
scaleWithStrokes(paper.project.activeLayer, .5, new paper.Point());
|
|
||||||
const bounds = paper.project.activeLayer.bounds;
|
|
||||||
|
|
||||||
this.props.onUpdateSvg(
|
|
||||||
paper.project.exportSVG({
|
|
||||||
asString: true,
|
|
||||||
bounds: 'content',
|
|
||||||
matrix: new paper.Matrix().translate(-bounds.x, -bounds.y)
|
|
||||||
}),
|
|
||||||
(paper.project.view.center.x / 2) - bounds.x,
|
|
||||||
(paper.project.view.center.y / 2) - bounds.y);
|
|
||||||
|
|
||||||
scaleWithStrokes(paper.project.activeLayer, 2, new paper.Point());
|
|
||||||
paper.project.activeLayer.applyMatrix = true;
|
|
||||||
|
|
||||||
showGuideLayers(guideLayers);
|
|
||||||
if (raster) raster.remove();
|
|
||||||
|
|
||||||
if (!skipSnapshot) {
|
if (!skipSnapshot) {
|
||||||
performSnapshot(this.props.undoSnapshot, this.props.format);
|
performSnapshot(this.props.undoSnapshot, this.props.format);
|
||||||
|
@ -166,28 +167,28 @@ class PaintEditor extends React.Component {
|
||||||
paper.project.view.center = oldCenter;
|
paper.project.view.center = oldCenter;
|
||||||
}
|
}
|
||||||
handleUndo () {
|
handleUndo () {
|
||||||
performUndo(this.props.undoState, this.props.onUndo, this.props.setSelectedItems, this.handleUpdateSvg);
|
performUndo(this.props.undoState, this.props.onUndo, this.props.setSelectedItems, this.handleUpdateImage);
|
||||||
}
|
}
|
||||||
handleRedo () {
|
handleRedo () {
|
||||||
performRedo(this.props.undoState, this.props.onRedo, this.props.setSelectedItems, this.handleUpdateSvg);
|
performRedo(this.props.undoState, this.props.onRedo, this.props.setSelectedItems, this.handleUpdateImage);
|
||||||
}
|
}
|
||||||
handleGroup () {
|
handleGroup () {
|
||||||
groupSelection(this.props.clearSelectedItems, this.props.setSelectedItems, this.handleUpdateSvg);
|
groupSelection(this.props.clearSelectedItems, this.props.setSelectedItems, this.handleUpdateImage);
|
||||||
}
|
}
|
||||||
handleUngroup () {
|
handleUngroup () {
|
||||||
ungroupSelection(this.props.clearSelectedItems, this.props.setSelectedItems, this.handleUpdateSvg);
|
ungroupSelection(this.props.clearSelectedItems, this.props.setSelectedItems, this.handleUpdateImage);
|
||||||
}
|
}
|
||||||
handleSendBackward () {
|
handleSendBackward () {
|
||||||
sendBackward(this.handleUpdateSvg);
|
sendBackward(this.handleUpdateImage);
|
||||||
}
|
}
|
||||||
handleSendForward () {
|
handleSendForward () {
|
||||||
bringForward(this.handleUpdateSvg);
|
bringForward(this.handleUpdateImage);
|
||||||
}
|
}
|
||||||
handleSendToBack () {
|
handleSendToBack () {
|
||||||
sendToBack(this.handleUpdateSvg);
|
sendToBack(this.handleUpdateImage);
|
||||||
}
|
}
|
||||||
handleSendToFront () {
|
handleSendToFront () {
|
||||||
bringToFront(this.handleUpdateSvg);
|
bringToFront(this.handleUpdateImage);
|
||||||
}
|
}
|
||||||
canUndo () {
|
canUndo () {
|
||||||
return shouldShowUndo(this.props.undoState);
|
return shouldShowUndo(this.props.undoState);
|
||||||
|
@ -287,14 +288,14 @@ class PaintEditor extends React.Component {
|
||||||
canvas={this.state.canvas}
|
canvas={this.state.canvas}
|
||||||
colorInfo={this.state.colorInfo}
|
colorInfo={this.state.colorInfo}
|
||||||
format={this.props.format}
|
format={this.props.format}
|
||||||
|
image={this.props.image}
|
||||||
|
imageId={this.props.imageId}
|
||||||
isEyeDropping={this.props.isEyeDropping}
|
isEyeDropping={this.props.isEyeDropping}
|
||||||
name={this.props.name}
|
name={this.props.name}
|
||||||
rotationCenterX={this.props.rotationCenterX}
|
rotationCenterX={this.props.rotationCenterX}
|
||||||
rotationCenterY={this.props.rotationCenterY}
|
rotationCenterY={this.props.rotationCenterY}
|
||||||
setCanvas={this.setCanvas}
|
setCanvas={this.setCanvas}
|
||||||
setTextArea={this.setTextArea}
|
setTextArea={this.setTextArea}
|
||||||
svg={this.props.svg}
|
|
||||||
svgId={this.props.svgId}
|
|
||||||
textArea={this.state.textArea}
|
textArea={this.state.textArea}
|
||||||
onGroup={this.handleGroup}
|
onGroup={this.handleGroup}
|
||||||
onRedo={this.handleRedo}
|
onRedo={this.handleRedo}
|
||||||
|
@ -306,8 +307,8 @@ class PaintEditor extends React.Component {
|
||||||
onSwitchToVector={this.props.handleSwitchToVector}
|
onSwitchToVector={this.props.handleSwitchToVector}
|
||||||
onUndo={this.handleUndo}
|
onUndo={this.handleUndo}
|
||||||
onUngroup={this.handleUngroup}
|
onUngroup={this.handleUngroup}
|
||||||
|
onUpdateImage={this.handleUpdateImage}
|
||||||
onUpdateName={this.props.onUpdateName}
|
onUpdateName={this.props.onUpdateName}
|
||||||
onUpdateSvg={this.handleUpdateSvg}
|
|
||||||
onZoomIn={this.handleZoomIn}
|
onZoomIn={this.handleZoomIn}
|
||||||
onZoomOut={this.handleZoomOut}
|
onZoomOut={this.handleZoomOut}
|
||||||
onZoomReset={this.handleZoomReset}
|
onZoomReset={this.handleZoomReset}
|
||||||
|
@ -320,9 +321,14 @@ PaintEditor.propTypes = {
|
||||||
changeColorToEyeDropper: PropTypes.func,
|
changeColorToEyeDropper: PropTypes.func,
|
||||||
changeMode: PropTypes.func.isRequired,
|
changeMode: PropTypes.func.isRequired,
|
||||||
clearSelectedItems: PropTypes.func.isRequired,
|
clearSelectedItems: PropTypes.func.isRequired,
|
||||||
format: PropTypes.oneOf(Object.keys(Formats)).isRequired,
|
format: PropTypes.oneOf(Object.keys(Formats)),
|
||||||
handleSwitchToBitmap: PropTypes.func.isRequired,
|
handleSwitchToBitmap: PropTypes.func.isRequired,
|
||||||
handleSwitchToVector: PropTypes.func.isRequired,
|
handleSwitchToVector: PropTypes.func.isRequired,
|
||||||
|
image: PropTypes.oneOfType([
|
||||||
|
PropTypes.string,
|
||||||
|
PropTypes.instanceOf(HTMLImageElement)
|
||||||
|
]),
|
||||||
|
imageId: PropTypes.string,
|
||||||
isEyeDropping: PropTypes.bool,
|
isEyeDropping: PropTypes.bool,
|
||||||
mode: PropTypes.oneOf(Object.keys(Modes)).isRequired,
|
mode: PropTypes.oneOf(Object.keys(Modes)).isRequired,
|
||||||
name: PropTypes.string,
|
name: PropTypes.string,
|
||||||
|
@ -330,8 +336,8 @@ PaintEditor.propTypes = {
|
||||||
onKeyPress: PropTypes.func.isRequired,
|
onKeyPress: PropTypes.func.isRequired,
|
||||||
onRedo: PropTypes.func.isRequired,
|
onRedo: PropTypes.func.isRequired,
|
||||||
onUndo: PropTypes.func.isRequired,
|
onUndo: PropTypes.func.isRequired,
|
||||||
|
onUpdateImage: PropTypes.func.isRequired,
|
||||||
onUpdateName: PropTypes.func.isRequired,
|
onUpdateName: PropTypes.func.isRequired,
|
||||||
onUpdateSvg: PropTypes.func.isRequired,
|
|
||||||
previousTool: PropTypes.shape({ // paper.Tool
|
previousTool: PropTypes.shape({ // paper.Tool
|
||||||
activate: PropTypes.func.isRequired,
|
activate: PropTypes.func.isRequired,
|
||||||
remove: PropTypes.func.isRequired
|
remove: PropTypes.func.isRequired
|
||||||
|
@ -340,8 +346,6 @@ PaintEditor.propTypes = {
|
||||||
rotationCenterX: PropTypes.number,
|
rotationCenterX: PropTypes.number,
|
||||||
rotationCenterY: PropTypes.number,
|
rotationCenterY: PropTypes.number,
|
||||||
setSelectedItems: PropTypes.func.isRequired,
|
setSelectedItems: PropTypes.func.isRequired,
|
||||||
svg: PropTypes.string,
|
|
||||||
svgId: PropTypes.string,
|
|
||||||
textEditing: PropTypes.bool.isRequired,
|
textEditing: PropTypes.bool.isRequired,
|
||||||
undoSnapshot: PropTypes.func.isRequired,
|
undoSnapshot: PropTypes.func.isRequired,
|
||||||
undoState: PropTypes.shape({
|
undoState: PropTypes.shape({
|
||||||
|
|
|
@ -28,6 +28,7 @@ class PaperCanvas extends React.Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
super(props);
|
super(props);
|
||||||
bindAll(this, [
|
bindAll(this, [
|
||||||
|
'checkFormat',
|
||||||
'convertToBitmap',
|
'convertToBitmap',
|
||||||
'convertToVector',
|
'convertToVector',
|
||||||
'setCanvas',
|
'setCanvas',
|
||||||
|
@ -51,15 +52,26 @@ class PaperCanvas extends React.Component {
|
||||||
paper.settings.handleSize = 0;
|
paper.settings.handleSize = 0;
|
||||||
// Make layers.
|
// Make layers.
|
||||||
setupLayers();
|
setupLayers();
|
||||||
if (this.props.svg) {
|
if (this.props.image) {
|
||||||
this.importSvg(this.props.svg, this.props.rotationCenterX, this.props.rotationCenterY);
|
if (isBitmap(this.checkFormat(this.props.image))) {
|
||||||
|
// import bitmap
|
||||||
|
this.props.changeFormat(Formats.BITMAP_SKIP_CONVERT);
|
||||||
|
performSnapshot(this.props.undoSnapshot, this.props.format);
|
||||||
|
getRaster().drawImage(
|
||||||
|
this.props.image,
|
||||||
|
paper.project.view.center.x - this.props.rotationCenterX,
|
||||||
|
paper.project.view.center.y - this.props.rotationCenterY);
|
||||||
|
} else if (isVector(this.checkFormat(this.props.image))) {
|
||||||
|
this.props.changeFormat(Formats.VECTOR_SKIP_CONVERT);
|
||||||
|
this.importSvg(this.props.image, this.props.rotationCenterX, this.props.rotationCenterY);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
performSnapshot(this.props.undoSnapshot, this.props.format);
|
performSnapshot(this.props.undoSnapshot, this.props.format);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
componentWillReceiveProps (newProps) {
|
componentWillReceiveProps (newProps) {
|
||||||
if (this.props.svgId !== newProps.svgId) {
|
if (this.props.imageId !== newProps.imageId) {
|
||||||
this.switchCostume(newProps.svg, newProps.rotationCenterX, newProps.rotationCenterY);
|
this.switchCostume(newProps.image, newProps.rotationCenterX, newProps.rotationCenterY);
|
||||||
} else if (isVector(this.props.format) && newProps.format === Formats.BITMAP) {
|
} else if (isVector(this.props.format) && newProps.format === Formats.BITMAP) {
|
||||||
this.convertToBitmap();
|
this.convertToBitmap();
|
||||||
} else if (isBitmap(this.props.format) && newProps.format === Formats.VECTOR) {
|
} else if (isBitmap(this.props.format) && newProps.format === Formats.VECTOR) {
|
||||||
|
@ -77,7 +89,7 @@ class PaperCanvas extends React.Component {
|
||||||
}
|
}
|
||||||
// Backspace, delete
|
// Backspace, delete
|
||||||
if (event.key === 'Delete' || event.key === 'Backspace') {
|
if (event.key === 'Delete' || event.key === 'Backspace') {
|
||||||
if (deleteSelection(this.props.mode, this.props.onUpdateSvg)) {
|
if (deleteSelection(this.props.mode, this.props.onUpdateImage)) {
|
||||||
this.props.setSelectedItems();
|
this.props.setSelectedItems();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,13 +121,14 @@ class PaperCanvas extends React.Component {
|
||||||
const img = new Image();
|
const img = new Image();
|
||||||
img.onload = () => {
|
img.onload = () => {
|
||||||
const raster = new paper.Raster(img);
|
const raster = new paper.Raster(img);
|
||||||
|
raster.remove();
|
||||||
raster.onLoad = () => {
|
raster.onLoad = () => {
|
||||||
const subCanvas = raster.canvas;
|
const subCanvas = raster.canvas;
|
||||||
getRaster().drawImage(
|
getRaster().drawImage(
|
||||||
subCanvas,
|
subCanvas,
|
||||||
new paper.Point(Math.floor(bounds.topLeft.x), Math.floor(bounds.topLeft.y)));
|
new paper.Point(Math.floor(bounds.topLeft.x), Math.floor(bounds.topLeft.y)));
|
||||||
paper.project.activeLayer.removeChildren();
|
paper.project.activeLayer.removeChildren();
|
||||||
this.props.onUpdateSvg();
|
this.props.onUpdateImage();
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
img.src = `data:image/svg+xml;charset=utf-8,${svgString}`;
|
img.src = `data:image/svg+xml;charset=utf-8,${svgString}`;
|
||||||
|
@ -133,9 +146,15 @@ class PaperCanvas extends React.Component {
|
||||||
paper.project.activeLayer.addChild(raster);
|
paper.project.activeLayer.addChild(raster);
|
||||||
}
|
}
|
||||||
clearRaster();
|
clearRaster();
|
||||||
this.props.onUpdateSvg();
|
this.props.onUpdateImage();
|
||||||
}
|
}
|
||||||
switchCostume (svg, rotationCenterX, rotationCenterY) {
|
checkFormat (image) {
|
||||||
|
if (image instanceof HTMLImageElement) return Formats.BITMAP;
|
||||||
|
if (typeof image === 'string') return Formats.VECTOR;
|
||||||
|
log.error(`Image could not be read.`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
switchCostume (image, rotationCenterX, rotationCenterY) {
|
||||||
for (const layer of paper.project.layers) {
|
for (const layer of paper.project.layers) {
|
||||||
if (layer.data.isRasterLayer) {
|
if (layer.data.isRasterLayer) {
|
||||||
clearRaster();
|
clearRaster();
|
||||||
|
@ -147,16 +166,29 @@ class PaperCanvas extends React.Component {
|
||||||
this.props.clearSelectedItems();
|
this.props.clearSelectedItems();
|
||||||
this.props.clearHoveredItem();
|
this.props.clearHoveredItem();
|
||||||
this.props.clearPasteOffset();
|
this.props.clearPasteOffset();
|
||||||
if (svg) {
|
if (image) {
|
||||||
this.props.changeFormat(Formats.VECTOR_SKIP_CONVERT);
|
if (isBitmap(this.checkFormat(image))) {
|
||||||
// Store the zoom/pan and restore it after importing a new SVG
|
// import bitmap
|
||||||
const oldZoom = paper.project.view.zoom;
|
this.props.changeFormat(Formats.BITMAP_SKIP_CONVERT);
|
||||||
const oldCenter = paper.project.view.center.clone();
|
getRaster().drawImage(
|
||||||
resetZoom();
|
image,
|
||||||
this.props.updateViewBounds(paper.view.matrix);
|
paper.project.view.center.x - rotationCenterX,
|
||||||
this.importSvg(svg, rotationCenterX, rotationCenterY);
|
paper.project.view.center.y - rotationCenterY);
|
||||||
paper.project.view.zoom = oldZoom;
|
performSnapshot(this.props.undoSnapshot, this.props.format);
|
||||||
paper.project.view.center = oldCenter;
|
} else if (isVector(this.checkFormat(image))) {
|
||||||
|
this.props.changeFormat(Formats.VECTOR_SKIP_CONVERT);
|
||||||
|
// Store the zoom/pan and restore it after importing a new SVG
|
||||||
|
const oldZoom = paper.project.view.zoom;
|
||||||
|
const oldCenter = paper.project.view.center.clone();
|
||||||
|
resetZoom();
|
||||||
|
this.props.updateViewBounds(paper.view.matrix);
|
||||||
|
this.importSvg(image, rotationCenterX, rotationCenterY);
|
||||||
|
paper.project.view.zoom = oldZoom;
|
||||||
|
paper.project.view.center = oldCenter;
|
||||||
|
} else {
|
||||||
|
log.error(`Couldn't open image.`);
|
||||||
|
performSnapshot(this.props.undoSnapshot, this.props.format);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
performSnapshot(this.props.undoSnapshot, this.props.format);
|
performSnapshot(this.props.undoSnapshot, this.props.format);
|
||||||
}
|
}
|
||||||
|
@ -290,14 +322,17 @@ PaperCanvas.propTypes = {
|
||||||
clearPasteOffset: PropTypes.func.isRequired,
|
clearPasteOffset: PropTypes.func.isRequired,
|
||||||
clearSelectedItems: PropTypes.func.isRequired,
|
clearSelectedItems: PropTypes.func.isRequired,
|
||||||
clearUndo: PropTypes.func.isRequired,
|
clearUndo: PropTypes.func.isRequired,
|
||||||
format: PropTypes.oneOf(Object.keys(Formats)).isRequired,
|
format: PropTypes.oneOf(Object.keys(Formats)),
|
||||||
|
image: PropTypes.oneOfType([
|
||||||
|
PropTypes.string,
|
||||||
|
PropTypes.instanceOf(HTMLImageElement)
|
||||||
|
]),
|
||||||
|
imageId: PropTypes.string,
|
||||||
mode: PropTypes.oneOf(Object.keys(Modes)),
|
mode: PropTypes.oneOf(Object.keys(Modes)),
|
||||||
onUpdateSvg: PropTypes.func.isRequired,
|
onUpdateImage: PropTypes.func.isRequired,
|
||||||
rotationCenterX: PropTypes.number,
|
rotationCenterX: PropTypes.number,
|
||||||
rotationCenterY: PropTypes.number,
|
rotationCenterY: PropTypes.number,
|
||||||
setSelectedItems: PropTypes.func.isRequired,
|
setSelectedItems: PropTypes.func.isRequired,
|
||||||
svg: PropTypes.string,
|
|
||||||
svgId: PropTypes.string,
|
|
||||||
undoSnapshot: PropTypes.func.isRequired,
|
undoSnapshot: PropTypes.func.isRequired,
|
||||||
updateViewBounds: PropTypes.func.isRequired
|
updateViewBounds: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
|
@ -65,7 +65,7 @@ class RectMode extends React.Component {
|
||||||
this.tool = new RectTool(
|
this.tool = new RectTool(
|
||||||
this.props.setSelectedItems,
|
this.props.setSelectedItems,
|
||||||
this.props.clearSelectedItems,
|
this.props.clearSelectedItems,
|
||||||
this.props.onUpdateSvg
|
this.props.onUpdateImage
|
||||||
);
|
);
|
||||||
this.tool.setColorState(this.props.colorState);
|
this.tool.setColorState(this.props.colorState);
|
||||||
this.tool.activate();
|
this.tool.activate();
|
||||||
|
@ -96,7 +96,7 @@ RectMode.propTypes = {
|
||||||
isRectModeActive: PropTypes.bool.isRequired,
|
isRectModeActive: PropTypes.bool.isRequired,
|
||||||
onChangeFillColor: PropTypes.func.isRequired,
|
onChangeFillColor: PropTypes.func.isRequired,
|
||||||
onChangeStrokeColor: PropTypes.func.isRequired,
|
onChangeStrokeColor: PropTypes.func.isRequired,
|
||||||
onUpdateSvg: PropTypes.func.isRequired,
|
onUpdateImage: PropTypes.func.isRequired,
|
||||||
selectedItems: PropTypes.arrayOf(PropTypes.instanceOf(paper.Item)),
|
selectedItems: PropTypes.arrayOf(PropTypes.instanceOf(paper.Item)),
|
||||||
setSelectedItems: PropTypes.func.isRequired
|
setSelectedItems: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
|
@ -45,7 +45,7 @@ class ReshapeMode extends React.Component {
|
||||||
this.props.clearHoveredItem,
|
this.props.clearHoveredItem,
|
||||||
this.props.setSelectedItems,
|
this.props.setSelectedItems,
|
||||||
this.props.clearSelectedItems,
|
this.props.clearSelectedItems,
|
||||||
this.props.onUpdateSvg
|
this.props.onUpdateImage
|
||||||
);
|
);
|
||||||
this.tool.setPrevHoveredItemId(this.props.hoveredItemId);
|
this.tool.setPrevHoveredItemId(this.props.hoveredItemId);
|
||||||
this.tool.activate();
|
this.tool.activate();
|
||||||
|
@ -72,7 +72,7 @@ ReshapeMode.propTypes = {
|
||||||
handleMouseDown: PropTypes.func.isRequired,
|
handleMouseDown: PropTypes.func.isRequired,
|
||||||
hoveredItemId: PropTypes.number,
|
hoveredItemId: PropTypes.number,
|
||||||
isReshapeModeActive: PropTypes.bool.isRequired,
|
isReshapeModeActive: PropTypes.bool.isRequired,
|
||||||
onUpdateSvg: PropTypes.func.isRequired,
|
onUpdateImage: PropTypes.func.isRequired,
|
||||||
setHoveredItem: PropTypes.func.isRequired,
|
setHoveredItem: PropTypes.func.isRequired,
|
||||||
setSelectedItems: PropTypes.func.isRequired
|
setSelectedItems: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
|
@ -45,7 +45,7 @@ class RoundedRectMode extends React.Component {
|
||||||
this.props.clearHoveredItem,
|
this.props.clearHoveredItem,
|
||||||
this.props.setSelectedItems,
|
this.props.setSelectedItems,
|
||||||
this.props.clearSelectedItems,
|
this.props.clearSelectedItems,
|
||||||
this.props.onUpdateSvg
|
this.props.onUpdateImage
|
||||||
);
|
);
|
||||||
this.tool.activate();
|
this.tool.activate();
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,7 @@ RoundedRectMode.propTypes = {
|
||||||
handleMouseDown: PropTypes.func.isRequired,
|
handleMouseDown: PropTypes.func.isRequired,
|
||||||
hoveredItemId: PropTypes.number,
|
hoveredItemId: PropTypes.number,
|
||||||
isRoundedRectModeActive: PropTypes.bool.isRequired,
|
isRoundedRectModeActive: PropTypes.bool.isRequired,
|
||||||
onUpdateSvg: PropTypes.func.isRequired,
|
onUpdateImage: PropTypes.func.isRequired,
|
||||||
setHoveredItem: PropTypes.func.isRequired,
|
setHoveredItem: PropTypes.func.isRequired,
|
||||||
setSelectedItems: PropTypes.func.isRequired
|
setSelectedItems: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
|
@ -49,7 +49,7 @@ class SelectMode extends React.Component {
|
||||||
this.props.clearHoveredItem,
|
this.props.clearHoveredItem,
|
||||||
this.props.setSelectedItems,
|
this.props.setSelectedItems,
|
||||||
this.props.clearSelectedItems,
|
this.props.clearSelectedItems,
|
||||||
this.props.onUpdateSvg
|
this.props.onUpdateImage
|
||||||
);
|
);
|
||||||
this.tool.activate();
|
this.tool.activate();
|
||||||
}
|
}
|
||||||
|
@ -74,7 +74,7 @@ SelectMode.propTypes = {
|
||||||
handleMouseDown: PropTypes.func.isRequired,
|
handleMouseDown: PropTypes.func.isRequired,
|
||||||
hoveredItemId: PropTypes.number,
|
hoveredItemId: PropTypes.number,
|
||||||
isSelectModeActive: PropTypes.bool.isRequired,
|
isSelectModeActive: PropTypes.bool.isRequired,
|
||||||
onUpdateSvg: PropTypes.func.isRequired,
|
onUpdateImage: PropTypes.func.isRequired,
|
||||||
selectedItems: PropTypes.arrayOf(PropTypes.instanceOf(paper.Item)),
|
selectedItems: PropTypes.arrayOf(PropTypes.instanceOf(paper.Item)),
|
||||||
setHoveredItem: PropTypes.func.isRequired,
|
setHoveredItem: PropTypes.func.isRequired,
|
||||||
setSelectedItems: PropTypes.func.isRequired
|
setSelectedItems: PropTypes.func.isRequired
|
||||||
|
|
|
@ -21,10 +21,10 @@ class StrokeColorIndicator extends React.Component {
|
||||||
this._hasChanged = false;
|
this._hasChanged = false;
|
||||||
}
|
}
|
||||||
componentWillReceiveProps (newProps) {
|
componentWillReceiveProps (newProps) {
|
||||||
const {strokeColorModalVisible, onUpdateSvg} = this.props;
|
const {strokeColorModalVisible, onUpdateImage} = this.props;
|
||||||
if (strokeColorModalVisible && !newProps.strokeColorModalVisible) {
|
if (strokeColorModalVisible && !newProps.strokeColorModalVisible) {
|
||||||
// Submit the new SVG, which also stores a single undo/redo action.
|
// Submit the new SVG, which also stores a single undo/redo action.
|
||||||
if (this._hasChanged) onUpdateSvg();
|
if (this._hasChanged) onUpdateImage();
|
||||||
this._hasChanged = false;
|
this._hasChanged = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ StrokeColorIndicator.propTypes = {
|
||||||
isEyeDropping: PropTypes.bool.isRequired,
|
isEyeDropping: PropTypes.bool.isRequired,
|
||||||
onChangeStrokeColor: PropTypes.func.isRequired,
|
onChangeStrokeColor: PropTypes.func.isRequired,
|
||||||
onCloseStrokeColor: PropTypes.func.isRequired,
|
onCloseStrokeColor: PropTypes.func.isRequired,
|
||||||
onUpdateSvg: PropTypes.func.isRequired,
|
onUpdateImage: PropTypes.func.isRequired,
|
||||||
strokeColor: PropTypes.string,
|
strokeColor: PropTypes.string,
|
||||||
strokeColorModalVisible: PropTypes.bool.isRequired,
|
strokeColorModalVisible: PropTypes.bool.isRequired,
|
||||||
textEditTarget: PropTypes.number
|
textEditTarget: PropTypes.number
|
||||||
|
|
|
@ -16,7 +16,7 @@ class StrokeWidthIndicator extends React.Component {
|
||||||
}
|
}
|
||||||
handleChangeStrokeWidth (newWidth) {
|
handleChangeStrokeWidth (newWidth) {
|
||||||
if (applyStrokeWidthToSelection(newWidth, this.props.textEditTarget)) {
|
if (applyStrokeWidthToSelection(newWidth, this.props.textEditTarget)) {
|
||||||
this.props.onUpdateSvg();
|
this.props.onUpdateImage();
|
||||||
}
|
}
|
||||||
this.props.onChangeStrokeWidth(newWidth);
|
this.props.onChangeStrokeWidth(newWidth);
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ const mapDispatchToProps = dispatch => ({
|
||||||
StrokeWidthIndicator.propTypes = {
|
StrokeWidthIndicator.propTypes = {
|
||||||
disabled: PropTypes.bool.isRequired,
|
disabled: PropTypes.bool.isRequired,
|
||||||
onChangeStrokeWidth: PropTypes.func.isRequired,
|
onChangeStrokeWidth: PropTypes.func.isRequired,
|
||||||
onUpdateSvg: PropTypes.func.isRequired,
|
onUpdateImage: PropTypes.func.isRequired,
|
||||||
strokeWidth: PropTypes.number,
|
strokeWidth: PropTypes.number,
|
||||||
textEditTarget: PropTypes.number
|
textEditTarget: PropTypes.number
|
||||||
};
|
};
|
||||||
|
|
|
@ -73,7 +73,7 @@ class TextMode extends React.Component {
|
||||||
this.props.textArea,
|
this.props.textArea,
|
||||||
this.props.setSelectedItems,
|
this.props.setSelectedItems,
|
||||||
this.props.clearSelectedItems,
|
this.props.clearSelectedItems,
|
||||||
this.props.onUpdateSvg,
|
this.props.onUpdateImage,
|
||||||
this.props.setTextEditTarget,
|
this.props.setTextEditTarget,
|
||||||
);
|
);
|
||||||
this.tool.setColorState(this.props.colorState);
|
this.tool.setColorState(this.props.colorState);
|
||||||
|
@ -105,7 +105,7 @@ TextMode.propTypes = {
|
||||||
isTextModeActive: PropTypes.bool.isRequired,
|
isTextModeActive: PropTypes.bool.isRequired,
|
||||||
onChangeFillColor: PropTypes.func.isRequired,
|
onChangeFillColor: PropTypes.func.isRequired,
|
||||||
onChangeStrokeColor: PropTypes.func.isRequired,
|
onChangeStrokeColor: PropTypes.func.isRequired,
|
||||||
onUpdateSvg: PropTypes.func.isRequired,
|
onUpdateImage: PropTypes.func.isRequired,
|
||||||
selectedItems: PropTypes.arrayOf(PropTypes.instanceOf(paper.Item)),
|
selectedItems: PropTypes.arrayOf(PropTypes.instanceOf(paper.Item)),
|
||||||
setSelectedItems: PropTypes.func.isRequired,
|
setSelectedItems: PropTypes.func.isRequired,
|
||||||
setTextEditTarget: PropTypes.func.isRequired,
|
setTextEditTarget: PropTypes.func.isRequired,
|
||||||
|
|
|
@ -8,11 +8,11 @@ import {getGuideLayer} from '../layer';
|
||||||
*/
|
*/
|
||||||
class BrushTool extends paper.Tool {
|
class BrushTool extends paper.Tool {
|
||||||
/**
|
/**
|
||||||
* @param {!function} onUpdateSvg A callback to call when the image visibly changes
|
* @param {!function} onUpdateImage A callback to call when the image visibly changes
|
||||||
*/
|
*/
|
||||||
constructor (onUpdateSvg) {
|
constructor (onUpdateImage) {
|
||||||
super();
|
super();
|
||||||
this.onUpdateSvg = onUpdateSvg;
|
this.onUpdateImage = onUpdateImage;
|
||||||
|
|
||||||
// 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.
|
||||||
|
@ -87,7 +87,7 @@ class BrushTool extends paper.Tool {
|
||||||
if (event.event.button > 0 || !this.active) return; // only first mouse button
|
if (event.event.button > 0 || !this.active) return; // only first mouse button
|
||||||
|
|
||||||
forEachLinePoint(this.lastPoint, event.point, this.draw.bind(this));
|
forEachLinePoint(this.lastPoint, event.point, this.draw.bind(this));
|
||||||
this.onUpdateSvg();
|
this.onUpdateImage();
|
||||||
|
|
||||||
this.lastPoint = null;
|
this.lastPoint = null;
|
||||||
this.active = false;
|
this.active = false;
|
||||||
|
|
|
@ -9,11 +9,11 @@ import {ART_BOARD_WIDTH, ART_BOARD_HEIGHT} from '../view';
|
||||||
*/
|
*/
|
||||||
class LineTool extends paper.Tool {
|
class LineTool extends paper.Tool {
|
||||||
/**
|
/**
|
||||||
* @param {!function} onUpdateSvg A callback to call when the image visibly changes
|
* @param {!function} onUpdateImage A callback to call when the image visibly changes
|
||||||
*/
|
*/
|
||||||
constructor (onUpdateSvg) {
|
constructor (onUpdateImage) {
|
||||||
super();
|
super();
|
||||||
this.onUpdateSvg = onUpdateSvg;
|
this.onUpdateImage = onUpdateImage;
|
||||||
|
|
||||||
// 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.
|
||||||
|
@ -103,7 +103,7 @@ class LineTool extends paper.Tool {
|
||||||
this.drawTarget = getRaster();
|
this.drawTarget = getRaster();
|
||||||
forEachLinePoint(this.startPoint, event.point, this.draw.bind(this));
|
forEachLinePoint(this.startPoint, event.point, this.draw.bind(this));
|
||||||
this.drawTarget = null;
|
this.drawTarget = null;
|
||||||
this.onUpdateSvg();
|
this.onUpdateImage();
|
||||||
|
|
||||||
this.lastPoint = null;
|
this.lastPoint = null;
|
||||||
this.active = false;
|
this.active = false;
|
||||||
|
|
|
@ -27,13 +27,13 @@ class Blobbiness {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {function} onUpdateSvg call when the drawing has changed to let listeners know
|
* @param {function} onUpdateImage call when the drawing has changed to let listeners know
|
||||||
* @param {function} clearSelectedItems Callback to clear the set of selected items in the Redux state
|
* @param {function} clearSelectedItems Callback to clear the set of selected items in the Redux state
|
||||||
*/
|
*/
|
||||||
constructor (onUpdateSvg, clearSelectedItems) {
|
constructor (onUpdateImage, clearSelectedItems) {
|
||||||
this.broadBrushHelper = new BroadBrushHelper();
|
this.broadBrushHelper = new BroadBrushHelper();
|
||||||
this.segmentBrushHelper = new SegmentBrushHelper();
|
this.segmentBrushHelper = new SegmentBrushHelper();
|
||||||
this.onUpdateSvg = onUpdateSvg;
|
this.onUpdateImage = onUpdateImage;
|
||||||
this.clearSelectedItems = clearSelectedItems;
|
this.clearSelectedItems = clearSelectedItems;
|
||||||
|
|
||||||
// The following are stored to check whether these have changed and the cursor preview needs to be redrawn.
|
// The following are stored to check whether these have changed and the cursor preview needs to be redrawn.
|
||||||
|
@ -143,7 +143,7 @@ class Blobbiness {
|
||||||
|
|
||||||
// Remove cursor preview during snapshot, then bring it back
|
// Remove cursor preview during snapshot, then bring it back
|
||||||
blob.cursorPreview.remove();
|
blob.cursorPreview.remove();
|
||||||
blob.onUpdateSvg();
|
blob.onUpdateImage();
|
||||||
blob.cursorPreview.parent = getGuideLayer();
|
blob.cursorPreview.parent = getGuideLayer();
|
||||||
|
|
||||||
// Reset
|
// Reset
|
||||||
|
|
|
@ -11,10 +11,10 @@ const isGroup = function (item) {
|
||||||
* @param {!Array<paper.Item>} items Root level items to group
|
* @param {!Array<paper.Item>} items Root level items to group
|
||||||
* @param {!function} clearSelectedItems Function to clear Redux state's selected items
|
* @param {!function} clearSelectedItems Function to clear Redux state's selected items
|
||||||
* @param {!function} setSelectedItems Function to set Redux state with new list of selected items
|
* @param {!function} setSelectedItems Function to set Redux state with new list of selected items
|
||||||
* @param {!function} onUpdateSvg Function to let listeners know that SVG has changed.
|
* @param {!function} onUpdateImage Function to let listeners know that SVG has changed.
|
||||||
* @return {paper.Group} the group if one is created, otherwise false.
|
* @return {paper.Group} the group if one is created, otherwise false.
|
||||||
*/
|
*/
|
||||||
const groupItems = function (items, clearSelectedItems, setSelectedItems, onUpdateSvg) {
|
const groupItems = function (items, clearSelectedItems, setSelectedItems, onUpdateImage) {
|
||||||
if (items.length > 0) {
|
if (items.length > 0) {
|
||||||
const group = new paper.Group(items);
|
const group = new paper.Group(items);
|
||||||
clearSelection(clearSelectedItems);
|
clearSelection(clearSelectedItems);
|
||||||
|
@ -23,7 +23,7 @@ const groupItems = function (items, clearSelectedItems, setSelectedItems, onUpda
|
||||||
group.children[i].selected = true;
|
group.children[i].selected = true;
|
||||||
}
|
}
|
||||||
setSelectedItems();
|
setSelectedItems();
|
||||||
onUpdateSvg();
|
onUpdateImage();
|
||||||
return group;
|
return group;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -33,12 +33,12 @@ const groupItems = function (items, clearSelectedItems, setSelectedItems, onUpda
|
||||||
* Groups the selected items. Other things are then deselected and the new group is selected.
|
* Groups the selected items. Other things are then deselected and the new group is selected.
|
||||||
* @param {!function} clearSelectedItems Function to clear Redux state's selected items
|
* @param {!function} clearSelectedItems Function to clear Redux state's selected items
|
||||||
* @param {!function} setSelectedItems Function to set Redux state with new list of selected items
|
* @param {!function} setSelectedItems Function to set Redux state with new list of selected items
|
||||||
* @param {!function} onUpdateSvg Function to let listeners know that SVG has changed.
|
* @param {!function} onUpdateImage Function to let listeners know that SVG has changed.
|
||||||
* @return {paper.Group} the group if one is created, otherwise false.
|
* @return {paper.Group} the group if one is created, otherwise false.
|
||||||
*/
|
*/
|
||||||
const groupSelection = function (clearSelectedItems, setSelectedItems, onUpdateSvg) {
|
const groupSelection = function (clearSelectedItems, setSelectedItems, onUpdateImage) {
|
||||||
const items = getSelectedRootItems();
|
const items = getSelectedRootItems();
|
||||||
return groupItems(items, clearSelectedItems, setSelectedItems, onUpdateSvg);
|
return groupItems(items, clearSelectedItems, setSelectedItems, onUpdateImage);
|
||||||
};
|
};
|
||||||
|
|
||||||
const _ungroupLoop = function (group, recursive, setSelectedItems) {
|
const _ungroupLoop = function (group, recursive, setSelectedItems) {
|
||||||
|
@ -71,15 +71,15 @@ const _ungroupLoop = function (group, recursive, setSelectedItems) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ungroups the given items. The new group is selected only if setSelectedItems is passed in.
|
* Ungroups the given items. The new group is selected only if setSelectedItems is passed in.
|
||||||
* onUpdateSvg is called to notify listeners of a change on the SVG only if onUpdateSvg is passed in.
|
* onUpdateImage is called to notify listeners of a change on the SVG only if onUpdateImage is passed in.
|
||||||
* The reason these arguments are optional on ungroupItems is because ungroupItems is used for parts of
|
* The reason these arguments are optional on ungroupItems is because ungroupItems is used for parts of
|
||||||
* SVG import, which shouldn't change the selection or undo state.
|
* SVG import, which shouldn't change the selection or undo state.
|
||||||
*
|
*
|
||||||
* @param {!Array<paper.Item>} items Items to ungroup if they are groups
|
* @param {!Array<paper.Item>} items Items to ungroup if they are groups
|
||||||
* @param {?function} setSelectedItems Function to set Redux state with new list of selected items
|
* @param {?function} setSelectedItems Function to set Redux state with new list of selected items
|
||||||
* @param {?function} onUpdateSvg Function to let listeners know that SVG has changed.
|
* @param {?function} onUpdateImage Function to let listeners know that SVG has changed.
|
||||||
*/
|
*/
|
||||||
const ungroupItems = function (items, setSelectedItems, onUpdateSvg) {
|
const ungroupItems = function (items, setSelectedItems, onUpdateImage) {
|
||||||
if (items.length === 0) {
|
if (items.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -102,8 +102,8 @@ const ungroupItems = function (items, setSelectedItems, onUpdateSvg) {
|
||||||
emptyGroups[j].remove();
|
emptyGroups[j].remove();
|
||||||
}
|
}
|
||||||
// @todo: enable/disable grouping icons
|
// @todo: enable/disable grouping icons
|
||||||
if (onUpdateSvg) {
|
if (onUpdateImage) {
|
||||||
onUpdateSvg();
|
onUpdateImage();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -112,12 +112,12 @@ const ungroupItems = function (items, setSelectedItems, onUpdateSvg) {
|
||||||
*
|
*
|
||||||
* @param {!function} clearSelectedItems Function to clear Redux state's selected items
|
* @param {!function} clearSelectedItems Function to clear Redux state's selected items
|
||||||
* @param {!function} setSelectedItems Function to set Redux state with new list of selected items
|
* @param {!function} setSelectedItems Function to set Redux state with new list of selected items
|
||||||
* @param {!function} onUpdateSvg Function to let listeners know that SVG has changed.
|
* @param {!function} onUpdateImage Function to let listeners know that SVG has changed.
|
||||||
*/
|
*/
|
||||||
const ungroupSelection = function (clearSelectedItems, setSelectedItems, onUpdateSvg) {
|
const ungroupSelection = function (clearSelectedItems, setSelectedItems, onUpdateImage) {
|
||||||
const items = getSelectedRootItems();
|
const items = getSelectedRootItems();
|
||||||
clearSelection(clearSelectedItems);
|
clearSelection(clearSelectedItems);
|
||||||
ungroupItems(items, setSelectedItems, onUpdateSvg);
|
ungroupItems(items, setSelectedItems, onUpdateImage);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getItemsGroup = function (item) {
|
const getItemsGroup = function (item) {
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
import {getSelectedRootItems} from './selection';
|
import {getSelectedRootItems} from './selection';
|
||||||
|
|
||||||
const bringToFront = function (onUpdateSvg) {
|
const bringToFront = function (onUpdateImage) {
|
||||||
const items = getSelectedRootItems();
|
const items = getSelectedRootItems();
|
||||||
for (const item of items) {
|
for (const item of items) {
|
||||||
item.bringToFront();
|
item.bringToFront();
|
||||||
}
|
}
|
||||||
onUpdateSvg();
|
onUpdateImage();
|
||||||
};
|
};
|
||||||
|
|
||||||
const sendToBack = function (onUpdateSvg) {
|
const sendToBack = function (onUpdateImage) {
|
||||||
const items = getSelectedRootItems();
|
const items = getSelectedRootItems();
|
||||||
for (let i = items.length - 1; i >= 0; i--) {
|
for (let i = items.length - 1; i >= 0; i--) {
|
||||||
items[i].sendToBack();
|
items[i].sendToBack();
|
||||||
}
|
}
|
||||||
onUpdateSvg();
|
onUpdateImage();
|
||||||
};
|
};
|
||||||
|
|
||||||
const bringForward = function (onUpdateSvg) {
|
const bringForward = function (onUpdateImage) {
|
||||||
const items = getSelectedRootItems();
|
const items = getSelectedRootItems();
|
||||||
// Already at front
|
// Already at front
|
||||||
if (items.length === 0 || !items[items.length - 1].nextSibling) {
|
if (items.length === 0 || !items[items.length - 1].nextSibling) {
|
||||||
|
@ -27,10 +27,10 @@ const bringForward = function (onUpdateSvg) {
|
||||||
for (let i = items.length - 1; i >= 0; i--) {
|
for (let i = items.length - 1; i >= 0; i--) {
|
||||||
items[i].insertAbove(nextSibling);
|
items[i].insertAbove(nextSibling);
|
||||||
}
|
}
|
||||||
onUpdateSvg();
|
onUpdateImage();
|
||||||
};
|
};
|
||||||
|
|
||||||
const sendBackward = function (onUpdateSvg) {
|
const sendBackward = function (onUpdateImage) {
|
||||||
const items = getSelectedRootItems();
|
const items = getSelectedRootItems();
|
||||||
// Already at front
|
// Already at front
|
||||||
if (items.length === 0 || !items[0].previousSibling) {
|
if (items.length === 0 || !items[0].previousSibling) {
|
||||||
|
@ -41,7 +41,7 @@ const sendBackward = function (onUpdateSvg) {
|
||||||
for (const item of items) {
|
for (const item of items) {
|
||||||
item.insertBelow(previousSibling);
|
item.insertBelow(previousSibling);
|
||||||
}
|
}
|
||||||
onUpdateSvg();
|
onUpdateImage();
|
||||||
};
|
};
|
||||||
|
|
||||||
const shouldShowSendBackward = function () {
|
const shouldShowSendBackward = function () {
|
||||||
|
|
|
@ -28,25 +28,25 @@ const BoundingBoxModes = keyMirror({
|
||||||
* 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.
|
||||||
* @param {!function} onUpdateSvg A callback to call when the image visibly changes
|
* @param {!function} onUpdateImage A callback to call when the image visibly changes
|
||||||
*/
|
*/
|
||||||
class BoundingBoxTool {
|
class BoundingBoxTool {
|
||||||
/**
|
/**
|
||||||
* @param {Modes} mode Paint editor mode
|
* @param {Modes} mode Paint editor mode
|
||||||
* @param {function} setSelectedItems Callback to set the set of selected items in the Redux state
|
* @param {function} setSelectedItems Callback to set the set of selected items in the Redux state
|
||||||
* @param {function} clearSelectedItems Callback to clear the set of selected items in the Redux state
|
* @param {function} clearSelectedItems Callback to clear the set of selected items in the Redux state
|
||||||
* @param {!function} onUpdateSvg A callback to call when the image visibly changes
|
* @param {!function} onUpdateImage A callback to call when the image visibly changes
|
||||||
*/
|
*/
|
||||||
constructor (mode, setSelectedItems, clearSelectedItems, onUpdateSvg) {
|
constructor (mode, setSelectedItems, clearSelectedItems, onUpdateImage) {
|
||||||
this.onUpdateSvg = onUpdateSvg;
|
this.onUpdateImage = onUpdateImage;
|
||||||
this.mode = null;
|
this.mode = null;
|
||||||
this.boundsPath = null;
|
this.boundsPath = null;
|
||||||
this.boundsScaleHandles = [];
|
this.boundsScaleHandles = [];
|
||||||
this.boundsRotHandles = [];
|
this.boundsRotHandles = [];
|
||||||
this._modeMap = {};
|
this._modeMap = {};
|
||||||
this._modeMap[BoundingBoxModes.SCALE] = new ScaleTool(onUpdateSvg);
|
this._modeMap[BoundingBoxModes.SCALE] = new ScaleTool(onUpdateImage);
|
||||||
this._modeMap[BoundingBoxModes.ROTATE] = new RotateTool(onUpdateSvg);
|
this._modeMap[BoundingBoxModes.ROTATE] = new RotateTool(onUpdateImage);
|
||||||
this._modeMap[BoundingBoxModes.MOVE] = new MoveTool(mode, setSelectedItems, clearSelectedItems, onUpdateSvg);
|
this._modeMap[BoundingBoxModes.MOVE] = new MoveTool(mode, setSelectedItems, clearSelectedItems, onUpdateImage);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -5,13 +5,13 @@ class HandleTool {
|
||||||
/**
|
/**
|
||||||
* @param {function} setSelectedItems Callback to set the set of selected items in the Redux state
|
* @param {function} setSelectedItems Callback to set the set of selected items in the Redux state
|
||||||
* @param {function} clearSelectedItems Callback to clear the set of selected items in the Redux state
|
* @param {function} clearSelectedItems Callback to clear the set of selected items in the Redux state
|
||||||
* @param {!function} onUpdateSvg A callback to call when the image visibly changes
|
* @param {!function} onUpdateImage A callback to call when the image visibly changes
|
||||||
*/
|
*/
|
||||||
constructor (setSelectedItems, clearSelectedItems, onUpdateSvg) {
|
constructor (setSelectedItems, clearSelectedItems, onUpdateImage) {
|
||||||
this.hitType = null;
|
this.hitType = null;
|
||||||
this.setSelectedItems = setSelectedItems;
|
this.setSelectedItems = setSelectedItems;
|
||||||
this.clearSelectedItems = clearSelectedItems;
|
this.clearSelectedItems = clearSelectedItems;
|
||||||
this.onUpdateSvg = onUpdateSvg;
|
this.onUpdateImage = onUpdateImage;
|
||||||
this.selectedItems = [];
|
this.selectedItems = [];
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
@ -80,7 +80,7 @@ class HandleTool {
|
||||||
}
|
}
|
||||||
if (moved) {
|
if (moved) {
|
||||||
this.setSelectedItems();
|
this.setSelectedItems();
|
||||||
this.onUpdateSvg();
|
this.onUpdateImage();
|
||||||
}
|
}
|
||||||
this.selectedItems = [];
|
this.selectedItems = [];
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,14 +13,14 @@ class MoveTool {
|
||||||
* @param {Modes} mode Paint editor mode
|
* @param {Modes} mode Paint editor mode
|
||||||
* @param {function} setSelectedItems Callback to set the set of selected items in the Redux state
|
* @param {function} setSelectedItems Callback to set the set of selected items in the Redux state
|
||||||
* @param {function} clearSelectedItems Callback to clear the set of selected items in the Redux state
|
* @param {function} clearSelectedItems Callback to clear the set of selected items in the Redux state
|
||||||
* @param {!function} onUpdateSvg A callback to call when the image visibly changes
|
* @param {!function} onUpdateImage A callback to call when the image visibly changes
|
||||||
*/
|
*/
|
||||||
constructor (mode, setSelectedItems, clearSelectedItems, onUpdateSvg) {
|
constructor (mode, setSelectedItems, clearSelectedItems, onUpdateImage) {
|
||||||
this.mode = mode;
|
this.mode = mode;
|
||||||
this.setSelectedItems = setSelectedItems;
|
this.setSelectedItems = setSelectedItems;
|
||||||
this.clearSelectedItems = clearSelectedItems;
|
this.clearSelectedItems = clearSelectedItems;
|
||||||
this.selectedItems = null;
|
this.selectedItems = null;
|
||||||
this.onUpdateSvg = onUpdateSvg;
|
this.onUpdateImage = onUpdateImage;
|
||||||
this.boundsPath = null;
|
this.boundsPath = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ class MoveTool {
|
||||||
}
|
}
|
||||||
this._select(item, true, hitProperties.subselect);
|
this._select(item, true, hitProperties.subselect);
|
||||||
}
|
}
|
||||||
if (hitProperties.clone) cloneSelection(hitProperties.subselect, this.onUpdateSvg);
|
if (hitProperties.clone) cloneSelection(hitProperties.subselect, this.onUpdateImage);
|
||||||
this.selectedItems = this.mode === Modes.RESHAPE ? getSelectedLeafItems() : getSelectedRootItems();
|
this.selectedItems = this.mode === Modes.RESHAPE ? getSelectedLeafItems() : getSelectedRootItems();
|
||||||
if (this.boundsPath) {
|
if (this.boundsPath) {
|
||||||
this.selectedItems.push(this.boundsPath);
|
this.selectedItems.push(this.boundsPath);
|
||||||
|
@ -116,7 +116,7 @@ class MoveTool {
|
||||||
this.selectedItems = null;
|
this.selectedItems = null;
|
||||||
|
|
||||||
if (moved) {
|
if (moved) {
|
||||||
this.onUpdateSvg();
|
this.onUpdateImage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,11 +8,11 @@ import paper from '@scratch/paper';
|
||||||
class NudgeTool {
|
class NudgeTool {
|
||||||
/**
|
/**
|
||||||
* @param {function} boundingBoxTool to control the bounding box
|
* @param {function} boundingBoxTool to control the bounding box
|
||||||
* @param {!function} onUpdateSvg A callback to call when the image visibly changes
|
* @param {!function} onUpdateImage A callback to call when the image visibly changes
|
||||||
*/
|
*/
|
||||||
constructor (boundingBoxTool, onUpdateSvg) {
|
constructor (boundingBoxTool, onUpdateImage) {
|
||||||
this.boundingBoxTool = boundingBoxTool;
|
this.boundingBoxTool = boundingBoxTool;
|
||||||
this.onUpdateSvg = onUpdateSvg;
|
this.onUpdateImage = onUpdateImage;
|
||||||
}
|
}
|
||||||
onKeyDown (event) {
|
onKeyDown (event) {
|
||||||
if (event.event.target instanceof HTMLInputElement) {
|
if (event.event.target instanceof HTMLInputElement) {
|
||||||
|
@ -47,7 +47,7 @@ class NudgeTool {
|
||||||
if (selected.length === 0) return;
|
if (selected.length === 0) return;
|
||||||
|
|
||||||
if (event.key === 'up' || event.key === 'down' || event.key === 'left' || event.key === 'right') {
|
if (event.key === 'up' || event.key === 'down' || event.key === 'left' || event.key === 'right') {
|
||||||
this.onUpdateSvg();
|
this.onUpdateImage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,9 @@ class PointTool {
|
||||||
/**
|
/**
|
||||||
* @param {function} setSelectedItems Callback to set the set of selected items in the Redux state
|
* @param {function} setSelectedItems Callback to set the set of selected items in the Redux state
|
||||||
* @param {function} clearSelectedItems Callback to clear the set of selected items in the Redux state
|
* @param {function} clearSelectedItems Callback to clear the set of selected items in the Redux state
|
||||||
* @param {!function} onUpdateSvg A callback to call when the image visibly changes
|
* @param {!function} onUpdateImage A callback to call when the image visibly changes
|
||||||
*/
|
*/
|
||||||
constructor (setSelectedItems, clearSelectedItems, onUpdateSvg) {
|
constructor (setSelectedItems, clearSelectedItems, onUpdateImage) {
|
||||||
/**
|
/**
|
||||||
* Deselection often does not happen until mouse up. If the mouse is dragged before
|
* Deselection often does not happen until mouse up. If the mouse is dragged before
|
||||||
* mouse up, deselection is cancelled. This variable keeps track of which paper.Item to deselect.
|
* mouse up, deselection is cancelled. This variable keeps track of which paper.Item to deselect.
|
||||||
|
@ -29,7 +29,7 @@ class PointTool {
|
||||||
this.selectedItems = null;
|
this.selectedItems = null;
|
||||||
this.setSelectedItems = setSelectedItems;
|
this.setSelectedItems = setSelectedItems;
|
||||||
this.clearSelectedItems = clearSelectedItems;
|
this.clearSelectedItems = clearSelectedItems;
|
||||||
this.onUpdateSvg = onUpdateSvg;
|
this.onUpdateImage = onUpdateImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -191,7 +191,7 @@ class PointTool {
|
||||||
this.selectedItems = null;
|
this.selectedItems = null;
|
||||||
this.setSelectedItems();
|
this.setSelectedItems();
|
||||||
if (moved) {
|
if (moved) {
|
||||||
this.onUpdateSvg();
|
this.onUpdateImage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,22 +43,22 @@ class ReshapeTool extends paper.Tool {
|
||||||
* @param {function} clearHoveredItem Callback to clear the hovered item
|
* @param {function} clearHoveredItem Callback to clear the hovered item
|
||||||
* @param {function} setSelectedItems Callback to set the set of selected items in the Redux state
|
* @param {function} setSelectedItems Callback to set the set of selected items in the Redux state
|
||||||
* @param {function} clearSelectedItems Callback to clear the set of selected items in the Redux state
|
* @param {function} clearSelectedItems Callback to clear the set of selected items in the Redux state
|
||||||
* @param {!function} onUpdateSvg A callback to call when the image visibly changes
|
* @param {!function} onUpdateImage A callback to call when the image visibly changes
|
||||||
*/
|
*/
|
||||||
constructor (setHoveredItem, clearHoveredItem, setSelectedItems, clearSelectedItems, onUpdateSvg) {
|
constructor (setHoveredItem, clearHoveredItem, setSelectedItems, clearSelectedItems, onUpdateImage) {
|
||||||
super();
|
super();
|
||||||
this.setHoveredItem = setHoveredItem;
|
this.setHoveredItem = setHoveredItem;
|
||||||
this.clearHoveredItem = clearHoveredItem;
|
this.clearHoveredItem = clearHoveredItem;
|
||||||
this.onUpdateSvg = onUpdateSvg;
|
this.onUpdateImage = onUpdateImage;
|
||||||
this.prevHoveredItemId = null;
|
this.prevHoveredItemId = null;
|
||||||
this.lastEvent = null;
|
this.lastEvent = null;
|
||||||
this.active = false;
|
this.active = false;
|
||||||
this.mode = ReshapeModes.SELECTION_BOX;
|
this.mode = ReshapeModes.SELECTION_BOX;
|
||||||
this._modeMap = {};
|
this._modeMap = {};
|
||||||
this._modeMap[ReshapeModes.FILL] =
|
this._modeMap[ReshapeModes.FILL] =
|
||||||
new MoveTool(Modes.RESHAPE, setSelectedItems, clearSelectedItems, onUpdateSvg);
|
new MoveTool(Modes.RESHAPE, setSelectedItems, clearSelectedItems, onUpdateImage);
|
||||||
this._modeMap[ReshapeModes.POINT] = new PointTool(setSelectedItems, clearSelectedItems, onUpdateSvg);
|
this._modeMap[ReshapeModes.POINT] = new PointTool(setSelectedItems, clearSelectedItems, onUpdateImage);
|
||||||
this._modeMap[ReshapeModes.HANDLE] = new HandleTool(setSelectedItems, clearSelectedItems, onUpdateSvg);
|
this._modeMap[ReshapeModes.HANDLE] = new HandleTool(setSelectedItems, clearSelectedItems, onUpdateImage);
|
||||||
this._modeMap[ReshapeModes.SELECTION_BOX] =
|
this._modeMap[ReshapeModes.SELECTION_BOX] =
|
||||||
new SelectionBoxTool(Modes.RESHAPE, setSelectedItems, clearSelectedItems);
|
new SelectionBoxTool(Modes.RESHAPE, setSelectedItems, clearSelectedItems);
|
||||||
|
|
||||||
|
@ -271,7 +271,7 @@ class ReshapeTool extends paper.Tool {
|
||||||
if (selected.length === 0) return;
|
if (selected.length === 0) return;
|
||||||
|
|
||||||
if (event.key === 'up' || event.key === 'down' || event.key === 'left' || event.key === 'right') {
|
if (event.key === 'up' || event.key === 'down' || event.key === 'left' || event.key === 'right') {
|
||||||
this.onUpdateSvg();
|
this.onUpdateImage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
deactivateTool () {
|
deactivateTool () {
|
||||||
|
@ -279,7 +279,7 @@ class ReshapeTool extends paper.Tool {
|
||||||
this.clearHoveredItem();
|
this.clearHoveredItem();
|
||||||
this.setHoveredItem = null;
|
this.setHoveredItem = null;
|
||||||
this.clearHoveredItem = null;
|
this.clearHoveredItem = null;
|
||||||
this.onUpdateSvg = null;
|
this.onUpdateImage = null;
|
||||||
this.lastEvent = null;
|
this.lastEvent = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,13 +5,13 @@ import paper from '@scratch/paper';
|
||||||
*/
|
*/
|
||||||
class RotateTool {
|
class RotateTool {
|
||||||
/**
|
/**
|
||||||
* @param {!function} onUpdateSvg A callback to call when the image visibly changes
|
* @param {!function} onUpdateImage A callback to call when the image visibly changes
|
||||||
*/
|
*/
|
||||||
constructor (onUpdateSvg) {
|
constructor (onUpdateImage) {
|
||||||
this.rotItems = [];
|
this.rotItems = [];
|
||||||
this.rotGroupPivot = null;
|
this.rotGroupPivot = null;
|
||||||
this.prevRot = 90;
|
this.prevRot = 90;
|
||||||
this.onUpdateSvg = onUpdateSvg;
|
this.onUpdateImage = onUpdateImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -54,7 +54,7 @@ class RotateTool {
|
||||||
this.rotGroupPivot = null;
|
this.rotGroupPivot = null;
|
||||||
this.prevRot = 90;
|
this.prevRot = 90;
|
||||||
|
|
||||||
this.onUpdateSvg();
|
this.onUpdateImage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,9 +7,9 @@ import {getItems} from '../selection';
|
||||||
*/
|
*/
|
||||||
class ScaleTool {
|
class ScaleTool {
|
||||||
/**
|
/**
|
||||||
* @param {!function} onUpdateSvg A callback to call when the image visibly changes
|
* @param {!function} onUpdateImage A callback to call when the image visibly changes
|
||||||
*/
|
*/
|
||||||
constructor (onUpdateSvg) {
|
constructor (onUpdateImage) {
|
||||||
this.active = false;
|
this.active = false;
|
||||||
this.boundsPath = null;
|
this.boundsPath = null;
|
||||||
this.pivot = null;
|
this.pivot = null;
|
||||||
|
@ -20,7 +20,7 @@ class ScaleTool {
|
||||||
this.itemGroup = null;
|
this.itemGroup = null;
|
||||||
// Lowest item above all scale items in z index
|
// Lowest item above all scale items in z index
|
||||||
this.itemToInsertBelow = null;
|
this.itemToInsertBelow = null;
|
||||||
this.onUpdateSvg = onUpdateSvg;
|
this.onUpdateImage = onUpdateImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -144,7 +144,7 @@ class ScaleTool {
|
||||||
}
|
}
|
||||||
this.itemGroup.remove();
|
this.itemGroup.remove();
|
||||||
|
|
||||||
this.onUpdateSvg();
|
this.onUpdateImage();
|
||||||
this.active = false;
|
this.active = false;
|
||||||
}
|
}
|
||||||
_getRectCornerNameByIndex (index) {
|
_getRectCornerNameByIndex (index) {
|
||||||
|
|
|
@ -24,15 +24,15 @@ class SelectTool extends paper.Tool {
|
||||||
* @param {function} clearHoveredItem Callback to clear the hovered item
|
* @param {function} clearHoveredItem Callback to clear the hovered item
|
||||||
* @param {function} setSelectedItems Callback to set the set of selected items in the Redux state
|
* @param {function} setSelectedItems Callback to set the set of selected items in the Redux state
|
||||||
* @param {function} clearSelectedItems Callback to clear the set of selected items in the Redux state
|
* @param {function} clearSelectedItems Callback to clear the set of selected items in the Redux state
|
||||||
* @param {!function} onUpdateSvg A callback to call when the image visibly changes
|
* @param {!function} onUpdateImage A callback to call when the image visibly changes
|
||||||
*/
|
*/
|
||||||
constructor (setHoveredItem, clearHoveredItem, setSelectedItems, clearSelectedItems, onUpdateSvg) {
|
constructor (setHoveredItem, clearHoveredItem, setSelectedItems, clearSelectedItems, onUpdateImage) {
|
||||||
super();
|
super();
|
||||||
this.setHoveredItem = setHoveredItem;
|
this.setHoveredItem = setHoveredItem;
|
||||||
this.clearHoveredItem = clearHoveredItem;
|
this.clearHoveredItem = clearHoveredItem;
|
||||||
this.onUpdateSvg = onUpdateSvg;
|
this.onUpdateImage = onUpdateImage;
|
||||||
this.boundingBoxTool = new BoundingBoxTool(Modes.SELECT, setSelectedItems, clearSelectedItems, onUpdateSvg);
|
this.boundingBoxTool = new BoundingBoxTool(Modes.SELECT, setSelectedItems, clearSelectedItems, onUpdateImage);
|
||||||
const nudgeTool = new NudgeTool(this.boundingBoxTool, onUpdateSvg);
|
const nudgeTool = new NudgeTool(this.boundingBoxTool, onUpdateImage);
|
||||||
this.selectionBoxTool = new SelectionBoxTool(Modes.SELECT, setSelectedItems, clearSelectedItems);
|
this.selectionBoxTool = new SelectionBoxTool(Modes.SELECT, setSelectedItems, clearSelectedItems);
|
||||||
this.selectionBoxMode = false;
|
this.selectionBoxMode = false;
|
||||||
this.prevHoveredItemId = null;
|
this.prevHoveredItemId = null;
|
||||||
|
@ -140,7 +140,7 @@ class SelectTool extends paper.Tool {
|
||||||
this.boundingBoxTool.removeBoundsPath();
|
this.boundingBoxTool.removeBoundsPath();
|
||||||
this.setHoveredItem = null;
|
this.setHoveredItem = null;
|
||||||
this.clearHoveredItem = null;
|
this.clearHoveredItem = null;
|
||||||
this.onUpdateSvg = null;
|
this.onUpdateImage = null;
|
||||||
this.boundingBoxTool = null;
|
this.boundingBoxTool = null;
|
||||||
this.selectionBoxTool = null;
|
this.selectionBoxTool = null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -195,7 +195,7 @@ const getSelectedSegments = function () {
|
||||||
return segments;
|
return segments;
|
||||||
};
|
};
|
||||||
|
|
||||||
const _deleteItemSelection = function (items, onUpdateSvg) {
|
const _deleteItemSelection = function (items, onUpdateImage) {
|
||||||
// @todo: Update toolbar state on change
|
// @todo: Update toolbar state on change
|
||||||
if (items.length === 0) {
|
if (items.length === 0) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -203,12 +203,12 @@ const _deleteItemSelection = function (items, onUpdateSvg) {
|
||||||
for (let i = 0; i < items.length; i++) {
|
for (let i = 0; i < items.length; i++) {
|
||||||
items[i].remove();
|
items[i].remove();
|
||||||
}
|
}
|
||||||
onUpdateSvg();
|
onUpdateImage();
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Return true if anything was removed
|
// Return true if anything was removed
|
||||||
const _removeSelectedSegments = function (items, onUpdateSvg) {
|
const _removeSelectedSegments = function (items, onUpdateImage) {
|
||||||
const segmentsToRemove = [];
|
const segmentsToRemove = [];
|
||||||
|
|
||||||
for (let i = 0; i < items.length; i++) {
|
for (let i = 0; i < items.length; i++) {
|
||||||
|
@ -229,33 +229,33 @@ const _removeSelectedSegments = function (items, onUpdateSvg) {
|
||||||
removedSegments = true;
|
removedSegments = true;
|
||||||
}
|
}
|
||||||
if (removedSegments) {
|
if (removedSegments) {
|
||||||
onUpdateSvg();
|
onUpdateImage();
|
||||||
}
|
}
|
||||||
return removedSegments;
|
return removedSegments;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Return whether anything was deleted
|
// Return whether anything was deleted
|
||||||
const deleteSelection = function (mode, onUpdateSvg) {
|
const deleteSelection = function (mode, onUpdateImage) {
|
||||||
if (mode === Modes.RESHAPE) {
|
if (mode === Modes.RESHAPE) {
|
||||||
const selectedItems = getSelectedLeafItems();
|
const selectedItems = getSelectedLeafItems();
|
||||||
// If there are points selected remove them. If not delete the item selected.
|
// If there are points selected remove them. If not delete the item selected.
|
||||||
if (_removeSelectedSegments(selectedItems, onUpdateSvg)) {
|
if (_removeSelectedSegments(selectedItems, onUpdateImage)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return _deleteItemSelection(selectedItems, onUpdateSvg);
|
return _deleteItemSelection(selectedItems, onUpdateImage);
|
||||||
}
|
}
|
||||||
const selectedItems = getSelectedRootItems();
|
const selectedItems = getSelectedRootItems();
|
||||||
return _deleteItemSelection(selectedItems, onUpdateSvg);
|
return _deleteItemSelection(selectedItems, onUpdateImage);
|
||||||
};
|
};
|
||||||
|
|
||||||
const cloneSelection = function (recursive, onUpdateSvg) {
|
const cloneSelection = function (recursive, onUpdateImage) {
|
||||||
const selectedItems = recursive ? getSelectedLeafItems() : getSelectedRootItems();
|
const selectedItems = recursive ? getSelectedLeafItems() : getSelectedRootItems();
|
||||||
for (let i = 0; i < selectedItems.length; i++) {
|
for (let i = 0; i < selectedItems.length; i++) {
|
||||||
const item = selectedItems[i];
|
const item = selectedItems[i];
|
||||||
item.clone();
|
item.clone();
|
||||||
item.selected = false;
|
item.selected = false;
|
||||||
}
|
}
|
||||||
onUpdateSvg();
|
onUpdateImage();
|
||||||
};
|
};
|
||||||
|
|
||||||
const _checkBoundsItem = function (selectionRect, item, event) {
|
const _checkBoundsItem = function (selectionRect, item, event) {
|
||||||
|
|
|
@ -9,13 +9,13 @@ class FillTool extends paper.Tool {
|
||||||
/**
|
/**
|
||||||
* @param {function} setHoveredItem Callback to set the hovered item
|
* @param {function} setHoveredItem Callback to set the hovered item
|
||||||
* @param {function} clearHoveredItem Callback to clear the hovered item
|
* @param {function} clearHoveredItem Callback to clear the hovered item
|
||||||
* @param {!function} onUpdateSvg A callback to call when the image visibly changes
|
* @param {!function} onUpdateImage A callback to call when the image visibly changes
|
||||||
*/
|
*/
|
||||||
constructor (setHoveredItem, clearHoveredItem, onUpdateSvg) {
|
constructor (setHoveredItem, clearHoveredItem, onUpdateImage) {
|
||||||
super();
|
super();
|
||||||
this.setHoveredItem = setHoveredItem;
|
this.setHoveredItem = setHoveredItem;
|
||||||
this.clearHoveredItem = clearHoveredItem;
|
this.clearHoveredItem = clearHoveredItem;
|
||||||
this.onUpdateSvg = onUpdateSvg;
|
this.onUpdateImage = onUpdateImage;
|
||||||
|
|
||||||
// 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.
|
||||||
|
@ -150,7 +150,7 @@ class FillTool extends paper.Tool {
|
||||||
this.fillItem = null;
|
this.fillItem = null;
|
||||||
this.addedFillItem = null;
|
this.addedFillItem = null;
|
||||||
this.fillItemOrigColor = null;
|
this.fillItemOrigColor = null;
|
||||||
this.onUpdateSvg();
|
this.onUpdateImage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_noStroke (item) {
|
_noStroke (item) {
|
||||||
|
|
|
@ -15,15 +15,15 @@ class OvalTool extends paper.Tool {
|
||||||
/**
|
/**
|
||||||
* @param {function} setSelectedItems Callback to set the set of selected items in the Redux state
|
* @param {function} setSelectedItems Callback to set the set of selected items in the Redux state
|
||||||
* @param {function} clearSelectedItems Callback to clear the set of selected items in the Redux state
|
* @param {function} clearSelectedItems Callback to clear the set of selected items in the Redux state
|
||||||
* @param {!function} onUpdateSvg A callback to call when the image visibly changes
|
* @param {!function} onUpdateImage A callback to call when the image visibly changes
|
||||||
*/
|
*/
|
||||||
constructor (setSelectedItems, clearSelectedItems, onUpdateSvg) {
|
constructor (setSelectedItems, clearSelectedItems, onUpdateImage) {
|
||||||
super();
|
super();
|
||||||
this.setSelectedItems = setSelectedItems;
|
this.setSelectedItems = setSelectedItems;
|
||||||
this.clearSelectedItems = clearSelectedItems;
|
this.clearSelectedItems = clearSelectedItems;
|
||||||
this.onUpdateSvg = onUpdateSvg;
|
this.onUpdateImage = onUpdateImage;
|
||||||
this.boundingBoxTool = new BoundingBoxTool(Modes.OVAL, setSelectedItems, clearSelectedItems, onUpdateSvg);
|
this.boundingBoxTool = new BoundingBoxTool(Modes.OVAL, setSelectedItems, clearSelectedItems, onUpdateImage);
|
||||||
const nudgeTool = new NudgeTool(this.boundingBoxTool, onUpdateSvg);
|
const nudgeTool = new NudgeTool(this.boundingBoxTool, onUpdateImage);
|
||||||
|
|
||||||
// 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.
|
||||||
|
@ -120,7 +120,7 @@ class OvalTool extends paper.Tool {
|
||||||
|
|
||||||
ovalPath.selected = true;
|
ovalPath.selected = true;
|
||||||
this.setSelectedItems();
|
this.setSelectedItems();
|
||||||
this.onUpdateSvg();
|
this.onUpdateImage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.active = false;
|
this.active = false;
|
||||||
|
|
|
@ -15,15 +15,15 @@ class RectTool extends paper.Tool {
|
||||||
/**
|
/**
|
||||||
* @param {function} setSelectedItems Callback to set the set of selected items in the Redux state
|
* @param {function} setSelectedItems Callback to set the set of selected items in the Redux state
|
||||||
* @param {function} clearSelectedItems Callback to clear the set of selected items in the Redux state
|
* @param {function} clearSelectedItems Callback to clear the set of selected items in the Redux state
|
||||||
* @param {!function} onUpdateSvg A callback to call when the image visibly changes
|
* @param {!function} onUpdateImage A callback to call when the image visibly changes
|
||||||
*/
|
*/
|
||||||
constructor (setSelectedItems, clearSelectedItems, onUpdateSvg) {
|
constructor (setSelectedItems, clearSelectedItems, onUpdateImage) {
|
||||||
super();
|
super();
|
||||||
this.setSelectedItems = setSelectedItems;
|
this.setSelectedItems = setSelectedItems;
|
||||||
this.clearSelectedItems = clearSelectedItems;
|
this.clearSelectedItems = clearSelectedItems;
|
||||||
this.onUpdateSvg = onUpdateSvg;
|
this.onUpdateImage = onUpdateImage;
|
||||||
this.boundingBoxTool = new BoundingBoxTool(Modes.RECT, setSelectedItems, clearSelectedItems, onUpdateSvg);
|
this.boundingBoxTool = new BoundingBoxTool(Modes.RECT, setSelectedItems, clearSelectedItems, onUpdateImage);
|
||||||
const nudgeTool = new NudgeTool(this.boundingBoxTool, onUpdateSvg);
|
const nudgeTool = new NudgeTool(this.boundingBoxTool, onUpdateImage);
|
||||||
|
|
||||||
// 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.
|
||||||
|
@ -113,7 +113,7 @@ class RectTool extends paper.Tool {
|
||||||
} else {
|
} else {
|
||||||
this.rect.selected = true;
|
this.rect.selected = true;
|
||||||
this.setSelectedItems();
|
this.setSelectedItems();
|
||||||
this.onUpdateSvg();
|
this.onUpdateImage();
|
||||||
this.rect = null;
|
this.rect = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,15 +10,15 @@ class RoundedRectTool extends paper.Tool {
|
||||||
* @param {function} clearHoveredItem Callback to clear the hovered item
|
* @param {function} clearHoveredItem Callback to clear the hovered item
|
||||||
* @param {function} setSelectedItems Callback to set the set of selected items in the Redux state
|
* @param {function} setSelectedItems Callback to set the set of selected items in the Redux state
|
||||||
* @param {function} clearSelectedItems Callback to clear the set of selected items in the Redux state
|
* @param {function} clearSelectedItems Callback to clear the set of selected items in the Redux state
|
||||||
* @param {!function} onUpdateSvg A callback to call when the image visibly changes
|
* @param {!function} onUpdateImage A callback to call when the image visibly changes
|
||||||
*/
|
*/
|
||||||
constructor (setHoveredItem, clearHoveredItem, setSelectedItems, clearSelectedItems, onUpdateSvg) {
|
constructor (setHoveredItem, clearHoveredItem, setSelectedItems, clearSelectedItems, onUpdateImage) {
|
||||||
super();
|
super();
|
||||||
this.setHoveredItem = setHoveredItem;
|
this.setHoveredItem = setHoveredItem;
|
||||||
this.clearHoveredItem = clearHoveredItem;
|
this.clearHoveredItem = clearHoveredItem;
|
||||||
this.setSelectedItems = setSelectedItems;
|
this.setSelectedItems = setSelectedItems;
|
||||||
this.clearSelectedItems = clearSelectedItems;
|
this.clearSelectedItems = clearSelectedItems;
|
||||||
this.onUpdateSvg = onUpdateSvg;
|
this.onUpdateImage = onUpdateImage;
|
||||||
this.prevHoveredItemId = null;
|
this.prevHoveredItemId = null;
|
||||||
|
|
||||||
// We have to set these functions instead of just declaring them because
|
// We have to set these functions instead of just declaring them because
|
||||||
|
|
|
@ -34,18 +34,18 @@ class TextTool extends paper.Tool {
|
||||||
* @param {HTMLTextAreaElement} textAreaElement dom element for the editable text field
|
* @param {HTMLTextAreaElement} textAreaElement dom element for the editable text field
|
||||||
* @param {function} setSelectedItems Callback to set the set of selected items in the Redux state
|
* @param {function} setSelectedItems Callback to set the set of selected items in the Redux state
|
||||||
* @param {function} clearSelectedItems Callback to clear the set of selected items in the Redux state
|
* @param {function} clearSelectedItems Callback to clear the set of selected items in the Redux state
|
||||||
* @param {!function} onUpdateSvg A callback to call when the image visibly changes
|
* @param {!function} onUpdateImage A callback to call when the image visibly changes
|
||||||
* @param {!function} setTextEditTarget Call to set text editing target whenever text editing is active
|
* @param {!function} setTextEditTarget Call to set text editing target whenever text editing is active
|
||||||
*/
|
*/
|
||||||
constructor (textAreaElement, setSelectedItems, clearSelectedItems, onUpdateSvg, setTextEditTarget) {
|
constructor (textAreaElement, setSelectedItems, clearSelectedItems, onUpdateImage, setTextEditTarget) {
|
||||||
super();
|
super();
|
||||||
this.element = textAreaElement;
|
this.element = textAreaElement;
|
||||||
this.setSelectedItems = setSelectedItems;
|
this.setSelectedItems = setSelectedItems;
|
||||||
this.clearSelectedItems = clearSelectedItems;
|
this.clearSelectedItems = clearSelectedItems;
|
||||||
this.onUpdateSvg = onUpdateSvg;
|
this.onUpdateImage = onUpdateImage;
|
||||||
this.setTextEditTarget = setTextEditTarget;
|
this.setTextEditTarget = setTextEditTarget;
|
||||||
this.boundingBoxTool = new BoundingBoxTool(Modes.TEXT, setSelectedItems, clearSelectedItems, onUpdateSvg);
|
this.boundingBoxTool = new BoundingBoxTool(Modes.TEXT, setSelectedItems, clearSelectedItems, onUpdateImage);
|
||||||
this.nudgeTool = new NudgeTool(this.boundingBoxTool, onUpdateSvg);
|
this.nudgeTool = new NudgeTool(this.boundingBoxTool, onUpdateImage);
|
||||||
this.lastEvent = null;
|
this.lastEvent = null;
|
||||||
|
|
||||||
// We have to set these functions instead of just declaring them because
|
// We have to set these functions instead of just declaring them because
|
||||||
|
@ -249,7 +249,7 @@ class TextTool extends paper.Tool {
|
||||||
handleTextInput (event) {
|
handleTextInput (event) {
|
||||||
// Save undo state if you paused typing for long enough.
|
// Save undo state if you paused typing for long enough.
|
||||||
if (this.lastTypeEvent && event.timeStamp - this.lastTypeEvent.timeStamp > TextTool.TYPING_TIMEOUT_MILLIS) {
|
if (this.lastTypeEvent && event.timeStamp - this.lastTypeEvent.timeStamp > TextTool.TYPING_TIMEOUT_MILLIS) {
|
||||||
this.onUpdateSvg();
|
this.onUpdateImage();
|
||||||
}
|
}
|
||||||
this.lastTypeEvent = event;
|
this.lastTypeEvent = event;
|
||||||
if (this.mode === TextTool.TEXT_EDIT_MODE) {
|
if (this.mode === TextTool.TEXT_EDIT_MODE) {
|
||||||
|
@ -317,7 +317,7 @@ class TextTool extends paper.Tool {
|
||||||
|
|
||||||
// If you finished editing a textbox, save undo state
|
// If you finished editing a textbox, save undo state
|
||||||
if (this.textBox && this.textBox.content.trim().length) {
|
if (this.textBox && this.textBox.content.trim().length) {
|
||||||
this.onUpdateSvg();
|
this.onUpdateImage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
deactivateTool () {
|
deactivateTool () {
|
||||||
|
|
|
@ -4,7 +4,6 @@ import paper from '@scratch/paper';
|
||||||
import {hideGuideLayers, showGuideLayers, getRaster} from '../helper/layer';
|
import {hideGuideLayers, showGuideLayers, getRaster} from '../helper/layer';
|
||||||
import Formats from '../lib/format';
|
import Formats from '../lib/format';
|
||||||
import {isVector, isBitmap} from '../lib/format';
|
import {isVector, isBitmap} from '../lib/format';
|
||||||
import log from '../log/log';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Take an undo snapshot
|
* Take an undo snapshot
|
||||||
|
@ -20,7 +19,7 @@ const performSnapshot = function (dispatchPerformSnapshot, format) {
|
||||||
showGuideLayers(guideLayers);
|
showGuideLayers(guideLayers);
|
||||||
};
|
};
|
||||||
|
|
||||||
const _restore = function (entry, setSelectedItems, onUpdateSvg) {
|
const _restore = function (entry, setSelectedItems, onUpdateImage) {
|
||||||
for (let i = paper.project.layers.length - 1; i >= 0; i--) {
|
for (let i = paper.project.layers.length - 1; i >= 0; i--) {
|
||||||
const layer = paper.project.layers[i];
|
const layer = paper.project.layers[i];
|
||||||
if (!layer.data.isBackgroundGuideLayer) {
|
if (!layer.data.isBackgroundGuideLayer) {
|
||||||
|
@ -32,36 +31,30 @@ const _restore = function (entry, setSelectedItems, onUpdateSvg) {
|
||||||
|
|
||||||
setSelectedItems();
|
setSelectedItems();
|
||||||
getRaster().onLoad = function () {
|
getRaster().onLoad = function () {
|
||||||
onUpdateSvg(true /* skipSnapshot */);
|
onUpdateImage(true /* skipSnapshot */);
|
||||||
};
|
};
|
||||||
if (getRaster().loaded) {
|
if (getRaster().loaded) {
|
||||||
getRaster().onLoad();
|
getRaster().onLoad();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const performUndo = function (undoState, dispatchPerformUndo, setSelectedItems, onUpdateSvg) {
|
const performUndo = function (undoState, dispatchPerformUndo, setSelectedItems, onUpdateImage) {
|
||||||
if (undoState.pointer > 0) {
|
if (undoState.pointer > 0) {
|
||||||
const state = undoState.stack[undoState.pointer - 1];
|
const state = undoState.stack[undoState.pointer - 1];
|
||||||
_restore(state, setSelectedItems, onUpdateSvg);
|
_restore(state, setSelectedItems, onUpdateImage);
|
||||||
const format = isVector(state.paintEditorFormat) ? Formats.VECTOR_SKIP_CONVERT :
|
const format = isVector(state.paintEditorFormat) ? Formats.VECTOR_SKIP_CONVERT :
|
||||||
isBitmap(state.paintEditorFormat) ? Formats.BITMAP_SKIP_CONVERT : null;
|
isBitmap(state.paintEditorFormat) ? Formats.BITMAP_SKIP_CONVERT : null;
|
||||||
if (!format) {
|
|
||||||
log.error(`Invalid format: ${state.paintEditorFormat}`);
|
|
||||||
}
|
|
||||||
dispatchPerformUndo(format);
|
dispatchPerformUndo(format);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const performRedo = function (undoState, dispatchPerformRedo, setSelectedItems, onUpdateSvg) {
|
const performRedo = function (undoState, dispatchPerformRedo, setSelectedItems, onUpdateImage) {
|
||||||
if (undoState.pointer >= 0 && undoState.pointer < undoState.stack.length - 1) {
|
if (undoState.pointer >= 0 && undoState.pointer < undoState.stack.length - 1) {
|
||||||
const state = undoState.stack[undoState.pointer + 1];
|
const state = undoState.stack[undoState.pointer + 1];
|
||||||
_restore(state, setSelectedItems, onUpdateSvg);
|
_restore(state, setSelectedItems, onUpdateImage);
|
||||||
const format = isVector(state.paintEditorFormat) ? Formats.VECTOR_SKIP_CONVERT :
|
const format = isVector(state.paintEditorFormat) ? Formats.VECTOR_SKIP_CONVERT :
|
||||||
isBitmap(state.paintEditorFormat) ? Formats.BITMAP_SKIP_CONVERT : null;
|
isBitmap(state.paintEditorFormat) ? Formats.BITMAP_SKIP_CONVERT : null;
|
||||||
if (!format) {
|
|
||||||
log.error(`Invalid format: ${state.paintEditorFormat}`);
|
|
||||||
}
|
|
||||||
dispatchPerformRedo(format);
|
dispatchPerformRedo(format);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -28,30 +28,36 @@ class Playground extends React.Component {
|
||||||
super(props);
|
super(props);
|
||||||
bindAll(this, [
|
bindAll(this, [
|
||||||
'handleUpdateName',
|
'handleUpdateName',
|
||||||
'handleUpdateSvg'
|
'handleUpdateImage'
|
||||||
]);
|
]);
|
||||||
this.state = {
|
this.state = {
|
||||||
name: 'meow',
|
name: 'meow',
|
||||||
rotationCenterX: 20,
|
rotationCenterX: 20,
|
||||||
rotationCenterY: 400,
|
rotationCenterY: 400,
|
||||||
svg: svgString
|
image: svgString
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
handleUpdateName (name) {
|
handleUpdateName (name) {
|
||||||
this.setState({name});
|
this.setState({name});
|
||||||
}
|
}
|
||||||
handleUpdateSvg (svg, rotationCenterX, rotationCenterY) {
|
handleUpdateImage (isVector, image, rotationCenterX, rotationCenterY) {
|
||||||
console.log(svg);
|
console.log(image);
|
||||||
console.log(`rotationCenterX: ${rotationCenterX} rotationCenterY: ${rotationCenterY}`);
|
console.log(`rotationCenterX: ${rotationCenterX} rotationCenterY: ${rotationCenterY}`);
|
||||||
this.setState({svg, rotationCenterX, rotationCenterY});
|
if (isVector) {
|
||||||
|
this.setState({image, rotationCenterX, rotationCenterY});
|
||||||
|
} else { // is Bitmap
|
||||||
|
const imageElement = new Image();
|
||||||
|
imageElement.src = image.toDataURL("image/png");
|
||||||
|
this.setState({imageElement, rotationCenterX, rotationCenterY});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
render () {
|
render () {
|
||||||
return (
|
return (
|
||||||
<PaintEditor
|
<PaintEditor
|
||||||
{...this.state}
|
{...this.state}
|
||||||
svgId="meow"
|
imageId="meow"
|
||||||
onUpdateName={this.handleUpdateName}
|
onUpdateName={this.handleUpdateName}
|
||||||
onUpdateSvg={this.handleUpdateSvg}
|
onUpdateImage={this.handleUpdateImage}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ import log from '../log/log';
|
||||||
import {UNDO, REDO} from './undo';
|
import {UNDO, REDO} from './undo';
|
||||||
|
|
||||||
const CHANGE_FORMAT = 'scratch-paint/formats/CHANGE_FORMAT';
|
const CHANGE_FORMAT = 'scratch-paint/formats/CHANGE_FORMAT';
|
||||||
const initialState = Formats.VECTOR;
|
const initialState = null;
|
||||||
|
|
||||||
const reducer = function (state, action) {
|
const reducer = function (state, action) {
|
||||||
if (typeof state === 'undefined') state = initialState;
|
if (typeof state === 'undefined') state = initialState;
|
||||||
|
@ -13,6 +13,7 @@ const reducer = function (state, action) {
|
||||||
case REDO:
|
case REDO:
|
||||||
/* falls through */
|
/* falls through */
|
||||||
case CHANGE_FORMAT:
|
case CHANGE_FORMAT:
|
||||||
|
if (!action.format) return state;
|
||||||
if (action.format in Formats) {
|
if (action.format in Formats) {
|
||||||
return action.format;
|
return action.format;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import {undo, redo} from '../../src/reducers/undo';
|
||||||
|
|
||||||
test('initialState', () => {
|
test('initialState', () => {
|
||||||
let defaultState;
|
let defaultState;
|
||||||
expect(reducer(defaultState /* state */, {type: 'anything'} /* action */) in Formats).toBeTruthy();
|
expect(reducer(defaultState /* state */, {type: 'anything'} /* action */)).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('changeFormat', () => {
|
test('changeFormat', () => {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue