I want to draw a stave on the react and I'm reading the Using EasyScore : Vexflow official tutorial
Below is my react code.
import React, { useRef, useEffect , useState } from 'react'
import Vex from 'vexflow'
import './App.css'
export default function App()
{
const VF = Vex.Flow;
var vf = new VF.Factory({renderer: {elementId: 'boo'}});
var score = vf.EasyScore();
var system = vf.System();
system.addStave({
voices: [score.voice(score.notes('C#5/q, B4, A4, G#4'))]
}).addClef('treble').addTimeSignature('4/4');
vf.draw();
return (
<div id="boo"></div>
)
}
And I got an error in the react TypeError: this.element.appendChild is not a function
new SVGContext
C:/easyscore/KAISTcamp-project3-Server/example/node_modules/vexflow/src/svgcontext.js:41
38 | this.svgNS = 'http://www.w3.org/2000/svg';
39 | const svg = this.create('svg');
40 | // Add it to the canvas:
> 41 | this.element.appendChild(svg);
| ^ 42 |
43 | // Point to it:
44 | this.svg = svg;
Some of my code was involved
App
C:/easyscore/KAISTcamp-project3-Server/example/src/App.js:8
5 | export default function App()
6 | {
7 | const VF = Vex.Flow;
> 8 | var vf = new VF.Factory({renderer: {elementId: 'boo'}});
9 | var score = vf.EasyScore();
10 | var system = vf.System();
11 |
Module.<anonymous>
C:/easyscore/KAISTcamp-project3-Server/example/src/index.js:7
4 | import App from './App';
5 | import reportWebVitals from './reportWebVitals';
6 |
> 7 | ReactDOM.render(
8 | <React.StrictMode>
9 | <App />
10 | </React.StrictMode>,
I would appreciate your help. Please give me some advices.
I can't give advice on your code specifically, but I found this component that's a great start for understanding how to work with Vexflow in React.
Put this in Score.js
in your src
directory:
import React, { useRef, useEffect } from 'react'
import VexFlow from 'vexflow'
const VF = VexFlow.Flow
const { Formatter, Renderer, Stave, StaveNote } = VF
const clefAndTimeWidth = 60
export function Score({
staves = [],
clef = 'treble',
timeSignature = '4/4',
width = 450,
height = 150,
}) {
const container = useRef()
const rendererRef = useRef()
useEffect(() => {
if (rendererRef.current == null) {
rendererRef.current = new Renderer(
container.current,
Renderer.Backends.SVG
)
}
const renderer = rendererRef.current
renderer.resize(width, height)
const context = renderer.getContext()
context.setFont('Arial', 10, '').setBackgroundFillStyle('#eed')
const staveWidth = (width - clefAndTimeWidth) / staves.length
let currX = 0
staves.forEach((notes, i) => {
const stave = new Stave(currX, 0, staveWidth)
if (i === 0) {
stave.setWidth(staveWidth + clefAndTimeWidth)
stave.addClef(clef).addTimeSignature(timeSignature)
}
currX += stave.getWidth()
stave.setContext(context).draw()
const processedNotes = notes
.map(note => (typeof note === 'string' ? { key: note } : note))
.map(note =>
Array.isArray(note) ? { key: note[0], duration: note[1] } : note
)
.map(({ key, ...rest }) =>
typeof key === 'string'
? {
key: key.includes('/') ? key : `${key[0]}/${key.slice(1)}`,
...rest,
}
: rest
)
.map(
({ key, keys, duration = 'q' }) =>
new StaveNote({
keys: key ? [key] : keys,
duration: String(duration),
})
)
Formatter.FormatAndDraw(context, stave, processedNotes, {
auto_beam: true,
})
})
}, [staves])
return <div ref={container} />
}
Then in App.js
you can pass arrays of notes as props to the <Score />
component.
import React from 'react'
import { Score } from './Score'
function App() {
return (
<Score
staves={[
['g3', 'd4', 'e4', 'd4'],
['a4', 'd4', 'e4', 'd4'],
['a4', 'a4', 'b4', 'a4'],
['d4', 'e4', ['g3', 2]],
]}
/>
)
}
export default App;
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.