解决echartsY轴溢出以及多Y轴动态设置offest

一、描述

由于上一篇文章已经介绍了处理方法,这篇文章主要展示处理数据的完整代码

1、处理数据的hooks

import http from '../../../../utils';

import rest from '../../../../common/rest.json';

import dayjs from 'dayjs';

import Utils from '../../../../tools'

import { useState } from 'react';

const useMultidimensionAlanalysisApi = (baseUrl) => {

  const [tableData, setTableData] = useState([]); // 图表数据

  const [loading, setLoading] = useState(false)

  const [seriesData, setSeriesData] = useState([]);

  const [Xdata, setXData] = useState([]);

  const [lengedData, setLengedData] = useState([]);

  const color = ['#FFC627', '#7EB338', '#009FF5', "#5E7DEC", "#BE271C"]

  // 处理图表数据

  const [yAxisArr, setYAxisArr] = useState([])

  // 获取数据

  const getData = (index, data, timeRange) => {

    if (!data.length) return;

    setLoading(true)

    http.post(baseUrl + rest.energy.multidimension.pointData, {

      pointNames: data.map((el) => el.text),

      startTime: dayjs(timeRange[0]).format('YYYY-MM-DD 00:00:00'),

      endTime: dayjs(timeRange[1]).format('YYYY-MM-DD 23:59:59')

    }).then((res) => {

      formatData(res.data.data);

      setLoading(false)

    }).catch((e) => {

      console.log(e);

    });

  };

  const formatData = (lineData) => {

    if (lineData.length) {

      lineData = lineData.sort(function (a, b) {

        return b.unit.length  - a.unit.length

      })

      const lengedArr = [];

      let yAxisData = []

      let timeData = [];

      let unitData = []

      lineData.forEach((el) => {

        el.samples = el.samples.map(el => ({

          ...el,

          value: el.value,

          collectTime: Date.parse(el.collectTime)

        })).sort(function (a, b) {

          return a.collectTime - b.collectTime

        })

        timeData = el.samples.map(el => dayjs(el.collectTime).format("YYYY-MM-DD HH:mm"))

        unitData.push(el?.unit)

      });

      setTableData(lineData)

      unitData = [...new Set(unitData)]

      setXData(timeData);

      unitData.forEach((el, index) => {

        yAxisData.push({

          position: index === 0 ? "left" : "right",

          // offset: formatdDistance(index),

          type: 'value',

          name: el,

          nameTextStyle: {

            color: "#A0A0A0",

            fontSize: '.875rem',

            padding: index === 0 ? [0, 35, 15, 0] : [0, 0, 15, 40]

          },

          alignTicks: true, // !!配置多坐标轴标签对齐

          splitLine: {

            lineStyle: {

              color: '#707070',

            },

          },

          axisLabel: {

            fontSize: '.875rem',

            color: '#A0A0A0',

          },

        })

      })

      const arr = lineData.map((el, index) => {

        lengedArr.push(el.pointName);

        const unitIndex = unitData.findIndex(item => item === el.unit)

        return {

          name: el.pointName,

          type: 'line',

          color: index < 5 ? color[index] : Utils.randomHexColor(),

          data: el.samples.map((item) => item.value),

          yAxisIndex: unitIndex,

          symbol: 'circle',

          symbolSize:8,

          unit: el.unit,

          // showAllSymbol:true

          // connectNulls: true

        };

      });

      setLengedData([...lengedArr]);

      setYAxisArr([...yAxisData])

      setSeriesData([...arr]);

    } else {

      setLengedData([]);

      setSeriesData([]);

      setTableData([])

    }

  };

  return {

    tableData,

    seriesData,

    lengedData,

    Xdata,

    yAxisArr,

    loading,

    getData,

    setTableData,

    setSeriesData,

  };

};

export default useMultidimensionAlanalysisApi;

2、echarts组件

 

import React, { useEffect, useState, memo } from 'react';

import 'echarts/lib/component/markLine';

import 'echarts/lib/component/markPoint';

import Utils from '../../../../tools'

import ChartUtil from '../../../../common/chart/chart-util';

import { nowSize } from '../../../../common/commonUtil';

import { useECharts } from '../../../../common/chart/useECharts';

import { intervalScaleNiceTicks } from 'echarts/lib/scale/helper.js';

function getActualWidthOfChars(text, options = {}) {

  const { size = 14, family = 'Honeywell Sans Web, Verdana, sans-serif' } = options;

  let canvas = document.createElement('canvas');

  const ctx = canvas.getContext('2d');

  ctx.font = `${size}px ${family}`;

  const metrics = ctx.measureText(text);

  const actual =

    Math.abs(metrics.actualBoundingBoxLeft) +

    Math.abs(metrics.actualBoundingBoxRight);

  canvas = null;

  return Math.max(metrics.width, actual);

}

function getMaxWidth(extend, option) {

  let LMaxWidth = 0;

  if (!(extend[0] === 0 && extend[1] === 0)) {

    const lTick = intervalScaleNiceTicks(extend, 5);

    const min =

      lTick.niceTickExtent[0] < 0

        ? lTick.niceTickExtent[0] - lTick.interval

        : lTick.niceTickExtent[0];

    const max = lTick.niceTickExtent[1] + lTick.interval;

    const lMin = Utils.formatNumber(min, 0);

    const lMax = Utils.formatNumber(max, 0);

    LMaxWidth = getActualWidthOfChars(

      lMax.toString().length > lMin.toString().length ? lMax : lMin,

      option

    );

  }

  return LMaxWidth;

}

const LineChart = memo(

  ({ seriesData, Xdata, lengedData, style, theme, yAxisArr }) => {

    const { setOptions: setLineChart, getInstance } = useECharts('LineChart', theme);

    const fontFamily = 'Honeywell Sans Web, Verdana, sans-serif';

    const fontSize = nowSize(14);

    let otherWidth = 0

    let lengedWidth = 0

    let firstWidth = 0

    let leftWidth = 0

    const useLineChart = () => {

      const option = {

        dataZoom: [

          {

            type: 'inside',

            start: 0,

            end: 100,

          },

          {

            type: 'slider', // slider表示有滑动块的,inside表示内置的

            show: true, // 是否显示dataZoom,在完全自定义的时候需要用到

            xAxisIndex: [0], // dataZoom控制的图标的是哪条x轴,因为会有多轴一图,可以控制多轴

            // yAxisIndex: [0, 1], // dataZoom控制的图标的是哪条y轴,因为会有多轴一图,可以控制多轴

            start: 0, // 和startValue不要弄混,这里是百分比

            end: 100, // 和endValue不要弄混,这里是百分比

            startValue: 0, // 滑块左端对应的x值

            endValue: 500, // 滑块右端对应的x值

            height: 10, // dataZoom整体高度

            backgroundColor: '#404040',

            filterMode: 'none', // 过滤模式,有filter, weakFilter, empty, none四个值,过滤会把整个数据段隐藏,而none则只是移动坐标轴

            right: '4%',

            // width: '90%',

            left: '4.8%',

            bottom: 0, // dataZoom相对图标的位置

            animation: true, // 设置动画效果

            throttle: 100, // 设置视图刷新的频率,ms

            showDetail: true,

            showDataShadow: false,

            borderColor: '#0000', // dataZoom边框颜色

            fillerColor: '#ffffff4c', //  滑块颜色

            brushSelect: false, // 是否允许拖动滑块长度改变视图范围,不允许就是固定范围

            handleIcon:

              'M-9.35,34.56V42m0-40V9.5m-2,0h4a2,2,0,0,1,2,2v21a2,2,0,0,1-2,2h-4a2,2,0,0,1-2-2v-21A2,2,0,0,1-11.35,9.5Z',

          },

        ],

        tooltip: {

          trigger: 'axis',

          formatter: function (params) {

            let str = '';

            let title = '';

            params?.forEach((item, index) => {

              const unit = seriesData[seriesData.findIndex(el => el.name === item.seriesName)].unit

              title = `<div style="color:#E0E0E0">${item.axisValue}</div>`;

              str += `<div style="display:flex;align-items:center;background-color:#454545;">

            <div style="width:.2437rem;height:.9375rem;margin-right:.6875rem;background:${item.color}"></div>

            <div style="margin-left:.625rem;color:#A0A0A0;font">${item.seriesName}</div>

            <div style="margin-left:.625rem;margin-right:.625rem;color:#FFFFFF">${item.value}</div>

            <div style="color:#A0A0A0;margin-left:auto">${!unit ? "" : unit}</div>

          </div>`;

            });

            return title + str;

          },

          extraCssText: `border-radius: .375rem;

        border-color:#454545;

        background-color:#454545;`,

        },

        xAxis: {

          type: 'category',

          data: Xdata,

          name: Utils.translate('energy.multidimensionality.xUnit'),

          axisPointer: {

            type: 'shadow',

          },

          axisTick: {

            alignWithLabel: true, // true:标签位于刻度线正下方;false:标签位于2个刻度线中间

          },

          nameTextStyle: {

            // x轴name的样式调整

            align: 'right',

            color: '#A0A0A0',

            fontSize: '1rem',

            verticalAlign: 'top',

            padding: [20, yAxisArr?.length === 1 ? -(leftWidth - 15) : -(otherWidth - 40), 0, 0],

          },

          axisLabel: {

            margin: 20,

            textStyle: {

              color: '#A0A0A0',

              fontSize: '1rem',

            },

          },

        },

        yAxis: yAxisArr,

        grid: {

          top: '18%',

          left: leftWidth + 5,

          right: otherWidth ? otherWidth < 260 ? otherWidth : 260 : leftWidth + 25,

          bottom: '19%',

          // containLabel: true,

        },

        legend: {

          data: lengedData,

          itemHeight: 8,

          itemWidth: 14,

          itemGap: 20,

          orient: 'horizontal',

          textStyle: {

            color: '#A0A0A0',

            fontSize: '.875rem',

          },

          right: lengedWidth,

          y: 'top',

          icon: 'path://M8.82929 2H12V4H8.82929C8.41746 5.16519 7.30622 6 6 6C4.69378 6 3.58254 5.16519 3.17071 4H0V2H3.17071C3.58254 0.834808 4.69378 0 6 0C7.30622 0 8.41746 0.834808 8.82929 2Z',

        },

        series: seriesData,

      };

      setLineChart(option)

    }

    useEffect(() => {

      if (seriesData?.length) {

        formatData(seriesData)

      }

    }, [seriesData]);

    const formatData = (seriesData) => {

      seriesData.forEach((el, index) => {

        const LeftExtend = [0, 0];

        const beforeLeftExtend = [0, 0]

        const data = el.data.filter((item) => item !== '-').map((itme) => parseFloat(itme)) || [];

        const beforeData = seriesData[index - 1]?.data.filter((item) => item !== '-').map((itme) => parseFloat(itme)) || [];

        LeftExtend[1] = Math.max(...data) > LeftExtend[1] ? Math.max(...data) : LeftExtend[1];

        beforeLeftExtend[1] = Math.max(...beforeData) > beforeLeftExtend[1] ? Math.max(...beforeData) : beforeLeftExtend[1];

        const w = getActualWidthOfChars(Math.ceil(LeftExtend[1]).toString())

        const w1 = getActualWidthOfChars(Math.ceil(beforeLeftExtend[1]).toString())

        if (yAxisArr[index]) {

          yAxisArr[index].nameTextStyle = {

            color: "#A0A0A0",

            fontSize: '.875rem',

            padding: index === 0 ? [0, nowSize(w + 15), nowSize(15), 0] : [0, 0, nowSize(15), nowSize(w + 15)]

          }

          if (index !== 0) {

            otherWidth += Math.ceil(w) + 25

          } else firstWidth = Math.ceil(w) + 30

          if (index === 0 || index === 1) {

            yAxisArr[index].offset = 0

          } else yAxisArr[index].offset = yAxisArr[index - 1].offset + Math.ceil(w1) + 25

        }

      })

      if (yAxisArr.length === 2) otherWidth += 25

      lengedData.forEach((el) => {

        lengedWidth += Math.ceil(getActualWidthOfChars(el))

      })

      lengedWidth = getMaxWidth(lengedWidth, {

        size: fontSize,

        family: fontFamily,

      }) - 8

      leftWidth = getActualWidthOfChars(Xdata[0]) / 2

      useLineChart()

    }

    return <div

      id="chart-LineChart"

      style={style}

    ></div>

  }

)

export default LineChart;

  • 24
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值