tokimeki-image-editor 0.2.3 → 0.2.4
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.
|
@@ -15,10 +15,11 @@ const colorPresets = ['#FF6B6B', '#FFA94D', '#FFD93D', '#6BCB77', '#4D96FF', '#9
|
|
|
15
15
|
// Drawing state
|
|
16
16
|
let isDrawing = $state(false);
|
|
17
17
|
let currentAnnotation = $state(null);
|
|
18
|
-
// Panning state (Space + drag)
|
|
18
|
+
// Panning state (Space + drag on desktop, 2-finger drag on mobile)
|
|
19
19
|
let isSpaceHeld = $state(false);
|
|
20
20
|
let isPanning = $state(false);
|
|
21
21
|
let panStart = $state(null);
|
|
22
|
+
let isTwoFingerTouch = $state(false);
|
|
22
23
|
// Helper to get coordinates from mouse or touch event
|
|
23
24
|
function getEventCoords(event) {
|
|
24
25
|
if ('touches' in event && event.touches.length > 0) {
|
|
@@ -289,12 +290,79 @@ function pointToSegmentDistance(px, py, a, b) {
|
|
|
289
290
|
function handleClearAll() {
|
|
290
291
|
onUpdate([]);
|
|
291
292
|
}
|
|
292
|
-
|
|
293
|
-
|
|
293
|
+
function handleTouchStart(event) {
|
|
294
|
+
// Two-finger touch starts panning
|
|
295
|
+
if (event.touches.length === 2) {
|
|
296
|
+
event.preventDefault();
|
|
297
|
+
isTwoFingerTouch = true;
|
|
298
|
+
// Use the midpoint of the two touches
|
|
299
|
+
const touch1 = event.touches[0];
|
|
300
|
+
const touch2 = event.touches[1];
|
|
301
|
+
const midX = (touch1.clientX + touch2.clientX) / 2;
|
|
302
|
+
const midY = (touch1.clientY + touch2.clientY) / 2;
|
|
303
|
+
// Cancel any current drawing
|
|
304
|
+
if (isDrawing) {
|
|
305
|
+
isDrawing = false;
|
|
306
|
+
currentAnnotation = null;
|
|
307
|
+
}
|
|
308
|
+
isPanning = true;
|
|
309
|
+
panStart = {
|
|
310
|
+
x: midX,
|
|
311
|
+
y: midY,
|
|
312
|
+
offsetX: viewport.offsetX,
|
|
313
|
+
offsetY: viewport.offsetY
|
|
314
|
+
};
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
// Single finger - normal drawing (only if not already in two-finger mode)
|
|
318
|
+
if (event.touches.length === 1 && !isTwoFingerTouch) {
|
|
319
|
+
handleMouseDown(event);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
function handleTouchMove(event) {
|
|
323
|
+
// Two-finger panning
|
|
324
|
+
if (event.touches.length === 2 && isPanning && panStart && onViewportChange) {
|
|
325
|
+
event.preventDefault();
|
|
326
|
+
const touch1 = event.touches[0];
|
|
327
|
+
const touch2 = event.touches[1];
|
|
328
|
+
const midX = (touch1.clientX + touch2.clientX) / 2;
|
|
329
|
+
const midY = (touch1.clientY + touch2.clientY) / 2;
|
|
330
|
+
const dx = midX - panStart.x;
|
|
331
|
+
const dy = midY - panStart.y;
|
|
332
|
+
onViewportChange({
|
|
333
|
+
offsetX: panStart.offsetX + dx,
|
|
334
|
+
offsetY: panStart.offsetY + dy
|
|
335
|
+
});
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
// Single finger drawing (only if not in two-finger mode)
|
|
339
|
+
if (event.touches.length === 1 && !isTwoFingerTouch) {
|
|
340
|
+
handleMouseMove(event);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
294
343
|
function handleTouchEnd(event) {
|
|
344
|
+
// When all fingers are lifted
|
|
295
345
|
if (event.touches.length === 0) {
|
|
346
|
+
if (isPanning) {
|
|
347
|
+
isPanning = false;
|
|
348
|
+
panStart = null;
|
|
349
|
+
}
|
|
350
|
+
isTwoFingerTouch = false;
|
|
296
351
|
handleMouseUp();
|
|
297
352
|
}
|
|
353
|
+
// When going from 2 fingers to 1, stay in pan mode but don't draw
|
|
354
|
+
else if (event.touches.length === 1 && isTwoFingerTouch) {
|
|
355
|
+
// Update pan start to the remaining finger position
|
|
356
|
+
if (isPanning && onViewportChange) {
|
|
357
|
+
const touch = event.touches[0];
|
|
358
|
+
panStart = {
|
|
359
|
+
x: touch.clientX,
|
|
360
|
+
y: touch.clientY,
|
|
361
|
+
offsetX: viewport.offsetX,
|
|
362
|
+
offsetY: viewport.offsetY
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
}
|
|
298
366
|
}
|
|
299
367
|
// Generate smooth SVG path using quadratic bezier curves
|
|
300
368
|
function generateSmoothPath(points) {
|
|
@@ -350,7 +418,7 @@ let currentAnnotationCanvas = $derived.by(() => {
|
|
|
350
418
|
<div
|
|
351
419
|
bind:this={containerElement}
|
|
352
420
|
class="annotation-tool-overlay"
|
|
353
|
-
class:panning={isSpaceHeld}
|
|
421
|
+
class:panning={isSpaceHeld || isTwoFingerTouch}
|
|
354
422
|
onmousedown={handleMouseDown}
|
|
355
423
|
role="button"
|
|
356
424
|
tabindex="-1"
|
|
@@ -103,7 +103,7 @@ function handleSheetDragEnd() {
|
|
|
103
103
|
|
|
104
104
|
@media (max-width: 767px) {
|
|
105
105
|
.tool-panel {
|
|
106
|
-
position:
|
|
106
|
+
position: fixed;
|
|
107
107
|
left: 0;
|
|
108
108
|
right: 0;
|
|
109
109
|
top: auto;
|
|
@@ -112,10 +112,11 @@ function handleSheetDragEnd() {
|
|
|
112
112
|
min-width: auto;
|
|
113
113
|
height: var(--sheet-max-height, 400px);
|
|
114
114
|
border-radius: 16px 16px 0 0;
|
|
115
|
-
z-index:
|
|
115
|
+
z-index: 9999;
|
|
116
116
|
overflow-y: auto;
|
|
117
117
|
overscroll-behavior: contain;
|
|
118
118
|
padding-top: 0;
|
|
119
|
+
padding-bottom: 1.5rem;
|
|
119
120
|
transform: translateY(var(--sheet-offset, 0px));
|
|
120
121
|
will-change: transform;
|
|
121
122
|
backdrop-filter: none
|