Accessing StaveNote objects

942 views
Skip to first unread message

cortez

unread,
Nov 3, 2015, 8:54:50 AM11/3/15
to vexflow
Hi,

I am currently storing my StaveNote objects in an array and stuffing that into a variable for later access. I run a function createNotes, like this:

var notes = createNotes(clef, note_data);

Then I do something like:

var voice = new Vex.Flow.Voice({num_beats: 4, beat_value: 4, resolution: Vex.Flow.RESOLUTION});
voice.addTickables(notes);
// Format and draw
Vex.Flow.Formatter.FormatAndDraw(ctx, stave, notes);


I suspect this is not the best way to store StaveNote objects for later access, however. I have some user interaction, such as setting the colour of the note on mouse click, which I've been doing like this:

note.setStyle({fillStyle: "blue", strokeStyle: "blue"});

Where note is one of my stored StaveNotes. This does not work, however, unless I immediately call:

note.draw();

Also if I try and access the bounding box of the notehead of one of my stored notes I get an error, "Can't call getBoundingBox on an unformatted note."

So, I guess I need to access notes in a different way?

C

cortez

unread,
Nov 5, 2015, 9:05:41 AM11/5/15
to vexflow
For some reason I thought simply setting the style should have been enough, but of course I have to clear and then redraw the canvas (or preferably the relevant part of it), which is what I'm doing now.

I figured out I could access the StaveNote objects directly through voice.tickables.

C

Mohit Muthanna Cheppudira

unread,
Nov 5, 2015, 9:09:28 AM11/5/15
to vexflow
Hey,

Interactivity is far simpler in SVG -- (infact almost everything is better in SVG, but that's a separate conversation.) Take a look at the interactive tests in tests/stavenote_tests.js for an example of how to change color on a mouse hover. You can make it work for just heads, stems, flags, all together, include/exclude modifiers, etc.

Right now only stave notes have been instrumented for interactivity -- but I hope to over time instrument the whole API. (It's not difficult, but there's just a lot to cover.)

Mohit.

--
--
You received this message because you are subscribed to the Google
Groups "vexflow" group.
To post to this group, send email to vex...@googlegroups.com
To unsubscribe from this group, send email to
vexflow+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/vexflow?hl=en

---
You received this message because you are subscribed to the Google Groups "vexflow" group.
To unsubscribe from this group and stop receiving emails from it, send an email to vexflow+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Mohit Muthanna [mohit (at) muthanna (uhuh) com]

cortez

unread,
Nov 9, 2015, 6:33:54 AM11/9/15
to vexflow, mo...@muthanna.com
Thanks Mohit. Indeed I had breifly looked at SVG and dismissed it, but having now investigated it more thoroughly it seems like the best way to go.

I looked at tests/stavenote_tests.js, but I was a bit puzzled as to how to actually access the underlying SVG path object so as to attach an event listener. The following at line 463 seems relevant:

var item = staveNote.getElem();

This seems like it should be grabbing the elem property, which is presumably where the DOM element is referenced, but in my own tests with the Raphael backend I've only ever found that to be undefined. For example:

<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="raphael-min.js"></script>
<script src="vexflow-min.js"></script>
</head>
<body>
<div id="vxf-div"></div>
<script>
$(document).ready(function () {
 
  var div = $("#vxf-div")[0];
  var renderer = new Vex.Flow.Renderer(div, Vex.Flow.Renderer.Backends.RAPHAEL);

  var ctx = renderer.getContext();
  var stave = new Vex.Flow.Stave(10, 0, 500);
  stave.addClef("treble").setContext(ctx).draw();

  var note = new Vex.Flow.StaveNote({ keys: ["c/4"], duration: "q" });

  var voice = new Vex.Flow.Voice({num_beats: 1, beat_value: 4, resolution: Vex.Flow.RESOLUTION});

  voice.addTickables([note]);

  var formatter = new Vex.Flow.Formatter().joinVoices([voice]).format([voice], 500);

  voice.draw(ctx, stave);
  console.log(note.getElem()); // This is always 'undefined' for me.
 
});
</script>
</body>


What am I doing wrong?

Best,
C

Mohit Muthanna Cheppudira

unread,
Nov 10, 2015, 10:00:02 AM11/10/15
to vexflow
Hi cortez,

You should be using the SVG backend instead of RAPHAEL, which has been deprecated.

SVGContext is lighter weight, faster, has no external dependencies, and supports the interactivity features mentioned earlier.

Mohit.

cortez

unread,
Nov 10, 2015, 1:08:40 PM11/10/15
to vexflow, mo...@muthanna.com
Thanks so much Mohit, that worked! I had completely missed that the RAPHAEL context had been deprecated, apologies.

I was a bit reluctant to swap to SVG initially, having worked a lot with canvas-type interfaces on the desktop, but I can appreciate the benefits of SVG over bitmap rendering in this context. Thanks again.

C
Reply all
Reply to author
Forward
0 new messages