解决 ECharts 在高分辨率屏幕下的缩放问题

解决 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);

✨显示正常

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT枫斗者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值