-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathverovio.js
84 lines (74 loc) · 2.83 KB
/
verovio.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import React from "react"
import Layout from "../components/layout"
import Popup from "../components/popup"
import "./verovio.css"
const Verovio = () => {
// This state keeps track of the SVG rendered by Verovio
const [svg, setSvg] = React.useState()
// This state indicates whether we need to show a popup or not
const [showPopup, setShowPopup] = React.useState(false)
// This state hold data to show in a popup
const [popupData, setPopupData] = React.useState()
// This will let us access the SVG DOM once it's available.
const verRef = React.useRef()
React.useEffect(() => {
// We load Verovio dynamically. useEffect() runs after rendering
const script = document.createElement("script");
script.type = "application/javascript";
script.src =
"https://www.verovio.org/javascript/latest/verovio-toolkit-wasm.js";
document.body.appendChild(script);
const verovioHandler = () => {
window.verovio.module.onRuntimeInitialized = async _ => {
const tk = new window.verovio.toolkit()
fetch("https://www.verovio.org/examples/downloads/Schubert_Lindenbaum.mei")
.then((response) => response.text())
.then((meiXML) => {
tk.setOptions({
scale: 30,
landscape: true,
adjustPageWidth: true
});
setSvg(tk.renderData(meiXML, {}));
});
}
}
script.defer = true;
script.addEventListener("load", verovioHandler);
// Event handlers should always be removed.
return () => {
script.removeEventListener("load", verovioHandler);
}
}, []) // [] is used to run this once.
// useLayoutEffect runs after changes to the HTML DOM. We use it to interact with the SVG DOM once it's loaded
React.useLayoutEffect(() => {
// This is give us access to the Verovio SVG DOM to add interactivity.
// A more "reacty" way of handling this would require routing SVG elements of note to React components
// (Like what we do with TEI).
if (verRef.current) {
const notation = verRef.current;
notation.querySelectorAll('g.beam').forEach(function (chord) {
chord.addEventListener("click", (event) => {
// We adjust the state to show a popup.
setPopupData({
title: "Info",
toggle: () => {setShowPopup(false)},
content: "You clicked on some beamed notes!"
})
setShowPopup(true)
});
})
}
}, [svg]) // this will run every time the svg state changes.
const score = svg
? <div dangerouslySetInnerHTML={{__html: svg}} ref={verRef}/> : "Loading Verovio..."
const popup = showPopup ? <Popup {...popupData} >{popupData.content}</Popup> : null
return (
<Layout location="home">
<h1>Verovio example</h1>
{score}
{popup}
</Layout>
)
}
export default Verovio