echarts图表自适应--hooks封装

189 阅读3分钟

在初始化的时候有一点不同,使用svg方式渲染更清晰

echarts.init(dom, undefined, { renderer: "svg" });

期望结果:

  • 鼠标滚轮缩放,图表字体自适应,图形自适应

本次封装比较草率,实在看不下去就自己修改一下

先说使用方式

useSelfAdaptionEcharts(option, myChart);//option图表配置,myChart图表实例

注意needDefaultFields这个变量上面的注释说明

import * as echarts from "echarts";
import { ECharts } from "echarts";
type EChartsOption = echarts.EChartsOption;
// 需要转为自适应的字段
const fields = [
  "borderDashOffset",
  "fontSize",
  "width",
  "height",
  "left",
  "right",
  "top",
  "bottom",
  "distance",
  "padding",
  "nameGap",
  "borderWidth",
  "borderRadius",
  "shadowOffsetX",
  "shadowOffsetY",
  "itemWidth",
  "itemHeight",
  "radius"
];
/*
需要设置默认值的字段🤪
{
  key:字段名
  pathList:[
     [该字段所涉及的层级关系]
  ]
}
在传入的option中需要把需要设置默认值的字段层级写到上一层
例如:需要将tooltip中的textStyle的fontSize设置默认值
option中只需要写  tooltip:{textStyle:{}}
 */
const needDefaultFields = [
  {
    key: "fontSize",
    defaultVal: 10,
    pathList: [
      ["legend", "textStyle"],
      ["xAxis", "axisLabel"],
      ["yAxis", "axisLabel"],
      ["series","label"],
      ["yAxis", "nameTextStyle"]
    ]
  },
  {
    key: "fontSize",
    defaultVal: 14,
    pathList: [["tooltip", "textStyle"]]
  }
];
const standWidth = window.innerWidth;
const standFontSize = 1920 / 16; //定义标准 1rem ===16px
const countSize = (currentSize: number) => {
  // 计算字体大小对应的rem数值
  const transformRemVal = currentSize / 16;
  const curWidth = window.innerWidth;
  const fontSize = curWidth / standFontSize;
  return transformRemVal * fontSize;
};
let curVal = null; //当前取值
let tempKey = null; //存储数组所在的key
let findResKey = null; //key查找结果
let newOptions = null;
const isComplexType = obj => (typeof obj === 'object' || typeof obj === 'function')&&(obj !==null)
 const deepCopy = obj =>{
   if (typeof obj !== "object" || obj == null) {
    return obj
  }
  //定义返回值result
  // 判断传进来的数据类型 是数组/对象 就给result一个数组/对象
  let result = Array.isArray(obj) ? [] : {};
  //循环遍历方便拷贝
  for (let key in obj) {
    //判读自有属性
    if (obj.hasOwnProperty(key)) {
      //函数递归实现深层拷贝
      result[key] = deepCopy(obj[key])
    }
  }
  //返回出去
  return result
 }
const isInFields = (key: string) => fields.find(item => item === key);
const isObject = (val: any) => val instanceof Object;
const isArray = (val: any) => val instanceof Array;
/**
 * [hanldeOptions 将配置中所涉及到的字段使用计算函数进行尺寸计算]
 * @optionObj 图表配置
 * @arrKey    数组项所属的key名
 */
function hanldeOptions<T>(optionObj: any, arrKey = null): T {
    // debugger
  for (let key in optionObj) {
    // 如果还是对象继续递归,函数不作处理
    curVal = optionObj[key];
    if (typeof curVal === "object" && typeof curVal !== "function") {
      tempKey = null;
      isArray(curVal) && (tempKey = key);
      hanldeOptions(curVal, tempKey);
    } else {

      if (arrKey) findResKey = isInFields(arrKey);
      else findResKey = isInFields(key);
      if (findResKey && typeof optionObj[findResKey] === "number") {
        optionObj[findResKey] = countSize(optionObj[findResKey]);
      }
    }
  }
  return optionObj;
}
/**
 * [useSelfAdaptionEcharts 将需要设置默认值的配置信息赋值]
 * @optionObj 图表配置
 * @keyArr    目标key的层级关系数组
 * @tarVal    目标key需要的值
 * @tarKey    目标key名称
 */
const setDefaultSize = (optionObj: any, keyArr: any, tarVal: number, tarKey: string) => {
  if (keyArr.length === 0) {
    // 保留原始值,如果配置中有值就不再设置
    if (!optionObj[tarKey]) optionObj[tarKey] = tarVal;
    return optionObj;
  }
  let currentKey = keyArr.shift();
  /*
    首先捕捉到 外层都没有这个属性就没必要递归下去了
    例如:legend这个属性都没有,没必要设置它里面的fontSize了
          因为可能不想展示图例,如果optionObj[currentKey] = {};就违背了最初的设定😎
   */
  if (!optionObj[currentKey]) return optionObj// optionObj[currentKey] = {};
  if (isArray(optionObj[currentKey])) {
    optionObj[currentKey].forEach(item => (item = setDefaultSize(item, keyArr, tarVal, tarKey)));
  } else optionObj[currentKey] = setDefaultSize(optionObj[currentKey], keyArr, tarVal, tarKey);
  return optionObj;
};
/**
 * [handleDefaultOptionsSize 将已有的option中指定配置使用自适应计算]
 * @options 图表配置
 */
const handleDefaultOptionsSize = (options: EChartsOption) => {
  let newOption = deepCopy(options);
  needDefaultFields.forEach(defaultItem => {
    defaultItem.pathList.forEach(pathItem => {
      setDefaultSize(newOption, deepCopy(pathItem), defaultItem.defaultVal, defaultItem.key);
    });
  });
  return newOption;
};
/**
 * [useSelfAdaptionEcharts 将已有的option中指定配置使用自适应计算]
 * @options 图表配置
 * @echartsInstance  图表实例
 * @needDefault 是否需要设置常用字段的默认值
 */
export const useSelfAdaptionEcharts = (options: EChartsOption, echartsInstance: ECharts, needDefault = true) => {
  let newOptions = null;
  curVal = null; //当前取值
  tempKey = null; //存储数组所在的key
  findResKey = null; //key查找结果
  if (needDefault) newOptions = handleDefaultOptionsSize(options);
  const resOptions = hanldeOptions(deepCopy(newOptions ?? options));
  echartsInstance.setOption(resOptions);
  window.addEventListener("resize", () => {
    const resOptions = hanldeOptions(deepCopy(newOptions ?? options));
    echartsInstance.setOption(resOptions);
    echartsInstance.resize();
  });
};