jueves, 9 de abril de 2020

29. Vaadin 14. Integrating external Js libraries from npm (1). Playing a note with Tone.js

0. Introduction

This post is based on a contribution to Vaadin form by Arthur Signell. This is a very important and useful contribution.

The steps for achieving these aims are:
  1. Create a js file (in the frontend folder) that defines the calls to the js library. 
  2. Create a java file that imports the js library from the npm and execute the functions of the previously created js file

1. JS important tips

1. Nearly all the variables and functions created are local! That means that they cannot be used in a Vaadin Java class. For instance variable "a" and function "myfunct" are local:
  
     var a = 5; 
     myfunc ( c, d) { return c + d; }
  
2. If you want a variable or function that can be recognized by a Vaadin component, (that means to make them global), you must attach it to window object. For instance  variable "b" and function "otherfunct" are global:

    window.b = 5;
    window.otherfunct= function ( c, d) { return c + d; }

3. If you want to make an "import" of the external javascript library for instance:

    import * as TONE from "tone";
 
  The reference to the external javascript library must be made by means of @NpmPackage  annotation in the Vaadin component class that uses it:

   @NpmPackage (value = "tone", version = "13.8.25")

Here we are importing the library "tone.js" version "13.8.25" from the npm repository

4. To reference the created js file from the Vaadin Component class, the @JsModule annotation can be used:
 
   @JsModule("./tone-test.js")

2. Create the js file

This simple file makes visible (global) the variables and functions we need to use and call from our Vaadin component.

This file must be in the "frontend" folder!. 

Here is a file ( tone-test.js )  that plays a note with a specific duration using tone.jshttps://tonejs.github.io/ library 


 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
import * as TONE from "tone";

class ToneTest {
 //Create the synthesizer
 init() {
  this.synth = new TONE.Synth().toMaster();
 }
 
 // Play notes
 play(note, duration) {
  this.synth.triggerAttackRelease(note, duration)
 }  
}  

//Make the functions global

//Create the synthesizer
window.initTone = function() {
 window.tt = new ToneTest(); //makes the variable global
 window.tt.init();
}

// Play the notes
window.play = function (note,duration) {
 window.tt.play(note,duration);
}

Now it is possible to call the functions "window.initTone" and "window.play" as they are attached to the window that is a global object (Lines 18 and 24)

Don't forget to make the imports (Line 1)

There is an intermediate class (ToneTest)  for managing direct calls to tone.js functions (Lines 3-13)


3. The Vaadin Component Class

It is important to note:
  1.  Line 21: the @NpmPackage annotation for importing the library tone.js version 13.8.25 from npm
  2. Line 20: The @JsModule that import the previous "tone-test.js" javascript file that was saved in the frontend folder. If we had saved it in an inner folder of the frontend folder, for instance, frontend/tone the annotation would have been @JsModule("./tone/tone-test.js")
  3. Line 28: In the init() method annotated as PostConstruct, we make sure to initialize the synthesizer. To execute a js code the getElement().executeJs(function,parameters...) is used.
  4. Line 32: The click event of the button is assigned to the js call to play a "C4" note for a duration of an 8th of a whole note.

 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
package com.gmail.ximo;

import com.vaadin.flow.component.Key;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.dependency.JsModule;
import com.vaadin.flow.component.dependency.NpmPackage;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.server.PWA;

import javax.annotation.PostConstruct;
import javax.inject.Inject;

/**
 * The main view contains a simple label element and a template element.
 */
@SuppressWarnings("serial")
@Route("")
@PWA(name = "Project Base for Vaadin Flow with CDI", shortName = "Project Base")
@JsModule("./tone-test.js")
@NpmPackage(value = "tone", version = "13.8.25")
public class MainView extends VerticalLayout {


    @PostConstruct
    public void init() {
        //Initialize the synthesizer        
        this.getElement().executeJs("window.initTone()");

        // Play a C4 Note with a duration of a 8th
        Button button = new Button("Say hello",
            e -> getElement().executeJs("window.play($0,$1)", "C4", "8n"));
        // You can specify keyboard shortcuts for buttons.
        // Example: Pressing enter in this view clicks the Button.
        button.addClickShortcut(Key.ENTER);

        add(button);
    }

}

I hope you have a good time!

No hay comentarios:

Publicar un comentario