JSFiddle - React, Tailwind, and code Playground

by chriswilsondc

HTML

<div id="canvas" style="height:300px"></div>
<input type="button" value="play" id="play" />

JavaScript

var paper = Raphael(0, 0, 300, 300);

var metronome = function(opts) {    
    opts = opts || {};
    
    //primary variables
    var len = opts.len || 200, // length of metronome arm
        angle = opts.angle || 20,
        width = len * Math.sin(Math.PI * angle / 180),
        x = opts.x || 0,
        y = opts.y || 0,
        tempo = 100;
        
    console.log(width);
    
    var arm = paper.path("M" + (x + width) + "," + y + "v" + len).attr({
        'stroke-width': 5,
        stroke: "#999"
    }).data("id", "arm");
        
    var weight = paper.path("M" + (x + width) + ","  + (y + len) + "h9l3,-18h-24l3,18h12").attr({
        'stroke-width': 0,
        fill: '#666'
    }).data("id", "weight");
                
    //start the weight at the halfway point, which is 18px less than length bc of weight height
    weight.position = (len - 18) / 2;
    weight.transform("T0,-" + weight.position);
        
    var label = paper.text(x + width, y + len + 15, tempo);
    
    // track drag position
    var drag_position; 

    weight.drag(
        function(x, y, dx, dy, e) {
            // restrict weight to top of bar and very bottom, allowing for 18px height of weight
            drag_position = Math.min(len - 18, Math.max(0, this.position - y));
            
            // calculate tempo based on position, with range of 20 bpm to 180 bpm
            tempo = Math.round(20 + 160 * drag_position / (len - 18));
            label.attr("text", tempo);
            this.transform('T0,-' + drag_position);            
        },
        function(x, y, e) {
            this.attr("fill", "#99F");
        },
        function(e) {
            this.position = drag_position;
            this.attr("fill", "#666");
            console.log(this.position);
        }
    );
        
    return {
        play: function(repeats) {            
            var armAnim = {
                "25%": { transform:"R" + angle + " " + (x + width) + "," + (y + len), easing: "sinoid" },
     ...