作为一个VUE新手,我接了一个任务,是写一个可以动态生成的五线谱,通过后台传递数据,每次显示的五线谱不同,我不识谱啊,这就很离谱。

通过一顿Google搜索,我找到了一个不错的JS/TS生成工具,Vexflow 它可以通过Canvas 或 SVG生成五线谱。

说啥也没用,反正都不会用,先安装!

npm i vexflow

先从简单教程开始,如果跳过简单教程的话可以直接看API:

我们先考虑五线谱是怎么组成的,五条线,小节,开始符号(我不知道叫啥),和一大堆音符。

首先看文档中的内容,如何生成第一小节:

准备工作,声明一个Renderer(渲染器)来承载这个SVG,我对这个类进行了一个简单的封装,渲染器的初始化放在了构造函数中。

constructor(element: string, width: number, height: number, scale: number, color: string = '#e6b626') {

this.lineColor = color; //设置线的颜色

this.fillColor = color; //设置音符的颜色

const div = document.querySelector(element) as HTMLDivElement;

const renderer = new Renderer(div, Renderer.Backends.SVG);//初始化渲染器

renderer.resize(width, height); //设置大小

this._context = renderer.getContext();

this._context.setFillStyle(this.fillColor);

this._context.setStrokeStyle(this.lineColor);

this._context.scale(scale, scale); //设置缩放X,Y

}

 element作为一个承载的对象,我这里使用的是一个div来承载,程序会在div中渲染一个SVG。

创建一个新的行:

treble代表高音谱号,在网上可以找到一些开头的例子如图。

高音谱号使用颜色填充,这个音普是没有间隔的一个小节,如果希望整个音普之间都没有间隔,可以给260这个参数调整的稍微大一些,他就会变的很长。

Y轴的意义是调整新行的位置。

public getNewLine(y: number, context: RenderContext = this._context) {

const newStave = new Stave(0, y, 260); //X轴,Y轴,长度

//高音谱号treble 使用颜色填充

newStave.addClef("treble").setStyle({ fillStyle: this.fillColor, strokeStyle: this.lineColor });

return newStave.setContext(context).draw();

}

但是对于一个五线谱来说应该是分小节的,在我小学音乐的认知中,好像4分之4拍是在一个小节中有4个音符。

那么我就要开始在这个新的行后面跟上后续的小节:

/**

* 在指定的stave后生成一个新的小节,返回这个新小节的stave

* @param stave 第一小节的stave对象

* @param context 图谱的上下文

*/

public getLineBar(stave: Stave, context: RenderContext = this._context) {

const newStave = new Stave(stave.getWidth() + stave.getX(), stave.getY(), 260);

newStave.setStyle({ fillStyle: this.fillColor, strokeStyle: this.lineColor });

return newStave.setContext(context).draw();

}

stave.getWidth()+stave.getX() 可以获得到当前这个stave(五线谱)的结束位置,在这后面追加五线谱。

最后,在五线谱上需要出现音符:

/**

* 生成普通音符

* @param stave 要生成音符的小节五线谱

* @param notes 要生成的音符

* @param context 图谱的上下文

* @param beats 节拍 默认4

* @param value 节奏值 默认4

*/

public AddNoteToStave(stave: Stave, notes: Array, context: RenderContext = this._context, beats = 4, value = 4) {

const voice = new Voice({ num_beats: beats, beat_value: value });

voice.addTickables(notes);

new Formatter().joinVoices([voice]).format([voice], 210);

voice.draw(context, stave);

return voice;

}

这个示例我给的默认值是4/4拍的,我觉得可能4/4拍的节奏比较普遍吧?反正我也不懂,先给上。

这里.format([voice], 210); 是指音符之间的间距,通过加大这个值,可以让五线谱中的音符间距加大,但是五线谱不会变化。

这里的notes(音符)是一个StaveNote对象:

const notes1 = [

// A quarter-note C.

new StaveNote({ keys: ["c/4"], duration: "q" })

.addModifier(new Annotation("这是").setVerticalJustification(AnnotationVerticalJustify.BOTTOM), 0),

// A quarter-note D.

new StaveNote({ keys: ["d/4"], duration: "q" }),

// A quarter-note rest. Note that the key (b/4) specifies the vertical

// position of the rest.

new StaveNote({ keys: ["b/4"], duration: "qr" }),

// A C-Major chord.

new StaveNote({ keys: ["c/4", "e/4", "g/4"], duration: "q" })

.addModifier(new Annotation("测试").setVerticalJustification(AnnotationVerticalJustify.BOTTOM), 0),

];

我最不明白的就是这个,不过有个对比图可以看一下。

 我认为Keys指的是这个键位,但是我分不清多瑞咪,所以给我看也没啥意义。

重点是想说一下.addModifier(new Annotation("测试")

.setVerticalJustification(AnnotationVerticalJustify.BOTTOM)

这两段方法的意义在于可以再音符的下面增加文字,如果是歌词和音符之间有紧密关系的话,可以再这里增加一个文字,AnnotationVerticalJustify.BOTTOM是指在音符的下方出现。

目前我已知的就,我现在还不知道(♪)和跑跑(♫♬)如何处理,我也在继续研究中,如果有更好的方式我会继续补充。

文章链接

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。