i2 Notebook SDK
Search results for

    Show/hide table of contents

    Untracked element style editing

    Untracked mutations provide a powerful way to apply automatic formatting and visual changes to chart elements without affecting the user's undo stack. This makes them ideal for temporary visual enhancements, dynamic styling, and non-persistent UI feedback.

    Overview

    When you use untracked mutations to edit the appearance of nodes, edges, and edge summaries, the changes are:

    • Local only: Applied in the browser and not sent to the server
    • Not persisted: Lost when the page or chart is reloaded
    • Not undoable: Do not appear in the undo stack, preserving the user's workflow

    These characteristics make untracked style editing particularly useful for automatic formatting scenarios where you want to enhance the visual presentation without creating permanent changes and affecting the undo stack.

    Available editing methods

    The IUntrackedMutations interface provides methods for editing element appearance:

    • editNode() - Returns an INodeEditor for modifying node appearance
    • editEdge() - Returns an IEdgeEditor for modifying edge appearance

    Common use cases

    Automatic visual highlighting

    You can use untracked mutations to automatically change certain elements based on their properties or context, without requiring user interaction:

    // Apply highlighting when chart changes
    api.addEventListener('chartchange', (change) => {
      // Only process minor changes that contain detailed change information
      if (change.type === 'minor') {
        api.runUntrackedMutations((application, mutations) => {
          // Process added and changed records
          const recordsToCheck = [...change.records.added, ...change.records.changed];
    
          for (const record of recordsToCheck) {
            if (record.itemType.id === 'ET_Transaction') {
              const amount = record.getProperty('PT_Amount')?.value as number;
              const element = record.element;
              if (element.isEdge() && amount > 0) {
                // Use logarithmic scale to set edge width based on transaction amount
                // Log10 of amount scaled to reasonable width values (1-10)
                const logAmount = Math.log10(amount);
                const width = Math.max(1, Math.min(10, logAmount / 2));
                mutations.editEdge(element).setWidth(width);
              }
            }
          }
    
          return { type: 'commit' };
        });
      }
    });
    

    Conditional styling rules

    Apply styling rules that respond to data patterns or business logic:

    api.runUntrackedMutations((application, mutations) => {
      for (const record of application.chart.records) {
        // Apply color coding based on risk level
        const riskLevel = record.getProperty('PT_RiskLevel')?.value;
        let color: string | undefined;
    
        switch (riskLevel) {
          case 'High':
            color = '#DC143C'; // Crimson
            break;
          case 'Medium':
            color = '#FFA500'; // Orange
            break;
          case 'Low':
            color = '#32CD32'; // LimeGreen
            break;
        }
    
        if (color) {
          const element = record.element;
          if (element.isNode()) {
            mutations.editNode(element).setColor(color);
          }
        }
      }
    
      return { type: 'commit' };
    });
    

    Maintaining styles across undo operations

    Since untracked mutations are not part of the undo stack, your visual changes will be lost when a user performs an undo operation. If you want to maintain your automatic formatting across undo/redo, you can reapply it in response to chart change events:

    // Store your formatting logic as a reusable function
    function applyAutoFormatting(
      application: app.IApplicationContents,
      mutations: app.IUntrackedMutations
    ) {
      // Your formatting logic here
      for (const record of application.chart.records) {
        const priority = record.getProperty('PT_Priority')?.value;
        if (priority === 'Critical') {
          const element = record.element;
          if (element.isNode()) {
            mutations.editNode(element).setColor('#FF0000');
          }
        }
      }
    }
    
    // Apply initial formatting
    api.runUntrackedMutations((application, mutations) => {
      applyAutoFormatting(application, mutations);
      return { type: 'commit' };
    });
    
    // Reapply after chart changes
    api.addEventListener('chartchange', () => {
      api.runUntrackedMutations((application, mutations) => {
        applyAutoFormatting(application, mutations);
        return { type: 'commit' };
      });
    });
    

    Best practices

    When to use untracked style editing

    Use untracked mutations for style editing when:

    • The styling is automatic or computed, not user-initiated
    • You want to provide visual feedback without affecting the undo stack
    • The changes should be temporary or recalculated frequently
    • You're implementing dynamic visualizations that respond to data patterns

    When to use tracked mutations

    Use tracked mutations for style editing when:

    • The user explicitly requests a visual change
    • The change should be persistent and saved to the server
    • The user should be able to undo the change
    • The styling is part of a larger set of changes that should be undoable together

    Performance considerations

    • Batch operations: Group multiple style changes in a single untracked mutation rather than running many separate mutations
    • Filter efficiently: Pre-filter records and elements to only those that need styling changes
    • Avoid excessive reapplication: When listening to chart change events, consider throttling or debouncing your reapplication logic
    • Be selective: Only apply styles to visible or relevant elements when working with large charts

    User experience

    • Provide clarity: If your automatic formatting might confuse users, consider providing documentation or UI hints about what the colors/styles mean
    • Respect user preferences: Where appropriate, allow users to disable automatic formatting
    • Avoid conflicts: Be careful not to override user-applied styles in ways that might be disorienting
    • Test reload behavior: Remember that your styles will disappear on page reload, so ensure this doesn't negatively impact the user experience

    Respecting user-applied styles

    When applying automatic styling with untracked mutations, be aware that you may overwrite styles that users have explicitly set through the application UI. To avoid this, you can check whether a style property is using its default value before applying your automatic formatting:

    api.runUntrackedMutations((application, mutations) => {
      for (const record of application.chart.records) {
        const element = record.element;
        if (element.isNode()) {
          // Only apply automatic coloring if the node is using the default color
          if (element.style.color.isDefault) {
            const priority = record.getProperty('PT_Priority')?.value;
            if (priority === 'High') {
              mutations.editNode(element).setColor('#FF0000');
            }
          }
        }
      }
    
      return { type: 'commit' };
    });
    

    The isDefault property on style settings (such as color, size, width) indicates whether the value is inherited from the schema or has been explicitly set by the user. By checking this property, you can ensure your automatic formatting only applies to elements that haven't been manually styled, preserving the user's intentional customizations.

    Comparison with tracked mutations

    Aspect Untracked Mutations Tracked Mutations
    Undo/Redo Not in undo stack Added to undo stack
    Persistence Local only, lost on reload Sent to server, persisted
    Use case Automatic formatting, temporary feedback User-initiated changes, data modifications
    Impact on workflow No impact on user's undo history Can be undone by user
    Available operations Limited to visual styling Full record editing and chart modifications

    See also

    • Changing data from a plug-in - General overview of mutations
    • Supported mutation operations - Complete list of mutation operations
    • IUntrackedMutations - API reference
    • INodeEditor - Node styling methods
    • IEdgeEditor - Edge styling methods
    In this article
    Back to top © N. Harris Computer Corporation