AFFiNE icon indicating copy to clipboard operation
AFFiNE copied to clipboard

feat: add ElementTransformManager for edgeless element basic manipulation

Open doouding opened this issue 9 months ago • 3 comments

Overview:

We've been working with some legacy code in the default-tool and edgeless-selected-rect modules, which are responsible for fundamental operations like moving, resizing, and rotating elements. Currently, these operations are hardcoded, making it challenging to extend functionalities without diving deep into the code.

What's Changing:

Introducing ElementTransformManager to streamline the handling of basic transformations (move, resize, rotate) while allowing the business logic to dictate when these actions occur.

Providing two ways to extend the transformations behaviour:

  • Extends inside element view definition: Elements can decide how to handle move/resize events, such as enforcing size constraints.
  • Extension mechanism provided by this manager: Adjust or completely override default drag behaviors, like snapping elements into alignment.

Code Examples:

Delegate element movement to TransformManager:

class DefaultTool {
  override dragStart(event) {
    if(this.dragType === DragType.ContentMoving) {
      const transformManager = this.std.get(TransformManagerIdentifier);
      transformManager.startDrag({ selectedElements, event });
    }
  }
}

Enforce minimum width inside view definition:

class EdgelessNoteBlock extends GfxBlockComponent {
  onResizeDelta({ dw, dh }) {
    const bound = this.model.elementBound;
    bound.w = Math.min(MAX_WIDTH, bound.w + dw);
    bound.h = Math.min(MAX_HEIGHT, bound.h + dh);
    this.model.xywh = bound.serialize();
  }
}

Use extension to implement element snapping:

import { TransformerExtension } from '@blocksuite/std/gfx';

// Just extends the TransformerExtension
class SnapManager extends TransformerExtension {
  static override key = 'snap-manager';
  onDragInitialize() {
    return {
      onDragMove(context) {
        const { dx, dy } = this.getAlignmentMoveDistance(context.elements);
        context.dx = dx;
        context.dy = dy;
      }
    }
  }
}

Others

The migration will be divided into several PRs. This PR mostly focus on refactoring elements movement part of default-tool.

  • Delegate elements movement to TransformManager
  • Rewrite the default tool extension into TransformManager extension
  • Add drag handler interface to gfx view (both GfxBlockComponent and GfxElementModelView) to allow element to define how it gonna react on drag

doouding avatar Mar 13 '25 08:03 doouding


How to use the Graphite Merge Queue

Add either label to this PR to merge it via the merge queue:

  • merge - adds this PR to the back of the merge queue
  • hotfix - for urgent hot fixes, skip the queue and merge this PR next

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has enabled the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

This stack of pull requests is managed by Graphite. Learn more about stacking.

doouding avatar Mar 13 '25 08:03 doouding

Codecov Report

Attention: Patch coverage is 74.03846% with 54 lines in your changes missing coverage. Please review.

Project coverage is 54.28%. Comparing base (89a0880) to head (1c8d25b). Report is 1 commits behind head on canary.

Files with missing lines Patch % Lines
...ot/src/edgeless/element-transform/mind-map-drag.ts 26.66% 11 Missing :warning:
...std/src/gfx/element-transform/transform-manager.ts 88.23% 7 Missing and 3 partials :warning:
...src/edgeless/element-transform/connector-filter.ts 43.75% 7 Missing and 2 partials :warning:
...eless/element-transform/frame-highlight-manager.ts 70.83% 3 Missing and 4 partials :warning:
...oot/src/edgeless/element-transform/snap-manager.ts 68.42% 3 Missing and 3 partials :warning:
.../affine/blocks/block-surface/src/view/connector.ts 45.45% 6 Missing :warning:
.../block-std/src/view/element/gfx-block-component.ts 57.14% 3 Missing :warning:
...e/framework/block-std/src/gfx/view/view-manager.ts 71.42% 1 Missing and 1 partial :warning:
Additional details and impacted files
@@            Coverage Diff             @@
##           canary   #10824      +/-   ##
==========================================
- Coverage   54.29%   54.28%   -0.02%     
==========================================
  Files        2478     2483       +5     
  Lines      114259   114298      +39     
  Branches    18742    18736       -6     
==========================================
+ Hits        62040    62048       +8     
+ Misses      50899    50874      -25     
- Partials     1320     1376      +56     
Flag Coverage Δ
server-test 78.95% <ø> (ø)
unittest 30.75% <66.82%> (+0.01%) :arrow_up:

Flags with carried forward coverage won't be shown. Click here to find out more.

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

codecov[bot] avatar Mar 13 '25 08:03 codecov[bot]

Merge activity

graphite-app[bot] avatar Mar 19 '25 13:03 graphite-app[bot]