使用烛线图展示二进制01离散量趋势图

自动控制领域里的遥信量一般是离散的只有0 1 两个值的,如果要做图展示需要跟常见的趋势图不同。这里是个例子

javascript 复制代码
<!--
	此示例下载自 https://echarts.apache.org/examples/zh/editor.html?c=candlestick-touch
  烛线图,类似粗线是蜡烛身体,细线是火焰。但这个是横着放的。
  细线代表0,粗线代表1
-->
<!DOCTYPE html>
<html lang="en" style="height: 100%">
<head>
  <meta charset="utf-8">
</head>
<body style="height: 100%; margin: 0">
  <div id="container" style="height: 100%"></div> 
  <script type="text/javascript" src="https://fastly.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script>
  
  <script type="text/javascript">
    var dom = document.getElementById('container');
    var myChart = echarts.init(dom, null, {
      renderer: 'canvas',
      useDirtyRect: false
    });
    
    var option;

    // 生成简单的时间轴(每分钟一个数据点)
    const dates = [];
    const now = new Date();
    for (let i = 0; i < 50; i++) {
      const time = new Date(now.getTime() - (49 - i) * 60000);
      dates.push(time.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' }));
    }
    console.log('时间轴:', dates);
    // 二进制数据 (0, 1) - 0表示细线,1表示粗线
    // prettier-ignore
    const data = [0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0];
    console.log('数据:', data);
    // 为了实现不同线宽但连续的线条,创建分段数据
    function createSegmentData() {
      const segments = [];
      let start = 0;
      
      for (let i = 1; i <= data.length; i++) {
        // 当值发生变化时,或到达数组末尾时,创建一个段
        if (i === data.length || data[i] !== data[i - 1]) {
          const segmentData = [];
          // 创建该段的所有数据点
          for (let j = start; j < i; j++) {
            segmentData.push([j, 0.5]);
          }
          // 如果不是最后一段,添加下一个点以保证连续性
          if (i < data.length) {
            segmentData.push([i, 0.5]);
          }
          console.log('分段数据:', segmentData);
          segments.push({
            data: segmentData,
            lineWidth: data[start] === 0 ? 3 : 10,
            color: data[start] === 0 ? '#52c41a' : '#ff4d4f'
          });
          
          start = i;
        }
      }
      
      return segments;
    }

    const segments = createSegmentData();
    console.log('分段数据:', segments);
    option = {
      animation: false,
      title: {
        left: 'center',
        text: '二进制状态图'
      },
      tooltip: {
        trigger: 'axis',
        formatter: function (params) {
          // 用第一个系列的点的全局索引获取时间          
          // console.log('params------:', params);
          const globalIndex = params[0].data[0];// params[0].data[params[0].dataIndex][0];
          const time = dates[globalIndex];
          let html = time + '<br/>';
            let p = params[0];           
            const val = data[globalIndex];            
            html += `${p.marker}系列A: ` + (val === 0 ? '低电平(0)' : '高电平(1)') + '<br/>';          
          return html;
        }
      },
      xAxis: {
        type: 'category',
        data: dates,
        boundaryGap: false,
        axisLine: { lineStyle: { color: '#777' } },
        axisLabel: {
          show: true,
          color: '#666'
        }
      },
      yAxis: {
        type: 'value',
        show: false,  // 隐藏y轴信息
        min: 0,
        max: 1
      },
      grid: {
        left: 20,
        right: 20,
        top: 80,
        bottom: 50
      },
      series: segments.map((segment, index) => ({
        name: `状态段${index}`,
        type: 'line',
        data: segment.data,
        showSymbol: false,
        lineStyle: {
          width: segment.lineWidth,
          color: segment.color
        }
      }))
    };

    if (option && typeof option === 'object') {
      myChart.setOption(option);
    }

    window.addEventListener('resize', myChart.resize);
  </script>
</body>
</html>

双系列,多系列

javascript 复制代码
<!--
	此示例下载自 https://echarts.apache.org/examples/zh/editor.html?c=candlestick-touch
  烛线图,类似粗线是蜡烛身体,细线是火焰。但这个是横着放的。
  细线代表0,粗线代表1
-->
<!DOCTYPE html>
<html lang="en" style="height: 100%">
<head>
  <meta charset="utf-8">
</head>
<body style="height: 100%; margin: 0">
  <div id="container" style="height: 100%"></div> 
  <script type="text/javascript" src="https://fastly.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script>
  
  <script type="text/javascript">
    var dom = document.getElementById('container');
    var myChart = echarts.init(dom, null, {
      renderer: 'canvas',
      useDirtyRect: false
    });
    
    var option;

    // 生成简单的时间轴(每分钟一个数据点)
    const dates = [];
    const now = new Date();
    for (let i = 0; i < 50; i++) {
      const time = new Date(now.getTime() - (49 - i) * 60000);
      dates.push(time.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' }));
    }

    // 二进制数据 (0, 1) - 0表示细线,1表示粗线
    // prettier-ignore
    const data = [0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0];
    console.log('数据:', data);

    // 第二条离散量数据
    const data2 = [1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0];
    console.log('数据2:', data2);
    // 为了实现不同线宽但连续的线条,创建分段数据
    function createSegmentData() {
      const segments = [];
      let start = 0;
      
      for (let i = 1; i <= data.length; i++) {
        // 当值发生变化时,或到达数组末尾时,创建一个段
        if (i === data.length || data[i] !== data[i - 1]) {
          const segmentData = [];
          // 创建该段的所有数据点
          for (let j = start; j < i; j++) {
            segmentData.push([j, 0.5]);
          }
          // 如果不是最后一段,添加下一个点以保证连续性
          if (i < data.length) {
            segmentData.push([i, 0.5]);
          }
          
          segments.push({
            data: segmentData,
            lineWidth: data[start] === 0 ? 3 : 10,
            color: data[start] === 0 ? '#52c41a' : '#ff4d4f'
          });
          
          start = i;
        }
      }
      
      return segments;
    }

    const segments = createSegmentData();

      // 第二条线的分段数据生成
      function createSegmentData2() {
        const segments = [];
        let start = 0;
        for (let i = 1; i <= data2.length; i++) {
          if (i === data2.length || data2[i] !== data2[i - 1]) {
            const segmentData = [];
            for (let j = start; j < i; j++) {
              segmentData.push([j, 0.2]); // 第二条线y值不同,避免重叠
            }
            if (i < data2.length) {
              segmentData.push([i, 0.2]);
            }
            segments.push({
              data: segmentData,
              lineWidth: data2[start] === 0 ? 3 : 10,
              color: data2[start] === 0 ? '#1890ff' : '#faad14' // 蓝色/橙色
            });
            start = i;
          }
        }
        return segments;
      }
      const segments2 = createSegmentData2();
    
    option = {
      animation: false,
      title: {
        left: 'center',
        text: '二进制状态图'
      },
      tooltip: {
        trigger: 'axis',
        formatter: function (params) {
          if (!params || !params.length) return '';
          // console.log('params------:', params);
          // const dataIndex = params[0].dataIndex;
          // const time = dates[dataIndex];
          const dataIndex = params[0].data[0];// params[0].data[params[0].dataIndex][0];
          const time = dates[dataIndex];
          let result = time + '<br/>';
          let serAry = []
          for (var i =0;i<params.length;i++) {
            let item = params[i];            
 
          // 判断是第一个系列还是第二个系列
            let seriesLabel = item.seriesName.startsWith('系列1') ? '系列1' : '系列2';
            if (serAry.includes(seriesLabel)) {
              // 已经处理过了,就忽略
              continue;
            }
            serAry.push(seriesLabel);
            // 判断当前系列用哪个数据源
            let value = seriesLabel === '系列1' ? data[dataIndex] : data2[dataIndex];
            let valueText = value === 0 ? '低电平(0)' : '高电平(1)';
            result += `${seriesLabel}: ${valueText}<br/>`;
          };
          return result;
        }
      },
      xAxis: {
        type: 'category',
        data: dates,
        boundaryGap: false,
        axisLine: { lineStyle: { color: '#777' } },
        axisLabel: {
          show: true,
          color: '#666'
        }
      },
      yAxis: {
        type: 'value',
        show: false,  // 隐藏y轴信息
        min: 0,
        max: 1
      },
      grid: {
        left: 20,
        right: 20,
        top: 80,
        bottom: 50
      },
      series: [
        ...segments.map((segment, index) => ({
          name: `系列1-段${index}`,
          type: 'line',
          data: segment.data,
          showSymbol: false,
          lineStyle: {
            width: segment.lineWidth,
            color: segment.color
          }
        })),
        ...segments2.map((segment, index) => ({
          name: `系列2-段${index}`,
          type: 'line',
          data: segment.data,
          showSymbol: false,
          lineStyle: {
            width: segment.lineWidth,
            color: segment.color
          }
        }))
      ]
    };

    if (option && typeof option === 'object') {
      myChart.setOption(option);
    }

    window.addEventListener('resize', myChart.resize);
  </script>
</body>
</html>
相关推荐
你挚爱的强哥17 分钟前
SCSS上传图片占位区域样式
前端·css·scss
奶球不是球18 分钟前
css新特性
前端·css
Nicholas6819 分钟前
flutter滚动视图之Viewport、RenderViewport源码解析(六)
前端
无羡仙29 分钟前
React 状态更新:如何避免为嵌套数据写一长串 ...?
前端·react.js
TimelessHaze1 小时前
🔥 一文掌握 JavaScript 数组方法(2025 全面指南):分类解析 × 业务场景 × 易错点
前端·javascript·trae
jvxiao1 小时前
搭建个人博客系列--(4) 利用Github Actions自动构建博客
前端
袁煦丞2 小时前
SimpleMindMap私有部署团队脑力风暴:cpolar内网穿透实验室第401个成功挑战
前端·程序员·远程工作
li理2 小时前
鸿蒙 Next 布局开发实战:6 大核心布局组件全解析
前端
EndingCoder2 小时前
React 19 与 Next.js:利用最新 React 功能
前端·javascript·后端·react.js·前端框架·全栈·next.js
li理2 小时前
鸿蒙 Next 布局大师课:从像素级控制到多端适配的实战指南
前端