sadr0b0t / babbler-robots

0 stars 1 forks source link

Рисовать рабочее поле по всей высоте окна #7

Open sadr0b0t opened 7 years ago

sadr0b0t commented 7 years ago

Нужно рисовать рабочее поле по всей высоте окна: растягивать в высоту, если есть много свободного места, сжимать, если места не достаточно (можно до варианта minHeight).

Сейчас ширина рабочего поля меняется автоматом за окном - для этого оказалось достаточным задать для тега svg width="100%". В случае с высотой height="100%" этот прикол не работает (точнее работает, но поле растягивается не на свободную видимую область экрана, а, похоже, просто на высоту окна, и нижняя часть уходит со скроллом вниз).

Вариант - задавать фиксированную высоту 450px работает, но не очень красивый - если на экране будет много вертикального места, оно не будет использовано для рисования рабочей области.

Если с CSS этот трюк провернуть не получится, можно попробовать сделать хак на JS.

Здесь обсуждают аналогичную проблему

How to animate height , when element heght is not fixed https://github.com/chenglou/react-motion/issues/62

и, судя по коментам, решение на чистом CSS тоже не находят. На JS тоже не все просто - чтобы получить значение высоты для дива, нужно дать страничке хотя бы один раз отрисоваться, иначе, будет 0. А для первого рендера подготовить значение по умолчанию.

sadr0b0t commented 7 years ago

Для начала, что не сработало.

  1. У реакта есть колбэк на завершение рендера - последний параметр https://facebook.github.io/react/blog/2015/10/01/react-render-and-top-level-api.html
    this.component = ReactDOM.render(element, this.container, callback);

Но толку от него нет, т.к. рендер не вызывается при изменении размера окна. Здесь можно было еще что-то придумать, но нарисовались новые варианты.

React “after render” code? http://stackoverflow.com/questions/26556436/react-after-render-code

Below is an example component. I want to be able to set app-content's height to be 100% of the window minus the size of the ActionBar and BalanceBar, but how do I know when everything is rendered and where would I put the calculation stuff in this React Class?

ответ

In modern browsers you can use flexbox to do this better. Otherwise Harborhoffer's answer.

  1. Flexbox - блок-контейнер, который может растягивать внутренние элементы по всей своей высоте.

A Complete Guide to Flexbox https://css-tricks.com/snippets/css/a-guide-to-flexbox/

flex-basis https://css-tricks.com/almanac/properties/f/flex-basis/

How can I make my flexbox layout take 100% vertical space? http://stackoverflow.com/questions/23090136/how-can-i-make-my-flexbox-layout-take-100-vertical-space

Вроде как похоже на то, что нужно, но по факту вылезли проблемы:

  1. Еще какой-то дискасс о том, что чел не может сделать таб 100% высоты экрана в MaterialUI https://github.com/callemall/material-ui/issues/2085

  2. Еще прям целый трактат о том, как делать полноростовые веб-приложения 2011 года (похоже, совсем устарел)

Full-height app layouts: A CSS trick to make it easier http://blog.stevensanderson.com/2011/10/05/full-height-app-layouts-a-css-trick-to-make-it-easier/

Flexbox and vertical scroll in a full-height app using NEWER flexbox api http://stackoverflow.com/questions/14962468/flexbox-and-vertical-scroll-in-a-full-height-app-using-newer-flexbox-api/34362676

CSS3 Flexbox full-height app and overflow http://stackoverflow.com/questions/9251447/css3-flexbox-full-height-app-and-overflow

  1. Еще какой-то странный виджет для ректа, может пригодится

flexbox for svg in react https://dlmanning.github.io/react-flexbox-svg/ https://github.com/dlmanning/react-flexbox-svg

  1. И, наконец, правильный ответ: использовать height:100vh, никакой флексбокс не нужен.

Containing a SVG image within Flexbox http://stackoverflow.com/questions/37242454/containing-a-svg-image-within-flexbox http://codepen.io/anon/pen/eZoXgE демо исправленного решения: https://i.stack.imgur.com/jokCs.gif

sadr0b0t commented 7 years ago

Подробнее про vh (viewport unit)

Простой способ растянуть блок на всю высоту экрана, или CSS3 Viewport Units https://habrahabr.ru/post/243161/

Единицы измерения vh и vw vh и vw можно расшифровать, как viewport height и viewport width — высота и ширина области просмотра соответственно. 1vh равен одному проценту от высоты области просмотра, 1vw равняется одному проценту от ширины области просмотра.

Единицы измерения vmin и vmax vmin и vmax расшифровывается, как viewport minimal и viewport maximal. 1vmin сравнивает значения 1vh и 1vw, выбирая меньшее из них. 1vmax делает то же самое, но выбирает большее из двух значений. Иначе говоря, если у смартфона ширина экрана меньше высоты, то vmin будет рассчитываться относительно ширины, а vmax будет рассчитываться относительно высоты экрана.

Варианты:

  1. Назначить нужную высоту тегу SVG напрямую

    <svg style={{backgroundColor: "blue", width: "100%", height: "calc(100vh - 150px)"}} .../>
  2. Назначить нужную высоту обрамляющему диву, в svg в таком случае нужно выставить ширину и высоту 100%

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

И да, старые атрибуты SVG x,y,width,height (передавались через параметр screen) все порезали, вместо них CSS.

Замечания

Математика разметки с помощью CSS: разбираемся с calc https://habrahabr.ru/post/243821/

Далее: теперь нужно сделать все то же самое, только чтобы по высоте масштабировался и вписывался не только элемент с картинкой SVG, но обрамляющие его кнопки управления со всем 3хколоночным лэйаутом и нижней строкой.

Есть ощущение, что от display: table придется отказаться. Возможно, в этом поможет CSS Grid.

A Complete Guide to Grid https://css-tricks.com/snippets/css/complete-guide-grid/

sadr0b0t commented 7 years ago

Нормальный пост про flexbox (разжевано, что такое flex-shink, flex-grow, flex-basic, в отличие от "комплит гайда", где от них только названия) Практическое применение FlexBox https://habrahabr.ru/post/242545/

Короче, 3 колонки:

колонка посередине

Правильное решение:

<div style={{display: "flex", flexFlow: "row"}}>
    <div style={{flexBasis:"0px"}}>кнопки слева</div>

    <div style={{flexBasis:"100%", textAlign: "center"}}>
        <DekartCanvas style={{width: "100%", height: "calc(100vh - 250px)"}}/>
        <div>еще кнопки</div>
    </div>

    <div style={{flexBasis:"0px"}}>кнопки справа</div>
</div>

Т.е. по краям выставляем flex-basis 0px (минимальная ширина колонки - уже кнопок их див все равно не сожмется), а для средней - 100% (все оставшееся место). Аналогичного результата еще можно достигнуть, если поиграть немного с полем flex-grow (по краям выставить 0, а по центру 1: тогда по центру не обязательно ставить flex-basis 100%, но для крайних колонок все равно придется выставить минимальную ширину flex-basis, иначе на auto их растянет в ширину в ряд кнопок вместо столбца).

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

sadr0b0t commented 7 years ago

Вынес стиль для DekartCanvas внутри CncTaskControl в отдельное поле dekartStyle, правильную высоту нужно указывать здесь (это логично, т.к. значение разницы между необходимой высотой поля и реальным размером экрана будет известно только на самом верхнем уровне, где добавляются всякие верхние и нижние панели).

<CncTaskControl babblerCnc={babblerCnc1}
    dekartStyle={{width: "100%", height: "calc(100vh - 250px)", minHeight:350}} 
    fold={{dimX: 300, dimY:216, dimZ:100}}/>

minHeight, кстати, в такой верстке тоже заработала.

Осталось понять, откуда взялись эти безумные 250px (это уже с кнопками, без кнопок было 150px) вместо 40-50 реальных пикселей, занимаемых от высоты экрана горизонтальными панелями, максимум.

sadr0b0t commented 7 years ago

https://github.com/1i7/babbler-robots/commit/d19debc28b3bc9cc09068a424b00404831769d45