美文网首页
Html5 canvas 绘制心电波形图

Html5 canvas 绘制心电波形图

作者: lesliefang | 来源:发表于2020-12-16 22:39 被阅读0次
ecg.png pic.png

仅供参考

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>

    <style>
        .boack {
            position: absolute;
            left: 0px;
            top: 10px;
            width: 800px;
            height: 300px;
        }
    </style>
</head>
<body>

<div class="boack">
    <canvas id="background" width="800" height="300" style="margin-left: 20px;">
    </canvas>
</div>

<div class="boack">
    <canvas id="line" width="800" height="300" style="margin-left: 20px;">
    </canvas>
</div>

<script>
    var canvas = document.getElementById("background");
    var width = canvas.width;
    var height = canvas.height;
    var ctx = canvas.getContext("2d");
    var grid_width = 5; // 每一个小网格的宽高
    var hLineNum = parseInt(height / grid_width); // 横线个数
    var vLineNum = parseInt(width / grid_width); // 竖线个数
    var x_start = grid_width * 5; // X起点,从第二个大格子开始画

    var lineCanvas = document.getElementById("line");
    var lineCtx = lineCanvas.getContext("2d");
    lineCtx.lineWidth = 2;
    lineCtx.strokeStyle = "#0f0";

    console.log(hLineNum);
    console.log(vLineNum);

    function drawGrid() {
        ctx.beginPath();
        ctx.lineWidth = 1;
        ctx.strokeStyle = "#ffbebe";
        for (let i = 0; i < hLineNum; i++) {
            if (i == 0 || i % 5 != 0) {
                ctx.moveTo(0, i * grid_width);
                ctx.lineTo(width, i * grid_width);
                ctx.stroke();
            }
        }

        ctx.beginPath();
        ctx.lineWidth = 1;
        ctx.strokeStyle = "#ffbebe";
        for (let i = 0; i < vLineNum; i++) {
            if (i == 0 || i % 5 != 0) {
                ctx.moveTo(i * grid_width, 0);
                ctx.lineTo(i * grid_width, height);
                ctx.stroke();
            }
        }
        ctx.beginPath();
        ctx.lineWidth = 1;
        ctx.strokeStyle = "#FF7F50";
        for (let i = 5; i <= vLineNum; i += 5) {
            ctx.moveTo(i * grid_width, 0);
            ctx.lineTo(i * grid_width, height);
            ctx.stroke();
        }

        ctx.beginPath();
        ctx.lineWidth = 1;
        ctx.strokeStyle = "#FF7F50";
        for (let i = 5; i <= hLineNum; i += 5) {
            ctx.moveTo(0, i * grid_width);
            ctx.lineTo(width, i * grid_width);
            ctx.stroke();
        }
    }

    function addfilltext() {
        var waves = ["I", "RESP", "PLETH"];
        ctx.font = "bold 14px";
        ctx.fillText("" + waves[0] + "", 5, 50)
        ctx.fillText("" + waves[1] + "", 5, 150)
        ctx.fillText("" + waves[2] + "", 5, 250)
    }

    class WaveView {
        currentX = 0;
        currentY = 0;
        lastX = 0;
        lastY = 0;
        // 每次画几个点
        step = 10;
        // Y值最大值
        yMax = 300;
        // 每个波形的高度
        itemHeight = 100;
        // 橡皮檫宽度
        clearGap = 20;
        y_offset = 0;
        // 队列
        queue = [];
        strokeStyle = "#0f0";

        /**
         * @param frameSize 1秒多少个点
         * @param yMax
         * @param y_offset y偏移
         * @param step 每次画几个点
         * @param speedRatio 扫纸速度,默认 25mm/s (1秒25个小格子 每个小格子0.04s)。 0.5表示扫纸速度为 12.5mm/s。2表示扫纸速度为 50mm/s。
         * @param strokeStyle 线的样式
         */
        constructor(frameSize, yMax, y_offset, step, speedRatio, strokeStyle) {
            this.frameSize = frameSize;
            this.yMax = yMax;
            this.lastY = this.itemHeight / 2;
            this.y_offset = y_offset;
            this.step = step;
            this.speedRatio = speedRatio;
            this.strokeStyle = strokeStyle;
            this.drawInterval = Math.floor((1 / this.frameSize) * 1000 * this.step); // 绘制时间间隔
        }

        draw = () => {
            lineCtx.beginPath();
            lineCtx.strokeStyle = this.strokeStyle;
            if (this.lastX === 0) {
                lineCtx.clearRect(x_start - 2, this.y_offset, this.clearGap, this.itemHeight);
            } else {
                lineCtx.clearRect(x_start + this.lastX, this.y_offset, this.clearGap, this.itemHeight);
            }

            for (let i = 0; i < this.step; i++) {
                if (this.queue.length === 0) {
                    this.currentY = this.itemHeight / 2;
                } else {
                    this.currentY = (-1.0 * this.queue.shift()) / this.yMax * this.itemHeight + this.itemHeight;
                }

                if (this.currentY > this.itemHeight) {
                    this.currentY = this.itemHeight;
                }

                lineCtx.moveTo(x_start + this.lastX, this.y_offset + this.lastY);
                lineCtx.lineTo(x_start + this.currentX, this.y_offset + this.currentY);

                this.lastX = this.currentX;
                this.lastY = this.currentY;

                this.currentX += (grid_width * 25 * this.speedRatio) / this.frameSize;
                if (x_start + this.currentX >= width - 25) {
                    this.currentX = 0;
                    this.lastX = 0;
                }
            }

            lineCtx.stroke();
        }

        loop = () => {
            this.draw();
            setTimeout(this.loop, this.drawInterval);

            // TODO for test only 添加测试数据,实际中会从后台取
            this.addData(base64ToUint8Array('enp6enp6enp6enp6enp6enp7fX+ChYeJiouMjIuKiIaCf318e3p6enp6enp6enp6enp6enp6enp5d3Rxb4SXq77S5dK+q5eEcHJ1eHp6enp6enp6enp6enp6enp6enp6enp6enp6enp6ent8fH6Ag4WGiIyPkJKVlpiZmZqbnJ2cm5mZmJaVkpGOioeFgX98e3p6enp6enp6enp6enp6enp6enp6enp6enp6enp6enp6enp6enp6enp6enp6enp6enp6enp6enp6enp6enp6enp6enp6enp6enp6enp6enp6enp6enp6enp6enp6enp6enp6enp6enp6eg=='));
        }

        addData = (arr) => {
            for (let i = 0; i < arr.length; i++) {
                this.queue.push(arr[i]);
            }
        }
    }

    // function sleep(t) {
    //     let now = new Date().getTime();
    //     for (let i = 0; i < 10000000; i++) {
    //         if ((new Date().getTime() - now) > t) {
    //             break
    //         }
    //     }
    // }

    function base64ToUint8Array(base64String) {
        const padding = '='.repeat((4 - base64String.length % 4) % 4);
        const base64 = (base64String + padding)
            .replace(/\-/g, '+')
            .replace(/_/g, '/');

        const rawData = window.atob(base64);
        const outputArray = new Uint8Array(rawData.length);

        for (let i = 0; i < rawData.length; ++i) {
            outputArray[i] = rawData.charCodeAt(i);
        }
        return outputArray;
    }

    let ecgWave = new WaveView(250, 250, 0, 10, 1, '#00ff00');

    let respWave = new WaveView(125, 250, 100, 10, 0.5, '#00ff00');

    let spo2Wave = new WaveView(60, 250, 200, 4, 1, '#00F5FF');

    drawGrid();
    addfilltext();

    ecgWave.loop();

    respWave.loop();

    spo2Wave.loop();


</script>

</body>
</html>

相关文章

网友评论

      本文标题:Html5 canvas 绘制心电波形图

      本文链接:https://www.haomeiwen.com/subject/amtagktx.html