diff --git a/src/components/paint-editor.jsx b/src/components/paint-editor.jsx index 090b9bed..306bde8f 100644 --- a/src/components/paint-editor.jsx +++ b/src/components/paint-editor.jsx @@ -3,6 +3,7 @@ import React from 'react'; import PaperCanvas from '../containers/paper-canvas.jsx'; import BrushMode from '../containers/brush-mode.jsx'; import EraserMode from '../containers/eraser-mode.jsx'; +import PropTypes from 'prop-types'; import LineMode from '../containers/line-mode.jsx'; class PaintEditorComponent extends React.Component { @@ -21,10 +22,24 @@ class PaintEditorComponent extends React.Component { if (this.state.canvas) { return (
- - - - + + + +
); } @@ -36,4 +51,11 @@ class PaintEditorComponent extends React.Component { } } +PaintEditorComponent.propTypes = { + onUpdateSvg: PropTypes.func.isRequired, + rotationCenterX: PropTypes.number, + rotationCenterY: PropTypes.number, + svg: PropTypes.string +}; + export default PaintEditorComponent; diff --git a/src/containers/blob/blob.js b/src/containers/blob/blob.js index bc7f63d1..22f4cda5 100644 --- a/src/containers/blob/blob.js +++ b/src/containers/blob/blob.js @@ -24,9 +24,13 @@ class Blobbiness { return 9; } - constructor () { + /** + * @param {function} updateCallback call when the drawing has changed to let listeners know + */ + constructor (updateCallback) { this.broadBrushHelper = new BroadBrushHelper(); this.segmentBrushHelper = new SegmentBrushHelper(); + this.updateCallback = updateCallback; } /** @@ -113,6 +117,9 @@ class Blobbiness { blob.mergeBrush(lastPath); } + blob.cursorPreview.visible = false; + blob.updateCallback(); + blob.cursorPreview.visible = true; blob.cursorPreview.bringToFront(); blob.cursorPreview.position = event.point; diff --git a/src/containers/brush-mode.jsx b/src/containers/brush-mode.jsx index e751030f..c89e08f9 100644 --- a/src/containers/brush-mode.jsx +++ b/src/containers/brush-mode.jsx @@ -16,7 +16,7 @@ class BrushMode extends React.Component { 'deactivateTool', 'onScroll' ]); - this.blob = new Blobbiness(); + this.blob = new Blobbiness(this.props.onUpdateSvg); } componentDidMount () { if (this.props.isBrushModeActive) { @@ -70,7 +70,8 @@ BrushMode.propTypes = { canvas: PropTypes.instanceOf(Element).isRequired, changeBrushSize: PropTypes.func.isRequired, handleMouseDown: PropTypes.func.isRequired, - isBrushModeActive: PropTypes.bool.isRequired + isBrushModeActive: PropTypes.bool.isRequired, + onUpdateSvg: PropTypes.func.isRequired }; const mapStateToProps = state => ({ diff --git a/src/containers/eraser-mode.jsx b/src/containers/eraser-mode.jsx index af932329..0972ed36 100644 --- a/src/containers/eraser-mode.jsx +++ b/src/containers/eraser-mode.jsx @@ -16,7 +16,7 @@ class EraserMode extends React.Component { 'deactivateTool', 'onScroll' ]); - this.blob = new Blobbiness(); + this.blob = new Blobbiness(this.props.onUpdateSvg); } componentDidMount () { if (this.props.isEraserModeActive) { @@ -66,7 +66,8 @@ EraserMode.propTypes = { brushSize: PropTypes.number.isRequired }), handleMouseDown: PropTypes.func.isRequired, - isEraserModeActive: PropTypes.bool.isRequired + isEraserModeActive: PropTypes.bool.isRequired, + onUpdateSvg: PropTypes.func.isRequired }; const mapStateToProps = state => ({ diff --git a/src/containers/line-mode.jsx b/src/containers/line-mode.jsx index 030b33ba..7648c045 100644 --- a/src/containers/line-mode.jsx +++ b/src/containers/line-mode.jsx @@ -209,6 +209,7 @@ class LineMode extends React.Component { } this.hitResult = null; } + this.props.onUpdateSvg(); // TODO add back undo // if (this.path) { @@ -280,7 +281,8 @@ LineMode.propTypes = { isLineModeActive: PropTypes.bool.isRequired, lineModeState: PropTypes.shape({ lineWidth: PropTypes.number.isRequired - }) + }), + onUpdateSvg: PropTypes.func.isRequired }; const mapStateToProps = state => ({ diff --git a/src/containers/paint-editor.jsx b/src/containers/paint-editor.jsx index 772d8985..ba260313 100644 --- a/src/containers/paint-editor.jsx +++ b/src/containers/paint-editor.jsx @@ -4,23 +4,50 @@ import PaintEditorComponent from '../components/paint-editor.jsx'; import {changeMode} from '../reducers/modes'; import Modes from '../modes/modes'; import {connect} from 'react-redux'; +import bindAll from 'lodash.bindall'; +import paper from 'paper'; class PaintEditor extends React.Component { + constructor (props) { + super(props); + bindAll(this, [ + 'handleUpdateSvg' + ]); + } componentDidMount () { document.addEventListener('keydown', this.props.onKeyPress); } componentWillUnmount () { document.removeEventListener('keydown', this.props.onKeyPress); } + handleUpdateSvg () { + const bounds = paper.project.activeLayer.bounds; + this.props.onUpdateSvg( + paper.project.exportSVG({ + asString: true, + matrix: new paper.Matrix().translate(-bounds.x, -bounds.y) + }), + paper.project.view.center.x - bounds.x, + paper.project.view.center.y - bounds.y); + } render () { return ( - + ); } } PaintEditor.propTypes = { - onKeyPress: PropTypes.func.isRequired + onKeyPress: PropTypes.func.isRequired, + onUpdateSvg: PropTypes.func.isRequired, + rotationCenterX: PropTypes.number, + rotationCenterY: PropTypes.number, + svg: PropTypes.string }; const mapDispatchToProps = dispatch => ({ diff --git a/src/containers/paper-canvas.jsx b/src/containers/paper-canvas.jsx index 4ccb0b58..fdd6e44d 100644 --- a/src/containers/paper-canvas.jsx +++ b/src/containers/paper-canvas.jsx @@ -7,27 +7,50 @@ class PaperCanvas extends React.Component { constructor (props) { super(props); bindAll(this, [ - 'setCanvas' + 'setCanvas', + 'importSvg' ]); } componentDidMount () { paper.setup(this.canvas); - // Create a Paper.js Path to draw a line into it: - const path = new paper.Path(); - // Give the stroke a color - path.strokeColor = 'black'; - const start = new paper.Point(100, 100); - // Move to start and draw a line from there - path.moveTo(start); - // Note that the plus operator on Point objects does not work - // in JavaScript. Instead, we need to call the add() function: - path.lineTo(start.add([200, -50])); - // Draw the view now: - paper.view.draw(); + if (this.props.svg) { + this.importSvg(this.props.svg, this.props.rotationCenterX, this.props.rotationCenterY); + } + } + componentWillReceiveProps (newProps) { + paper.project.activeLayer.removeChildren(); + this.importSvg(newProps.svg, newProps.rotationCenterX, newProps.rotationCenterY); } componentWillUnmount () { paper.remove(); } + importSvg (svg, rotationCenterX, rotationCenterY) { + const imported = paper.project.importSVG(svg, + { + expandShapes: true, + onLoad: function (item) { + // Remove viewbox + if (item.clipped) { + item.clipped = false; + // Consider removing clip mask here? + } + while (item.reduce() !== item) { + item = item.reduce(); + } + } + }); + if (typeof rotationCenterX !== 'undefined' && typeof rotationCenterY !== 'undefined') { + imported.position = + paper.project.view.center + .add(imported.bounds.width / 2, imported.bounds.height / 2) + .subtract(rotationCenterX, rotationCenterY); + } else { + // Center + imported.position = paper.project.view.center; + } + + paper.project.view.update(); + } setCanvas (canvas) { this.canvas = canvas; if (this.props.canvasRef) { @@ -44,7 +67,10 @@ class PaperCanvas extends React.Component { } PaperCanvas.propTypes = { - canvasRef: PropTypes.func + canvasRef: PropTypes.func, + rotationCenterX: PropTypes.number, + rotationCenterY: PropTypes.number, + svg: PropTypes.string }; export default PaperCanvas; diff --git a/src/playground/playground.jsx b/src/playground/playground.jsx index 9f68704a..f59ef2b0 100644 --- a/src/playground/playground.jsx +++ b/src/playground/playground.jsx @@ -13,10 +13,28 @@ const store = createStore( intlInitialState, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__() ); +const svgString = + '' + + '' + + '' + + '' + + ''; +const onUpdateSvg = function (newSvgString, rotationCenterX, rotationCenterY) { + console.log(newSvgString); + console.log(`rotationCenterX: ${rotationCenterX} rotationCenterY: ${rotationCenterY}`); +}; ReactDOM.render(( - + ), appTarget);