mirror of
https://github.com/scratchfoundation/scratch-paint.git
synced 2025-06-08 11:14:51 -04:00
Add line tool
This commit is contained in:
parent
83e417a7f1
commit
0755df9990
8 changed files with 317 additions and 35 deletions
src
components
containers
helper/bit-tools
lib
|
@ -1,27 +1,25 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
import {ComingSoonTooltip} from '../coming-soon/coming-soon.jsx';
|
|
||||||
import ToolSelectComponent from '../tool-select-base/tool-select-base.jsx';
|
import ToolSelectComponent from '../tool-select-base/tool-select-base.jsx';
|
||||||
|
|
||||||
import lineIcon from './line.svg';
|
import lineIcon from './line.svg';
|
||||||
|
|
||||||
const BitLineComponent = () => (
|
const BitLineComponent = props => (
|
||||||
<ComingSoonTooltip
|
<ToolSelectComponent
|
||||||
place="right"
|
imgDescriptor={{
|
||||||
tooltipId="bit-line-mode"
|
defaultMessage: 'Line',
|
||||||
>
|
description: 'Label for the line tool, which draws straight line segments',
|
||||||
<ToolSelectComponent
|
id: 'paint.lineMode.line'
|
||||||
disabled
|
}}
|
||||||
imgDescriptor={{
|
imgSrc={lineIcon}
|
||||||
defaultMessage: 'Line',
|
isSelected={props.isSelected}
|
||||||
description: 'Label for the line tool, which draws straight line segments',
|
onMouseDown={props.onMouseDown}
|
||||||
id: 'paint.lineMode.line'
|
/>
|
||||||
}}
|
|
||||||
imgSrc={lineIcon}
|
|
||||||
isSelected={false}
|
|
||||||
onMouseDown={function () {}} // eslint-disable-line react/jsx-no-bind
|
|
||||||
/>
|
|
||||||
</ComingSoonTooltip>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
BitLineComponent.propTypes = {
|
||||||
|
isSelected: PropTypes.bool.isRequired,
|
||||||
|
onMouseDown: PropTypes.func.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
export default BitLineComponent;
|
export default BitLineComponent;
|
||||||
|
|
|
@ -15,14 +15,15 @@ import InputGroup from '../input-group/input-group.jsx';
|
||||||
import LabeledIconButton from '../labeled-icon-button/labeled-icon-button.jsx';
|
import LabeledIconButton from '../labeled-icon-button/labeled-icon-button.jsx';
|
||||||
import Modes from '../../lib/modes';
|
import Modes from '../../lib/modes';
|
||||||
import Formats from '../../lib/format';
|
import Formats from '../../lib/format';
|
||||||
import {isBitmap} from '../../lib/format';
|
import {isBitmap, isVector} from '../../lib/format';
|
||||||
import styles from './mode-tools.css';
|
import styles from './mode-tools.css';
|
||||||
|
|
||||||
import copyIcon from './icons/copy.svg';
|
import copyIcon from './icons/copy.svg';
|
||||||
import pasteIcon from './icons/paste.svg';
|
import pasteIcon from './icons/paste.svg';
|
||||||
|
|
||||||
import brushIcon from '../brush-mode/brush.svg';
|
|
||||||
import bitBrushIcon from '../bit-brush-mode/brush.svg';
|
import bitBrushIcon from '../bit-brush-mode/brush.svg';
|
||||||
|
import bitLineIcon from '../bit-line-mode/line.svg';
|
||||||
|
import brushIcon from '../brush-mode/brush.svg';
|
||||||
import curvedPointIcon from './icons/curved-point.svg';
|
import curvedPointIcon from './icons/curved-point.svg';
|
||||||
import eraserIcon from '../eraser-mode/eraser.svg';
|
import eraserIcon from '../eraser-mode/eraser.svg';
|
||||||
import flipHorizontalIcon from './icons/flip-horizontal.svg';
|
import flipHorizontalIcon from './icons/flip-horizontal.svg';
|
||||||
|
@ -39,6 +40,11 @@ const ModeToolsComponent = props => {
|
||||||
description: 'Label for the brush size input',
|
description: 'Label for the brush size input',
|
||||||
id: 'paint.modeTools.brushSize'
|
id: 'paint.modeTools.brushSize'
|
||||||
},
|
},
|
||||||
|
lineSize: {
|
||||||
|
defaultMessage: 'Line size',
|
||||||
|
description: 'Label for the line size input',
|
||||||
|
id: 'paint.modeTools.lineSize'
|
||||||
|
},
|
||||||
eraserSize: {
|
eraserSize: {
|
||||||
defaultMessage: 'Eraser size',
|
defaultMessage: 'Eraser size',
|
||||||
description: 'Label for the eraser size input',
|
description: 'Label for the eraser size input',
|
||||||
|
@ -80,18 +86,22 @@ const ModeToolsComponent = props => {
|
||||||
case Modes.BRUSH:
|
case Modes.BRUSH:
|
||||||
/* falls through */
|
/* falls through */
|
||||||
case Modes.BIT_BRUSH:
|
case Modes.BIT_BRUSH:
|
||||||
|
/* falls through */
|
||||||
|
case Modes.BIT_LINE:
|
||||||
{
|
{
|
||||||
const currentBrushIcon = isBitmap(props.format) ? bitBrushIcon : brushIcon;
|
const currentIcon = isVector(props.format) ? brushIcon :
|
||||||
|
props.mode === Modes.BIT_LINE ? bitLineIcon : bitBrushIcon;
|
||||||
const currentBrushValue = isBitmap(props.format) ? props.bitBrushSize : props.brushValue;
|
const currentBrushValue = isBitmap(props.format) ? props.bitBrushSize : props.brushValue;
|
||||||
const changeFunction = isBitmap(props.format) ? props.onBitBrushSliderChange : props.onBrushSliderChange;
|
const changeFunction = isBitmap(props.format) ? props.onBitBrushSliderChange : props.onBrushSliderChange;
|
||||||
|
const currentMessage = props.mode === Modes.BIT_LINE ? messages.lineSize : messages.brushSize;
|
||||||
return (
|
return (
|
||||||
<div className={classNames(props.className, styles.modeTools)}>
|
<div className={classNames(props.className, styles.modeTools)}>
|
||||||
<div>
|
<div>
|
||||||
<img
|
<img
|
||||||
alt={props.intl.formatMessage(messages.brushSize)}
|
alt={props.intl.formatMessage(currentMessage)}
|
||||||
className={styles.modeToolsIcon}
|
className={styles.modeToolsIcon}
|
||||||
draggable={false}
|
draggable={false}
|
||||||
src={currentBrushIcon}
|
src={currentIcon}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<LiveInput
|
<LiveInput
|
||||||
|
|
|
@ -11,7 +11,7 @@ import {shouldShowGroup, shouldShowUngroup} from '../../helper/group';
|
||||||
import {shouldShowBringForward, shouldShowSendBackward} from '../../helper/order';
|
import {shouldShowBringForward, shouldShowSendBackward} from '../../helper/order';
|
||||||
|
|
||||||
import BitBrushMode from '../../containers/bit-brush-mode.jsx';
|
import BitBrushMode from '../../containers/bit-brush-mode.jsx';
|
||||||
import BitLineMode from '../../components/bit-line-mode/bit-line-mode.jsx';
|
import BitLineMode from '../../containers/bit-line-mode.jsx';
|
||||||
import BitOvalMode from '../../components/bit-oval-mode/bit-oval-mode.jsx';
|
import BitOvalMode from '../../components/bit-oval-mode/bit-oval-mode.jsx';
|
||||||
import BitRectMode from '../../components/bit-rect-mode/bit-rect-mode.jsx';
|
import BitRectMode from '../../components/bit-rect-mode/bit-rect-mode.jsx';
|
||||||
import BitTextMode from '../../components/bit-text-mode/bit-text-mode.jsx';
|
import BitTextMode from '../../components/bit-text-mode/bit-text-mode.jsx';
|
||||||
|
@ -410,7 +410,9 @@ const PaintEditorComponent = props => {
|
||||||
<BitBrushMode
|
<BitBrushMode
|
||||||
onUpdateSvg={props.onUpdateSvg}
|
onUpdateSvg={props.onUpdateSvg}
|
||||||
/>
|
/>
|
||||||
<BitLineMode />
|
<BitLineMode
|
||||||
|
onUpdateSvg={props.onUpdateSvg}
|
||||||
|
/>
|
||||||
<BitOvalMode />
|
<BitOvalMode />
|
||||||
<BitRectMode />
|
<BitRectMode />
|
||||||
<BitTextMode />
|
<BitTextMode />
|
||||||
|
|
107
src/containers/bit-line-mode.jsx
Normal file
107
src/containers/bit-line-mode.jsx
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import React from 'react';
|
||||||
|
import {connect} from 'react-redux';
|
||||||
|
import bindAll from 'lodash.bindall';
|
||||||
|
import Modes from '../lib/modes';
|
||||||
|
import {MIXED} from '../helper/style-path';
|
||||||
|
|
||||||
|
import {changeFillColor, DEFAULT_COLOR} from '../reducers/fill-color';
|
||||||
|
import {changeMode} from '../reducers/modes';
|
||||||
|
import {clearSelectedItems} from '../reducers/selected-items';
|
||||||
|
import {clearSelection} from '../helper/selection';
|
||||||
|
|
||||||
|
import BitLineModeComponent from '../components/bit-line-mode/bit-line-mode.jsx';
|
||||||
|
import BitLineTool from '../helper/bit-tools/line-tool';
|
||||||
|
|
||||||
|
class BitLineMode extends React.Component {
|
||||||
|
constructor (props) {
|
||||||
|
super(props);
|
||||||
|
bindAll(this, [
|
||||||
|
'activateTool',
|
||||||
|
'deactivateTool'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
componentDidMount () {
|
||||||
|
if (this.props.isBitLineModeActive) {
|
||||||
|
this.activateTool(this.props);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
componentWillReceiveProps (nextProps) {
|
||||||
|
if (this.tool && nextProps.color !== this.props.color) {
|
||||||
|
this.tool.setColor(nextProps.color);
|
||||||
|
}
|
||||||
|
if (this.tool && nextProps.bitBrushSize !== this.props.bitBrushSize) {
|
||||||
|
this.tool.setLineSize(nextProps.bitBrushSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nextProps.isBitLineModeActive && !this.props.isBitLineModeActive) {
|
||||||
|
this.activateTool();
|
||||||
|
} else if (!nextProps.isBitLineModeActive && this.props.isBitLineModeActive) {
|
||||||
|
this.deactivateTool();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shouldComponentUpdate (nextProps) {
|
||||||
|
return nextProps.isBitLineModeActive !== this.props.isBitLineModeActive;
|
||||||
|
}
|
||||||
|
activateTool () {
|
||||||
|
clearSelection(this.props.clearSelectedItems);
|
||||||
|
// Force the default line color if fill is MIXED or transparent
|
||||||
|
let color = this.props.color;
|
||||||
|
if (!color || color === MIXED) {
|
||||||
|
this.props.onChangeFillColor(DEFAULT_COLOR);
|
||||||
|
color = DEFAULT_COLOR;
|
||||||
|
}
|
||||||
|
this.tool = new BitLineTool(
|
||||||
|
this.props.onUpdateSvg
|
||||||
|
);
|
||||||
|
this.tool.setColor(color);
|
||||||
|
this.tool.setLineSize(this.props.bitBrushSize);
|
||||||
|
|
||||||
|
this.tool.activate();
|
||||||
|
}
|
||||||
|
deactivateTool () {
|
||||||
|
this.tool.deactivateTool();
|
||||||
|
this.tool.remove();
|
||||||
|
this.tool = null;
|
||||||
|
}
|
||||||
|
render () {
|
||||||
|
return (
|
||||||
|
<BitLineModeComponent
|
||||||
|
isSelected={this.props.isBitLineModeActive}
|
||||||
|
onMouseDown={this.props.handleMouseDown}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BitLineMode.propTypes = {
|
||||||
|
bitBrushSize: PropTypes.number.isRequired,
|
||||||
|
clearSelectedItems: PropTypes.func.isRequired,
|
||||||
|
color: PropTypes.string,
|
||||||
|
handleMouseDown: PropTypes.func.isRequired,
|
||||||
|
isBitLineModeActive: PropTypes.bool.isRequired,
|
||||||
|
onChangeFillColor: PropTypes.func.isRequired,
|
||||||
|
onUpdateSvg: PropTypes.func.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapStateToProps = state => ({
|
||||||
|
bitBrushSize: state.scratchPaint.bitBrushSize,
|
||||||
|
color: state.scratchPaint.color.fillColor,
|
||||||
|
isBitLineModeActive: state.scratchPaint.mode === Modes.BIT_LINE
|
||||||
|
});
|
||||||
|
const mapDispatchToProps = dispatch => ({
|
||||||
|
clearSelectedItems: () => {
|
||||||
|
dispatch(clearSelectedItems());
|
||||||
|
},
|
||||||
|
handleMouseDown: () => {
|
||||||
|
dispatch(changeMode(Modes.BIT_LINE));
|
||||||
|
},
|
||||||
|
onChangeFillColor: fillColor => {
|
||||||
|
dispatch(changeFillColor(fillColor));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
mapStateToProps,
|
||||||
|
mapDispatchToProps
|
||||||
|
)(BitLineMode);
|
|
@ -49,6 +49,7 @@ class PaintEditor extends React.Component {
|
||||||
'handleZoomReset',
|
'handleZoomReset',
|
||||||
'canRedo',
|
'canRedo',
|
||||||
'canUndo',
|
'canUndo',
|
||||||
|
'switchMode',
|
||||||
'onMouseDown',
|
'onMouseDown',
|
||||||
'setCanvas',
|
'setCanvas',
|
||||||
'setTextArea',
|
'setTextArea',
|
||||||
|
@ -81,11 +82,9 @@ class PaintEditor extends React.Component {
|
||||||
this.stopEyeDroppingLoop();
|
this.stopEyeDroppingLoop();
|
||||||
}
|
}
|
||||||
|
|
||||||
// @todo move to correct corresponding tool
|
if ((isVector(this.props.format) && isBitmap(prevProps.format)) ||
|
||||||
if (isVector(this.props.format) && isBitmap(prevProps.format)) {
|
(isVector(prevProps.format) && isBitmap(this.props.format))) {
|
||||||
this.props.changeMode(Modes.BRUSH);
|
this.switchMode(this.props.format);
|
||||||
} else if (isVector(prevProps.format) && isBitmap(this.props.format)) {
|
|
||||||
this.props.changeMode(Modes.BIT_BRUSH);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
componentWillUnmount () {
|
componentWillUnmount () {
|
||||||
|
@ -94,6 +93,31 @@ class PaintEditor extends React.Component {
|
||||||
document.removeEventListener('mousedown', this.onMouseDown);
|
document.removeEventListener('mousedown', this.onMouseDown);
|
||||||
document.removeEventListener('touchstart', this.onMouseDown);
|
document.removeEventListener('touchstart', this.onMouseDown);
|
||||||
}
|
}
|
||||||
|
switchMode (newFormat) {
|
||||||
|
if (isVector(newFormat)) {
|
||||||
|
switch (this.props.mode) {
|
||||||
|
case Modes.BIT_BRUSH:
|
||||||
|
this.props.changeMode(Modes.BRUSH);
|
||||||
|
break;
|
||||||
|
case Modes.BIT_LINE:
|
||||||
|
this.props.changeMode(Modes.LINE);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
this.props.changeMode(Modes.BRUSH);
|
||||||
|
}
|
||||||
|
} else if (isBitmap(newFormat)) {
|
||||||
|
switch (this.props.mode) {
|
||||||
|
case Modes.BRUSH:
|
||||||
|
this.props.changeMode(Modes.BIT_BRUSH);
|
||||||
|
break;
|
||||||
|
case Modes.LINE:
|
||||||
|
this.props.changeMode(Modes.BIT_LINE);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
this.props.changeMode(Modes.BIT_BRUSH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
handleUpdateSvg (skipSnapshot) {
|
handleUpdateSvg (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
|
||||||
|
@ -300,6 +324,7 @@ PaintEditor.propTypes = {
|
||||||
handleSwitchToBitmap: PropTypes.func.isRequired,
|
handleSwitchToBitmap: PropTypes.func.isRequired,
|
||||||
handleSwitchToVector: PropTypes.func.isRequired,
|
handleSwitchToVector: PropTypes.func.isRequired,
|
||||||
isEyeDropping: PropTypes.bool,
|
isEyeDropping: PropTypes.bool,
|
||||||
|
mode: PropTypes.oneOf(Object.keys(Modes)).isRequired,
|
||||||
name: PropTypes.string,
|
name: PropTypes.string,
|
||||||
onDeactivateEyeDropper: PropTypes.func.isRequired,
|
onDeactivateEyeDropper: PropTypes.func.isRequired,
|
||||||
onKeyPress: PropTypes.func.isRequired,
|
onKeyPress: PropTypes.func.isRequired,
|
||||||
|
@ -331,6 +356,7 @@ const mapStateToProps = state => ({
|
||||||
clipboardItems: state.scratchPaint.clipboard.items,
|
clipboardItems: state.scratchPaint.clipboard.items,
|
||||||
format: state.scratchPaint.format,
|
format: state.scratchPaint.format,
|
||||||
isEyeDropping: state.scratchPaint.color.eyeDropper.active,
|
isEyeDropping: state.scratchPaint.color.eyeDropper.active,
|
||||||
|
mode: state.scratchPaint.mode,
|
||||||
pasteOffset: state.scratchPaint.clipboard.pasteOffset,
|
pasteOffset: state.scratchPaint.clipboard.pasteOffset,
|
||||||
previousTool: state.scratchPaint.color.eyeDropper.previousTool,
|
previousTool: state.scratchPaint.color.eyeDropper.previousTool,
|
||||||
selectedItems: state.scratchPaint.selectedItems,
|
selectedItems: state.scratchPaint.selectedItems,
|
||||||
|
|
|
@ -96,10 +96,6 @@ class BrushTool extends paper.Tool {
|
||||||
handleMouseDrag (event) {
|
handleMouseDrag (event) {
|
||||||
if (event.event.button > 0 || !this.active) return; // only first mouse button
|
if (event.event.button > 0 || !this.active) return; // only first mouse button
|
||||||
|
|
||||||
if (this.isBoundingBoxMode) {
|
|
||||||
this.boundingBoxTool.onMouseDrag(event);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
forEachLinePoint(this.lastPoint, event.point, this.draw.bind(this));
|
forEachLinePoint(this.lastPoint, event.point, this.draw.bind(this));
|
||||||
this.lastPoint = event.point;
|
this.lastPoint = event.point;
|
||||||
}
|
}
|
||||||
|
|
142
src/helper/bit-tools/line-tool.js
Normal file
142
src/helper/bit-tools/line-tool.js
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
import paper from '@scratch/paper';
|
||||||
|
import {getRaster} from '../layer';
|
||||||
|
import {forEachLinePoint, fillEllipse} from '../bitmap';
|
||||||
|
import {getGuideLayer} from '../layer';
|
||||||
|
import {ART_BOARD_WIDTH, ART_BOARD_HEIGHT} from '../view';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tool for drawing lines with the bitmap brush.
|
||||||
|
*/
|
||||||
|
class LineTool extends paper.Tool {
|
||||||
|
/**
|
||||||
|
* @param {!function} onUpdateSvg A callback to call when the image visibly changes
|
||||||
|
*/
|
||||||
|
constructor (onUpdateSvg) {
|
||||||
|
super();
|
||||||
|
this.onUpdateSvg = onUpdateSvg;
|
||||||
|
|
||||||
|
// We have to set these functions instead of just declaring them because
|
||||||
|
// paper.js tools hook up the listeners in the setter functions.
|
||||||
|
this.onMouseMove = this.handleMouseMove;
|
||||||
|
this.onMouseDown = this.handleMouseDown;
|
||||||
|
this.onMouseDrag = this.handleMouseDrag;
|
||||||
|
this.onMouseUp = this.handleMouseUp;
|
||||||
|
|
||||||
|
this.colorState = null;
|
||||||
|
this.active = false;
|
||||||
|
this.startPoint = null;
|
||||||
|
this.cursorPreview = null;
|
||||||
|
// Raster to which to draw
|
||||||
|
this.drawTarget = null;
|
||||||
|
}
|
||||||
|
setColor (color) {
|
||||||
|
this.color = color;
|
||||||
|
}
|
||||||
|
setLineSize (size) {
|
||||||
|
// For performance, make sure this is an integer
|
||||||
|
this.size = Math.max(1, ~~size);
|
||||||
|
}
|
||||||
|
// Draw a brush mark at the given point
|
||||||
|
draw (x, y) {
|
||||||
|
const roundedUpRadius = Math.ceil(this.size / 2);
|
||||||
|
this.drawTarget.drawImage(this.tmpCanvas, new paper.Point(~~x - roundedUpRadius, ~~y - roundedUpRadius));
|
||||||
|
}
|
||||||
|
updateCursorIfNeeded () {
|
||||||
|
if (!this.size) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// The cursor preview was unattached from the view by an outside process,
|
||||||
|
// such as changing costumes or undo.
|
||||||
|
if (this.cursorPreview && !this.cursorPreview.parent) {
|
||||||
|
this.cursorPreview = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.cursorPreview || !(this.lastSize === this.size && this.lastColor === this.color)) {
|
||||||
|
if (this.cursorPreview) {
|
||||||
|
this.cursorPreview.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.tmpCanvas = document.createElement('canvas');
|
||||||
|
const roundedUpRadius = Math.ceil(this.size / 2);
|
||||||
|
this.tmpCanvas.width = roundedUpRadius * 2;
|
||||||
|
this.tmpCanvas.height = roundedUpRadius * 2;
|
||||||
|
const context = this.tmpCanvas.getContext('2d');
|
||||||
|
context.imageSmoothingEnabled = false;
|
||||||
|
context.fillStyle = this.color;
|
||||||
|
// Small squares for pixel artists
|
||||||
|
if (this.size <= 5) {
|
||||||
|
if (this.size % 2) {
|
||||||
|
context.fillRect(1, 1, this.size, this.size);
|
||||||
|
} else {
|
||||||
|
context.fillRect(0, 0, this.size, this.size);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const roundedDownRadius = ~~(this.size / 2);
|
||||||
|
fillEllipse(roundedDownRadius, roundedDownRadius, roundedDownRadius, roundedDownRadius, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.cursorPreview = new paper.Raster(this.tmpCanvas);
|
||||||
|
this.cursorPreview.guide = true;
|
||||||
|
this.cursorPreview.parent = getGuideLayer();
|
||||||
|
this.cursorPreview.data.isHelperItem = true;
|
||||||
|
}
|
||||||
|
this.lastSize = this.size;
|
||||||
|
this.lastColor = this.color;
|
||||||
|
}
|
||||||
|
handleMouseMove (event) {
|
||||||
|
this.updateCursorIfNeeded();
|
||||||
|
this.cursorPreview.position = new paper.Point(~~event.point.x, ~~event.point.y);
|
||||||
|
}
|
||||||
|
handleMouseDown (event) {
|
||||||
|
if (event.event.button > 0) return; // only first mouse button
|
||||||
|
this.active = true;
|
||||||
|
|
||||||
|
this.cursorPreview.remove();
|
||||||
|
|
||||||
|
const tmpCanvas = document.createElement('canvas');
|
||||||
|
tmpCanvas.width = ART_BOARD_WIDTH;
|
||||||
|
tmpCanvas.height = ART_BOARD_HEIGHT;
|
||||||
|
this.drawTarget = new paper.Raster(tmpCanvas);
|
||||||
|
this.drawTarget.parent = getGuideLayer();
|
||||||
|
this.drawTarget.guide = true;
|
||||||
|
this.drawTarget.locked = true;
|
||||||
|
this.drawTarget.position = getRaster().position;
|
||||||
|
|
||||||
|
this.draw(event.point.x, event.point.y);
|
||||||
|
this.startPoint = event.point;
|
||||||
|
}
|
||||||
|
handleMouseDrag (event) {
|
||||||
|
if (event.event.button > 0 || !this.active) return; // only first mouse button
|
||||||
|
|
||||||
|
// Clear
|
||||||
|
const context = this.drawTarget.canvas.getContext('2d');
|
||||||
|
context.clearRect(0, 0, ART_BOARD_WIDTH, ART_BOARD_HEIGHT);
|
||||||
|
|
||||||
|
forEachLinePoint(this.startPoint, event.point, this.draw.bind(this));
|
||||||
|
}
|
||||||
|
handleMouseUp (event) {
|
||||||
|
if (event.event.button > 0 || !this.active) return; // only first mouse button
|
||||||
|
|
||||||
|
this.drawTarget.remove();
|
||||||
|
this.drawTarget = getRaster();
|
||||||
|
forEachLinePoint(this.startPoint, event.point, this.draw.bind(this));
|
||||||
|
this.drawTarget = null;
|
||||||
|
this.onUpdateSvg();
|
||||||
|
|
||||||
|
this.lastPoint = null;
|
||||||
|
this.active = false;
|
||||||
|
|
||||||
|
this.updateCursorIfNeeded();
|
||||||
|
this.cursorPreview.position = new paper.Point(~~event.point.x, ~~event.point.y);
|
||||||
|
}
|
||||||
|
deactivateTool () {
|
||||||
|
this.active = false;
|
||||||
|
this.tmpCanvas = null;
|
||||||
|
if (this.cursorPreview) {
|
||||||
|
this.cursorPreview.remove();
|
||||||
|
this.cursorPreview = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LineTool;
|
|
@ -2,6 +2,7 @@ import keyMirror from 'keymirror';
|
||||||
|
|
||||||
const Modes = keyMirror({
|
const Modes = keyMirror({
|
||||||
BIT_BRUSH: null,
|
BIT_BRUSH: null,
|
||||||
|
BIT_LINE: null,
|
||||||
BRUSH: null,
|
BRUSH: null,
|
||||||
ERASER: null,
|
ERASER: null,
|
||||||
LINE: null,
|
LINE: null,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue