katspaugh/wavesurfer.js

Created Regions Not Removed When Using 'Regions.Remove()'

Closed this issue · 7 comments

Bug description

Attempting to ensure that only one region can be created at a time. I created code that removes regions, however, that are still visible on screen although the list of regions has been reduced.

Utilizing region.remove() does not visibly remove regions created with 'regions.addRegion'
I thought it was possibly my environment but I pasted the minimal code snippet into https://wavesurfer.xyz/examples/?regions.js and obtained the same behavior.

Environment

  • Browser: Firefox

Minimal code snippet


regions.addRegion({{
    start: 12,
    end: 17,
    content: 'Drag me',
    color: 'rgba(0, 255, 0, 0.1)
    resize: false,
}})

regions.enableDragSelection({{
    color: 'rgba(255, 0, 0, 0.1)',
    drag: false,
    resize: true,
}})

var regionTest = [];

// Listen for region creation
regions.on('region-created', (region) => {{
    const now = Date.now();

    // Add the new region with its timestamp
    regionTest.push({ region, timestamp: now });

    // If there is more than one recent region, remove all but the last
    if (regionTest.length > 1) {{
        const regionsToRemove = regionTest.slice(0, -1); // All but the last
        console.log('regionsToRemove', regionsToRemove);

        // Remove each region except the last
        regionsToRemove.forEach(item => {{
            console.log('removing region', item.region);
            item.region.remove(); // Remove the region from Wavesurfer
        }});

        // Keep only the last region in the array
        regionTest = [regionTest[regionTest.length - 1]];
    }}
}});

Expected result

Removal of all regions except the last created region, regardless of whether it was created with '.addRegion' or user drag creation associated with enableDragSelection.

Additionally, any drag creation of a region would remove previously created regions, leaving only the newly created region.

Obtained result

Regions that were created with 'regions.addRegion' remain on screen

Screenshots

image

Same here
As workaround I clear all regions and then add every region that should exit

The code you pasted works as intended for me:

https://wavesurfer.xyz/examples/?5cc63deca8da61df67c85b01d4004247

Tested in Chrome and Firefox.

I borrowed the portion of https://wavesurfer.xyz/examples/?regions.js example that creates the regions.

The full code shown will remove the most recently created region when you perform a drag selection to create a region but the other existing regions remain visible.

I am using firefox 132.0.2 (64-bit) on Ubuntu.

    <script src="https://unpkg.com/wavesurfer.js"></script>
    <script src="https://unpkg.com/wavesurfer.js@7"></script>
    <script src="https://unpkg.com/wavesurfer.js@7/dist/plugins/regions.min.js"></script>

My actual code is pulling the javascript but it behaves the same way as the code below

// Regions plugin

import WaveSurfer from 'wavesurfer.js'
import RegionsPlugin from 'wavesurfer.js/dist/plugins/regions.esm.js'

// Initialize the Regions plugin
const regions = RegionsPlugin.create()

// Create a WaveSurfer instance
const ws = WaveSurfer.create({
  container: '#waveform',
  waveColor: 'rgb(200, 0, 200)',
  progressColor: 'rgb(100, 0, 100)',
  url: '/examples/audio/audio.wav',
  plugins: [regions],
})

// Give regions a random color when they are created
const random = (min, max) => Math.random() * (max - min) + min
const randomColor = () => `rgba(${random(0, 255)}, ${random(0, 255)}, ${random(0, 255)}, 0.5)`

// Create some regions at specific time ranges
ws.on('decode', () => {
  // Regions
  regions.addRegion({
    start: 0,
    end: 8,
    content: 'Resize me',
    color: randomColor(),
    drag: false,
    resize: true,
  })
  regions.addRegion({
    start: 9,
    end: 10,
    content: 'Cramped region',
    color: randomColor(),
    minLength: 1,
    maxLength: 10,
  })
  regions.addRegion({
    start: 12,
    end: 17,
    content: 'Drag me',
    color: randomColor(),
    resize: false,
  })

  // Markers (zero-length regions)
  regions.addRegion({
    start: 19,
    content: 'Marker',
    color: randomColor(),
  })
  regions.addRegion({
    start: 20,
    content: 'Second marker',
    color: randomColor(),
  })
})

regions.enableDragSelection({
  color: 'rgba(255, 0, 0, 0.1)',
})

regions.on('region-updated', (region) => {
  console.log('Updated region', region)
})

var regionTest = [];

// Listen for region creation
regions.on('region-created', (region) => {{
    const now = Date.now();

    // Add the new region with its timestamp
    regionTest.push({ region, timestamp: now });

    // If there is more than one recent region, remove all but the last
    if (regionTest.length > 1) {{
        const regionsToRemove = regionTest.slice(0, -1); // All but the last
        console.log('regionsToRemove', regionsToRemove);

        // Remove each region except the last
        regionsToRemove.forEach(item => {{
            console.log('removing region', item.region);
            item.region.remove(); // Remove the region from Wavesurfer
        }});

        // Keep only the last region in the array
        regionTest = [regionTest[regionTest.length - 1]];
    }}
}});

/*
  <html>
    <div id="waveform"></div>

    <p>
      <label>
        <input type="checkbox" checked="${loop}" />
        Loop regions
      </label>

      <label style="margin-left: 2em">
        Zoom: <input type="range" min="10" max="1000" value="10" />
      </label>
    </p>

    <p>
      📖 <a href="https://wavesurfer.xyz/docs/classes/plugins_regions.RegionsPlugin">Regions plugin docs</a>
    </p>
  </html>
*/

That's because you're adding and immediately removing regions. Adding a small timeout inside the region-created callback will help.

I may not be doing it in a way that you suggested. I added a one second delay to see the outcome.
All of the regions were not removed. The goal is to have only one region be active, even when multiple ranges exist.

var regionTest = [];

// Listen for region creation
regions.on('region-created', (region) => {
    const now = Date.now();

    // Add the new region with its timestamp
    regionTest.push({ region, timestamp: now });

    // If there is more than one recent region, remove all but the last
    if (regionTest.length > 1) {
        const regionsToRemove = regionTest.slice(0, -1); // All but the last
        console.log('regionsToRemove', regionsToRemove);

        // Delay the removal of regions except the last one
        setTimeout(() => {
            // Remove each region except the last
            regionsToRemove.forEach(item => {
                console.log('removing region', item.region);
                item.region.remove(); // Remove the region from Wavesurfer
            });

            // Keep only the last region in the array
            regionTest = [regionTest[regionTest.length - 1]];
        }, 1000); // 1000ms delay (1 second)
    }
});

Jackpot --- What you said worked, I just had to think about it differently

var regionTest = [];

// Listen for region creation
regions.on('region-created', (region) => {
    const now = Date.now();

    // Add the new region with its timestamp
    regionTest.push({ region, timestamp: now });

    // If there is more than one recent region, remove all but the last
    if (regionTest.length > 1) {
        const regionsToRemove = regionTest.slice(0, -1); // All but the last
        console.log('regionsToRemove', regionsToRemove);

        // Remove each region with a delay
        regionsToRemove.forEach((item, index) => {
            const delay = 50 * (index + 1); // Delay increases for each region removed (e.g., 1s, 2s, 3s)
            setTimeout(() => {
                console.log('removing region', item.region);
                item.region.remove(); // Remove the region from Wavesurfer
            }, delay);
        });

        // Keep only the last region in the array
        regionTest = [regionTest[regionTest.length - 1]];
    }
});

Cool! I'll keep this issue open because ideally it should work w/o a delay. I suspect the root cause is a virtualized rendering.