echarts绘制立体图示法的坐标系

594 阅读3分钟

需求分析

使用echarts绘制如下图的立体坐标系,需要用到echarts-gl,该坐标系有如下特点:

  • 三个坐标轴(立体坐标系)
  • 大刻度步进值为10倍:0 ~ 0.10.1 ~ 11 ~ 10
  • 第一段刻度的子刻度为10个:00.01……0.1
  • 其他段刻度的子刻度为9个:0.10.2……1
  • 只显示大刻度:0.1110
段 / 子刻度位置1234567891011
第一段00.010.020.030.040.050.060.070.080.090.1
第二段0.10.20.30.40.50.60.70.80.91缺少一格
第三段12345678910缺少一格

立体坐标轴.png

因为子刻度分别为10个和9个,所以考虑了两种方案来绘制

方式一:小刻度宽度一致

  • 每个小刻度的宽度为10px
  • 第一段刻度的宽度:100px
  • 其他段刻度的宽度:90px

优点:10px是整数,计算精度时结果完整

缺点:大刻度宽度不一样

为何小刻度的宽度为10px

方便精度计算,例如:

  • 0 ~ 0.1刻度中,绘制 0.012这个点,那么这个点的所在像素位置为

10px * 0.012 * 100 = 12px

  • 0.1 ~ 1刻度中,绘制 0.34这个点,那么这个点的所在像素位置为

100px + 10px * 0.34 * 10 = 134px

  • 1 ~ 10刻度中,绘制 2.5这个点,那么这个点的所在像素位置为

100px + 90px + 10px * (2.5 - 1) = 205px

绘制结果

image.png

绘制结果分析

因为第一段100px而其他段为90px,所以刻度的实际像素位置分别为100px190px280px,这三个数的最小公因数为10,所以绘制结果的刻度线看起来密密麻麻

下方是绘制刻度标签的代码:

xAxis3D: {
    type: 'value',
    name: 'X',
    min: 0,
    max: 280, // 最大像素
    interval: 10, // 间隔10
    axisLabel: {
      formatter: function (value) {
        switch (value) {
          case 0:
            return '0'
          case 100:
            return '0.1'
          case 190:
            return '1.0'
          case 280:
            return '10'
        }
        return ''
      }
}

完整代码

<template>
  <b-container>
    <div id="main-honyee" style="width: 800px;height:500px;"></div>
  </b-container>
</template>

<script>
import * as echarts from 'echarts';
import 'echarts-gl';

export default {
  methods: {
    startDraw() {
      let chartInstance = echarts.init(document.getElementById('main-honyee'));
      const option = {
        tooltip: {},
        xAxis3D: this.axisConfig('X'),
        yAxis3D: this.axisConfig('Y'),
        zAxis3D: this.axisConfig('Z'),
        grid3D: {
          show: true,
          temporalSuperSampling: {
            enable: true
          },
          viewControl: {
            alpha: 30,
            beta: 160
          },
        },
        series: []
      }
      chartInstance.setOption(option);

    },
    axisConfig(name) {
      return {
        type: 'value',
        name: name,
        min: 0,
        max: 280,
        interval: 10,
        axisLabel: this.axisLabelConfig(),
      }
    },
    axisLabelConfig() {
      return {
        formatter: function(value){
          // 隐藏原点
          switch (value) {
            case 0:
              return '0'
            case 100:
              return '0.1'
            case 190:
              return '1.0'
            case 280:
              return 10
          }
          return ''
        }
      }
    },
  },
  mounted() {
    this.startDraw();
  }
}
</script>

方式二:大刻度宽度一致

  • 每一段大刻度的宽度为100px
  • 第一段小刻度的宽度:100px ÷ 10 = 10px
  • 其他段刻度的宽度:100px ÷ 9 ≈ 11.1px

优点:大刻度宽度相同,看着比较整齐,且与需求坐标图一致

缺点:10px11.1px相差11%左右,小刻度长度不一致。且11.1px是四舍五入后的结果,所以位置像素计算结果会存在些许误差

绘制结果

image.png

绘制结果分析

下方是绘制刻度标签的代码:

<template>
  <b-container>
    <div id="main-honyee" style="width: 800px;height:500px;"></div>
  </b-container>
</template>

<script>
import * as echarts from 'echarts';
import 'echarts-gl';

export default {
  methods: {
    startDraw() {
      let chartInstance = echarts.init(document.getElementById('main-honyee'));
      const option = {
        tooltip: {},
        xAxis3D: this.axisConfig('X'),
        yAxis3D: this.axisConfig('Y'),
        zAxis3D: this.axisConfig('Z'),
        grid3D: {
          show: true,
          temporalSuperSampling: {
            enable: true
          },
          viewControl: {
            alpha: 30,
            beta: 160
          },
        },
        series: []
      }
      chartInstance.setOption(option);

    },
    axisConfig(name) {
      return {
        type: 'value',
        name: name,
        min: 0,
        max: 300,
        interval: 100, // 间隔100
        axisLabel: this.axisLabelConfig()
      }
    },
    axisLabelConfig() {
      const base = 10
      const scaleLength = base * 10 // 每段长度
      return {
        formatter: function (value) {
          switch (value) {
            case 0:
              return '0'
            case scaleLength:
              return '0.1'
            case scaleLength * 2:
              return '1.0'
            case scaleLength * 3:
              return 10
          }
          return ''
        }
      }
    },
  },
  mounted() {
    this.startDraw();
  }
}
</script>

结论

两种方式都可以,优缺点取舍