Skip to content

Conversation

@MinCrohn
Copy link
Collaborator

This update includes significant architectural improvements to the Patch Map library, redesigning the core interaction model to provide more powerful and extensible editing capabilities. The existing single select method has been replaced with a more flexible State Manager, and a new Transformer feature has been added to visually represent selected objects.

Major Changes

💥 Breaking Change: patchmap.select() Method Removed

The previously used patchmap.select(options) method has been removed. All selection-related functionalities are now managed through the newly introduced stateManager.

Migration Guide:

  • Before:

    patchmap.select({
      enabled: true,
      draggable: true,
      onSelect: (obj) => { /* ... */ },
      onDragSelect: (objs) => { /* ... */ }
    });
  • After:

    patchmap.stateManager.set('selection', {
      draggable: true,
      onSelect: (obj, event) => { /* ... */ },
      onDragSelect: (objs, event) => { /* ... */ }
    });

✨ New Feature: State Manager (patchmap.stateManager)

A StateManager has been introduced to systematically manage user interactions. This allows for the definition and easy switching between various states such as 'selection mode', 'drawing mode', and 'editing mode'.

  • SelectionState (Default State): This is the default state that provides the existing single and drag-selection functionalities. It is automatically registered under the name 'selection' when patchmap.draw() is called. You can activate it and pass callback functions via stateManager.set('selection', options).

    patchmap.stateManager.set('selection', {
      draggable: true, // Enable drag selection
      selectUnit: 'group', // Set selection unit to 'group'
      filter: (obj) => obj.type !== 'relations', // Exclude 'relations' objects from selection
      onSelect: (selectedObject, event) => {
        console.log('Object selected:', selectedObject);
      },
      onDragSelect: (selectedObjects, event) => {
        console.log('Multiple objects drag-selected:', selectedObjects);
      }
    });
  • Creating Custom States: You can create your own interaction states, such as 'drawing mode' or 'editing mode', by extending the State class.

    • static handledEvents: An array of event names the state will listen to (e.g., ['onpointerdown', 'onkeydown']).
    • enter(context, ...args): Called once when the state becomes active.
    • exit(): Called once when the state becomes inactive.
    • on[EventName](event): A handler function called when an event registered in handledEvents occurs.
    • PROPAGATE_EVENT: Returning this value from an event handler allows the event to propagate to the next state in the stack.
    import { State, PROPAGATE_EVENT } from '@conalog/patch-map';
    
    // 1. Define a new state class
    class CustomState extends State {
      static handledEvents = ['onpointerdown', 'onkeydown'];
    
      enter(context, customOptions) {
        super.enter(context);
        console.log('CustomState has started.', customOptions);
        this.context.viewport.cursor = 'crosshair';
      }
    
      exit() {
        console.log('CustomState has ended.');
        this.context.viewport.cursor = 'default';
        super.exit();
      }
    
      onpointerdown(event) {
        console.log('Pointer down in CustomState');
      }
    
      onkeydown(event) {
        if (event.key === 'Escape') {
          this.context.stateManager.set('selection'); // Switch to the default state
        }
      }
    }
    
    // 2. Register with the StateManager
    patchmap.stateManager.register('custom', CustomState);
    
    // 3. Switch states when needed
    patchmap.stateManager.set('custom', { message: 'Hello World' });

✨ New Feature: Transformer (patchmap.transformer)

A Transformer feature has been added to provide visual feedback by drawing an outline around selected objects. This also serves as a foundation for future object transformations (resizing, rotation, etc.).

  • Key Features:

    • Displays a real-time outline of the selected objects.
    • The outline thickness automatically adjusts with the viewport zoom level, providing a consistent visual experience.
    • Allows customization of the outline style (wireframeStyle) and display mode (boundsDisplayMode).
  • Usage:
    It is activated by creating a Transformer instance and assigning it to the patchmap.transformer property. You can use it in conjunction with stateManager callbacks to dynamically display selected objects.

    import { Patchmap, Transformer } from '@conalog/patch-map';
    
    const patchmap = new Patchmap();
    await patchmap.init(element);
    patchmap.draw(data);
    
    // 1. Create a Transformer instance and assign it to patchmap
    patchmap.transformer = new Transformer({
      wireframeStyle: {
        thickness: 2,
        color: '#007AFF'
      },
      boundsDisplayMode: 'groupOnly' // Display only the outline for the group
    });
    
    // 2. Link with SelectionState to display selected objects
    patchmap.stateManager.set('selection', {
      draggable: true,
      onSelect: (obj) => {
        patchmap.transformer.elements = obj;
      },
      onDragSelect: (objs) => {
        patchmap.transformer.elements = objs;
      }
    });

Other Improvements

  • update Method Enhancement: The logic has been improved to safely handle cases where x, y, rotation, or angle properties are undefined or null when using the relativeTransform option, preventing errors.
  • Relations Object Selection Improvement: The hit area for Relations objects has been improved, allowing for more precise selection on the canvas.
  • Useful Utility Functions: The following utility functions are now exported from the library to assist in implementing advanced interactions:
    • uid: Generates a unique ID.
    • findIntersectObject: Finds an object at specific coordinates.
    • isMoved: Checks if the mouse has moved beyond a certain threshold.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary of Changes

Hello @MinCrohn, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces significant architectural improvements to the Patch Map library by replacing the monolithic select() method with a flexible StateManager and a visual Transformer. The StateManager centralizes interaction logic, allowing developers to define and switch between various interaction modes seamlessly. The Transformer provides immediate visual feedback for selected objects and sets the stage for advanced manipulation features. These changes enhance the library's extensibility, making it easier to build complex and custom user interactions while also improving the robustness of existing functionalities.

Highlights

  • Breaking Change: Removal of patchmap.select(): The previous patchmap.select() method has been completely removed. All selection and interaction logic is now managed through the new StateManager. This is a breaking change, and existing code using patchmap.select() will need to be updated to use patchmap.stateManager.set('selection', options).
  • New Feature: State Manager: A new StateManager (patchmap.stateManager) has been introduced to provide a robust and extensible way to manage different user interaction modes (e.g., selection, drawing, editing). It allows for easy switching between states and custom state creation by extending the base State class.
  • New Feature: Transformer for Visual Feedback: A Transformer (patchmap.transformer) feature has been added to visually represent selected objects by drawing an outline around them. This provides immediate visual feedback and serves as a foundation for future object transformation capabilities like resizing and rotation.
  • Improved Robustness and Selection Accuracy: The update method's applyRelativeTransform logic has been enhanced to safely handle undefined or null values for x, y, rotation, and angle, preventing potential errors during transformations. Additionally, the hit area for Relations objects has been improved for more precise selection.
  • New Exported Utility Functions: Several useful utility functions, such as uid (for unique IDs), findIntersectObject (for finding objects at coordinates), and isMoved (for checking mouse movement), are now exported from the library, enabling developers to implement more advanced custom interactions.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces significant architectural improvements by adding a StateManager and a Transformer. The changes are well-structured and greatly enhance the library's extensibility. I've identified a few issues, including a critical one in the new Transformer component that would cause a runtime error, and a couple of high-severity bugs in the state management logic that could lead to incorrect behavior. I've also included some medium-severity suggestions to improve consistency and prevent potential issues. Overall, this is a great feature addition, and with these fixes, it will be a solid enhancement.

@MinCrohn
Copy link
Collaborator Author

/gemini review

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a major architectural refactoring by replacing the select method with a more extensible StateManager and adding a Transformer for visual feedback on selected objects. The changes are well-structured and significantly improve the library's interaction model. I've identified a couple of high-severity issues: one in the new SelectionState that causes the onSelect callback to fire twice, and another in the Transformer's elements setter that could lead to a crash with nullish values. I've also included some suggestions to improve the documentation's clarity and consistency. Overall, this is a great enhancement, and with these fixes, it will be a solid foundation for future features.

@MinCrohn
Copy link
Collaborator Author

/gemini review

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces significant and well-designed architectural improvements by adding a StateManager and a Transformer. This greatly enhances the extensibility of interactions, moving away from the monolithic select method. The new state-based approach is powerful and the code is generally of high quality.

My review includes a few suggestions to improve the new features further:

  • Adjusting the selection event trigger to be more conventional.
  • Preventing the transformer's wireframe from being selectable.
  • Improving consistency and clarity in the documentation.

@MinCrohn MinCrohn merged commit d176053 into v0.3.x Aug 19, 2025
@MinCrohn MinCrohn deleted the feat/add-transformer-and-event-management branch August 19, 2025 01:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants