humdrum-notation-plugin

A javascript plugin for displaying music notation on a webpage using Humdrum data

Resizing music notation

Automatic resizing of a musical example can be done with the Humdrum notation plugin by setting the autoResize option to true.

This page demonstrates how to automatically resize music notation when the web browser changes size, as well as resizing music notation inside of a <div> element (or similar) within a webpage. Resizing in this context means to change the width of the music while keeping the same zoom scale. In other words, the music is re-typeset whenever the width of its HTML container changes.

Resizing music in a div

The following example music can be resized according to the width red box that contains it. Try resizing the red box by dragging the bottom right corner of the box. You can even drag the box out into the right margin of the page beyond the text. When the music cannot be fully displayed inside of the box, the contents of the box will become scrollable.

The above example was generated with this HTML code:

<style>
div.resize {
   min-width: 200px;
   width: 260px;
   position: relative;
   resize: both;
   overflow: scroll;
   border: 1px solid #ff00aa77;
}
</style>
<div style="height:150px;" class="resize">
<script>
displayHumdrum({
   source: "example",
   pageMarginRight: 100,
   autoResize: true,
   scale: 28,
   url: "https://raw.githubusercontent.com/craigsapp/mozart-piano-sonatas/master/kern/sonata11-1a.krn"
})</script>
<script type="text/x-humdrum" id="example"></script>
</div>

Note that the Safari web-browser will not let you resize an element to make it smaller, only larger.

Resizing incipits

Incipits are short excerpts from the start of a work or movement. Use the incipit: true option to display only the first system of the music contained in the example. Then to resize the incipit, also add the autoResize: true option as demonstrated in the following example. Try dragging the right bottom corner of the red box to the left and right to resize the incipit:

Here is the HTML code that created the above example:

<style>
div.resize-incipit {
   min-width: 200px;
   width: 340px;
   resize: horizontal;
   overflow: hidden;
   border: 1px solid #ff00aa77;
}
</style>
<div class="resize-incipit">
<script>
displayHumdrum({
   source: "example2",
   autoResize: true,
   incipit: true,
   scale: 35,
   pageMarginRight: 100,
   url: "https://raw.githubusercontent.com/craigsapp/mozart-piano-sonatas/master/kern/sonata11-1a.krn"
})</script>
<script type="text/x-humdrum" id="example2"></script>
</div>

Full-page resizing

This webpage limits the text and music notation to a region smaller than the full width of the web-browser window. Click on this link to view a full-page resizing example, using the first movement of Beethoven’s Moonlight sonata. The music will be resized to the full width of the window and overflow of the music off the bottom of the page will be scrollable.

Here is an example of the music when the browser is wide:

And here is an example of the music when the browser is narrow:

You can also rescale the page (typically with the command or control key in combination with the plus/minus keys). Here is an example of zooming out to view the full Moonlight sonata first movement in the web browser:

You can click on any of the above images to view them in more detail.

The HTML code of the example webpage is:

<html>
<head>
<title>Moonlight sonata</title>
<script src="https://verovio-script.humdrum.org/scripts/verovio-toolkit.js"></script>
<script src="https://plugin.humdrum.org/scripts/humdrum-notation-plugin.js"></script>
<script>var vrvToolkit = new verovio.toolkit()</script>
</head>
<body>

<h1 style="text-align: center; font-weight: normal">
   Beethoven: Piano sonata no. 14 in C&sharp; minor, op. 27/2, mvmt. 1
</h1>

<script>
displayHumdrum({
   source: "example",
   autoResize: true,
   url: "https://raw.githubusercontent.com/craigsapp/beethoven-piano-sonatas/master/kern/sonata14-1.krn"
})</script>
<script type="text/x-humdrum" id="example"> </script>

</body>
</html>

Try copy-and-pasting this source code into an HTML page and view it on your local browser (usually by double-clicking on the file in the Desktop).

Resizing on your own

Instead of using autoResize: true, you can alternatively control music re-drawing yourself by setting up an event listener that triggers when the size of the window changes. Here is an example of this:

Here is the source code for the above example:


<script>
displayHumdrum({
   source: "manual",
   scale: 35,
   url: "https://raw.githubusercontent.com/craigsapp/mozart-piano-sonatas/master/kern/sonata11-1a.krn",
   postFunction: function (baseid) {
      window.addEventListener("resize", function() {
         displayHumdrum(baseid);
      })
   }
})</script>

<div class="full-width">
<script type="text/x-humdrum" id="manual"></script>
</div>


<style>
.full-width {
   position: relative;
   width: 100vw;
   margin-left: -50vw;
   left: 50%;
   background-color: #ffcc00;
   z-index: 1000;
}
</style>


The postFunction parameter in the options to displayHumdrum() contains this function:

function (baseid) {
   window.addEventListener("resize", function() {
      displayHumdrum(baseid);
   })
}

which adds and event listener that is run every time the window is resized (resizing based on other elements inside of a webpage is more difficult to implement). The function given to postFuction will be given the ID of the Humdrum script (which is “manual” in this case). The function call displayHumdrum(id) can be used after initial setup to redraw the notation with the data store in the Humdrum script that has the given ID.

Resizing with clicks

Here is another example where you can click on the music notation to toggle between paragraph width and full-screen width:

Each time the music is clicked on, it is re-typeset for the space it has available. Also notice in the HTML content below for this example, the music is displayed in two sizes: at scale:20 when it is in the paragraph, and at scale:35 when it is displayed with a full-window width.

<script>
var smallprint = 20;
var largeprint = 55;
displayHumdrum({
   source: "toggle",
   scale: smallprint,
   url: "https://raw.githubusercontent.com/craigsapp/mozart-piano-sonatas/master/kern/sonata11-1a.krn",
   postFunction: function (baseid) {
      window.addEventListener("resize", function() {
         displayHumdrum(baseid);
      });
      var mydiv = document.querySelector("#mydiv");
      mydiv.addEventListener("click", function (event) {
         if (this.className) {
            this.className = "";
            setHumdrumOption(baseid, "scale", smallprint);
         } else {
            this.className = "full-window";
            setHumdrumOption(baseid, "scale", largeprint);
         }
         displayHumdrum(baseid);
      });
      
   }
})
</script>

<div id="mydiv">
<script type="text/x-humdrum" id="toggle"></script>
</div>

<style>
.full-window {
   position: relative;
   width: 100vw;
   margin-left: -50vw;
   left: 50%;
   background-color: #ffcc00;
   z-index: 1000;
}
</style>

Zoom with clicks

If you want to keep the same layout for the small and large versions of some music notation, then it is not necessary to re-typeset the music for different sizes. In this example, clicking on the music will expand the notation to the full-width of the music, where the resizing is done by scaling the SVG image to the full width of the window rather than regenerating a new SVG image:

Notice that this example is much more responsive when clicking on the notation. This is because the music notation is not recalculated after each click—only the size of the SVG image is changed. Also notice that the SVG image’s size will be adjusted to the full width of the window when in expanded view.

Here is the HTML code for the example:


<script>
displayHumdrum({
   source: "zoom",
   scale: 20,
   url: "https://raw.githubusercontent.com/craigsapp/mozart-piano-sonatas/master/kern/sonata11-1a.krn"
})
</script>

<div id="mydiv-zoom">
<script type="text/x-humdrum" id="zoom"></script>
</div>


<style>
.zoom-window {
   position: relative;
   width: 100vw;
   height: auto;
   margin-left: -50vw;
   left: 50%;
   background-color: #ffcc00;
   z-index: 1000;
}
.zoom-window svg {
   width: 100% !important;
   height: 100% !important;
}
</style>

<script>
   var mydiv = document.querySelector("#mydiv-zoom");
   mydiv.addEventListener("click", function (event) {
      this.className = this.className ? "" : "zoom-window";
   });
</script>


Incipit to full page

Below is an example of showing an incipit in the text region. After clicking on the incipit, the full score will be displayed in the div, covering the entire page. Clicking on the full-page example will revert the example to the incipit again.

HTML code for this example:


<script>
var smallprint = 25;
var largeprint = 35;
var INCIPITS = {};
displayHumdrum({
   source: "toggle-incipit",
   scale: smallprint,
   incipit: true,
   url: "https://raw.githubusercontent.com/craigsapp/mozart-piano-sonatas/master/kern/sonata11-3.krn",
   postFunction: function (baseid) {
      window.addEventListener("resize", function() {
         displayHumdrum(baseid);
      });
      var mydiv = document.querySelector("#mydiv2");
      mydiv.addEventListener("click", function (event) {

         setTimeout(function() {
            document.body.style.cursor = "progress";
         }, 0);

         var svgcontainer = document.querySelector("[id='" + baseid + "-svg']");
         svgcontainer.style.visibility = "hidden";

         if (this.className) {
            this.className = "";
            setHumdrumOption(baseid, "scale", smallprint);
            setHumdrumOption(baseid, "incipit", true);
            setHumdrumOption(baseid, "header", false);
         } else {
            this.className = "entire-window";
            setHumdrumOption(baseid, "scale", largeprint);
            setHumdrumOption(baseid, "incipit", false);
            setHumdrumOption(baseid, "header", true);
            if (!INCIPITS[baseid]) {
               INCIPITS[baseid] = svgcontainer.innerHTML;
            }
         }

         setTimeout(function() {
            if (getHumdrumOption(baseid, "incipit")) {
               svgcontainer.innerHTML = INCIPITS[baseid];
	    } else {
               displayHumdrum(baseid);
            }
            svgcontainer.style.visibility = "visible";
            document.body.style.cursor = "default";
         }, 50);
      });
      
   }
})
</script>

<div id="mydiv2">
<script type="text/x-humdrum" id="toggle-incipit"></script>
</div>

<style>
.entire-window {
   position: fixed;
   top: 0;
   bottom: 0;
   left: 50%;
   width: 90vw;
   overflow-y: scroll;
   margin-left: -45vw;
   padding-right: 10px; /* space needed for scroll-bar */
   background-color: #ffcc00;
   z-index: 1000;
}
</style>

The Javascript code is fairly complicated to (1) buffering the incipit SVG so that it does not have to be regenerated every time (the incipit does not resize, so no need to generate it again). An in-progress icon is also displayed for the mouse while the full-page notation is generated, since this takes a second or two.