mirror of
https://github.com/igorski/bitmappery.git
synced 2026-07-12 01:48:51 +02:00
Holding down shift while using the lasso tool will snap the line to 45 degree increments
This commit is contained in:
@@ -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 )
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user