简体   繁体   中英

(javascript to react) Cannot execute the easyscore tutorial of vexflow

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM