如何更改图形数据流的速率

时间:2019-02-11 16:38:17

标签: javascript python-3.x html5 graph requestanimationframe

我已经实现了使用python flask在浏览器上实时流式传输的ecg图,以及我从该博客中学到的知识。 http://theblogofpeterchen.blogspot.com/2015/02/html5-high-performance-real-time.html

我的图表看起来不错,并且可以按照我想要的方式进行播放,但是我想制作它,以便用户可以改变心率,从而使图表发生变化。任何有关如何实现这一目标的建议将不胜感激。

我尝试调整g.speed设置,但这似乎对速度没有影响。我有信心在用户界面上添加心率控件,但我不确定如何接受用户输入并响应于此输入而使图形循环更快/更慢,因为g.speed参数似乎并不影响数据流的速率。

liveGraph.js:

   /*
   * Helper function to convert a number to the graph coordinate
   * ----------------------------------------------------------- */
  function convertToGraphCoord(g, num){
      return Math.floor((g.height / 2) * -(num * g.scaleFactor) + 
g.height / 2);
  }

  /*
   * Constructor for the LiveGraph object
   * ----------------------------------------------------------- */
  function LiveGraph(cid, datacb){

var g             =   this;
g.canvas_id       =   cid;
g.canvas          =   $("#" + cid);
g.context         =   g.canvas[0].getContext("2d");
g.width           =   $("#" + cid).width();
g.height          =   $("#" + cid).height();
g.white_out       =   g.width * 0.01;
g.fade_out        =   g.width * 0.10;
g.fade_opacity    =   0.2;
g.current_x       =   0;
g.current_y       =   0;
g.erase_x         =   null;
g.speed           =   2;
g.linewidth       =   1;
g.scaleFactor     =   1;
g.stop_graph      =   true;
g.plethStarted    =   false;
g.plethBuffer     =   new Array();

devicePixelRatio = window.devicePixelRatio || 1,
backingStoreRatio = g.context.webkitBackingStorePixelRatio ||
                    g.context.mozBackingStorePixelRatio ||
                    g.context.msBackingStorePixelRatio ||
                    g.context.oBackingStorePixelRatio ||
                    g.context.backingStorePixelRatio || 1,

ratio = devicePixelRatio / backingStoreRatio;


var oldWidth = g.canvas[0].width;
var oldHeight = g.canvas[0].height;

g.canvas[0].width = oldWidth * ratio;
g.canvas[0].height = oldHeight * ratio;

g.canvas[0].style.width = oldWidth + 'px';
g.canvas[0].style.height = oldHeight + 'px';

// scale the context to counter
// the fact that we've manually scaled
// the canvas element
g.context.scale(ratio, ratio);


/*
 * The call to fill the data buffer using
 * the data callback
 * ---------------------------------------- */
g.fillData = function() {
  g.plethBuffer = datacb();
  };

/*
 * The call to check whether graphing is on
 * ---------------------------------------- */
g.isActive = function() {
  return !g.stop_graph;
};

/*
 * The call to stop the graphing
 * ---------------------------------------- */
g.stop = function() {
  g.stop_graph = true;
};


/*
 * The call to wrap start the graphing
 * ---------------------------------------- */
g.start = function() {
  g.stop_graph = false;
  g.animate();
};


/*
 * The call to start the graphing
 * ---------------------------------------- */
g.animate = function() {
  reqAnimFrame =   window.requestAnimationFrame       ||
                   window.mozRequestAnimationFrame    ||
                   window.webkitRequestAnimationFrame ||
                   window.msRequestAnimationFrame     ||
                   window.oRequestAnimationFrame;

  // Recursive call to do animation frames
  if (!g.stop_graph) reqAnimFrame(g.animate);

  // fill in data into the buffer so we know what to draw
  g.fillData();

  // Draw the frame (with the supplied data buffer)
  g.draw();
};


g.draw = function() {
  // Circle back the draw point back to zero when needed (ring drawing)
  g.current_x = (g.current_x > g.width) ? 0 : g.current_x;

  // "White out" a region before the draw point
  for( i = 0; i < g.white_out ; i++){
    g.erase_x = (g.current_x + i) % g.width;
    g.context.clearRect(g.erase_x, 0, 1, g.height);
  }

  // "Fade out" a region before the white out region
  for( i = g.white_out ; i < g.fade_out ; i++ ){
    g.erase_x = (g.current_x + i) % g.width;
    g.context.fillStyle="rgba(255, 255, 255, " + g.fade_opacity.toString() + ")";
    g.context.fillRect(g.erase_x, 0, 1, g.height);
  }

  // If this is first time, draw the first y point depending on the buffer
  if (!g.started) {
    g.current_y = convertToGraphCoord(g, g.plethBuffer[0]);
    g.started = true;
  }

  // Start the drawing
  g.context.beginPath();

  // first move to the current x and y position (last point)
  g.context.moveTo(g.current_x, g.current_y);

  for (i = 0; i < g.plethBuffer.length; i++) {
    // Put the new y point in from the buffer
    g.current_y = convertToGraphCoord(g, g.plethBuffer[i]);

    // Draw the line to the new x and y point
    g.context.lineTo(g.current_x += g.speed, g.current_y);

    // Set the 
    g.context.lineWidth   = g.linewidth;
    g.context.lineJoin    = "round";

    // Create stroke
    g.context.stroke();
  }

  // Stop the drawing
  g.context.closePath();
};
 }

  var lastData =0;

  // Create a random function that is dependent on the last value
  function hysteresisRandom(){
    lastData += (Math.floor((Math.random() * 5) + 1)-3)/50;
    if (Math.abs(lastData) >= 1) lastData = (lastData > 0) ? 1 : -1;
    return lastData;
  }

  // Generate a real time data grab of various length
  function generateData(){
    buffer = new Array();
    var inputLength = Math.floor((Math.random() * 1) + 1);;
    for( i = 0 ; i < inputLength ; i++ ) buffer[i] = hysteresisRandom();
    return buffer;
  }

ecg.js:

/*45 data points*/
var ECG_data = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
            0.08, 0.18, 0.08, 0, 0, 0, 0, 0, 0, -0.04, 
            -0.08, 0.3, 0.7, 0.3, -0.17, 0.00, 0.04, 0.04, 
            0.05, 0.05, 0.06, 0.07, 0.08, 0.10, 0.11, 0.11, 
            0.10, 0.085, 0.06, 0.04, 0.03, 0.01, 0.01, 0.01, 
            0.01, 0.02, 0.03, 0.05, 0.05, 0.05, 0.03, 0.02, 0, 0, 0];

var ECG_idx = 0;

function get_ECG_data(){
  if (ECG_idx++ >= ECG_data.length - 1) ECG_idx=0;
  var output = new Array();
  output[0] = ECG_data[ECG_idx] + hysteresisRandom()/10;
  return output;
}
var ecg;



$(document).ready(function(){
    ecg = new LiveGraph("ecg", get_ECG_data);
    ecg.speed = 1.4; 
    ecg.scaleFactor = 0.8;
    ecg.start();

});

index.html:

<!DOCTYPE html>
<html lang="en">
    <head>
    <meta charset="utf-8" />
    <meta http-equiv="x-ua-compatible" content="ie=edge">
    <title>{{ title }}</title>
    <meta name="description" content="">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="/static/normalize.css">
    <link rel="stylesheet" href="/static/main.css">

    <script type="text/javascript" src="{{ url_for('static', filename='smoothie.js') }}"></script>

    <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.6/socket.io.min.js"></script>
    <script type="text/javascript" src="{{ url_for('static', filename='modernizr-3.6.0.min.js') }}"></script>

</head>
<body>
    <script type="text/javascript" src="{{ url_for('static', filename='jquery-3.3.1.min.js') }}"></script>
      <div class="hidden-on-main-page">

    <script type="text/javascript" src="{{ url_for('static', filename='liveGraph.js') }}"></script>

    <h1>{{ title }}!</h1>
    <h2> The date and time on the server is: {{ time }}</h2>
    <h2> GPIO mode status: {{ gpio_mode }}</h2>
    <h2> Last Command sent: {{ last_cmd }}</h3>
    <br>
    <h2> Commands </h2>
    <h3>
        Lung Rate Control:
        <h4>
        <a href="/lung_rate_apnea" class="button"> APNEA</a>
        <a href="/lung_rate_5" class="button"> RR=5</a>
        <a href="/lung_rate_30" class="button"> RR=30</a>
        </h4>
    </h3>
    <h3>
        Pupil Control:
        <h4>
        <a href="/pupil_r_constricted" class="button"> constricted</a>
        <a href="/pupil_r_normal" class="button"> normal</a>
        <a href="/pupil_r_dilated" class="button"> dilated</a>
        </h4>
    </h3>

    <div class="container" id="content">
        <div class="row">
            <p>ECG</p>
            <div id="log">
            </div> <!-- /#log -->
        </div>
    </div>
    <div class="wrapper">
      <h1>ECG</h1>

    <div style="width: 100%;">
    <center>
    <canvas id="ecg" width="1200"  height="200" style="border: 1px solid #cccccc; border-radius: 5px; cursor: pointer;"></canvas>
    <script type="text/javascript" src="{{ url_for('static', filename='ecg.js') }}"></script>
    </center>
    </div>
</body>

我希望心电图可以调整,以便客户可以调整心率。

更新:2019/02/13:

我找到了一种方法(可能不是一种很好的方法),但是还是一种通过在ECG_data数组开始时更改零数来更改心率的方法。增加零的数目将使心率出现较慢,减少零的数目使心率出现较快。现在的问题是我没有JavaScript。我可以对零进行硬编码以查看结果,但是当我向javascript中添加一些基本使用array.splice()和array.push()来控制零数目的函数时,我似乎无法使其正常工作。我使用.push()是因为我发现,将所有零都放在数组的末尾而不是如示例中所示的开头,可以更轻松地进行操作。有人可以帮我提供一个可行的工作示例,或者如何使它更好的方法吗?

0 个答案:

没有答案