我需要在画布上绘制一张ECG数据图,用于每次数据迭代时的套接字数据。
我试图查看几个使用画布绘制图形的图形插件,尝试http://www.flotcharts.org/但没有成功。
我尝试使用以下基本的html5画布画线和样本数据绘制图表。
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);
}
但它没有给我一个精确的图表视图作为附加图像。我无法理解如何实现像ecg图这样的图形。请帮我摆脱这个问题。
答案 0 :(得分:8)
心电图的特征是绘制水平朝向空白间隙的信号。当到达右侧的末端时返回到左侧并透过现有的图形。
<强>设置强>
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();
主循环:
循环将绘制任何时刻信号幅度的任何值。您可以通过Web插座等注入窦或其他信号或从实际传感器读取。
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);
}
注入一个值只需更新py
(外部循环)。
答案 1 :(得分:1)
由于您的实时数据是不间断的流式传输,因此您需要一个计划来处理溢出画布的图形。
这是一个平移画布的解决方案,始终只显示最新数据。
演示:http://jsfiddle.net/m1erickson/f5sT4/
以下是说明此解决方案的起始代码:
<!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.com/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 incoming 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>
答案 2 :(得分:0)
如果你包含了做所产生的图像,那将会更有帮助,而不是声明它不会那样做。无论如何,看起来你每帧只画了一行。你需要在里面运行一个带有lineTo的循环,遍历n的所有值。
除了声音合成器之外,还有下面的内容。请注意有一个绘制循环的事实。就我而言,通常需要在仅几百像素宽的画布上绘制40,000或50,000个样本。在我的情况下,它似乎是多余的绘图,但是直观的是,每个像素的单个点会导致图像不准确。它的输出看起来像(每1024像素88200个样本)
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();
}
答案 3 :(得分:0)
我认为the documentation Web组件既漂亮又易于使用。它使用画布作为绘制的后端。如果要使用它,您要做的就是在每个出现的节拍上呼叫bang()
document.body.innerHTML += '<ecg-line></ecg-line>';
ecgLine((bang) => setInterval(() => bang(), 1000));