172 lines
5.1 KiB
TypeScript
172 lines
5.1 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import test from 'node:test';
|
|
import { resolveLineDraft, type DrawShapeLike } from '../../src/features/layout/draw/lineDraft.ts';
|
|
|
|
const canvasWidth = 500;
|
|
const canvasHeight = 300;
|
|
|
|
function line(shape: Omit<Extract<DrawShapeLike, { type: 'line' }>, 'type'>): DrawShapeLike {
|
|
return { type: 'line', ...shape };
|
|
}
|
|
|
|
function rect(): DrawShapeLike {
|
|
return { type: 'rect', x: 40, y: 40, width: 80, height: 60 };
|
|
}
|
|
|
|
test('creates a vertical divider from a horizontal gesture when no horizontal crossing line exists ahead', () => {
|
|
assert.deepEqual(resolveLineDraft(120, 80, 300, 90, [], canvasWidth, canvasHeight), {
|
|
startX: 120,
|
|
startY: 0,
|
|
endX: 120,
|
|
endY: canvasHeight,
|
|
orientation: 'vertical',
|
|
});
|
|
|
|
assert.deepEqual(resolveLineDraft(120, 80, 10, 70, [], canvasWidth, canvasHeight), {
|
|
startX: 120,
|
|
startY: 0,
|
|
endX: 120,
|
|
endY: canvasHeight,
|
|
orientation: 'vertical',
|
|
});
|
|
});
|
|
|
|
test('creates a horizontal divider from a vertical gesture when no vertical crossing line exists ahead', () => {
|
|
assert.deepEqual(resolveLineDraft(120, 80, 130, 220, [], canvasWidth, canvasHeight), {
|
|
startX: 0,
|
|
startY: 80,
|
|
endX: canvasWidth,
|
|
endY: 80,
|
|
orientation: 'horizontal',
|
|
});
|
|
|
|
assert.deepEqual(resolveLineDraft(120, 80, 110, 10, [], canvasWidth, canvasHeight), {
|
|
startX: 0,
|
|
startY: 80,
|
|
endX: canvasWidth,
|
|
endY: 80,
|
|
orientation: 'horizontal',
|
|
});
|
|
});
|
|
|
|
test('stops at the nearest horizontal crossing line for a horizontal gesture divider', () => {
|
|
const shapes: DrawShapeLike[] = [
|
|
line({ x1: 20, y1: 40, x2: 220, y2: 40, orientation: 'horizontal' }),
|
|
line({ x1: 40, y1: 180, x2: 260, y2: 180, orientation: 'horizontal' }),
|
|
];
|
|
|
|
assert.deepEqual(resolveLineDraft(120, 80, 480, 90, shapes, canvasWidth, canvasHeight), {
|
|
startX: 120,
|
|
startY: 40,
|
|
endX: 120,
|
|
endY: 180,
|
|
orientation: 'vertical',
|
|
});
|
|
});
|
|
|
|
test('stops at the nearest vertical crossing line for a vertical gesture divider', () => {
|
|
const shapes: DrawShapeLike[] = [
|
|
line({ x1: 60, y1: 20, x2: 60, y2: 180, orientation: 'vertical' }),
|
|
line({ x1: 260, y1: 20, x2: 260, y2: 160, orientation: 'vertical' }),
|
|
];
|
|
|
|
assert.deepEqual(resolveLineDraft(120, 80, 130, 260, shapes, canvasWidth, canvasHeight), {
|
|
startX: 60,
|
|
startY: 80,
|
|
endX: 260,
|
|
endY: 80,
|
|
orientation: 'horizontal',
|
|
});
|
|
});
|
|
|
|
test('ignores crossing lines that are behind the start point or outside the crossing range', () => {
|
|
const shapes: DrawShapeLike[] = [
|
|
line({ x1: 60, y1: 20, x2: 60, y2: 180, orientation: 'vertical' }),
|
|
line({ x1: 320, y1: 120, x2: 320, y2: 220, orientation: 'vertical' }),
|
|
line({ x1: 20, y1: 20, x2: 260, y2: 20, orientation: 'horizontal' }),
|
|
rect(),
|
|
];
|
|
|
|
assert.deepEqual(resolveLineDraft(120, 80, 480, 90, shapes, canvasWidth, canvasHeight), {
|
|
startX: 120,
|
|
startY: 20,
|
|
endX: 120,
|
|
endY: canvasHeight,
|
|
orientation: 'vertical',
|
|
});
|
|
|
|
assert.deepEqual(resolveLineDraft(120, 80, 130, 260, shapes, canvasWidth, canvasHeight), {
|
|
startX: 60,
|
|
startY: 80,
|
|
endX: canvasWidth,
|
|
endY: 80,
|
|
orientation: 'horizontal',
|
|
});
|
|
});
|
|
|
|
test('does not snap to a crossing line that starts exactly at the same point', () => {
|
|
const shapes: DrawShapeLike[] = [
|
|
line({ x1: 120, y1: 40, x2: 120, y2: 160, orientation: 'vertical' }),
|
|
line({ x1: 120, y1: 180, x2: 240, y2: 180, orientation: 'horizontal' }),
|
|
];
|
|
|
|
assert.deepEqual(resolveLineDraft(120, 80, 300, 90, shapes, canvasWidth, canvasHeight), {
|
|
startX: 120,
|
|
startY: 0,
|
|
endX: 120,
|
|
endY: 180,
|
|
orientation: 'vertical',
|
|
});
|
|
|
|
assert.deepEqual(resolveLineDraft(120, 180, 130, 260, shapes, canvasWidth, canvasHeight), {
|
|
startX: 0,
|
|
startY: 180,
|
|
endX: canvasWidth,
|
|
endY: 180,
|
|
orientation: 'horizontal',
|
|
});
|
|
});
|
|
|
|
test('extends to the nearest crossing line on both forward and reverse directions', () => {
|
|
const shapes: DrawShapeLike[] = [
|
|
line({ x1: 60, y1: 20, x2: 60, y2: 180, orientation: 'vertical' }),
|
|
line({ x1: 260, y1: 20, x2: 260, y2: 180, orientation: 'vertical' }),
|
|
line({ x1: 20, y1: 40, x2: 220, y2: 40, orientation: 'horizontal' }),
|
|
line({ x1: 20, y1: 180, x2: 220, y2: 180, orientation: 'horizontal' }),
|
|
];
|
|
|
|
assert.deepEqual(resolveLineDraft(120, 80, 320, 90, shapes, canvasWidth, canvasHeight), {
|
|
startX: 120,
|
|
startY: 40,
|
|
endX: 120,
|
|
endY: 180,
|
|
orientation: 'vertical',
|
|
});
|
|
|
|
assert.deepEqual(resolveLineDraft(120, 100, 130, 260, shapes, canvasWidth, canvasHeight), {
|
|
startX: 60,
|
|
startY: 100,
|
|
endX: 260,
|
|
endY: 100,
|
|
orientation: 'horizontal',
|
|
});
|
|
});
|
|
|
|
test('respects preferred orientation when the pointer drift would otherwise flip the axis', () => {
|
|
assert.deepEqual(resolveLineDraft(120, 80, 140, 160, [], canvasWidth, canvasHeight, 'horizontal'), {
|
|
startX: 0,
|
|
startY: 80,
|
|
endX: canvasWidth,
|
|
endY: 80,
|
|
orientation: 'horizontal',
|
|
});
|
|
|
|
assert.deepEqual(resolveLineDraft(120, 80, 260, 100, [], canvasWidth, canvasHeight, 'vertical'), {
|
|
startX: 120,
|
|
startY: 0,
|
|
endX: 120,
|
|
endY: canvasHeight,
|
|
orientation: 'vertical',
|
|
});
|
|
});
|