echarts通过输入框‘控件来改变brush已选中的rect区域大小

113 阅读2分钟
<template>
  <div class="chart-container">
    <!-- 控制区域 -->
    <div class="control-area">
      <div class="input-group">
        <label>X最小值:</label>
        <el-input-number 
          v-model="brushRange.xMin" 
          :min="xAxisMin" 
          :max="xAxisMax"
          :precision="2"
          @change="handleBrushChange"
        />
      </div>
      <div class="input-group">
        <label>X最大值:</label>
        <el-input-number
          v-model="brushRange.xMax"
          :min="xAxisMin"
          :max="xAxisMax"
          :precision="2"
          @change="handleBrushChange"
        />
      </div>
      <div class="input-group">
        <label>Y最小值:</label>
        <el-input-number
          v-model="brushRange.yMin"
          :min="yAxisMin"
          :max="yAxisMax"
          :precision="2"
          @change="handleBrushChange"
        />
      </div>
      <div class="input-group">
        <label>Y最大值:</label>
        <el-input-number
          v-model="brushRange.yMax"
          :min="yAxisMin"
          :max="yAxisMax"
          :precision="2"
          @change="handleBrushChange"
        />
      </div>
    </div>

    <!-- 图表容器 -->
    <div ref="chart" class="echarts-container"></div>
  </div>
</template>




<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue'
import * as echarts from 'echarts'

// 图表实例
const chart = ref(null)
let chartInstance = null

// 坐标轴范围配置
const axisRange = ref({
  x: [0, 10], // X轴范围
  y: [0, 20]  // Y轴范围
})

// 刷选区域数据
const brushRange = ref({
  xMin: 0,
  xMax: 0,
  yMin: 0,
  yMax: 0
})

// 初始化图表
const initChart = () => {
  chartInstance = echarts.init(chart.value)
  
  // 生成模拟数据
  const generateData = () => {
    return Array.from({length: 100}, (_, i) => [
      +(i * 0.1).toFixed(2),
      +(Math.sin(i * 0.2) * 10 + 10).toFixed(2)
    ])
  }

  // 基础配置
  const option = {
    xAxis: {
      type: 'value',
      name: 'X轴',
      min: axisRange.value.x[0],
      max: axisRange.value.x[1],
      axisLabel: { formatter: '{value} °' }
    },
    yAxis: {
      type: 'value',
      name: 'Y轴',
      min: axisRange.value.y[0],
      max: axisRange.value.y[1],
      axisLabel: { formatter: '{value} N·m' }
    },
    series: [{
      type: 'line',
      data: generateData(),
      smooth: true,
      symbol: 'none',
      lineStyle: { 
        width: 2,
        color: '#5470C6'
      },
      areaStyle: {
        color: 'rgba(84, 112, 198, 0.1)'
      }
    }],
    brush: {
      toolbox: ['rect', 'clear'],
      xAxisIndex: 0,
      yAxisIndex: 0,
      brushStyle: {
        borderWidth: 2,
        color: 'rgba(135,206,250,0.3)',
        borderColor: '#5470C6'
      }
    }
  }

  chartInstance.setOption(option)
  
  // 设置初始刷选区
  updateBrushArea()
  
  // 监听刷选事件
  chartInstance.on('brush', handleBrushSelect)
}

// 更新刷选区
const updateBrushArea = () => {
  chartInstance.dispatchAction({
    type: 'brush',
    areas: [{
      brushType: 'rect',
      coordRange: [
        [brushRange.value.xMin, brushRange.value.xMax],
        [brushRange.value.yMin, brushRange.value.yMax]
      ],
      xAxisIndex: 0,
      yAxisIndex: 0
    }]
  })
}

// 处理输入框变化
const handleBrushChange = () => {
  // 边界校验
  brushRange.value.xMin = Math.max(axisRange.value.x[0], 
    Math.min(brushRange.value.xMin, brushRange.value.xMax))
  
  brushRange.value.xMax = Math.min(axisRange.value.x[1], 
    Math.max(brushRange.value.xMax, brushRange.value.xMin))
  
  brushRange.value.yMin = Math.max(axisRange.value.y[0], 
    Math.min(brushRange.value.yMin, brushRange.value.yMax))
  
  brushRange.value.yMax = Math.min(axisRange.value.y[1], 
    Math.max(brushRange.value.yMax, brushRange.value.yMin))

  // 更新图表
  updateBrushArea()
}

// 处理图表刷选事件
const handleBrushSelect = (params) => {
  if (!params.areas || params.areas.length === 0) return
  
  const range = params.areas[0].coordRange
  if (!range) return

  // 更新输入框值
  brushRange.value = {
    xMin: +range[0][0].toFixed(2),
    xMax: +range[0][1].toFixed(2),
    yMin: +range[1][0].toFixed(2),
    yMax: +range[1][1].toFixed(2)
  }
}

// 生命周期
onMounted(() => {
  initChart()
  window.addEventListener('resize', () => chartInstance?.resize())
})

onBeforeUnmount(() => {
  window.removeEventListener('resize', () => chartInstance?.resize())
  chartInstance?.dispose()
})
</script>
<style scoped>
.chart-container {
  width: 100%;
  height: 100vh;
  display: flex;
  flex-direction: column;
}

.control-area {
  padding: 20px;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 15px;
  background: #f8f9fa;
  border-bottom: 1px solid #eee;
}

.input-group {
  display: flex;
  align-items: center;
  gap: 8px;
  
  label {
    white-space: nowrap;
    color: #666;
  }
  
  :deep(.el-input-number) {
    width: 120px;
    
    .el-input__inner {
      text-align: center;
    }
  }
}

.echarts-container {
  flex: 1;
  min-height: 400px;
}
</style>