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 anINodeEditorfor modifying node appearanceeditEdge()- Returns anIEdgeEditorfor 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 referenceINodeEditor- Node styling methodsIEdgeEditor- Edge styling methods