From d6e5f84af70caf81451b8bcf7dfad0ac60ebb5b7 Mon Sep 17 00:00:00 2001 From: Harrison Deng Date: Sat, 23 Apr 2022 08:51:52 -0500 Subject: [PATCH] Added a Mapping Demonstration tutorial page. Moved numerical mapping code to the "bins" support module. --- src/mappings/coloring.js | 2 +- src/mappings/dimensions.js | 2 +- src/mappings/mappings.js | 3 +- src/mappings/numeric.js | 57 ------ src/support/bins.js | 53 ++++++ src/support/support.js | 4 +- tutorials/MappingDemonstration.html | 265 ++++++++++++++++++++++++++++ tutorials/VisMusicPlayer.html | 210 +--------------------- 8 files changed, 326 insertions(+), 270 deletions(-) delete mode 100644 src/mappings/numeric.js create mode 100644 tutorials/MappingDemonstration.html diff --git a/src/mappings/coloring.js b/src/mappings/coloring.js index f8f8871..e759f05 100644 --- a/src/mappings/coloring.js +++ b/src/mappings/coloring.js @@ -1,6 +1,6 @@ import { hslaToCssHsla, hslaToRgba, parseColorToHsla, parseColorToRgba, rgbaToCssRgba, rgbaToHexRgba, rgbaToHsla } from "../support/colors.js"; import VisUpdateRouter from "../visualization/VisUpdateRouter.js"; -import { numericalBins } from "./numeric.js"; +import { numericalBins } from "../support/bins.js"; /**@module */ diff --git a/src/mappings/dimensions.js b/src/mappings/dimensions.js index 323979a..d3aedc6 100644 --- a/src/mappings/dimensions.js +++ b/src/mappings/dimensions.js @@ -1,5 +1,5 @@ import VisUpdateRouter from "../visualization/VisUpdateRouter.js"; -import { numericalBins } from "./numeric.js"; +import { numericalBins } from "../support/bins.js"; /**@module */ diff --git a/src/mappings/mappings.js b/src/mappings/mappings.js index 8328696..4e9da11 100644 --- a/src/mappings/mappings.js +++ b/src/mappings/mappings.js @@ -1,6 +1,5 @@ import * as dimensions from "./dimensions.js"; -import * as numeric from "./numeric.js"; import * as coloring from "./coloring.js"; -export { dimensions, numeric, coloring }; \ No newline at end of file +export { dimensions, coloring }; \ No newline at end of file diff --git a/src/mappings/numeric.js b/src/mappings/numeric.js deleted file mode 100644 index a74a78a..0000000 --- a/src/mappings/numeric.js +++ /dev/null @@ -1,57 +0,0 @@ -import { createUniAvgSel } from "../support/bins.js"; -import { createEaseLinear } from "../support/easings.js"; -import VisUpdateRouter from "../visualization/VisUpdateRouter.js"; - -/**@module */ - -/** - * - * @callback numericalGetter - * @returns {number} The number this value currently represents. - */ - -/** - * @callback numericalSetter - * @param {number} value The new numerical value to update to. - */ - -// PEND: Warnings about interpolator not being defined are broken. Docs generate fine. - -/** - * Maps the average of a range of bins to numerical value defined by a getter and a setter. - * - * @param {object} conf A configuration for how to map a numerical value. - * @param {number} conf.minVal The minimum value of the numerical value. - * @param {number} conf.maxVal The maximum value of the numerical value. - * @param {number} conf.lowerBin The lower bin of the range of bins this value is to be mapped to. - * @param {module:mappings/numeric~numericalGetter} conf.getter The getter callback to be used to get the current number. - * @param {module:mappings/numeric~numericalSetter} conf.setter The setter callback to be used to set the new number. - * @param {VisUpdateRouter} conf.visUpdateRouter the visualizer update manager this mapping corresponds with. - * @param {module:support/bins~binSelector} [conf.binSelector=undefined] The bin selector function to use to get a number for the mapping. - * @param {number} [conf.upperBin=undefined] The upper bin of the range of bins this value is to be mapped to. - * @param {module:support/easings~interpolator} [conf.interpolator=undefined] The interpolation function to use. - * @param {boolean} [conf.reversed = false] If true, then high amplitudes will be mapped to low values and vice versa. - * @returns {{lower: number, upper: number, listener: VisUpdateRouter.visualizerRangedUpdateListener}} An object containing the lower and upper bounds for the range of a listener, which is also in the object. - */ -export function numericalBins({ minVal, maxVal, lowerBin, getter, setter, visUpdateRouter, binSelector = undefined, upperBin = undefined, interpolator = undefined, reversed = false }) { - if (!binSelector) binSelector = createUniAvgSel(); - if (!interpolator) interpolator = createEaseLinear(2); - const rangedListener = { - lower: lowerBin, - upper: upperBin ? upperBin : lowerBin, - listener: (timeDelta, bins) => { - // TODO: Future: add weighting / distribution system? - let normAvg = binSelector(bins); - normAvg /= 255; - - const range = maxVal - minVal; - let interpolated = interpolator((getter() - minVal) / range, normAvg, Math.min(timeDelta, 1)); - if (reversed) interpolated = 1 - interpolated; - setter(minVal + range * interpolated); - } - }; - if (visUpdateRouter.addUpdateListener(rangedListener)) { - return rangedListener; - } - return null; // Technically doesn't occur since the functions are anonymous? -} \ No newline at end of file diff --git a/src/support/bins.js b/src/support/bins.js index 3fe28d3..98f5dbc 100644 --- a/src/support/bins.js +++ b/src/support/bins.js @@ -1,5 +1,7 @@ /**@module */ +import { createEaseLinear } from "./easings.js"; + /** * @callback binSelector * @param {number[]} bins Array of frequency bins. @@ -20,4 +22,55 @@ export function createUniAvgSel() { normAvg /= bins.length; return normAvg; }; +} + +/** + * + * @callback numericalGetter + * @returns {number} The number this value currently represents. + */ + +/** + * @callback numericalSetter + * @param {number} value The new numerical value to update to. + */ + +// PEND: Warnings about interpolator not being defined are broken. Docs generate fine. + +/** + * Maps the average of a range of bins to numerical value defined by a getter and a setter. + * + * @param {object} conf A configuration for how to map a numerical value. + * @param {number} conf.minVal The minimum value of the numerical value. + * @param {number} conf.maxVal The maximum value of the numerical value. + * @param {number} conf.lowerBin The lower bin of the range of bins this value is to be mapped to. + * @param {module:support/bins~numericalGetter} conf.getter The getter callback to be used to get the current number. + * @param {module:support/bins~numericalSetter} conf.setter The setter callback to be used to set the new number. + * @param {VisUpdateRouter} conf.visUpdateRouter the visualizer update manager this mapping corresponds with. + * @param {module:support/bins~binSelector} [conf.binSelector=undefined] The bin selector function to use to get a number for the mapping. + * @param {number} [conf.upperBin=undefined] The upper bin of the range of bins this value is to be mapped to. + * @param {module:support/easings~interpolator} [conf.interpolator=undefined] The interpolation function to use. + * @param {boolean} [conf.reversed = false] If true, then high amplitudes will be mapped to low values and vice versa. + * @returns {{lower: number, upper: number, listener: VisUpdateRouter.visualizerRangedUpdateListener}} An object containing the lower and upper bounds for the range of a listener, which is also in the object. + */ +export function numericalBins({ minVal, maxVal, lowerBin, getter, setter, visUpdateRouter, binSelector = undefined, upperBin = undefined, interpolator = undefined, reversed = false }) { + if (!binSelector) binSelector = createUniAvgSel(); + if (!interpolator) interpolator = createEaseLinear(2); + const rangedListener = { + lower: lowerBin, + upper: upperBin ? upperBin : lowerBin, + listener: (timeDelta, bins) => { + let normAvg = binSelector(bins); + normAvg /= 255; + + const range = maxVal - minVal; + let interpolated = interpolator((getter() - minVal) / range, normAvg, Math.min(timeDelta, 1)); + if (reversed) interpolated = 1 - interpolated; + setter(minVal + range * interpolated); + } + }; + if (visUpdateRouter.addUpdateListener(rangedListener)) { + return rangedListener; + } + return null; // Technically doesn't occur since the functions are anonymous? } \ No newline at end of file diff --git a/src/support/support.js b/src/support/support.js index 1c38d43..a274fc9 100644 --- a/src/support/support.js +++ b/src/support/support.js @@ -1,5 +1,5 @@ import * as colors from "./colors.js"; import * as easings from "./easings.js"; +import * as bins from "./bins.js"; - -export { colors, easings }; \ No newline at end of file +export { colors, easings, bins }; \ No newline at end of file diff --git a/tutorials/MappingDemonstration.html b/tutorials/MappingDemonstration.html new file mode 100644 index 0000000..1c18827 --- /dev/null +++ b/tutorials/MappingDemonstration.html @@ -0,0 +1,265 @@ + + + + +
+

Mapping Demonstration

+

Here we will show off some of the mappings currently in the library. This list may not be exhaustive, and you should check the actual documentation for all the mapping modules. Additionally, feel free to create your own mappings using the provided support tools!

+
+
+
+
+
+
+
+

Mapping Width

+

The first one here shows mapping the width.

+
+
+
+

+            ask.mappings.dimensions.width({ // The mapping function.
+                element: document.getElementById("width-map-demo"), // The element this mapping applies to.
+                growLower: 2, // The smallest value the width can be. 
+                growUpper: 8, // The largest value the width can be.
+                unit: "rem", // The unit used for the above two values.
+                lowerBin: 24, // The lower bin to map to.
+                upperBin: 60, // The upper bin to map to.
+                visUpdateRouter: player.visUpdateRouter, // The update router to use for the mapping.
+                interpolator: ask.support.easings.createEaseLinear(2.5) // The interpolation function to use.
+            });
+        
+
+
+

Mapping Height

+

This next one does the same, except with height.

+
+
+
+

+            ask.mappings.dimensions.height({ // Only big difference is the function being called.
+                element: document.getElementById("height-map-demo"),
+                growLower: 2, // height smallest can be 2 rem, tallest can be 8 rem.
+                growUpper: 8,
+                unit: "rem",
+                lowerBin: 80, // Changed the bin range just for fun.
+                upperBin: 120,
+                visUpdateRouter: player.visUpdateRouter,
+                interpolator: ask.support.easings.createEaseLinear(2.5)
+            });
+        
+
+
+

Mapping Multiple Style Properties

+

What's that? you want multiple mappings on one? Here it is!

+
+
+
+

+            const squareElemConf = { // Use an object for commonly used mappings.
+                element: document.getElementById("square-map-demo"), // Same stuff as before..
+                growLower: 0.5,
+                growUpper: 8,
+                unit: "rem",
+                lowerBin: 128,
+                upperBin: 160,
+                visUpdateRouter: player.visUpdateRouter,
+                interpolator: ask.support.easings.createEaseLinear(2.5)
+            }
+            ask.mappings.dimensions.width(squareElemConf); // Apply them easily!
+            ask.mappings.dimensions.height(squareElemConf);
+        
+
+
+

Mapping Font Size

+

You can map font size to frequency bins as well.

+
+
+ Wonky text! +
+
+

+            ask.mappings.dimensions.fontSize({
+                element: document.getElementById("font-size-map-demo"), // Nothing new here, just calling a different mapping function.
+                growLower: 1,
+                growUpper: 3,
+                unit: "rem",
+                lowerBin: 200,
+                upperBin: 256,
+                visUpdateRouter: player.visUpdateRouter,
+                interpolator: ask.support.easings.createEaseLinear(2)
+            });
+        
+
+
+

Mapping Font Color

+

Now for a bit more of an eccentric mapping, you can map the color of a font to the music!

+
+
+ Hello colors! +
+
+

+            ask.mappings.coloring.fontColorRgba({ // Under mappings, the text module. We just want to map one of the RGBA color components...
+                element: document.getElementById("font-color-rgba-map-demo"), // The element to map (same as above examples).
+                select: "r", // Choose the red component.
+                lowerBin: 128, // All other values are what we've seen above.
+                upperBin: 160,
+                visUpdateRouter: player.visUpdateRouter,
+                interpolator: ask.support.easings.createEaseLinear(2.5)
+            });
+        
+
+
+

In the same vein of mapping, we can also map HSL values. If you haven't heard of HSL values, you can read up about it anywhere online really, but essentially, it's another way of describing a color where a hue is used to describe a color, and then the color is adjusted by its saturation and lightness. Importantly for your case, it may make it easier to achieve the type of dynamic color mapping you're looking for (potentially when used in conjunction with any of RGBA components).

+
+
+ Hello more colors! +
+
+

+            ask.mappings.coloring.fontColorHsla({ // Similar to the rgba example, except now with hsla.
+                element: document.getElementById("font-color-hsla-map-demo"),
+                select: "h", // Selecting the "hue" component.
+                lowerBin: 200,
+                upperBin: 220,
+                visUpdateRouter: player.visUpdateRouter,
+                interpolator: ask.support.easings.createEaseLinear(2.5)
+            })
+        
+
+
+

Mapping Background Color

+

This is kind of like the one for fonts, except, instead, rgba for background colors!

+
+
+
+
+

+            ask.mappings.coloring.backgroundColorRgba({
+                element: document.getElementById("bg-color-rgba-map-demo"),
+                select: "g", // Selecting the green component this time...
+                lowerBin: 200,
+                upperBin: 220,
+                visUpdateRouter: player.visUpdateRouter,
+                interpolator: ask.support.easings.createEaseLinear(2.5)
+            });
+        
+

And of course we can use hsla values too.

+
+
+
+
+

+            ask.mappings.coloring.backgroundColorHsla({
+                element: document.getElementById("bg-color-hsla-map-demo"),
+                select: "h", 
+                lowerBin: 200,
+                upperBin: 220,
+                visUpdateRouter: player.visUpdateRouter,
+                interpolator: ask.support.easings.createEaseLinear(2.5)
+            });
+        
+
+
+ \ No newline at end of file diff --git a/tutorials/VisMusicPlayer.html b/tutorials/VisMusicPlayer.html index 4800c61..743c079 100644 --- a/tutorials/VisMusicPlayer.html +++ b/tutorials/VisMusicPlayer.html @@ -5,6 +5,7 @@

Visualizing Music

This is the fun part. We can use a {@link VisualizedMusicPlayer} and a {@link MusicPlaylist} to create a music player that is like {@link MusicPlayer} but with the ability to automatically fetch the current {@link Visualizer}. On top of that, it then routes that visualizer data to {@link VisualizerUpdateManager} which can be to make much more refined mappings.

+ This library comes with a variety of mapping tools:

Visualization

-

The actual visualization can be performed in a variety of ways. We can use canvases, or even better, actual HTML elements! Remember to hit the play button above to see the mappings in effect!

+

The actual visualization can be performed in a variety of ways. We can use canvases, or even better, actual HTML elements! We'll demonstrate an example of the latter below, but check out [the Mapping Demonstration tutorial]{@tutorial MappingDemonstration} for many other mappings! Hit the play button to see the what the mapping did.

-

Mapping Width

-

The first one here shows mapping the width.

-

To do this, we need to perform what's called a mapping between a range of frequency bins, or a single frequency bin, and the width property of the div element. We can then define a multitude of parameters to specify how the mapping will work. Following is the code that produced the example above with comment annotations.

+

Here, we perform what's called a mapping between a range of frequency bins, or a single frequency bin, and the width property of the div element. We can then define a multitude of parameters to specify how the mapping will work. Following is the code that produced the example above with comment annotations.


             ask.mappings.dimensions.width({ // The mapping function.
                 element: document.getElementById("width-map-demo"), // The element this mapping applies to.
@@ -54,138 +53,6 @@
             });
         
-
-

Mapping Height

-

This next one does the same, except with height.

-
-
-
-

-            ask.mappings.dimensions.height({ // Only big difference is the function being called.
-                element: document.getElementById("height-map-demo"),
-                growLower: 2, // height smallest can be 2 rem, tallest can be 8 rem.
-                growUpper: 8,
-                unit: "rem",
-                lowerBin: 80, // Changed the bin range just for fun.
-                upperBin: 120,
-                visUpdateRouter: player.visUpdateRouter,
-                interpolator: ask.support.easings.createEaseLinear(2.5)
-            });
-        
-
-
-

Mapping Multiple Style Properties

-

What's that? you want multiple mappings on one? Here it is!

-
-
-
-

-            const squareElemConf = { // Use an object for commonly used mappings.
-                element: document.getElementById("square-map-demo"), // Same stuff as before..
-                growLower: 0.5,
-                growUpper: 8,
-                unit: "rem",
-                lowerBin: 128,
-                upperBin: 160,
-                visUpdateRouter: player.visUpdateRouter,
-                interpolator: ask.support.easings.createEaseLinear(2.5)
-            }
-            ask.mappings.dimensions.width(squareElemConf); // Apply them easily!
-            ask.mappings.dimensions.height(squareElemConf);
-        
-
-
-

Mapping Font Size

-

You can map font size to frequency bins as well.

-
-
- Wonky text! -
-
-

-            ask.mappings.dimensions.fontSize({
-                element: document.getElementById("font-size-map-demo"), // Nothing new here, just calling a different mapping function.
-                growLower: 1,
-                growUpper: 3,
-                unit: "rem",
-                lowerBin: 200,
-                upperBin: 256,
-                visUpdateRouter: player.visUpdateRouter,
-                interpolator: ask.support.easings.createEaseLinear(2)
-            });
-        
-
-
-

Mapping Font Color

-

Now for a bit more of an eccentric mapping, you can map the color of a font to the music!

-
-
- Hello colors! -
-
-

-            ask.mappings.coloring.fontColorRgba({ // Under mappings, the text module. We just want to map one of the RGBA color components...
-                element: document.getElementById("font-color-rgba-map-demo"), // The element to map (same as above examples).
-                select: "r", // Choose the red component.
-                lowerBin: 128, // All other values are what we've seen above.
-                upperBin: 160,
-                visUpdateRouter: player.visUpdateRouter,
-                interpolator: ask.support.easings.createEaseLinear(2.5)
-            });
-        
-
-
-

In the same vein of mapping, we can also map HSL values. If you haven't heard of HSL values, you can read up about it anywhere online really, but essentially, it's another way of describing a color where a hue is used to describe a color, and then the color is adjusted by its saturation and lightness. Importantly for your case, it may make it easier to achieve the type of dynamic color mapping you're looking for (potentially when used in conjunction with any of RGBA components).

-
-
- Hello more colors! -
-
-

-            ask.mappings.coloring.fontColorHsla({ // Similar to the rgba example, except now with hsla.
-                element: document.getElementById("font-color-hsla-map-demo"),
-                select: "h", // Selecting the "hue" component.
-                lowerBin: 200,
-                upperBin: 220,
-                visUpdateRouter: player.visUpdateRouter,
-                interpolator: ask.support.easings.createEaseLinear(2.5)
-            })
-        
-
-
-

Mapping Background Color

-

This is kind of like the one for fonts, except, instead, rgba for background colors!

-
-
-
-
-

-            ask.mappings.coloring.backgroundColorRgba({
-                element: document.getElementById("bg-color-rgba-map-demo"),
-                select: "g", // Selecting the green component this time...
-                lowerBin: 200,
-                upperBin: 220,
-                visUpdateRouter: player.visUpdateRouter,
-                interpolator: ask.support.easings.createEaseLinear(2.5)
-            });
-        
-

And of course we can use hsla values too.

-
-
-
-
-

-            ask.mappings.coloring.backgroundColorHsla({
-                element: document.getElementById("bg-color-hsla-map-demo"),
-                select: "h", 
-                lowerBin: 200,
-                upperBin: 220,
-                visUpdateRouter: player.visUpdateRouter,
-                interpolator: ask.support.easings.createEaseLinear(2.5)
-            });
-        
-
-
\ No newline at end of file