js-draw 0.13.0 → 0.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,7 +9,7 @@ export const makeColorInput = (editor, onColorChange) => {
9
9
  colorInput.classList.add('coloris_input');
10
10
  colorInputContainer.classList.add('color-input-container');
11
11
  colorInputContainer.appendChild(colorInput);
12
- addPipetteTool(editor, colorInputContainer, (color) => {
12
+ const pipetteController = addPipetteTool(editor, colorInputContainer, (color) => {
13
13
  colorInput.value = color.toHexString();
14
14
  onInputEnd();
15
15
  // Update the color preview, if it exists (may be managed by Coloris).
@@ -41,6 +41,7 @@ export const makeColorInput = (editor, onColorChange) => {
41
41
  kind: EditorEventType.ColorPickerToggled,
42
42
  open: true,
43
43
  });
44
+ pipetteController.cancel();
44
45
  });
45
46
  colorInput.addEventListener('close', () => {
46
47
  editor.notifier.dispatch(EditorEventType.ColorPickerToggled, {
@@ -102,5 +103,11 @@ const addPipetteTool = (editor, container, onColorChange) => {
102
103
  }
103
104
  };
104
105
  container.appendChild(pipetteButton);
106
+ return {
107
+ // Cancel a pipette color selection if one is in progress.
108
+ cancel: () => {
109
+ endColorSelectMode();
110
+ },
111
+ };
105
112
  };
106
113
  export default makeColorInput;
@@ -21,11 +21,12 @@ export default class PanZoom extends BaseTool {
21
21
  private editor;
22
22
  private mode;
23
23
  private transform;
24
- private lastAngle;
25
24
  private lastDist;
26
25
  private lastScreenCenter;
27
26
  private lastTimestamp;
28
27
  private lastPointerDownTimestamp;
28
+ private initialTouchAngle;
29
+ private initialViewportRotation;
29
30
  private inertialScroller;
30
31
  private velocity;
31
32
  constructor(editor: Editor, mode: PanZoomMode, description: string);
@@ -34,6 +35,7 @@ export default class PanZoom extends BaseTool {
34
35
  onPointerDown({ allPointers: pointers, current: currentPointer }: PointerEvt): boolean;
35
36
  private updateVelocity;
36
37
  private getCenterDelta;
38
+ private toSnappedRotationDelta;
37
39
  private handleTwoFingerMove;
38
40
  private handleOneFingerMove;
39
41
  onPointerMove({ allPointers }: PointerEvt): void;
@@ -78,6 +78,8 @@ export default class PanZoom extends BaseTool {
78
78
  this.mode = mode;
79
79
  this.transform = null;
80
80
  this.lastPointerDownTimestamp = 0;
81
+ this.initialTouchAngle = 0;
82
+ this.initialViewportRotation = 0;
81
83
  this.inertialScroller = null;
82
84
  this.velocity = null;
83
85
  }
@@ -104,9 +106,10 @@ export default class PanZoom extends BaseTool {
104
106
  const isRightClick = this.allPointersAreOfType(pointers, PointerDevice.RightButtonMouse);
105
107
  if (allAreTouch && pointers.length === 2 && this.mode & PanZoomMode.TwoFingerTouchGestures) {
106
108
  const { screenCenter, angle, dist } = this.computePinchData(pointers[0], pointers[1]);
107
- this.lastAngle = angle;
108
109
  this.lastDist = dist;
109
110
  this.lastScreenCenter = screenCenter;
111
+ this.initialTouchAngle = angle;
112
+ this.initialViewportRotation = this.editor.viewport.getRotationAngle();
110
113
  handlingGesture = true;
111
114
  }
112
115
  else if (pointers.length === 1 && ((this.mode & PanZoomMode.OneFingerTouchGestures && allAreTouch)
@@ -149,20 +152,42 @@ export default class PanZoom extends BaseTool {
149
152
  const delta = this.editor.viewport.screenToCanvasTransform.transformVec3(screenCenter.minus(this.lastScreenCenter));
150
153
  return delta;
151
154
  }
155
+ // Snaps `angle` to common desired rotations. For example, if `touchAngle` corresponds
156
+ // to a viewport rotation of 90.1 degrees, this function returns a rotation delta that,
157
+ // when applied to the viewport, rotates the viewport to 90.0 degrees.
158
+ //
159
+ // Returns a snapped rotation delta that, when applied to the viewport, rotates the viewport,
160
+ // from its position on the last touchDown event, by `touchAngle - initialTouchAngle`.
161
+ toSnappedRotationDelta(touchAngle) {
162
+ const deltaAngle = touchAngle - this.initialTouchAngle;
163
+ let fullRotation = deltaAngle + this.initialViewportRotation;
164
+ const snapToMultipleOf = Math.PI / 2;
165
+ const roundedFullRotation = Math.round(fullRotation / snapToMultipleOf) * snapToMultipleOf;
166
+ // The maximum angle for which we snap the given angle to a multiple of
167
+ // `snapToMultipleOf`.
168
+ const maxSnapAngle = 0.07;
169
+ // Snap the rotation
170
+ if (Math.abs(fullRotation - roundedFullRotation) < maxSnapAngle) {
171
+ fullRotation = roundedFullRotation;
172
+ }
173
+ return fullRotation - this.editor.viewport.getRotationAngle();
174
+ }
152
175
  handleTwoFingerMove(allPointers) {
153
176
  const { screenCenter, canvasCenter, angle, dist } = this.computePinchData(allPointers[0], allPointers[1]);
154
177
  const delta = this.getCenterDelta(screenCenter);
155
- let rotation = angle - this.lastAngle;
178
+ let deltaRotation;
156
179
  if (this.isRotationLocked()) {
157
- rotation = 0;
180
+ deltaRotation = 0;
181
+ }
182
+ else {
183
+ deltaRotation = this.toSnappedRotationDelta(angle);
158
184
  }
159
185
  this.updateVelocity(screenCenter);
160
186
  const transformUpdate = Mat33.translation(delta)
161
187
  .rightMul(Mat33.scaling2D(dist / this.lastDist, canvasCenter))
162
- .rightMul(Mat33.zRotation(rotation, canvasCenter));
188
+ .rightMul(Mat33.zRotation(deltaRotation, canvasCenter));
163
189
  this.lastScreenCenter = screenCenter;
164
190
  this.lastDist = dist;
165
- this.lastAngle = angle;
166
191
  this.transform = Viewport.transformBy(this.transform.transform.rightMul(transformUpdate));
167
192
  }
168
193
  handleOneFingerMove(pointer) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "js-draw",
3
- "version": "0.13.0",
3
+ "version": "0.13.1",
4
4
  "description": "Draw pictures using a pen, touchscreen, or mouse! JS-draw is a drawing library for JavaScript and TypeScript. ",
5
5
  "main": "./dist/src/lib.d.ts",
6
6
  "types": "./dist/src/lib.js",
@@ -19,7 +19,7 @@ export const makeColorInput = (
19
19
  colorInputContainer.classList.add('color-input-container');
20
20
 
21
21
  colorInputContainer.appendChild(colorInput);
22
- addPipetteTool(editor, colorInputContainer, (color: Color4) => {
22
+ const pipetteController = addPipetteTool(editor, colorInputContainer, (color: Color4) => {
23
23
  colorInput.value = color.toHexString();
24
24
  onInputEnd();
25
25
 
@@ -58,6 +58,7 @@ export const makeColorInput = (
58
58
  kind: EditorEventType.ColorPickerToggled,
59
59
  open: true,
60
60
  });
61
+ pipetteController.cancel();
61
62
  });
62
63
  colorInput.addEventListener('close', () => {
63
64
  editor.notifier.dispatch(EditorEventType.ColorPickerToggled, {
@@ -132,6 +133,13 @@ const addPipetteTool = (editor: Editor, container: HTMLElement, onColorChange: O
132
133
  };
133
134
 
134
135
  container.appendChild(pipetteButton);
136
+
137
+ return {
138
+ // Cancel a pipette color selection if one is in progress.
139
+ cancel: () => {
140
+ endColorSelectMode();
141
+ },
142
+ };
135
143
  };
136
144
 
137
145
  export default makeColorInput;
@@ -90,11 +90,12 @@ class InertialScroller {
90
90
  export default class PanZoom extends BaseTool {
91
91
  private transform: ViewportTransform|null = null;
92
92
 
93
- private lastAngle: number;
94
93
  private lastDist: number;
95
94
  private lastScreenCenter: Point2;
96
95
  private lastTimestamp: number;
97
96
  private lastPointerDownTimestamp: number = 0;
97
+ private initialTouchAngle: number = 0;
98
+ private initialViewportRotation: number = 0;
98
99
 
99
100
  private inertialScroller: InertialScroller|null = null;
100
101
  private velocity: Vec2|null = null;
@@ -132,9 +133,11 @@ export default class PanZoom extends BaseTool {
132
133
 
133
134
  if (allAreTouch && pointers.length === 2 && this.mode & PanZoomMode.TwoFingerTouchGestures) {
134
135
  const { screenCenter, angle, dist } = this.computePinchData(pointers[0], pointers[1]);
135
- this.lastAngle = angle;
136
136
  this.lastDist = dist;
137
137
  this.lastScreenCenter = screenCenter;
138
+ this.initialTouchAngle = angle;
139
+ this.initialViewportRotation = this.editor.viewport.getRotationAngle();
140
+
138
141
  handlingGesture = true;
139
142
  } else if (pointers.length === 1 && (
140
143
  (this.mode & PanZoomMode.OneFingerTouchGestures && allAreTouch)
@@ -188,24 +191,51 @@ export default class PanZoom extends BaseTool {
188
191
  return delta;
189
192
  }
190
193
 
194
+ // Snaps `angle` to common desired rotations. For example, if `touchAngle` corresponds
195
+ // to a viewport rotation of 90.1 degrees, this function returns a rotation delta that,
196
+ // when applied to the viewport, rotates the viewport to 90.0 degrees.
197
+ //
198
+ // Returns a snapped rotation delta that, when applied to the viewport, rotates the viewport,
199
+ // from its position on the last touchDown event, by `touchAngle - initialTouchAngle`.
200
+ private toSnappedRotationDelta(touchAngle: number) {
201
+ const deltaAngle = touchAngle - this.initialTouchAngle;
202
+ let fullRotation = deltaAngle + this.initialViewportRotation;
203
+
204
+ const snapToMultipleOf = Math.PI / 2;
205
+ const roundedFullRotation = Math.round(fullRotation / snapToMultipleOf) * snapToMultipleOf;
206
+
207
+ // The maximum angle for which we snap the given angle to a multiple of
208
+ // `snapToMultipleOf`.
209
+ const maxSnapAngle = 0.07;
210
+
211
+ // Snap the rotation
212
+ if (Math.abs(fullRotation - roundedFullRotation) < maxSnapAngle) {
213
+ fullRotation = roundedFullRotation;
214
+ }
215
+
216
+ return fullRotation - this.editor.viewport.getRotationAngle();
217
+ }
218
+
191
219
  private handleTwoFingerMove(allPointers: Pointer[]) {
192
220
  const { screenCenter, canvasCenter, angle, dist } = this.computePinchData(allPointers[0], allPointers[1]);
193
221
 
194
222
  const delta = this.getCenterDelta(screenCenter);
195
- let rotation = angle - this.lastAngle;
223
+ let deltaRotation;
196
224
 
197
225
  if (this.isRotationLocked()) {
198
- rotation = 0;
226
+ deltaRotation = 0;
227
+ } else {
228
+ deltaRotation = this.toSnappedRotationDelta(angle);
199
229
  }
200
230
 
231
+
201
232
  this.updateVelocity(screenCenter);
202
233
 
203
234
  const transformUpdate = Mat33.translation(delta)
204
235
  .rightMul(Mat33.scaling2D(dist / this.lastDist, canvasCenter))
205
- .rightMul(Mat33.zRotation(rotation, canvasCenter));
236
+ .rightMul(Mat33.zRotation(deltaRotation, canvasCenter));
206
237
  this.lastScreenCenter = screenCenter;
207
238
  this.lastDist = dist;
208
- this.lastAngle = angle;
209
239
  this.transform = Viewport.transformBy(
210
240
  this.transform!.transform.rightMul(transformUpdate)
211
241
  );