Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/core/initialization/ModeInitialization.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export function initializeModeInfrastructure(instance) {
// Initialize all modes using factory
const availableModes = ModeFactory.getAvailableModes()
availableModes.forEach(modeName => {
instance.modes[modeName] = ModeFactory.createMode(modeName, instance, instance.state)
instance.modes[modeName] = ModeFactory.createMode(modeName, instance)
})
}

Expand Down
4 changes: 1 addition & 3 deletions src/modes/BaseMode.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,9 @@ export class BaseMode {
/**
* Constructor for base mode
* @param {GramFrame} instance - GramFrame instance
* @param {GramFrameState} state - GramFrame state object
*/
constructor(instance, state) {
constructor(instance) {
this.instance = instance
this.state = state
}

/**
Expand Down
15 changes: 7 additions & 8 deletions src/modes/ModeFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,23 @@ export class ModeFactory {
* Create a mode instance based on mode name
* @param {ModeType} modeName - Name of the mode
* @param {GramFrame} instance - GramFrame instance
* @param {GramFrameState} state - GramFrame state object
* @returns {BaseMode} Mode instance
* @throws {Error} If mode name is invalid or mode class is not available
*/
static createMode(modeName, instance, state) {
static createMode(modeName, instance) {
try {
switch (modeName) {
case 'analysis':
return new AnalysisMode(instance, state)
return new AnalysisMode(instance)

case 'harmonics':
return new HarmonicsMode(instance, state)
return new HarmonicsMode(instance)

case 'doppler':
return new DopplerMode(instance, state)
return new DopplerMode(instance)

case 'pan':
return new PanMode(instance, state)
return new PanMode(instance)

default:
throw new Error(`Invalid mode name: ${modeName}. Valid modes are: analysis, harmonics, doppler, pan`)
Expand All @@ -42,7 +41,7 @@ export class ModeFactory {
stack: error instanceof Error ? error.stack : undefined,
modeName,
instanceType: instance?.constructor?.name,
stateExists: !!state
stateExists: !!instance?.state
})

// In test environments, throw the error to fail fast
Expand All @@ -52,7 +51,7 @@ export class ModeFactory {

// Fallback to base mode to prevent complete failure in production
console.warn(`Falling back to BaseMode for "${modeName}" due to error`)
return new BaseMode(instance, state)
return new BaseMode(instance)
}
}

Expand Down
67 changes: 33 additions & 34 deletions src/modes/analysis/AnalysisMode.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,9 @@ export class AnalysisMode extends BaseMode {
/**
* Initialize AnalysisMode with drag handler
* @param {Object} instance - GramFrame instance
* @param {Object} state - State object
*/
constructor(instance, state) {
super(instance, state)
constructor(instance) {
super(instance)

// Initialize drag handler with analysis-specific callbacks
this.dragHandler = new BaseDragHandler(instance, {
Expand All @@ -35,14 +34,14 @@ export class AnalysisMode extends BaseMode {
*/
onMarkerDragStart(target, position) {
// Store drag state in analysis state
this.state.analysis.isDragging = true
this.state.analysis.draggedMarkerId = target.id
this.state.analysis.dragStartPosition = { ...position }
this.instance.state.analysis.isDragging = true
this.instance.state.analysis.draggedMarkerId = target.id
this.instance.state.analysis.dragStartPosition = { ...position }

// Auto-select the marker being dragged
const marker = this.state.analysis.markers.find(m => m.id === target.id)
const marker = this.instance.state.analysis.markers.find(m => m.id === target.id)
if (marker) {
const index = this.state.analysis.markers.findIndex(m => m.id === target.id)
const index = this.instance.state.analysis.markers.findIndex(m => m.id === target.id)
this.instance.setSelection('marker', target.id, index)
}
}
Expand All @@ -54,7 +53,7 @@ export class AnalysisMode extends BaseMode {
* @param {DataCoordinates} _startPos - Start position (unused)
*/
onMarkerDragUpdate(target, currentPos, _startPos) {
const marker = this.state.analysis.markers.find(m => m.id === target.id)
const marker = this.instance.state.analysis.markers.find(m => m.id === target.id)
if (marker) {
// Update marker position
marker.freq = currentPos.freq
Expand All @@ -75,7 +74,7 @@ export class AnalysisMode extends BaseMode {
}

// Notify listeners
notifyStateListeners(this.state, this.instance.stateListeners)
notifyStateListeners(this.instance.state, this.instance.stateListeners)
}
}

Expand All @@ -86,9 +85,9 @@ export class AnalysisMode extends BaseMode {
*/
onMarkerDragEnd(_target, _position) {
// Clear analysis drag state
this.state.analysis.isDragging = false
this.state.analysis.draggedMarkerId = null
this.state.analysis.dragStartPosition = null
this.instance.state.analysis.isDragging = false
this.instance.state.analysis.draggedMarkerId = null
this.instance.state.analysis.dragStartPosition = null
}

/**
Expand Down Expand Up @@ -188,7 +187,7 @@ export class AnalysisMode extends BaseMode {
*/
createMarkerAtPosition(dataCoords) {
// Get the current marker color from global state
const color = this.state.selectedColor || '#ff6b6b'
const color = this.instance.state.selectedColor || '#ff6b6b'

// Create marker object (we only need time/freq for positioning)
/** @type {AnalysisMarker} */
Expand All @@ -207,7 +206,7 @@ export class AnalysisMode extends BaseMode {
* Render persistent features for analysis mode
*/
renderPersistentFeatures() {
if (!this.instance.cursorGroup || !this.state.analysis?.markers) {
if (!this.instance.cursorGroup || !this.instance.state.analysis?.markers) {
return
}

Expand All @@ -216,7 +215,7 @@ export class AnalysisMode extends BaseMode {
existingMarkers.forEach(marker => marker.remove())

// Render all markers
this.state.analysis.markers.forEach(marker => {
this.instance.state.analysis.markers.forEach(marker => {
this.renderMarker(marker)
})
}
Expand Down Expand Up @@ -403,19 +402,19 @@ export class AnalysisMode extends BaseMode {
* @param {AnalysisMarker} marker - Marker object with all properties
*/
addMarker(marker) {
if (!this.state.analysis) {
this.state.analysis = {
if (!this.instance.state.analysis) {
this.instance.state.analysis = {
markers: [],
isDragging: false,
draggedMarkerId: null,
dragStartPosition: null
}
}

this.state.analysis.markers.push(marker)
this.instance.state.analysis.markers.push(marker)

// Auto-select the newly created marker
const index = this.state.analysis.markers.length - 1
const index = this.instance.state.analysis.markers.length - 1
this.instance.setSelection('marker', marker.id, index)

// Update markers table
Expand All @@ -427,25 +426,25 @@ export class AnalysisMode extends BaseMode {
}

// Notify listeners
notifyStateListeners(this.state, this.instance.stateListeners)
notifyStateListeners(this.instance.state, this.instance.stateListeners)
}

/**
* Remove a marker by ID
* @param {string} markerId - ID of marker to remove
*/
removeMarker(markerId) {
if (!this.state.analysis || !this.state.analysis.markers) return
if (!this.instance.state.analysis || !this.instance.state.analysis.markers) return

const index = this.state.analysis.markers.findIndex(m => m.id === markerId)
const index = this.instance.state.analysis.markers.findIndex(m => m.id === markerId)
if (index !== -1) {
// Clear selection if removing the selected marker
if (this.state.selection.selectedType === 'marker' &&
this.state.selection.selectedId === markerId) {
if (this.instance.state.selection.selectedType === 'marker' &&
this.instance.state.selection.selectedId === markerId) {
this.instance.clearSelection()
}

this.state.analysis.markers.splice(index, 1)
this.instance.state.analysis.markers.splice(index, 1)

// Update markers table
this.updateMarkersTable()
Expand All @@ -456,7 +455,7 @@ export class AnalysisMode extends BaseMode {
}

// Notify listeners
notifyStateListeners(this.state, this.instance.stateListeners)
notifyStateListeners(this.instance.state, this.instance.stateListeners)
}
}

Expand All @@ -467,11 +466,11 @@ export class AnalysisMode extends BaseMode {
* @returns {Object|null} Drag target if found, null otherwise
*/
findMarkerAtPosition(position) {
if (!this.state.analysis || !this.state.analysis.markers) return null
if (!this.instance.state.analysis || !this.instance.state.analysis.markers) return null

const tolerance = getUniformTolerance(this.getViewport(), this.instance.spectrogramImage)

const marker = this.state.analysis.markers.find(marker =>
const marker = this.instance.state.analysis.markers.find(marker =>
isWithinToleranceRadius(
position,
{ freq: marker.freq, time: marker.time },
Expand All @@ -497,10 +496,10 @@ export class AnalysisMode extends BaseMode {
updateMarkersTable() {
if (!this.uiElements.markersTableBody) return

if (!this.state.analysis || !this.state.analysis.markers) return
if (!this.instance.state.analysis || !this.instance.state.analysis.markers) return

const existingRows = this.uiElements.markersTableBody.querySelectorAll('tr')
const markers = this.state.analysis.markers
const markers = this.instance.state.analysis.markers

// Update existing rows or create new ones
markers.forEach((marker, index) => {
Expand Down Expand Up @@ -554,7 +553,7 @@ export class AnalysisMode extends BaseMode {
rebuildMarkersTableFrom(startIndex) {
if (!this.uiElements.markersTableBody) return

const markers = this.state.analysis.markers
const markers = this.instance.state.analysis.markers
const existingRows = this.uiElements.markersTableBody.querySelectorAll('tr')

// Remove rows from startIndex onward
Expand All @@ -576,8 +575,8 @@ export class AnalysisMode extends BaseMode {
}

// Toggle selection
if (this.state.selection.selectedType === 'marker' &&
this.state.selection.selectedId === marker.id) {
if (this.instance.state.selection.selectedType === 'marker' &&
this.instance.state.selection.selectedId === marker.id) {
this.instance.clearSelection()
} else {
this.instance.setSelection('marker', marker.id, index)
Expand Down
Loading