11import { listenPointerEvents } from '@stdlib/misc' ;
22import { Vec2 } from '@stdlib/misc' ;
33import { refProp , watchUntilTrue } from '@stdlib/vue' ;
4+ import { isCtrlDown } from 'src/code/utils/misc' ;
45import type { UnwrapRef } from 'vue' ;
56
67import type { Page } from '../page' ;
78import { roundTimeToMinutes } from './date' ;
9+ import type { PageNote } from './note' ;
810
911export interface IDraggingReact {
1012 active : boolean ;
1113
12- currentPos : Vec2 ;
13-
1414 dropRegionId ?: string ;
1515 dropIndex ?: number ;
1616}
@@ -23,57 +23,65 @@ export class NoteDragging {
2323 initialRegionId ?: string ;
2424 finalRegionId ?: string ;
2525
26+ initialPointerPos : Vec2 = new Vec2 ( ) ;
27+ originalNotePositions : Record < string , Vec2 > = { } ;
28+
2629 private _cancelPointerEvents ?: ( ) => void ;
2730
2831 constructor ( input : { page : Page } ) {
2932 this . page = input . page ;
3033
3134 this . react = refProp < IDraggingReact > ( this , 'react' , {
3235 active : false ,
33-
34- currentPos : new Vec2 ( ) ,
3536 } ) ;
3637 }
3738
38- start ( event : PointerEvent ) {
39+ start ( params : { note : PageNote ; event : PointerEvent } ) {
3940 if ( this . page . react . readOnly ) {
4041 return ;
4142 }
4243
4344 // Prevent dragging unmovable notes
4445
4546 if (
46- this . page . activeElem . react . value ?. type !== 'note' ||
47+ this . page . activeElem . react . value ?. type === 'note' &&
4748 ! this . page . activeElem . react . value . react . collab . movable
4849 ) {
49- if ( event . pointerType !== 'mouse' ) {
50- this . page . panning . start ( event ) ;
50+ if ( params . event . pointerType !== 'mouse' ) {
51+ this . page . panning . start ( params . event ) ;
5152 }
5253
5354 return ;
5455 }
5556
56- this . react = {
57- active : false ,
57+ this . react = { active : false } ;
5858
59- currentPos : this . page . pos . eventToClient ( event ) ,
60- } ;
59+ this . initialPointerPos = this . page . pos . eventToClient ( params . event ) ;
6160
62- this . _cancelPointerEvents = listenPointerEvents ( event , {
61+ this . _cancelPointerEvents = listenPointerEvents ( params . event , {
6362 dragStartDistance : 5 ,
6463
65- dragStart : this . _dragStart ,
64+ dragStart : ( ) => this . _dragStart ( params ) ,
6665 dragUpdate : this . _dragUpdate ,
6766 dragEnd : this . _dragFinish ,
6867 } ) ;
6968 }
7069
71- private _dragStart = async ( event : PointerEvent ) => {
70+ private _dragStart = async ( params : {
71+ note : PageNote ;
72+ event : PointerEvent ;
73+ } ) => {
7274 this . react . active = true ;
7375
7476 this . initialRegionId = this . page . activeRegion . react . value . id ;
7577 this . finalRegionId = this . page . id ;
7678
79+ if ( isCtrlDown ( params . event ) ) {
80+ this . page . selection . add ( params . note ) ;
81+
82+ await this . page . cloning . perform ( { shiftNotes : false } ) ;
83+ }
84+
7785 // Update note dragging states
7886
7987 for ( const selectedNote of this . page . selection . react . notes ) {
@@ -90,23 +98,38 @@ export class NoteDragging {
9098 await this . _dragOut ( ) ;
9199 }
92100
93- this . _dragUpdate ( event ) ;
101+ // Store original note positions
102+
103+ this . originalNotePositions = { } ;
104+
105+ for ( const selectedNote of this . page . selection . react . notes ) {
106+ this . originalNotePositions [ selectedNote . id ] = new Vec2 (
107+ selectedNote . react . collab . pos ,
108+ ) ;
109+ }
94110 } ;
95111
96112 private _dragUpdate = ( event : PointerEvent ) => {
97113 const clientPos = this . page . pos . eventToClient ( event ) ;
98114
99- const worldDelta = this . page . sizes . screenToWorld2D (
100- clientPos . sub ( this . react . currentPos ) ,
115+ const worldDiff = this . page . sizes . screenToWorld2D (
116+ clientPos . sub ( this . initialPointerPos ) ,
101117 ) ;
102118
103- this . react . currentPos = clientPos ;
119+ if ( event . shiftKey ) {
120+ if ( Math . abs ( worldDiff . x ) < Math . abs ( worldDiff . y ) ) {
121+ worldDiff . x = 0 ;
122+ } else {
123+ worldDiff . y = 0 ;
124+ }
125+ }
104126
105127 // Move selected notes
106128
107129 this . page . collab . doc . transact ( ( ) => {
108130 for ( const selectedNote of this . page . selection . react . notes ) {
109- const newPos = new Vec2 ( selectedNote . react . collab . pos ) . add ( worldDelta ) ;
131+ const newPos =
132+ this . originalNotePositions [ selectedNote . id ] . add ( worldDiff ) ;
110133
111134 selectedNote . react . collab . pos . x = newPos . x || 0 ;
112135 selectedNote . react . collab . pos . y = newPos . y || 0 ;
@@ -182,7 +205,7 @@ export class NoteDragging {
182205
183206 this . page . collab . doc . transact ( ( ) => {
184207 for ( const selectedNote of this . page . selection . react . notes ) {
185- const worldPos = this . page . pos . clientToWorld ( this . react . currentPos ) ;
208+ const worldPos = this . page . pos . clientToWorld ( this . initialPointerPos ) ;
186209 const mouseOffset = worldPos . sub ( prevCenters . get ( activeElem . id ) ! ) ;
187210
188211 const prevCenter = prevCenters . get ( selectedNote . id ) ! ;
0 commit comments