fix(B07): 집기 반경을 화면 기준으로 잡고, 누른 채 끄는 선택을 살린다
- 집기 반경이 월드 거리였다. HIGHLIGHT_ENTITY_DISTANCE를 월드 거리와 그대로 비교해 확대할수록 화면상 반경이 같이 커졌다(1369%에서 15월드 ≈ 205px). helpers/pick-radius로 확대율을 나눠 쓰고 상수를 화면 픽셀 10으로 낮췄다. 하이라이트·선택·그립·시퀀스 도구가 같은 반경을 본다. - 누른 채 끄는 선택이 없었다. 왼쪽 버튼은 mouseup에서만 클릭을 보내 누르고 끌어도 점이 하나만 찍혔고, 그래서 좌→우(창)·우→좌(교차) 구분이 먹히지 않는 것처럼 보였다. 선택 도구일 때만 누를 때 첫 점을 보내고, 4px 넘게 끌고 놓으면 그 자리로 사각형을 닫는다. 다른 도구는 예전처럼 놓을 때 한 점만 받는다. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -7,10 +7,10 @@
|
||||
*/
|
||||
import type { Point } from '@flatten-js/core';
|
||||
import { Actor, assign, createMachine, sendTo } from 'xstate';
|
||||
import { HIGHLIGHT_ENTITY_DISTANCE } from '../../App.consts';
|
||||
import type { Entity } from '../../entities/Entity';
|
||||
import { findClosestEntity } from '../../helpers/find-closest-entity';
|
||||
import { getPointFromEvent } from '../../helpers/get-point-from-event';
|
||||
import { pickRadius } from '../../helpers/pick-radius';
|
||||
import { queryEntitiesNearPoint } from '../../helpers/spatial-index';
|
||||
import {
|
||||
getScreenCanvasDrawController,
|
||||
@@ -146,8 +146,7 @@ function cursorPoint(event: StateEvent | undefined): Point {
|
||||
|
||||
/** 클릭 지점에서 가장 가까운 엔티티 (선택 반경 안에 있을 때만) */
|
||||
function pickEntityAt(worldPoint: Point): Entity | null {
|
||||
const scale = getScreenCanvasDrawController().getScreenScale() || 1;
|
||||
const radius = HIGHLIGHT_ENTITY_DISTANCE / scale;
|
||||
const radius = pickRadius();
|
||||
const candidates = queryEntitiesNearPoint(worldPoint.x, worldPoint.y, radius);
|
||||
const { distance, entity } = findClosestEntity(worldPoint, candidates);
|
||||
return entity && distance <= radius ? entity : null;
|
||||
@@ -175,11 +174,13 @@ export function createSequenceTool(config: SequenceToolConfig) {
|
||||
setGhostHelperEntities(ghosts);
|
||||
};
|
||||
|
||||
const pushPoint = assign(({ context, event }: { context: SequenceContext; event: StateEvent }) => {
|
||||
const point = getPointFromEvent(lastPoint(context.values), event as PointInputEvent);
|
||||
setAngleGuideOriginPoint(point);
|
||||
return { values: [...context.values, point], picks: [...context.picks, point] };
|
||||
});
|
||||
const pushPoint = assign(
|
||||
({ context, event }: { context: SequenceContext; event: StateEvent }) => {
|
||||
const point = getPointFromEvent(lastPoint(context.values), event as PointInputEvent);
|
||||
setAngleGuideOriginPoint(point);
|
||||
return { values: [...context.values, point], picks: [...context.picks, point] };
|
||||
}
|
||||
);
|
||||
|
||||
const pushNumberFromEvent = assign(
|
||||
({ context, event }: { context: SequenceContext; event: StateEvent }) => {
|
||||
@@ -197,10 +198,12 @@ export function createSequenceTool(config: SequenceToolConfig) {
|
||||
picks: [...context.picks, null],
|
||||
}));
|
||||
|
||||
const pushText = assign(({ context, event }: { context: SequenceContext; event: StateEvent }) => ({
|
||||
values: [...context.values, (event as TextInputEvent).value],
|
||||
picks: [...context.picks, null],
|
||||
}));
|
||||
const pushText = assign(
|
||||
({ context, event }: { context: SequenceContext; event: StateEvent }) => ({
|
||||
values: [...context.values, (event as TextInputEvent).value],
|
||||
picks: [...context.picks, null],
|
||||
})
|
||||
);
|
||||
|
||||
const pushEntity = assign(
|
||||
({ context, event }: { context: SequenceContext; event: StateEvent }) => {
|
||||
|
||||
@@ -3,7 +3,6 @@ import { compact } from 'es-toolkit';
|
||||
import { toast } from 'react-toastify';
|
||||
import {
|
||||
EPSILON,
|
||||
HIGHLIGHT_ENTITY_DISTANCE,
|
||||
SELECTION_RECTANGLE_COLOR_CONTAINS,
|
||||
SELECTION_RECTANGLE_COLOR_INTERSECTION,
|
||||
SELECTION_RECTANGLE_STYLE,
|
||||
@@ -15,6 +14,7 @@ import { pointDistance } from '../helpers/distance-between-points';
|
||||
import { expandSelectionWithGroups } from '../helpers/entity-groups';
|
||||
import { findEntitiesWithinDistance } from '../helpers/find-closest-entity';
|
||||
import { findGripAt, removePolylineVertex } from '../helpers/grips';
|
||||
import { pickRadius } from '../helpers/pick-radius';
|
||||
import {
|
||||
getActiveLayerId,
|
||||
getEntities,
|
||||
@@ -35,17 +35,13 @@ let lastPickPoint: Point | null = null;
|
||||
let pickCycleIndex = 0;
|
||||
|
||||
function pickEntityAt(worldPoint: Point): Entity | null {
|
||||
const candidates = findEntitiesWithinDistance(
|
||||
worldPoint,
|
||||
getEntities(),
|
||||
HIGHLIGHT_ENTITY_DISTANCE
|
||||
);
|
||||
const radius = pickRadius();
|
||||
const candidates = findEntitiesWithinDistance(worldPoint, getEntities(), radius);
|
||||
if (!candidates.length) {
|
||||
lastPickPoint = null;
|
||||
return null;
|
||||
}
|
||||
const samePlace =
|
||||
!!lastPickPoint && pointDistance(lastPickPoint, worldPoint) < HIGHLIGHT_ENTITY_DISTANCE;
|
||||
const samePlace = !!lastPickPoint && pointDistance(lastPickPoint, worldPoint) < radius;
|
||||
pickCycleIndex = samePlace ? (pickCycleIndex + 1) % candidates.length : 0;
|
||||
lastPickPoint = worldPoint;
|
||||
return candidates[pickCycleIndex];
|
||||
@@ -56,11 +52,7 @@ export function handleFirstSelectionPoint(
|
||||
event: MouseClickEvent
|
||||
): SelectContext {
|
||||
// 선택된 객체의 그립이 먼저다 — 집으면 그립 편집으로 넘어간다
|
||||
const gripHit = findGripAt(
|
||||
getSelectedEntities(),
|
||||
event.worldMouseLocation,
|
||||
HIGHLIGHT_ENTITY_DISTANCE
|
||||
);
|
||||
const gripHit = findGripAt(getSelectedEntities(), event.worldMouseLocation, pickRadius());
|
||||
if (gripHit) {
|
||||
if (event.holdingCtrl) {
|
||||
// Ctrl+클릭 => 폴리선 정점 제거 (다기능 그립)
|
||||
|
||||
Reference in New Issue
Block a user