Holding down shift while using the lasso tool will snap the line to 45 degree increments

This commit is contained in:
Igor Zinken
2021-02-02 21:06:19 +01:00
parent 5b8b67739b
commit edbd49a4d4
2 changed files with 46 additions and 11 deletions

View File

@@ -20,7 +20,7 @@
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
const { pow, sqrt, atan2 } = Math;
const { pow, sqrt, atan2, round, cos, sin, PI } = Math;
export const distanceBetween = ( point1, point2 ) => {
return sqrt( pow( point2.x - point1.x, 2 ) + pow( point2.y - point1.y, 2 ));
@@ -63,3 +63,28 @@ export const translatePoints = ( coordinateList, xTranslation = 0, yTranslation
y: y + yTranslation,
}));
};
/**
* Calculates the coordinate relative to given x, y and sourcePoint for an incremental snap
*
* @param {Number} x coordinate to snap to
* @param {Number} y coordinate to snap to
* @param {{ x: Number, y: Number }} sourcePoint coordinate to snap from
* @param {{ left: Number, top: Number }} viewport in case coordinates are panned
* @param {Number=} steps defaults to 4 (45 degree increments)
*/
export const snapToAngle = ( x, y, sourcePoint, { left = 0, top = 0 } = {}, steps = 4 ) => {
const deltaX = ( x - sourcePoint.x ) + left;
const deltaY = ( y - sourcePoint.y ) + top;
let dist = sqrt( pow( deltaX, 2 ) + pow( deltaY, 2 ));
const newAngle = atan2( deltaY, deltaX );
const shiftedAngle = round( newAngle / PI * steps ) / steps * PI;
dist *= cos( shiftedAngle - newAngle ); // closer to x, y
return {
x: sourcePoint.x - left + dist * cos( shiftedAngle ),
y: sourcePoint.y - top + dist * sin( shiftedAngle )
};
};

View File

@@ -25,11 +25,12 @@ import { sprite } from "zcanvas";
import { isInsideTransparentArea } from "@/utils/canvas-util";
import { enqueueState } from "@/factories/history-state-factory";
import { getCanvasInstance, getSpriteForLayer } from "@/factories/sprite-factory";
import { isPointInRange } from "@/math/point-math";
import { isPointInRange, snapToAngle } from "@/math/point-math";
import { rectangleToCoordinates } from "@/math/image-math";
import { isSelectionClosed } from "@/math/selection-math";
import ToolTypes from "@/definitions/tool-types";
import LayerSprite from "@/rendering/canvas-elements/layer-sprite";
import KeyboardService from "@/services/keyboard-service";
export const MODE_PAN = 0;
export const MODE_LAYER_SELECT = 1;
@@ -184,17 +185,24 @@ class InteractionPane extends sprite {
case MODE_SELECTION:
if ( !this._selectionClosed ) {
const document = this.getActiveDocument();
const document = this.getActiveDocument();
const { selection } = document;
// selection mode, set the click coordinate as the first point in the selection
const firstPoint = document.selection[ 0 ];
const firstPoint = selection[ 0 ];
let storeHistory = false;
if ( firstPoint && isPointInRange( x, y, firstPoint.x, firstPoint.y, 5 / this.canvas.zoomFactor )) {
this._selectionClosed = true;
x = firstPoint.x;
y = firstPoint.y;
storeHistory = true;
if ( firstPoint ) {
if ( KeyboardService.hasShift() ) {
({ x, y } = snapToAngle( x, y, selection[ selection.length - 1 ] ));
}
else if ( isPointInRange( x, y, firstPoint.x, firstPoint.y, 5 / this.canvas.zoomFactor )) {
// point was in range of start coordinate, snap and close selection
this._selectionClosed = true;
x = firstPoint.x;
y = firstPoint.y;
storeHistory = true;
}
}
document.selection.push({ x, y });
selection.push({ x, y });
if ( storeHistory ) {
storeSelectionHistory( document );
}
@@ -262,7 +270,9 @@ class InteractionPane extends sprite {
// for lasso selections, draw line to current cursor position
let currentPosition = null;
if ( !this._isRectangleSelect && !this._selectionClosed ) {
currentPosition = { x: localPointerX, y: localPointerY };
currentPosition = KeyboardService.hasShift() ?
snapToAngle( localPointerX, localPointerY, selection[ selection.length - 1 ], viewport )
: { x: localPointerX, y: localPointerY };
}
const { zoomFactor } = this.canvas;