Гибкая коробка из двух графиков переполняет экран

#javascript #css #reactjs #flexbox #chakra-ui

Вопрос:

У меня на странице есть две диаграммы. Вместе они занимают всю высоту экрана Flex (css flexbox). Первая диаграмма складывается через an Accordion .

Как мы можем сделать так, чтобы первая диаграмма заполняла 30% высоты экрана, а вторая диаграмма заполняла оставшиеся ~70%?

Мне удалось успешно сделать это, когда эти два графика-единственные вещи на странице:

введите описание изображения здесь

 // This works well.
<Flex direction="column" height="100vh">
  <Accordion allowToggle>
    <AccordionItem>
      <h2>
        <AccordionButton
          h={0}
          borderRadius="md"
          borderWidth="0px"
          _focus={{ boxShadow: "none" }}
        >
          <Box
            textAlign="left"
            h={3}
            _focus={{ boxShadow: "none" }}
          ></Box>
          <AccordionIcon />
        </AccordionButton>
      </h2>
      <AccordionPanel p="0">
        <Box height="30vh">
          <ThreeDataPoint />
        </Box>
      </AccordionPanel>
    </AccordionItem>
  </Accordion>
  <Box flex="1">
    <ThreeDataPoint />
  </Box>
</Flex>
 

Однако, если я объединю окно гибкого трубопровода строки и столбца вместе, это не сработает. Вторая диаграмма превышает высоту экрана.

Вот КОД и КОРОБКА

И вот скриншот:

введите описание изображения здесь

Комментарии:

1. возможно, использование чакры sx для добавления селектора «первый ребенок»/»n-й ребенок» поможет

Ответ №1:

Я внес некоторые изменения в ваш код, пытаясь добиться несколько удовлетворительного результата, который позволяет сохранить обе диаграммы на этой 100vh максимальной высоте и избежать прокрутки.

Высота второй диаграммы будет автоматически изменена, заполняя как можно больше свободного места в зависимости от того, свернута первая диаграмма или нет.

Вот некоторые стили, которые я добавил в ваш файл styles.css (прямо под вашим .test классом):

 .flex-wrapper {
  display: grid !important;
  grid-auto-flow: column;
  grid-auto-columns: max-content auto;
  gap: 15px;
  padding: 15px;
  max-height: 100%;
  width: 100%;
}

.accordion-box-container {
  display: grid !important;
  grid-template-rows: min-content auto;
  gap: 15px;
  overflow-y: hidden;
  width: 100%;
}

.accordion-wrapper {
  height: 100%;
}

.accordion-title {
  display: flex;
  align-items: center;
  padding: 5px 0;
  height: auto;
}

.accordion-button {
  width: min-content !important;
  margin-left: 5px;
}

.graph-wrapper {
  height: 100%;
}

.graph-wrapper div {
  height: 100% !important;
}
 

Тем временем я удалил некоторые классы начальной загрузки из вашего jsx index.tsx и добавил классы css выше в соответствующие компоненты:

 render(
  <ChakraProvider>
    <>
      <Flex direction="column" height="100vh" className="flex-wrapper">
        <div>123456789010</div>
        <Flex>
          <Box className="accordion-box-container">
            <Accordion className="accordion-wrapper" allowToggle>
              <AccordionItem>
                <h2 className="accordion-title">
                  <AccordionButton
                    className="accordion-button"
                    borderRadius="md"
                    borderWidth="0px"
                    _focus={{ boxShadow: "none" }}
                  >
                    <Box
                      textAlign="left"
                      h={3}
                      _focus={{ boxShadow: "none" }}
                    ></Box>
                    <AccordionIcon />
                  </AccordionButton>
                </h2>
                <AccordionPanel p="0">
                  <Box height="30vh">
                    <ThreeDataPoint />
                  </Box>
                </AccordionPanel>
              </AccordionItem>
            </Accordion>
            <div className="graph-wrapper">
              <ThreeDataPoint />
            </div>
          </Box>
        </Flex>
      </Flex>
    </>
  </ChakraProvider>,
  rootElement
);
 

Наконец, мне пришлось удалить ваше ограничение на размер, в BasicLineSeries.tsx котором применялась бы минимальная высота для обеих диаграмм, что делало невозможной настройку их высоты после отрисовки (изменилась только инструкция export):

 export default withSize()(
  withDeviceRatio()(BasicLineSeries)
);
 

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

предварительный просмотр1
предварительный просмотр2

Комментарии:

1. Привет, Кевин. Мне нужно, чтобы номер 123456789010 был на левой стороне аккордеона. Они должны быть отдельными колоннами. В моем приложении «123456789010» на самом деле является еще одним компонентом. Я просто поместил туда какой-то простой текст в качестве заполнителя для этого примера. Вот почему я использовал в своем примере гибкое окно строк. Мне интересно, есть ли простой способ изменить ваше решение, чтобы учесть это?

2. @ABC Да, я посмотрю на это, я просто неправильно понял ваши намерения. 🙂 Должны ли обе диаграммы находиться в одном столбце, отделенном от текста?

3. Я сожалею об этом, я должен был прояснить это в операции.

4. @ABC Закончил с правками, пожалуйста, проверьте предварительные просмотры и скажите мне, это то, что вы ожидали.

5. @ABC Рад был помочь, пожалуйста, отметьте это как решение вашего вопроса, если это сработает для вас.

Ответ №2:

Высота диаграмм рассчитывается при отображении страницы, поэтому после переключения верхнего графика высота нижнего графика не будет пересчитана. Вам нужно выполнить обходной путь, чтобы вызвать событие для пересчета высоты второго графика. Вы можете использовать onChange событие для <Accordion> переключения состояния и обернуть вторую диаграмму по <Box> высоте 100vh или 70vh на основе изменения состояния.

 import * as React from "react";
import { render } from "react-dom";
import "./styles.css";
import { ChakraProvider } from "@chakra-ui/react";
import BasicLineSeries from "./BasicLineSeries";
import {
  Box,
  Accordion,
  AccordionButton,
  AccordionItem,
  AccordionIcon,
  AccordionPanel,
  Flex,
  Text
} from "@chakra-ui/react";

const ThreeDataPoint = () => (
  <BasicLineSeries
    data={[
      {
        close: 120,
        open: 120,
        high: 140,
        low: 100,
        date: new Date(2020, 7, 8, 10, 0, 0, 0),
        volume: 1_000_000
      },
      {
        close: 140,
        open: 120,
        high: 150,
        low: 100,
        date: new Date(2020, 7, 8, 10, 1, 0, 0),
        volume: 1_000_000
      },
      {
        close: 120,
        open: 120,
        high: 140,
        low: 100,
        date: new Date(2020, 7, 8, 10, 2, 0, 0),
        volume: 1_000_000
      }
    ]}
  />
);

const Test = () => {
  const [expended, onExpend] = React.useState(false);

  return (
    <ChakraProvider>
      <>
        <Flex direction="column" height="100vh">
          <Flex flex="1" direction="row">
            <div>123456789010</div>
            <Flex flex="1" direction="column">
              <Accordion
                allowToggle
                onChange={(e) => {
                  if (e === 0) {
                    onExpend(true);
                  } else {
                    onExpend(false);
                  }
                }}
              >
                <AccordionItem>
                  <h2>
                    <AccordionButton
                      h={0}
                      borderRadius="md"
                      borderWidth="0px"
                      _focus={{ boxShadow: "none" }}
                    >
                      <Box
                        textAlign="left"
                        h={3}
                        _focus={{ boxShadow: "none" }}
                      ></Box>
                      <AccordionIcon />
                    </AccordionButton>
                  </h2>
                  <AccordionPanel p="0">
                    <Box height="30vh">
                      <ThreeDataPoint />
                    </Box>
                  </AccordionPanel>
                </AccordionItem>
              </Accordion>
              <Box flex={expended ? 2 : 3}>
                <ThreeDataPoint />
              </Box>
            </Flex>
          </Flex>
        </Flex>
      </>
    </ChakraProvider>
  );
};

const rootElement = document.getElementById("root");
render(<Test />, rootElement);
 

Комментарии:

1. Почти, но не совсем. Нижняя часть второго графика (ось x) обрезается. 30vh 70vh слишком велики, потому что они не учитывают ничего выше обоих графиков (в данном случае раскрывающееся меню аккордеона).

2. Это был быстрый пример того, как вы можете решить свою проблему. Я уверен, что у вас на странице будет какой-то верхний/нижний колонтитул, поэтому вам также следует учитывать это

3. Но даже при отсутствии верхнего и нижнего колонтитулов проблема не решена. Решение, которое вы предлагаете, вызывает переполнение страницы из-за самого аккордеона

4. Это странно, но у меня это не работает. Расширенный аккордеон все еще переполнен. См.: codesandbox.io/s/pedantic-meadow-ipx0b?file=/src/index.tsx

5. Какой браузер вы используете?