{"id":13768906,"url":"https://github.com/chrisweb/waveform-visualizer","last_synced_at":"2025-06-25T09:03:39.896Z","repository":{"id":20243112,"uuid":"23515529","full_name":"chrisweb/waveform-visualizer","owner":"chrisweb","description":"An opensource javascript (typescript) waveform visualizer that renders a waveform onto a 2d canvas HTML element, customizable size, colors and much more, as well as optional animated progress visualization","archived":false,"fork":false,"pushed_at":"2025-03-24T17:13:38.000Z","size":783,"stargazers_count":32,"open_issues_count":0,"forks_count":2,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-06-25T09:01:57.489Z","etag":null,"topics":["canvas","canvas2d","image","javascript","sound-wave-visualizer","soundwave","typescript","visualizer","waveform","waveform-visualizer"],"latest_commit_sha":null,"homepage":"https://chris.lu/myprojects","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chrisweb.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"chrisweb","buy_me_a_coffee":"chriswwweb"}},"created_at":"2014-08-31T14:39:48.000Z","updated_at":"2025-06-16T17:42:40.000Z","dependencies_parsed_at":"2023-11-30T21:29:21.659Z","dependency_job_id":"97e8491a-7f02-4f1d-91b6-04fb6439d7ce","html_url":"https://github.com/chrisweb/waveform-visualizer","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/chrisweb/waveform-visualizer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chrisweb%2Fwaveform-visualizer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chrisweb%2Fwaveform-visualizer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chrisweb%2Fwaveform-visualizer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chrisweb%2Fwaveform-visualizer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chrisweb","download_url":"https://codeload.github.com/chrisweb/waveform-visualizer/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chrisweb%2Fwaveform-visualizer/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261841824,"owners_count":23217910,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["canvas","canvas2d","image","javascript","sound-wave-visualizer","soundwave","typescript","visualizer","waveform","waveform-visualizer"],"created_at":"2024-08-03T16:01:27.957Z","updated_at":"2025-06-25T09:03:39.853Z","avatar_url":"https://github.com/chrisweb.png","language":"TypeScript","readme":"[![waveform-visualizer npm version](https://img.shields.io/npm/v/waveform-visualizer.svg?style=flat)](https://www.npmjs.com/package/waveform-visualizer)\n[![waveform-visualizer minified size](https://img.shields.io/bundlephobia/min/waveform-visualizer?style=flat)](https://www.npmjs.com/package/waveform-visualizer)\n[![waveform-visualizer license](https://img.shields.io/github/license/chrisweb/waveform-visualizer)](https://github.com/chrisweb/waveform-visualizer/blob/master/LICENSE)\n\n# waveform-visualizer\n\nVisualizes waveform data (peaks), for example the ones that got generated using: \u003chttps://github.com/chrisweb/waveform-data-generator\u003e\n\n![audio waveform visualizer output: waveform image](./docs/images/waveform-visualizer.gif)\n\nWaveform created using data that got generated using the [waveform data generator](https://github.com/chrisweb/waveform-data-generator)\n\n## installation\n\nif you want to use the waveform visualizer in your own project you can install it from npm using the following command:\n\n`npm i waveform-visualizer`\n\n## examples\n\nCheck out the [simple waveform example](/examples/simple-waveform/README.md)\n\n## documentation\n\n### vanilla javascript example\n\nOpen your project in your favorite IDE (VSCode) and then [install](#installation) the waveform dependency\n\nNow that the dependency is installed, import the waveform-visualizer package into your javascript code like this:\n\n```js\nimport { Waveform } from 'waveform-visualizer'\n```\n\nif you are using typescript, which is what I will do now for the rest of this example, also import the interfaces so that we have typed options objects (for the core and the layout options), like so:\n\n```ts\nimport { Waveform, IWaveLayoutOptions, IWaveCoreOptions, IWaveClickCallback } from 'waveform-visualizer'\n```\n\nnext create a layout options object, to tweak the look of the waveform a bit:\n\n```ts\nconst waveLayoutOptions: IWaveLayoutOptions = {\n    waveTopPercentage: 50,\n    peakTopFillStyle: 'deepskyblue',\n    peakBottomFillStyle: 'dodgerblue ',\n}\n```\n\nNote: a **fill style** can be a css color name (which is what we use here) or a color hex code or an rgb(a) color, a canvas gradient or a canvas pattern, for more details about what values can be used for the *FillStyle options, check out the [layout options chapter](#layout-options)\n\nAll layout options are optional, at this point we are only setting 3 options:\n\n* the first one is called \"waveTopPercentage\" and is used to the tell the waveform where the middle is, if you set it to 50 like in this example, then the top of the waveform will be 50% and the bottom 50% too, meaning the top peaks will be a mirror image of the bottom peaks\n* next we set **peakTopFillStyle** to deepskyblue, because we just set the waveTopPercentage to 50% the top half of the waveform peaks will use the **deepskyblue**\n* finally we **peakBottomFillStyle** to **dodgerblue** meaning the bottom half peaks will be another color (of course if you prefer you can also use the same color twice for the bottom as well as the top peaks)\n\nusing these 3 options this is the result you will get:\n\n![audio waveform visualizer output: waveform image](./docs/images/waveform_example_50.png)\n\nif you prefer a wave which only displays the top peaks then set the value for **waveTopPercentage** to 100, the result look like this:\n\n![audio waveform visualizer output: waveform image](./docs/images/waveform_example_100.png)\n\nif you want to only display bottom peaks set **waveTopPercentage** to 0:\n\n![audio waveform visualizer output: waveform image](./docs/images/waveform_example_0.png)\n\nand if you want the top peaks to be bigger (70% of the height) than the bottom peaks (30% of the height), then set the value for **waveTopPercentage** to 70:\n\n![audio waveform visualizer output: waveform image](./docs/images/waveform_example_70.png)\n\nNote: You can also change the width of the peaks, the width of the space between peaks and a lot more via the layout options, for a full list of available options and their default values, check out the [layout options chapter](#layout-options) in this readme\n\nNote 2: If you want to see an example of how to use gradient fill styles, check out the client code of the [simple waveform example](/examples/simple-waveform/README.md) in this repository\n\nnext we will create a **click callback** function, this callback will get triggered by the waveform every time a user clicks on the waveform, it will accept a parameter called **clickHorizontalPositionInPercent** which is the horizontal position (in percent) of the waveform based on the mouse position, this means that if the user clicks exactly in the middle of the waveform then this value will be 50%, based on that information you can then tell your audio (sound) player to seek (move) to that position of the song:\n\n```ts\nconst waveformClickCallback = (clickHorizontalPositionInPercent: number): void =\u003e {\n\n    console.log('waveformClickCallback: ', clickHorizontalPositionInPercent)\n\n    // tell the audio player to move to 50% of the sound\n\n}\n```\n\nNext create a core options object and we will add 4 options:\n\n* the out layout options object\n* the data for the waveform peaks\n* our click callback function\n* the ID of the canvas element\n\n```ts\nconst waveCoreOptions: IWaveCoreOptions = {\n    layout: waveLayoutOptions,\n    data: [10,16,14,15,17,15,17,18,24,23,21,40,64,66,66,63,68,70,68,70,71,69,68,66,66,67,71,30,29,29,30,67,59,59,69,67,60,64,66,69,64,64,70,66,58,61,36,31,31,31,37,35,31,31,35,36,38,34,36,33,31,50,71,68,55,69,69,62,60,78,59,92,100,98,78,65,63,72,71,68,66,65,65,61,63,62,65,65,66,69,64,70,46,28,29,23,62,64,57,64,70,71,56,61,67,69,62,70,66,58,61,47,33,35,33,33,34,32,32,66,69,57,55,85,78,59,66,65,58,81,86,81,78,61,68,73,57,55,74,84,70,53,75,62,68,72,72,80,66,66,37,30,24,23,67,62,58,66,67,60,58,64,67,65,64,70,66,57,63,68,70,58,61,68,64,59,64,62,73,63,71,71,61,57,47,20,21,20,21,22,22,21,22,25,25,29,25,24,19,21],\n    waveformClickCallback: onWaveClickHandler,\n}\n```\n\nNote: if you want to generate peaks data for one of your songs or sounds, you can for example use another tool I created which is called **waveform-data-generator**, it is written in javascript (nodejs) and available on github too: \u003chttps://github.com/chrisweb/waveform-data-generator\u003e\n\nNow it is time to create an instance of the waveform visualizer and pass the core options object to it:\n\n```ts\nconst waveform = new Waveform(waveCoreOptions)\n```\n\nNow we need to create an HTML canvas element to display the waveform, open your HTML document and create a new HTML canvas element like so:\n\n```html\n\u003ccanvas id=\"waveformCanvas\"\u003e\u003c/canvas\u003e\n```\n\nthen back into our javascript code, get the canvas element and then pass it to the waveform using the **setCanvasElement** method:\n\n```ts\nconst canvasElement = document.getElementById(visualizerOptions.canvasElementId) as HTMLCanvasElement\n\nwaveform.setCanvasElement(canvasRef.current)\n```\n\nNote: all the options can be set when creating the waveform instance or like above using setters, there are also getters for each option in case you want to read an option and know what value is currently set, for a full list of all setters and getters check out the [waveform methods chapter](#waveform-methods)\n\nIf you are not using vanilla javascript but React, then I recommend to use React Hook called [useRef](https://react.dev/reference/react/useRef) instead:\n\n```ts\nconst canvasRef = useRef\u003cHTMLCanvasElement\u003e()\n\nwaveform.setCanvasElement(canvasRef.current)\n```\n\nNote: for a full react example check out the next chapter [](#react-component-example)\n\nFinal step, we need to tell the waveform to perform the initial draw so that something gets painted inside of our canvas element, like so:\n\n```ts\nwaveform.draw()\n```\n\nThe draw function has an optional parameter called **range**, the range must be a number between 0 and 100, it tells the waveform at what position your sound (song) currently it, if you have a player and that player allows you to set a callback function when the sound (song) is playing, then you should call the draw function again every time that playing progress callback gets triggered, like so:\n\n```ts\nconst playerPlayingProgressCallback = (progressInPercent) =\u003e {\n    waveform.draw(progressInPercent)\n}\n```\n\nTo see an example of what it looks like when the range gets modified, check out the animated gif on top of this README or install the example from this repository, which uses an audio player that redraws the waveform element every time its progress callback gets triggered: [simple waveform and audio player example](/examples/simple-waveform/README.md)\n\nIf you want to replace the current waveform display with another waveform because your audio player got told to play the next song, then you don't need to create another waveform, just replace the wave peaks from the previous song with the peaks of the current song,like so:\n\n```ts\nwaveform.setWaveData(peaksArray)\n```\n\n### React component example\n\nNote: This code does the exact same thing as the previous example but uses React instead of vanilla javascript\n\nReact component example to create a waveform:\n\n```ts\nimport { useRef, useCallback, useEffect } from 'react'\nimport { Waveform, IWaveLayoutOptions, IWaveCoreOptions } from 'waveform-visualizer'\n\nconst WaveformComponent = () =\u003e {\n\n    const canvasRef = useRef\u003cHTMLCanvasElement\u003e()\n    const waveformRef = useRef\u003cWaveform | null\u003e(null)\n\n    const onWaveClickHandler = useCallback((clickHorizontalPositionInPercent: number): void =\u003e {\n\n        console.log('waveformClickCallback: ', clickHorizontalPositionInPercent)\n\n        // tell your audio player to move to 50% of the sound\n        // if you need an audio player checkout my other project:\n        // https://github.com/chrisweb/web-audio-api-player\n        //playerRef.current.goToPosition(clickHorizontalPositionInPercent)\n\n    }, [])\n\n    // here is some pseudo code to show you what to when another sound (song) gets played\n    // we replace the wave data (peaks) of the previous song with the data for the current song\n    //playerRef.current.onPlayCallback((sound) =\u003e {\n    //    const peaksArray = sound.waveData\n    //    waveformRef.current.setWaveData(peaksArray)\n    //})\n\n    // and here is some pseudo code to show you have to change the range display\n    // when your player is playing a sound (song)\n    // the range value is the playing progress in percent, so a value between 0 and 100\n    //playerRef.current.onPlayingCallback((progressInPercent) =\u003e {\n    //    waveformRef.current.draw(progressInPercent)\n    //})\n\n    const initializeWaveform = useCallback(() =\u003e {\n\n        const waveLayoutOptions: IWaveLayoutOptions = {\n            waveTopPercentage: 50,\n            peakTopFillStyle: 'deepskyblue',\n            peakBottomFillStyle: 'dodgerblue ',\n        }\n\n        const waveCoreOptions: IWaveCoreOptions = {\n            layout: waveLayoutOptions,\n            data: [10,16,14,15,17,15,17,18,24,23,21,40,64,66,66,63,68,70,68,70,71,69,68,66,66,67,71,30,29,29,30,67,59,59,69,67,60,64,66,69,64,64,70,66,58,61,36,31,31,31,37,35,31,31,35,36,38,34,36,33,31,50,71,68,55,69,69,62,60,78,59,92,100,98,78,65,63,72,71,68,66,65,65,61,63,62,65,65,66,69,64,70,46,28,29,23,62,64,57,64,70,71,56,61,67,69,62,70,66,58,61,47,33,35,33,33,34,32,32,66,69,57,55,85,78,59,66,65,58,81,86,81,78,61,68,73,57,55,74,84,70,53,75,62,68,72,72,80,66,66,37,30,24,23,67,62,58,66,67,60,58,64,67,65,64,70,66,57,63,68,70,58,61,68,64,59,64,62,73,63,71,71,61,57,47,20,21,20,21,22,22,21,22,25,25,29,25,24,19,21],\n            waveformClickCallback: onWaveClickHandler,\n        }\n\n        const waveform = new Waveform(waveCoreOptions)\n\n        waveformRef.current = waveform\n\n        waveform.setCanvasElement(canvasRef.current)\n\n        waveform.draw(0)\n\n    }, [onWaveClickHandler])\n\n    useEffect(() =\u003e {\n        initializeWaveform()\n        return () =\u003e {\n            if (waveformRef.current !== null) {\n                // on component umount, destroy the waveform\n                // the waveform will remove the click event listener\n                waveformRef.current.destroy()\n            }\n        }\n    }, [initializeWaveform])\n\n    return (\n        \u003cdiv className=\"audioWaveForm\"\u003e\n            \u003ccanvas ref={canvasRef} width=\"200px\" height=\"60px\" /\u003e\n        \u003c/div\u003e\n    )\n})\n\nexport default WaveformComponent\n```\n\n## core options\n\n* canvasElement?: [HTMLCanvasElement] (optional, if not set here you must use the **setCanvasElement** method) the canvas element that will get used to draw the waveform\n* data?: [number[]], (optional, if not set here you must use the **setWaveData** method) an array of numbers (list of peaks values)\n* layout?: [IWaveLayoutOptions], (optional, if not set the waveform will use its own default values, can be set later using the **setWaveData** method) a layout options object (for a full list of layout options check out the next [layout options chapter](#layout-options))\n* waveformClickCallback?: [IWaveClickCallback], (optional, if not set here you must use the **setWaveformClickCallback** method) a callback function that will get triggered when the user clicks on the waveform, the first parameter of the callback is a number, it tells you the horizontal position of the click, for example a value of 50 means the user clicked in the middle of the waveform, based on that number you can tell your player to seek to that position of the sound (song), to see a working example check out the client source code of [simple waveform example](/examples/simple-waveform/README.md)\n\n## layout options\n\n* waveHeightInPixel: [number] (default: 100) the height of the waveform inside of the canvas element\n* waveBackgroundFillStyle: [string (hex, rgb(a) or css color name) | CanvasGradient | CanvasPattern] (default: 'transparent') the background color of the waveform\n* peakWidthInPixel: [number] (default: 2) the width in pixel of a single peak\n* spaceWidthInPixel: [number] (default: 1) the width in pixel of the space between each peak\n* waveTopPercentage: [number] (default: 50) a percentage value that defines how big the top half is compared to the bottom half, a value of 50 means the top and bottom half are each 50% of the total height, a value of 70 would create a waveform where the top peaks are 70% high and the bottom 30% of the total height, a value of 100 would only draw the top peaks and a value of 0 would only draw the bottom peaks\n* peakTopFillStyle: [string (hex, rgb(a) or css color name) | CanvasGradient | CanvasPattern] (default: '#f222ff') the color used for the top peaks outside of the range (initial peak color, beyond the range)\n* peakBottomFillStyle: [string (hex, rgb(a) or css color name) | CanvasGradient | CanvasPattern] (default: '#ff2975') the color used for the bottom peaks outside of the range (initial peak color, beyond the range)\n* peakTopProgressFillStyle: [string (hex, rgb(a) or css color name) | CanvasGradient | CanvasPattern] (default: '#ffd319') the color used for the top peaks that are inside of the range\n* peakBottomProgressFillStyle: [string (hex, rgb(a) or css color name) | CanvasGradient | CanvasPattern] (default: '#ff901f') the color used for the bottom peaks that are inside of the range\n\nNote: every *FillStyle option accepts as value any [CSS color](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value) (so any color string like 'transparent' or 'blue', any hex color like '#000' (hex for black is the default value) or an rgb(a) color like 'rgb(255,255,255)' or 'rgba(0,0,0,0.8)'), a [canvas gradient](https://developer.mozilla.org/en-US/docs/Web/API/CanvasGradient), or a [canvas pattern](https://developer.mozilla.org/en-US/docs/Web/API/CanvasPattern), read more: [MDN: canvas fillStyle property](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/fillStyle)\n\nNote: there is no option for the width of a waveform, the width will be determined by the amount of peaks values are in your data array, the width you set for the peaks and the width for the space between each peak: \n\n`waveform width = (amount of peaks * peaks width) + ((amount of peaks -1) * peak space width)`\n\n## waveform methods\n\n* setCanvasElement(canvasElement: HTMLCanvasElement): void, to set the canvas element that will be used to draw the waveform\n* getCanvasElement(): HTMLCanvasElement, to get the canvas element\n* setWaveData(data: number[]): void, to set the data array containing the values (numbers) for each peak\n* getWaveData(): number[], to get the data of the peaks\n* setLayoutOptions(layout: IWaveLayoutOptions): void, to pass new layout options to the waveform and change all or some of the layout options after the initialization of the waveform\n* getLayoutOptions(): IWaveLayoutOptions, to get the current layout options\n* setWaveformClickCallback(waveformClickCallback: IWaveClickCallback): void, to add the click callback to the waveform (which will get triggered when the user clicks on the canvas of the waveform)\n* getWaveformClickCallback(): IWaveClickCallback, to get the current click callback\n* draw(range: number, force: boolean): void, if range is not set it will be zero by default, draw will tell the waveform to draw the peaks, range is a percentage value (it must be a number between 0 and 100) the color of the peaks inside of the range percentage can get drawn using a different color to show the current playing progress of the sound (or song), if force is set to true (default false) then the waveform will perform a redraw even if the range did not change (and wave data did not change) since last call\n* destroy(): void, tells the waveform visualizer to shutdown, which removes the click listener\n\n## development: build\n\ninstall the latest nodejs (if you haven't already) [nodejs](https://nodejs.org)  \n\ninstall or update to the latest git version [git scm downloads](https://git-scm.com/downloads) (During installation at the step \"choosing the default editor used by Git\", if like me you are using visual studio code you might want to chose the new option \"use visual studio code as Git's default editor\") (also if like me you are on windows, at the step \"adjusting your PATH environment\", ensure the second radio button option is selected \"git from the line and also from 3rd-party software\" to ensure git is added to the windows PATH, which will allow you to use git with any command line tool like windows powershell for example)  \n\ngit clone this repository to get a local copy  \n\n`git clone git@github.com:chrisweb/waveform-visualizer.git`\n\nopen your favorite command line tool and go to the root directory of this repository  \n\nupdate npm to latest version  \n\n`npm install npm@latest -g`\n\ninstall the dependencies  \n\n`npm i`\n\nto build the distributions, use the following command:  \n\n`npm run build`\n\nin development you can use watch to have the build getting rebuild every time you edit code / save one of the typescript files  \n\n## development: watch\n\n`npm run watch`\n\n## development: linting\n\nto lint the typescript files  \n\n`npm run lint`\n\n## changelog\n\nSee [github releases page](https://github.com/chrisweb/waveform-visualizer/releases)\n\n## contributing (help / PRs appreciated 😊)\n\nyou should first open a ticket and explain what fix or improvement you want to provide on the [github issues page](https://github.com/chrisweb/waveform-visualizer/issues) of this project (remember the github ticket number you will need it for the commit message later on)\n\ngo the [github page of this project](https://github.com/chrisweb/waveform-visualizer) and hit the fork button  \n\nfollow the instructions in the previous section [\"development: build\"](#development-build), but instead of cloning this projects repository, clone your own fork of the project  \n\n`git clone git@github.com:YOUR_USERNAME/waveform-visualizer.git`\n\nwhen you are done coding, commit your local changes (if your commit is related to a ticket start your commit message with the \"#TICKER_NUMBER\", this will \"link\" the commit to the ticket)  \n\n`git commit -m \"#TICKER_NUMBER commit message\"`\n\nnow open your forks github URL in your browser and hit the pull request button\n\n## note to self: publish package on npmjs.com\n\nlogin to npmjs.com  \n\n`npm login`\n\n!!! before using the next the command ensure the version of your package in the package.json has been updated  \n\npublish a new version on npmjs  \n\n`npm publish`\n\n## license\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details\n","funding_links":["https://github.com/sponsors/chrisweb","https://buymeacoffee.com/chriswwweb"],"categories":["UI components and libraries"],"sub_categories":["Visual waveform generators"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchrisweb%2Fwaveform-visualizer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchrisweb%2Fwaveform-visualizer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchrisweb%2Fwaveform-visualizer/lists"}