股票实时行情Echarts动态图表

0 阅读7分钟

1、x轴和数据都动态增加

image.png

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>股票折线图-无缝衔接11:30和13:00</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/echarts/5.4.3/echarts.min.js"></script>
    <style>
        body { margin: 0; padding: 20px; }
        #stock-chart {
            width: 100%;
            min-width: 800px;
            height: 600px;
            border: 1px solid #eee;
            box-sizing: border-box;
        }
    </style>
</head>
<body>
    <h2 style="text-align: center;">股票实时行情(无缝衔接午间休市)</h2>
    <div id="stock-chart"></div>

    <script>
        // 检查ECharts加载
        if (typeof echarts === 'undefined') {
            alert('ECharts加载失败,请检查网络!');
        }

        // 初始化图表
        const myChart = echarts.init(document.getElementById('stock-chart'));

        // 基础配置
        const option = {
            title: {
                text: '股票实时行情(9:30-11:30/13:00-15:00)',
                left: 'center'
            },
            tooltip: {
                trigger: 'axis',
                formatter: (params) => {
                    // 提示框显示真实时间和价格
                    const realTime = params[0].data[2]; // 第三个值存真实时间字符串
                    return `${realTime}<br/>价格:${params[0].data[1].toFixed(2)}元`;
                }
            },
            grid: {
                left: '5%', right: '5%', top: '15%', bottom: '10%', containLabel: true
            },
            xAxis: {
                type: 'category', // 改用分类轴,手动控制显示
                name: '交易时间',
                axisLabel: { fontSize: 11 },
                data: [] // 存储显示用的时间标签(真实时间)
            },
            yAxis: {
                type: 'value',
                name: '价格(元)',
                min: 95,
                max: 105
            },
            series: [{
                name: '股价',
                type: 'line',
                smooth: true,
                lineStyle: { width: 2 },
                data: [] // [虚拟索引, 价格, 真实时间字符串]
            }]
        };

        myChart.setOption(option);

        // ========== 核心:时间映射与数据生成 ==========
        class StockSimulator {
            constructor() {
                this.basePrice = 100;
                this.currentPrice = this.basePrice;
                // 生成所有真实交易时间点(9:30-11:30, 13:00-15:00)
                this.realTimePoints = this.generateRealTimePoints();
                // 虚拟时间轴(连续的索引,对应X轴的分类)
                this.virtualTimeIndex = 0;
                // 存储处理后的数据
                this.chartData = [];
                this.xAxisLabels = [];
                this.timer = null;
            }

            // 生成所有真实的交易时间点(分钟级)
            generateRealTimePoints() {
                const timePoints = [];
                // 上午:9:30-11:30
                for (let h = 9; h <= 11; h++) {
                    const startMin = h === 9 ? 30 : 0;
                    const endMin = h === 11 ? 31 : 60; // 11:30包含,11:31停止
                    for (let m = startMin; m < endMin; m++) {
                        const timeStr = `${h.toString().padStart(2, '0')}:${m.toString().padStart(2, '0')}`;
                        timePoints.push(timeStr);
                    }
                }
                // 下午:13:00-15:00
                for (let h = 13; h < 15; h++) {
                    for (let m = 0; m < 60; m++) {
                        const timeStr = `${h.toString().padStart(2, '0')}:${m.toString().padStart(2, '0')}`;
                        timePoints.push(timeStr);
                    }
                }
                // 15:00最后一个点
                timePoints.push('15:00');
                return timePoints;
            }

            // 生成随机股价
            generatePrice() {
                const randomChange = (Math.random() - 0.5) * 0.8;
                this.currentPrice = Math.max(95, Math.min(105, this.currentPrice + randomChange));
                return this.currentPrice;
            }

            // 启动动态更新
            startUpdate() {
                this.timer = setInterval(() => {
                    // 停止条件:所有时间点更新完毕
                    if (this.virtualTimeIndex >= this.realTimePoints.length) {
                        clearInterval(this.timer);
                        alert('今日交易结束!');
                        return;
                    }

                    // 获取当前真实时间点
                    const realTime = this.realTimePoints[this.virtualTimeIndex];
                    // 生成价格
                    const price = this.generatePrice();
                    
                    // 添加到数据数组:[虚拟索引, 价格, 真实时间]
                    this.chartData.push([this.virtualTimeIndex, price, realTime]);
                    // 添加X轴显示标签(真实时间)
                    this.xAxisLabels.push(realTime);
                    
                    // 每10个点显示一个标签,避免X轴文字拥挤
                    const showLabelXAxis = this.xAxisLabels.map((label, idx) => {
                        return idx % 10 === 0 ? label : '';
                    });

                    // 更新图表
                    myChart.setOption({
                        xAxis: { data: showLabelXAxis },
                        series: [{ data: this.chartData }]
                    });

                    // 推进虚拟索引
                    this.virtualTimeIndex++;
                }, 200); // 200ms更新一次,更快看到效果
            }
        }

        // 启动模拟
        window.onload = function() {
            const simulator = new StockSimulator();
            simulator.startUpdate();
        };

        // 窗口自适应
        window.addEventListener('resize', () => myChart.resize());
    </script>
</body>
</html>

2、x轴时间固定,数据动态前进,只是11:30 到 13:00 出现数据空白 比较突兀

image.png

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>股票实时行情-可正常显示版</title>
    <!-- 更换为更稳定的ECharts CDN -->
    <script src="https://cdn.bootcdn.net/ajax/libs/echarts/5.4.3/echarts.min.js"></script>
    <style>
        /* 强制设置容器尺寸,避免布局问题 */
        body {
            margin: 0;
            padding: 20px;
        }
        #stock-chart {
            width: 100%;
            min-width: 800px;
            height: 600px;
            border: 1px solid #eee; /* 加边框,确认容器存在 */
            box-sizing: border-box;
        }
    </style>
</head>
<body>
    <h2 style="text-align: center;">股票实时行情模拟</h2>
    <div id="stock-chart"></div>

    <script>
        // 第一步:先确认ECharts是否加载成功
        if (typeof echarts === 'undefined') {
            alert('ECharts加载失败,请检查网络或CDN链接!');
        }

        // 初始化图表(增加异常捕获)
        let myChart;
        try {
            const chartDom = document.getElementById('stock-chart');
            // 打印容器尺寸,调试用
            console.log('容器尺寸:', chartDom.offsetWidth, chartDom.offsetHeight);
            
            myChart = echarts.init(chartDom);
        } catch (e) {
            alert('图表初始化失败:' + e.message);
        }

        // 基础配置(简化+确保必选属性)
        const option = {
            title: {
                text: '股票实时行情(9:30-11:30/13:00-15:00)',
                left: 'center',
                textStyle: { fontSize: 16 }
            },
            tooltip: {
                trigger: 'axis',
                // 简化提示框格式化
                formatter: (params) => {
                    const time = new Date(params[0].data[0]);
                    const timeStr = `${time.getHours().toString().padStart(2, '0')}:${time.getMinutes().toString().padStart(2, '0')}`;
                    return `${timeStr}<br/>价格:${params[0].data[1].toFixed(2)}元`;
                }
            },
            grid: {
                left: '5%',
                right: '5%',
                top: '15%',
                bottom: '10%',
                containLabel: true
            },
            xAxis: {
                type: 'time',
                name: '交易时间',
                nameTextStyle: { fontSize: 12 },
                axisLabel: {
                    fontSize: 11,
                    formatter: (val) => {
                        const t = new Date(val);
                        return `${t.getHours()}:${t.getMinutes().toString().padStart(2, '0')}`;
                    }
                },
                // 固定时间范围,避免动态时间问题
                min: new Date(2026, 1, 27, 9, 30).getTime(), // 固定日期(2026-02-27)
                max: new Date(2026, 1, 27, 15, 0).getTime()
            },
            yAxis: {
                type: 'value',
                name: '价格(元)',
                nameTextStyle: { fontSize: 12 },
                // 固定Y轴范围,避免初始无数据时轴消失
                min: 95,
                max: 105
            },
            series: [{
                name: '股价',
                type: 'line',
                smooth: true,
                connectNulls: false,
                lineStyle: { width: 2 }, // 加粗折线,更易看到
                data: []
            }]
        };

        // 先渲染基础图表(无数据也显示框架)
        myChart.setOption(option);

        // ========== 数据生成与动态更新 ==========
        class StockSimulator {
            constructor() {
                this.basePrice = 100;
                this.currentPrice = this.basePrice;
                // 固定起始时间(避免系统时间导致的问题)
                this.currentTime = new Date(2026, 1, 27, 9, 30);
                this.chartData = [];
                this.timer = null;
            }

            // 判断是否为交易时间
            isTradingTime(time) {
                const hour = time.getHours();
                const minute = time.getMinutes();
                return (hour >= 9 && hour < 11) || (hour === 11 && minute <= 30) || (hour >= 13 && hour < 15);
            }

            // 生成下一个价格(简化波动逻辑)
            generateNextPrice() {
                const randomChange = (Math.random() - 0.5) * 0.8; // 小幅波动
                this.currentPrice = Math.max(95, Math.min(105, this.currentPrice + randomChange)); // 限制在95-105之间
                return this.currentPrice;
            }

            // 推进时间
            advanceTime() {
                this.currentTime.setMinutes(this.currentTime.getMinutes() + 1);
                // 跳过休市时间
                if (this.currentTime.getHours() === 11 && this.currentTime.getMinutes() > 30) {
                    this.currentTime.setHours(13, 0);
                }
            }

            // 启动更新
            startUpdate() {
                // 先添加第一个数据点,确保初始有数据
                const firstPrice = this.generateNextPrice();
                this.chartData.push([this.currentTime.getTime(), firstPrice]);
                myChart.setOption({ series: [{ data: this.chartData }] });

                // 定时器:每300ms更新一次(更快看到效果)
                this.timer = setInterval(() => {
                    if (this.currentTime.getHours() >= 15) {
                        clearInterval(this.timer);
                        alert('今日交易结束!');
                        return;
                    }

                    this.advanceTime();

                    if (this.isTradingTime(this.currentTime)) {
                        const price = this.generateNextPrice();
                        this.chartData.push([this.currentTime.getTime(), price]);
                        // 增量更新
                        myChart.setOption({ series: [{ data: this.chartData }] });
                    }
                }, 300);
            }
        }

        // 启动模拟(确保DOM加载完成后执行)
        window.onload = function() {
            const simulator = new StockSimulator();
            simulator.startUpdate();
        };

        // 窗口自适应
        window.addEventListener('resize', () => {
            if (myChart) myChart.resize();
        });
    </script>
</body>
</html>

3、x轴固定,上午休市,下午开市显示一起的

image.png

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>固定X轴-动态生成股价数据(11:30/13:00显示)</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/echarts/5.4.3/echarts.min.js"></script>
    <style>
        body { margin: 0; padding: 20px; }
        #stock-chart {
            width: 100%;
            min-width: 800px;
            height: 600px;
            border: 1px solid #eee;
            box-sizing: border-box;
        }
    </style>
</head>
<body>
    <h2 style="text-align: center;">股票实时行情(固定X轴+动态数据)</h2>
    <div id="stock-chart"></div>

    <script>
        // 检查ECharts加载
        if (typeof echarts === 'undefined') {
            alert('ECharts加载失败,请检查网络!');
        }

        // 初始化图表
        const myChart = echarts.init(document.getElementById('stock-chart'));

        // ========== 1. 预先生成完整的X轴标签(固定显示) ==========
        function generateFullXAxisLabels() {
            const labels = [];
            // 上午:9:30-11:30
            for (let h = 9; h <= 11; h++) {
                const startMin = h === 9 ? 30 : 0;
                const endMin = h === 11 ? 31 : 60; // 包含11:30
                for (let m = startMin; m < endMin; m++) {
                    let timeStr = `${h.toString().padStart(2, '0')}:${m.toString().padStart(2, '0')}`;
                    // 关键修改:将11:30的标签改为 "11:30/13:00"
                    if (h === 11 && m === 30) {
                        timeStr = '11:30/13:00';
                    }
                    labels.push(timeStr);
                }
            }
            // 下午:13:00-15:00
            for (let h = 13; h < 15; h++) {
                for (let m = 0; m < 60; m++) {
                    const timeStr = `${h.toString().padStart(2, '0')}:${m.toString().padStart(2, '0')}`;
                    labels.push(timeStr);
                }
            }
            // 最后添加15:00
            labels.push('15:00');
            return labels;
        }

        // 生成完整的X轴标签(固定)
        const fullXAxisLabels = generateFullXAxisLabels();
        // 初始化数据数组:所有位置先填null(空数据)
        let chartData = new Array(fullXAxisLabels.length).fill(null);

        // ========== 2. 图表基础配置(X轴固定) ==========
        const option = {
            title: {
                text: '股票实时行情(9:30–11:30/13:00–15:00)',
                left: 'center'
            },
            tooltip: {
                trigger: 'axis',
                formatter: (params) => {
                    const time = params[0].axisValue;
                    const price = params[0].data === null ? '无数据' : params[0].data.toFixed(2);
                    return `${time}<br/>价格:${price}元`;
                }
            },
            grid: {
                left: '5%', right: '5%', top: '15%', bottom: '10%', containLabel: true
            },
            xAxis: {
                type: 'category',
                name: '交易时间',
                axisLabel: { 
                    fontSize: 11,
                    // 每10个标签显示一次,避免拥挤
                    interval: (index, value) => {
                        // 强制显示"11:30/13:00"这个关键标签
                        if (value === '11:30/13:00') return true;
                        return index % 10 === 0;
                    }
                },
                // 固定X轴标签,不随数据变化
                data: fullXAxisLabels,
                // 强制X轴显示完整,不自动缩放
                boundaryGap: false
            },
            yAxis: {
                type: 'value',
                name: '价格(元)',
                min: 95,
                max: 105
            },
            series: [{
                name: '股价',
                type: 'line',
                smooth: true,
                lineStyle: { width: 2 },
                // 空数据不连接
                connectNulls: false,
                // 初始数据全为null
                data: chartData
            }]
        };

        // 初始化图表(X轴已固定显示)
        myChart.setOption(option);

        // ========== 3. 动态生成股价数据 ==========
        class StockSimulator {
            constructor() {
                this.basePrice = 100;
                this.currentPrice = this.basePrice;
                this.currentIndex = 0; // 当前更新到的X轴索引
                this.timer = null;
            }

            // 生成下一个价格
            generatePrice() {
                const randomChange = (Math.random() - 0.5) * 0.8;
                this.currentPrice = Math.max(95, Math.min(105, this.currentPrice + randomChange));
                return this.currentPrice;
            }

            // 启动动态更新
            startUpdate() {
                this.timer = setInterval(() => {
                    // 停止条件:更新完所有数据点
                    if (this.currentIndex >= fullXAxisLabels.length) {
                        clearInterval(this.timer);
                        alert('今日交易结束!');
                        return;
                    }

                    // 生成当前索引的价格数据
                    const price = this.generatePrice();
                    // 填充到数据数组对应位置
                    chartData[this.currentIndex] = price;

                    // 只更新数据,X轴保持不变
                    myChart.setOption({
                        series: [{
                            data: chartData
                        }]
                    });

                    // 推进索引
                    this.currentIndex++;
                }, 200); // 200ms更新一个数据点
            }
        }

        // 启动模拟(DOM加载完成后执行)
        window.onload = function() {
            const simulator = new StockSimulator();
            simulator.startUpdate();
        };

        // 窗口自适应
        window.addEventListener('resize', () => myChart.resize());
    </script>
</body>
</html>

建议第3种实现方式,也是一些股票交易平台使用的显示方式。