Skip to content

Commit 508d2fc

Browse files
author
Alexander
committed
Фиксим кейс когда значения расстояний могли прыгать на 1 пиксель
1 parent 591b3c0 commit 508d2fc

File tree

2 files changed

+91
-7
lines changed

2 files changed

+91
-7
lines changed

specs/src/editor/snapping-manager/index.spec.ts

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ describe('SnappingManager', () => {
264264

265265
const { activeSpacingGuides } = snappingManager as any
266266
expect(activeSpacingGuides.length).toBeGreaterThan(0)
267-
expect(activeSpacingGuides[0].distance).toBe(22)
267+
expect(activeSpacingGuides[0].distance).toBe(23)
268268
})
269269

270270
it('показывает равноудалённость по шагу и расстояние совпадает с фактическим зазором', () => {
@@ -350,6 +350,56 @@ describe('SnappingManager', () => {
350350
)
351351
})
352352

353+
it('показывает одинаковый display-distance для разных объектов в вертикальной цепочке', () => {
354+
const { editor, objects } = createSnappingTestContext()
355+
const top = createBoundsObject({ left: 0, top: 0, width: 50, height: 50, id: 'top' })
356+
const middle = createBoundsObject({ left: 0, top: 91, width: 50, height: 50, id: 'middle' })
357+
const bottom = createBoundsObject({ left: 0, top: 182, width: 50, height: 50, id: 'bottom' })
358+
objects.push(top)
359+
objects.push(middle)
360+
objects.push(bottom)
361+
362+
const middleSnappingManager = new SnappingManager({ editor });
363+
(middleSnappingManager as any)._handleMouseDown({ target: middle });
364+
(middleSnappingManager as any)._handleObjectMoving({ target: middle })
365+
const middleGuides = (middleSnappingManager as any).activeSpacingGuides
366+
const middleDistance = middleGuides[0]?.distance
367+
368+
const topSnappingManager = new SnappingManager({ editor });
369+
(topSnappingManager as any)._handleMouseDown({ target: top });
370+
(topSnappingManager as any)._handleObjectMoving({ target: top })
371+
const topGuides = (topSnappingManager as any).activeSpacingGuides
372+
const topDistance = topGuides[0]?.distance
373+
374+
expect(middleDistance).toBe(41)
375+
expect(topDistance).toBe(41)
376+
})
377+
378+
it('показывает одинаковый display-distance в вертикальной цепочке при уменьшенном среднем объекте', () => {
379+
const { editor, objects } = createSnappingTestContext()
380+
const top = createBoundsObject({ left: 0, top: 0, width: 80, height: 80, id: 'top' })
381+
const middle = createBoundsObject({ left: 0, top: 109, width: 80, height: 40, id: 'middle' })
382+
const bottom = createBoundsObject({ left: 0, top: 177, width: 80, height: 80, id: 'bottom' })
383+
objects.push(top)
384+
objects.push(middle)
385+
objects.push(bottom)
386+
387+
const middleSnappingManager = new SnappingManager({ editor });
388+
(middleSnappingManager as any)._handleMouseDown({ target: middle });
389+
(middleSnappingManager as any)._handleObjectMoving({ target: middle })
390+
const middleGuides = (middleSnappingManager as any).activeSpacingGuides
391+
const middleDistance = middleGuides[0]?.distance
392+
393+
const bottomSnappingManager = new SnappingManager({ editor });
394+
(bottomSnappingManager as any)._handleMouseDown({ target: bottom });
395+
(bottomSnappingManager as any)._handleObjectMoving({ target: bottom })
396+
const bottomGuides = (bottomSnappingManager as any).activeSpacingGuides
397+
const bottomDistance = bottomGuides[0]?.distance
398+
399+
expect(middleDistance).toBe(29)
400+
expect(bottomDistance).toBe(29)
401+
})
402+
353403
it('масштабирует объект по X с прилипаниями и фиксирует origin', () => {
354404
const { editor, objects } = createSnappingTestContext()
355405
const active = createScalingObject({

src/editor/snapping-manager/calculations.ts

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -321,8 +321,7 @@ const resolveCenteredEqualSpacing = ({
321321
const distanceDiff = Math.abs(beforeDistance - afterDistance)
322322
if (distanceDiff > 1) continue
323323

324-
const averageGap = (gapBefore + gapAfter) / 2
325-
const commonDistance = resolveDisplayDistance({ distance: averageGap })
324+
const commonDistance = Math.max(beforeDistance, afterDistance)
326325

327326
const nearestDiff = Math.max(
328327
Math.abs(gapBefore - targetGap),
@@ -348,6 +347,25 @@ const resolveCenteredEqualSpacing = ({
348347
return bestCandidate
349348
}
350349

350+
/**
351+
* Нормализует отображаемое расстояние для гайда равноудалённости.
352+
*/
353+
const resolveGuideDisplayDistance = ({
354+
currentGap,
355+
referenceGap
356+
}: {
357+
currentGap: number
358+
referenceGap: number
359+
}): number => {
360+
const currentDisplay = resolveDisplayDistance({ distance: currentGap })
361+
const referenceDisplay = resolveDisplayDistance({ distance: referenceGap })
362+
const displayDiff = Math.abs(currentDisplay - referenceDisplay)
363+
364+
if (displayDiff > 1) return referenceDisplay
365+
366+
return Math.max(currentDisplay, referenceDisplay)
367+
}
368+
351369
/**
352370
* Ищет ближайшую линию привязки по одной оси.
353371
*/
@@ -607,14 +625,18 @@ export const calculateVerticalSpacing = ({
607625
const postDiff = Math.abs(adjustedGap - refDistance)
608626

609627
if (postDiff > threshold) continue
628+
const distance = resolveGuideDisplayDistance({
629+
currentGap: adjustedGap,
630+
referenceGap: refDistance
631+
})
610632
const guide: SpacingGuide = {
611633
type: 'vertical',
612634
axis: centerX,
613635
refStart,
614636
refEnd,
615637
activeStart: prevBottom,
616638
activeEnd: adjustedTop,
617-
distance: refDistance
639+
distance
618640
}
619641

620642
options.push({ delta, guide, diff: postDiff })
@@ -632,14 +654,18 @@ export const calculateVerticalSpacing = ({
632654
const postDiff = Math.abs(adjustedGap - refDistance)
633655

634656
if (postDiff > threshold) continue
657+
const distance = resolveGuideDisplayDistance({
658+
currentGap: adjustedGap,
659+
referenceGap: refDistance
660+
})
635661
const guide: SpacingGuide = {
636662
type: 'vertical',
637663
axis: centerX,
638664
refStart,
639665
refEnd,
640666
activeStart: adjustedBottom,
641667
activeEnd: nextTop,
642-
distance: refDistance
668+
distance
643669
}
644670

645671
options.push({ delta, guide, diff: postDiff })
@@ -842,14 +868,18 @@ export const calculateHorizontalSpacing = ({
842868
const postDiff = Math.abs(adjustedGap - refDistance)
843869

844870
if (postDiff > threshold) continue
871+
const distance = resolveGuideDisplayDistance({
872+
currentGap: adjustedGap,
873+
referenceGap: refDistance
874+
})
845875
const guide: SpacingGuide = {
846876
type: 'horizontal',
847877
axis: centerY,
848878
refStart,
849879
refEnd,
850880
activeStart: prevRight,
851881
activeEnd: adjustedLeft,
852-
distance: refDistance
882+
distance
853883
}
854884

855885
options.push({ delta, guide, diff: postDiff })
@@ -867,14 +897,18 @@ export const calculateHorizontalSpacing = ({
867897
const postDiff = Math.abs(adjustedGap - refDistance)
868898

869899
if (postDiff > threshold) continue
900+
const distance = resolveGuideDisplayDistance({
901+
currentGap: adjustedGap,
902+
referenceGap: refDistance
903+
})
870904
const guide: SpacingGuide = {
871905
type: 'horizontal',
872906
axis: centerY,
873907
refStart,
874908
refEnd,
875909
activeStart: adjustedRight,
876910
activeEnd: nextLeft,
877-
distance: refDistance
911+
distance
878912
}
879913

880914
options.push({ delta, guide, diff: postDiff })

0 commit comments

Comments
 (0)