Мягкие диаграммы

внешний интерфейс JavaScript CSS ECharts
Мягкие диаграммы
Решение для адаптации экрана для Echarts.

Добро пожаловать в колонкуКодовая книга энтропии и монад

В веб-разработке, особенно в SPA типа панели инструментов, часто требуется, чтобы каждый компонент мог масштабироваться и адаптироваться к различным разрешениям экрана.Одним из распространенных решений является использование единиц длины rem и em в CSS в сочетании с медиа-запросами.

В некоторых недавних требованиях к визуализации данных компонент диаграммы использует Echarts.Обнаружено, что, поскольку Echarts генерирует диаграммы на основе метода рисования Canvas, в элементах конфигурации все расстояния и размеры могут быть установлены только в пикселях, что делает экран адаптация очень неудобная, при смене разрешения не только размер шрифта и расстояние в диаграмме не гармонируют с общим интерфейсом, но и шрифты часто перекрываются.

Подумав об этом, каждый раз, когда перерисовки Echarts передаются в конфигурации через метод setOption в JavaScript, вы можете использовать объект окна, чтобы получить размер окна, динамически установить переменную, которая будет играть роль размера шрифта корневого элемента. , и имитируйте rem Effects с помощью медиа-запросов.

Сначала создайте файл конфигурации стиля для компонента или добавьте его в существующий файл конфигурации:

// styleProps.js

const viewPort = window.screen.width;
let rootFontSize = 100;
if (viewPort <= 1480) rootFontSize = 71;
if (viewPort >= 1481 && viewPort <= 1760) rootFontSize = 83;
if (viewPort >= 2241 && viewPort <= 3200) rootFontSize = 130;
if (viewPort >= 3201) rootFontSize = 200;

export default {
  titleFontColor: 'rgba(255,255,255,0.97)',
  bodyFontColor: 'rgba(255,255,255,0.91)',
  titleFontSize: rootFontSize * 0.18,
  bodyFontSize: rootFontSize * 0.16,

  titleFontFamily: 'FangZhengZhengZhongHeiJT',
  bodyFontFamily: 'FangZhengZhengXianHeiJT',
};

Для того, чтобы решить проблему минимального размера шрифта 12px под браузером Chrome, принято устанавливать font-size корневого элемента в 100px, а rootFontSize здесь тоже выставлен в 100.

Получите ширину экрана через переменную viewPort и адаптируйтесь к следующим общим разрешениям экрана в соответствии с интервалом:

1366*768
1600*900
1920*1080
2560*1400
3840*2160

Если вы выберете ширину, в основном полный экран, проекционный экран и другие ситуации не будут затронуты.Конечно, поскольку это приложение типа панели инструментов, оно не учитывает странные ситуации, такие как пользователь, вытягивающий маленькую форму.

Эта конфигурация styleProps.js «изоморфна» нашим настройкам в CSS всего приложения:

html{
  font-size: 625%;
}
@media (max-width: 1480px) {
  html{
    font-size: 444%;
  }
}
@media (min-width: 1481px) and (max-width: 1760px) {
  html{
    font-size: 521%;
  }
}
@media (min-width: 2241px) and (max-width: 3200px) {
  html{
    font-size: 810%;
  }
}
@media (min-width: 3201px) {
  html{
    font-size: 1250%;
  }
}

body{
  font-size: 0.2rem;
  font-family: FangZhengZhengXianHeiJT;
  color: rgba(255,255,255,0.91);
}

h1 {
  font-size: 0.44rem;
  font-family: FangZhengZhengZhongHeiJT;
  color: rgba(255,255,255,0.97);
}
h2 {
  font-size: 0.32rem;
  font-family: FangZhengZhengZhongHeiJT;
  color: rgba(255,255,255,0.97);
}
h3 {
  font-size: 0.24rem;
  font-family: FangZhengZhengZhongHeiJT;
  color: rgba(255,255,255,0.97);
}

Затем просто оберните компонент для кривой и гистограмм:

import React from 'react';
import echarts from 'echarts';
import styleProps from '../styleProps';

export default class HArrayChart extends React.Component {
  static defaultProps = {
    title: '',
    /**
     * dataItem {
     *  data: [],
     *  type: '',
     *  name: '',
     *  axis: 'left' | 'right',
     * }
     */
    dataList: [],
    /**
     * {
     *  name: '',
     *  data: []
     * }
     */
    index: {},
    /**
     * ['发电量(kWh)','功率(kW)']
     */
    axes: []
  }
  componentDidMount() {
    this.chart = echarts.init(this.chart);
    this.updateChart();
  }
  componentDidUpdate() {
    this.updateChart();
  }
  updateChart = () => {
    const getSerisOption = (type) => {
      switch (type) {
        case 'line':
          return {
            symbol: 'none'
          };
        default:
          break;
      }
      return null;
    };
    this.chart.setOption({
      title: {
        text: this.props.title,
        x: 'center',
        textStyle: {
          color: styleProps.titleFontColor,
          fontFamily: styleProps.titleFontFamily,
          fontSize: styleProps.titleFontSize
        }
      },
      grid: {
        top: (styleProps.bodyFontSize * 2.4) + styleProps.titleFontSize,
        right: (styleProps.bodyFontSize * 3.8) + 8,
        bottom: (styleProps.bodyFontSize * 4.2) + 8,
        left: (styleProps.bodyFontSize * 3.8) + 8
      },
      yAxis: this.props.axes.map(name => ({
        name,
        nameGap: styleProps.bodyFontSize * 0.8,
        type: 'value',
        nameTextStyle: {
          color: styleProps.bodyFontColor,
          fontFamily: styleProps.bodyFontFamily,
          fontSize: styleProps.bodyFontSize
        },
        axisLine: {
          lineStyle: {
            color: styleProps.bodyFontColor
          }
        },
        axisLabel: {
          color: styleProps.bodyFontColor,
          fontFamily: styleProps.bodyFontFamily,
          fontSize: styleProps.bodyFontSize
        }
      })),
      legend: {
        data: this.props.dataList.map(dataItem => dataItem.name),
        icon: 'bar',
        bottom: 0,
        textStyle: {
          color: styleProps.bodyFontColor,
          fontFamily: styleProps.bodyFontFamily,
          fontSize: styleProps.bodyFontSize
        }
      },
      xAxis: {
        data: this.props.index.data,
        type: 'category',
        name: this.props.index.name,
        nameLocation: 'center',
        nameGap: (styleProps.bodyFontSize * 1.2) + 8,
        nameTextStyle: {
          color: styleProps.bodyFontColor,
          fontFamily: styleProps.bodyFontFamily,
          fontSize: styleProps.bodyFontSize
        },
        axisLine: {
          lineStyle: {
            color: styleProps.bodyFontColor
          }
        },
        axisLabel: {
          color: styleProps.bodyFontColor,
          fontFamily: styleProps.bodyFontFamily,
          fontSize: styleProps.bodyFontSize
        }
      },
      series: this.props.dataList.map(dataItem => ({
        data: dataItem.data,
        type: dataItem.type || 'line',
        name: dataItem.name,
        animation: false,
        yAxisIndex: dataItem.axis === 'right' ? 1 : 0,
        ...getSerisOption(dataItem.type || 'line')
      }))
    });
  }
  render() {
    return <div className={this.props.className} ref={(div) => { this.chart = div; }} />;
  }
}

Предыдущий файл конфигурации styleProps.js импортируется через импорт, и соответствующие параметры будут рассчитаны до создания компонента, что достаточно для адаптации к разрешению экрана.Конечно, если вы хотите иметь возможность более динамичной настройки, вы Также можно установить вид наблюдения за состоянием.Ширина рта, параметр пересчитывается в каждом компонентеWillUpdate.

Для удобства пользователей, не знакомых с конфигурацией Echarts, этот компонент предоставляет только 4 параметра:

title: '',
dataList: [],
index: {},
axes: []

dataList может передавать несколько рядов данных через массив, каждый из которых может быть независимо настроен с типом кривой или столбца и связан с левой или правой осью координат.Длина каждого ряда данных должна соответствовать длине индекса абсцисса. Конечно, такая конфигурация делает степень свободы очень малой, и элемент конфигурации опции также может быть предоставлен пользователю для переопределения конфигурации по умолчанию.

Так как настройка размера шрифта в конфигурации styleProps.js "изоморфна" с нашей настройкой в ​​CSS всего приложения, то через titleFontSize и bodyFontSize при изменении адаптивного соответствия разрешения экрана Echarts и в целом поведение интерфейса остается согласованы, а такие изменения, как размер шрифта и расстояние, координируются.

Расстояние между каждым элементом на диаграмме, такое как расстояние между легендой и осью x, расстояние между сеткой и четырьмя сторонами и т. д., также задается соотношением bodyFontSize, так что при изменении шрифтов на диаграмме они изменятся. не пересекаться друг с другом:

yAxis: this.props.axes.map(name => ({
  nameGap: styleProps.bodyFontSize * 0.8,        
})),

Так как в проекте используются styled-components, корневой элемент компонента должен быть передан в className={this.props.className} .

Когда используется последний компонент, это выглядит примерно так:

import styled from 'styled-components';
import { HArrayChart } from './hyphix';

const Chart = styled(HArrayChart)`
  width: 5rem;
  height: 3rem;
`;
const dataList = [
  {
    data: [2, 4, 5, 80, 22, 27, 39, 0, 12],
    name: '今日功率',
  },
  {
    data: [32, 33, 3, 8, 2, 27, 3, 3, 15],
    name: '昨日功率',
    type: 'bar'
  },
  {
    data: [837, 3099, 122, 3999, 100, 299, 3987, 3298, 1500],
    name: '昨日效率',
    axis: 'right'
  },
];
const index = { data: [1, 2, 3, 4, 5, 6, 7, 8, 9], name: '时间' };const Chart = styled(HArrayChart)`
  width: 500px;
  height: 300px;
`;
const dataList = [
  {
    data: [2, 4, 5, 80, 22, 27, 39, 0, 12],
    name: '今日功率',
  },
  {
    data: [32, 33, 3, 8, 2, 27, 3, 3, 15],
    name: '昨日功率',
    type: 'bar'
  },
  {
    data: [837, 3099, 122, 3999, 100, 299, 3987, 3298, 1500],
    name: '昨日效率',
    axis: 'right'
  },
];
const index = { data: [1, 2, 3, 4, 5, 6, 7, 8, 9], name: '时间' };

<Route path="/test" exact component={() => <Chart title={'今日发电功率曲线'} dataList={dataList} index={index} axes={['发电量(kWh)', '功率(kW)']} />} />

Поскольку нет красивых данных, изображение не будет отображаться.Компоненты - это только общая идея, а красивые детали необходимо улучшить.