解决 ECharts 在高分辨率屏幕下的缩放问题
问题
一些没有加单位的配置项,例如 fontSize: 12
以及一些没有自定义的配置项默认也是不带单位的,在 1080p 屏幕下显示大小合适,在 4K 屏幕下就小小的
解决
给配置项设置缩放值
使用一个函数传入 echarts 配置项,递归遍历每一个属性,对其中的数值乘上当前的缩放值。
import * as echarts from 'echarts';
import { difference } from 'lodash';
/**
* 根据页面和设计稿的缩放尺寸,对 ECharts 配置中的一些属性设置缩放(会改变传入的 echartsOptions 对象)
*
* @param echartsOptions - ECharts 配置
* @param includesProps - 更多需要处理的属性,默认包含:
* - 'width'
* - 'height'
* - 'fontSize'
* - 'lineHeight'
* - 'textShadowBlur'
* - 'padding'
* - 'letterSpacing'
* - 'wordSpacing'
* - 'symbolSize'
* - 'symbolOffset'
* - 'barWidth'
* - 'lineWidth'
* - 'itemWidth'
* - 'itemHeight'
* - 'itemGap'
* - 'top'
* - 'right'
* - 'bottom'
* - 'left'
* - 'margin'
* - 'borderWidth'
* @param excludesProps - 不需要处理的属性,默认:`[]`
*
* @returns 处理后的 ECharts 配置
*/
export function setScaleToEchartsOptions(
echartsOptions: echarts.EChartsOption,
includesProps = [] as string[],
excludesProps = [] as string[],
) {
/** 设计稿高度 */
const DESIGN_HEIGHT = 1080;
/** 当前的缩放值 */
const scale = window.innerHeight / DESIGN_HEIGHT;
const _includesProps = [
...new Set([
'width',
'height',
'fontSize',
'lineHeight',
'textShadowBlur',
'padding',
'letterSpacing',
'wordSpacing',
'symbolSize',
'symbolOffset',
'barWidth',
'lineWidth',
'itemWidth',
'itemHeight',
'itemGap',
'top',
'right',
'bottom',
'left',
'margin',
'borderWidth',
...includesProps,
]),
];
/** 需要缩放的属性集合 */
const props = difference(_includesProps, excludesProps);
/**
* 递归处理对象属性
* @param obj
* @returns
*/
const setScale = <T extends Record<string, any>>(obj: T) => {
if (typeof obj === 'object') {
// 遍历对象属性
for (const key in obj) {
// 只处理本身的属性
if (Object.prototype.hasOwnProperty.call(obj, key)) {
// 处理需要设置缩放值的属性
if (props.includes(key)) {
const valueType = typeof obj[key];
if (valueType === 'number') {
// 值是数字,直接乘以缩放值
(obj[key] as number) *= scale;
} else if (Array.isArray(obj[key])) {
// 值是数组,遍历数组每个元素乘以缩放值
(obj[key] as Array<number | string>) = (
obj[key] as Array<number | string>
).map((val) => {
return typeof val === 'number' ? val * scale : val;
});
}
}
// 处理 tooltip 大小自适应
if (key === 'tooltip') {
obj[key].renderMode = 'html';
obj[key].className = 'echarts-tooltip';
}
// 递归处理嵌套的对象
setScale(obj[key]);
}
}
}
return obj;
};
return setScale(echartsOptions);
}
自定义 tooltip
在上面的 setScaleToEchartsOptions
函数中给 tooltip 对象设置了渲染模式为 'html'
,并加上了自定义的 css class name 'echarts-tooltip'
,再通过 css 处理 tooltip 的大小。
由于渲染出来的 tooltip 元素几乎没带 class,所以改样式的选择器看起来很奇怪…
// echarts tooltip 大小自适应
.echarts-tooltip {
position: absolute !important;
box-shadow: rgba(0, 0, 0, 0.2) 1px 2px 10px !important;
border-radius: 4px !important;
padding: 10px !important;
// 用于清除浮动的元素
div[style='clear:both'] {
display: none;
}
// 单个数据系列的样式
@mixin series-item-style {
// 图例
span:nth-child(1) {
margin-right: 4px !important;
border-radius: 10px !important;
width: 10px !important;
height: 10px !important;
}
// 名称
span:nth-child(2) {
font-size: 14px !important;
margin-left: 2px !important;
}
// 值
span:nth-child(3) {
margin-left: 20px !important;
font-size: 14px !important;
}
}
// 单系列图表的 tooltip 样式(不显示分类名)
& > div > div {
@include series-item-style();
}
// 单系列图表的 tooltip 样式(显示分类名)
& > div > div {
// 分类名称
&:nth-child(1) {
font-size: 14px !important;
}
// 数据系列的内容
&:nth-child(2) {
@include series-item-style();
}
}
// 多系列图表的 tooltip 样式
& > div > div {
// 分类名称
& > div:nth-child(1) {
font-size: 14px !important;
}
// 数据系列列表的盒子
& > div:nth-child(2) {
margin: 10px 0 0 !important;
// 单个数据系列的盒子
& > div {
margin: 10px 0 0 !important;
// 数据系列的内容
& > div {
@include series-item-style();
}
}
}
}
}
使用
TypeScript 代码解读复制代码import { setScaleToEchartsOptions } from '../../utils';
const options = setScaleToEchartsOptions({
// ...图表配置
});
chartInstance.setOption(options);
✨显示正常