How to correctly Implement Hover Effect to Change Waveform Color with Mix-Blend-Mode?

66 views Asked by At

I have a need to create a hover effect on a waveform (generated using the WaveSurfer library). The purpose of this effect is to change the color of the waveform when the mouse cursor is hovered over it. To achieve this, I attempted to set the background-color value of a div element with the id "hover" to match the background color of the page, which is rgb(28, 28, 28), using the mix-blend-mode = 'plus-lighter' property. However, in the end, my div element with the class "hover" ends up with a color of rgb(56, 56, 56). The code is provided below.

My goal is to eliminate this light strip in the background and create visual effect, when I change a color for waveform only (keep light color for waveform only)

enter image description here

CSS:

import { makeStyles } from '@material-ui/core';

export const useStyles = makeStyles(
  (theme) => ({
    root: {
      position: 'relative',

      '& #hover': {
        position: 'absolute',
        left: 0,
        top: 0,
        zIndex: 10,
        pointerEvents: 'none',
        height: '55%',
        width: 0,
        opacity: 0,
        transition: 'opacity 0.2s ease',
        background: 'rgba(28, 28, 28)',
        mixBlendMode: 'plus-lighter',
      },

      '& #waveform': {
        cursor: 'pointer',
        position: 'relative',
      },

      '& #waveform:hover #hover': {
        opacity: 1,
      },
    },
  }),
  { name: 'SoundCloudWaveform' },
);

React component:

import { FC, useEffect } from 'react';
import WaveSurfer from 'wavesurfer.js';
import { useStyles } from 'src/components/PageTrack/Waveform/style';

interface WaveformProps {
  audioUrl: string;
}

const SoundcloudWaveform: FC<WaveformProps> = ({ audioUrl }) => {
  const classes = useStyles();

  useEffect(() => {
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');

    const gradient = ctx!.createLinearGradient(0, 0, 0, canvas.height * 1.35);
    gradient.addColorStop(0, '#656666'); // Top color
    gradient.addColorStop((canvas.height * 0.7) / canvas.height, '#656666'); // Top color
    gradient.addColorStop((canvas.height * 0.7 + 1) / canvas.height, '#ffffff'); // White line
    gradient.addColorStop((canvas.height * 0.7 + 2) / canvas.height, '#ffffff'); // White line
    gradient.addColorStop((canvas.height * 0.7 + 3) / canvas.height, '#B1B1B1'); // Bottom color
    gradient.addColorStop(1, '#B1B1B1'); // Bottom color

    // Define the progress gradient
    const progressGradient = ctx!.createLinearGradient(0,0,0,canvas.height * 1.35);
    progressGradient.addColorStop(0, '#EE772F'); // Top color
    progressGradient.addColorStop((canvas.height * 0.7) / canvas.height,'#EB4926'); // Top color
    progressGradient.addColorStop((canvas.height * 0.7 + 1) / canvas.height,'#ffffff'); // White line
    progressGradient.addColorStop((canvas.height * 0.7 + 2) / canvas.height,'#ffffff'); // White line
    progressGradient.addColorStop((canvas.height * 0.7 + 3) / canvas.height,'#F6B094'); // Bottom color
    progressGradient.addColorStop(1, '#F6B094'); // Bottom color

    const wavesurfer = WaveSurfer.create({
      container: '#waveform',
      waveColor: gradient,
      progressColor: progressGradient,
      barWidth: 3,
      url: audioUrl,
      dragToSeek: true,
    });

    // Create the waveform
    wavesurfer.load(audioUrl);

    // Play/pause on click
    wavesurfer.on('interaction', () => {
      wavesurfer.playPause();
    });

    const hover = document.querySelector('#hover')! as HTMLDivElement;
    const waveform = document.querySelector('#waveform')!;

    waveform.addEventListener('pointermove', (e) => {
      hover.style.width = `${(e as PointerEvent).offsetX}px`;
    });

    return () => {
      wavesurfer.destroy();
    };
  }, []);

  return (
    <div className={classes.root}>
      <div id="waveform">
        <div id="hover"></div>
      </div>
    </div>
  );
};

export default SoundcloudWaveform;
1

There are 1 answers

1
artyom.poteshkin98 On
import { makeStyles } from '@material-ui/core';

export const useStyles = makeStyles(
  (theme) => ({
    root: {
      position: 'relative',

      '& #hover': {
        position: 'absolute',
        left: 0,
        top: 0,
        zIndex: 10,
        pointerEvents: 'none',
        height: '55%',
        width: 0,
        opacity: 0,
        transition: 'opacity 0.2s ease',
        background: 'rgba(30,30,30)',
        mixBlendMode: 'plus-lighter',
      },

      '& #waveform': {
        cursor: 'pointer',
        position: 'relative',
        zIndex: 101,
      },

      '& #waveform:hover #hover': {
        opacity: 1,
      },
    },
  }),
  { name: 'SoundCloudWaveform' },
);

Updated CSS, that works (added zIndex = 101 to #waveform and updated a color to rgb(30,30,30). Waveform rendered under the hover div and mixBlendMode didn't work correctly