te')); return $arr; } /* 遍历用户所有主题 * @param $uid 用户ID * @param int $page 页数 * @param int $pagesize 每页记录条数 * @param bool $desc 排序方式 TRUE降序 FALSE升序 * @param string $key 返回的数组用那一列的值作为 key * @param array $col 查询哪些列 */ function thread_tid_find_by_uid($uid, $page = 1, $pagesize = 1000, $desc = TRUE, $key = 'tid', $col = array()) { if (empty($uid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('uid' => $uid), array('tid' => $orderby), $page, $pagesize, $key, $col); return $arr; } // 遍历栏目下tid 支持数组 $fid = array(1,2,3) function thread_tid_find_by_fid($fid, $page = 1, $pagesize = 1000, $desc = TRUE) { if (empty($fid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('fid' => $fid), array('tid' => $orderby), $page, $pagesize, 'tid', array('tid', 'verify_date')); return $arr; } function thread_tid_delete($tid) { if (empty($tid)) return FALSE; $r = thread_tid__delete(array('tid' => $tid)); return $r; } function thread_tid_count() { $n = thread_tid__count(); return $n; } // 统计用户主题数 大数量下严谨使用非主键统计 function thread_uid_count($uid) { $n = thread_tid__count(array('uid' => $uid)); return $n; } // 统计栏目主题数 大数量下严谨使用非主键统计 function thread_fid_count($fid) { $n = thread_tid__count(array('fid' => $fid)); return $n; } ?>javascript - Ecg graph with html5 canvas - Stack Overflow
最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Ecg graph with html5 canvas - Stack Overflow

programmeradmin4浏览0评论

My need is to draw a ECG graph on canvas for socket data per every data iteration.

I tried to look into several graph plugins which use canvas to plot graphs, tried / but didn't succeed.

I Tried to plot graph using below basic html5 canvas drawline with sample data.

var fps = 60;
var n = 1;

drawWave();
    function drawWave() {
        setTimeout(function() {
                requestAnimationFrame(drawWave2);
                ctx.lineWidth = "2";
                ctx.strokeStyle = 'green';
                // Drawing code goes here
                n += 1;
                if (n >= data.length) {
                    n = 1;
                }
                ctx.beginPath();
                ctx.moveTo(n - 1, data[n - 1] * 2);
                ctx.lineTo(n, data[n] * 2);
                ctx.stroke();
                ctx.clearRect(n + 1, 0, 10, canvas.height);
            }, 1000 / fps);
    }

But it is not giving me the exact graph view as attached image. I'm not able to understand how to achieve graph like ecg graph. Please help me to get rid of this problem.

My need is to draw a ECG graph on canvas for socket data per every data iteration.

I tried to look into several graph plugins which use canvas to plot graphs, tried http://www.flotcharts/ but didn't succeed.

I Tried to plot graph using below basic html5 canvas drawline with sample data.

var fps = 60;
var n = 1;

drawWave();
    function drawWave() {
        setTimeout(function() {
                requestAnimationFrame(drawWave2);
                ctx.lineWidth = "2";
                ctx.strokeStyle = 'green';
                // Drawing code goes here
                n += 1;
                if (n >= data.length) {
                    n = 1;
                }
                ctx.beginPath();
                ctx.moveTo(n - 1, data[n - 1] * 2);
                ctx.lineTo(n, data[n] * 2);
                ctx.stroke();
                ctx.clearRect(n + 1, 0, 10, canvas.height);
            }, 1000 / fps);
    }

But it is not giving me the exact graph view as attached image. I'm not able to understand how to achieve graph like ecg graph. Please help me to get rid of this problem.

Share Improve this question edited Dec 7, 2013 at 19:21 Kara 6,22616 gold badges53 silver badges58 bronze badges asked Dec 5, 2013 at 12:36 atluriajithatluriajith 7923 gold badges17 silver badges42 bronze badges
Add a ment  | 

5 Answers 5

Reset to default 8

The characteristics with an ECG is that is plots the signal horizontally headed by a blank gap. When the end of the right side is reached is returns to left side and overdraw the existing graph.

DEMO

Setup

var ctx = demo.getContext('2d'),
    w = demo.width,
    h = demo.height,

    /// plot x and y, old plot x and y, speed and scan bar width
    speed = 3,
    px = 0, opx = 0, 
    py = h * 0.8, opy = py,
    scanBarWidth = 20;

ctx.strokeStyle = '#00bd00';
ctx.lineWidth = 3;

/// for demo we use mouse as signal input source    
demo.onmousemove = function(e) {
    var r = demo.getBoundingClientRect();
    py = e.clientY - r.top;
}
loop();

The main loop:

The loop will plot whatever the signal amplitude is at any moment. You can inject a sinus or some other signal or read from an actual sensor over Web socket etc.

function loop() {

    /// move forward at defined speed
    px += speed;
    
    /// clear ahead (scan bar)
    ctx.clearRect(px,0, scanBarWidth, h);

    /// draw line from old plot point to new
    ctx.beginPath();
    ctx.moveTo(opx, opy);
    ctx.lineTo(px, py);
    ctx.stroke();
    
    /// update old plot point
    opx = px;
    opy = py;
    
    /// check if edge is reached and reset position
    if (opx > w) {
        px = opx = -speed;
    }
    
    requestAnimationFrame(loop);
}

To inject a value simply update py (outside loop).

It would be far more helpful, if you included an image of what it does produce, rather than stating that it doesn't do that. Anyhow, it looks like you're only drawing a single line per frame. You need to run a loop with lineTo inside, iterating through all values of n.

Something along the lines of the below except from a sound-synthesizer. Just pay attention to the fact that there's a drawing-loop. In my case, there are often 40,000 or 50,000 samples that need to be drawn on a canvas of only a few hundred pixels wide. It seems like redundant drawing in my case, but doing th intuitive thing, of a single point per pixel results in an inaccurate image. The output of this looks something (88200 samples per 1024 pixels)

function drawFloatArray(samples, canvas)
{
    var i, n = samples.length;
    var dur = (n / 44100 * 1000)>>0;
    canvas.title = 'Duration: ' +  dur / 1000.0 + 's';

    var width=canvas.width,height=canvas.height;
    var ctx = canvas.getContext('2d');
    ctx.strokeStyle = 'yellow';
    ctx.fillStyle = '#303030';
    ctx.fillRect(0,0,width,height);
    ctx.moveTo(0,height/2);
    ctx.beginPath();
    for (i=0; i<n; i++)
    {
        x = (i*width) / n;
        y = (samples[i]*height/2)+height/2;
        ctx.lineTo(x, y);
    }
    ctx.stroke();
    ctx.closePath();
}

Since your live data is streaming non-stop, you need a plan to deal with a graph that overflows the canvas.

Here's one solution that pans the canvas to always show only the most recent data.

Demo: http://jsfiddle/m1erickson/f5sT4/

Here's starting code illustrating this solution:

<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery./jquery.min.js"></script>

<style>
    body{ background-color: ivory; }
    #canvas{border:1px solid red;}
</style>

<script>
$(function(){

    var canvas=document.getElementById("canvas");
    var ctx=canvas.getContext("2d");

    // capture ining socket data in an array
    var data=[];

    // TESTING: fill data with some test values
    for(var i=0;i<5000;i++){
        data.push(Math.sin(i/10)*70+100);
    }

    // x is your most recent data-point in data[]
    var x=0;

    // panAtX is how far the plot will go rightward on the canvas
    // until the canvas is panned

    var panAtX=250;

    var continueAnimation=true;
    animate();


    function animate(){

        if(x>data.length-1){return;}

        if(continueAnimation){
            requestAnimationFrame(animate);
        }

        if(x++<panAtX){

            ctx.fillRect(x,data[x],1,1);

        }else{

            ctx.clearRect(0,0,canvas.width,canvas.height);

            // plot data[] from x-PanAtX to x 

            for(var xx=0;xx<panAtX;xx++){
                var y=data[x-panAtX+xx];
                ctx.fillRect(xx,y,1,1)
            }
        }
    }


    $("#stop").click(function(){continueAnimation=false;});

}); // end $(function(){});
</script>

</head>

<body>
    <button id="stop">Stop</button><br>
    <canvas id="canvas" width=300 height=300></canvas>
</body>
</html>

I think this web ponent is both prettier and easier to use. It using canvas as a backend of draw. If you going use it all you need to do is call bang() on every appearing beat

document.body.innerHTML += '<ecg-line></ecg-line>';
ecgLine((bang) => setInterval(() => bang(), 1000));

Do you mean something like this?

var canvas = document.getElementById("dm_graphs");

var ctx = canvas.getContext("2d");

ls = 0;
d = 7; // sesitivity

function updateFancyGraphs() {

  var gh = canvas.height;
  var gh2 = gh / 2;
  ctx.drawImage(canvas, -1, 0);
  ctx.fillRect(graphX, 0, 1, canvas.height);
  var size = Math.max(-gh, Math.min((3 * (Math.random() * 10 - 5)) * d, gh));
  ctx.beginPath();
  ctx.moveTo(graphX - 1, gh2 + ls / 2);
  ctx.lineTo(graphX, gh2 + size / 2);
  ctx.stroke();
  ls = size;
}

function resizeCanvas() {
  var w = window.innerWidth || document.body.offsetWidth;
  canvas.width = w / 1.5;
  canvas.height = window.innerHeight / 1.5;
  graphX = canvas.width - 1;
  ctx.lineWidth = 1; // 1.75 is nicer looking but loses a lot of information.
  ctx.strokeStyle = "Lime";
  ctx.fillStyle = "black";
}

window.addEventListener("resize", resizeCanvas);
resizeCanvas();

z = setInterval(() => updateFancyGraphs(), 20)
body {
  min-height: 100ev;
}

body,
html,
canvas {
  font: 15px sans-serif;
  height: 100hv;
  width: 100%;
  margin: 0;
  padding: 0;
  background: #113355;
  color: white;
  overflow: hidden;
}

#dm_status,
footer {
  text-align: center;
}

#dm_graphs {
  image-rendering: optimizeSpeed;
  background: rgba(0, 0, 0, 0.7);
}
<html>

<head>
  <title>Zibri's Graph</title>
  <meta name="viewport" content="width=device-width">

</head>

<body>
  <canvas id="dm_graphs"></canvas>
</body>

</html>

发布评论

评论列表(0)

  1. 暂无评论