{# The figure canvas. ONE workspace, and the canvas is nearly all of it. This markup used to be rendered in two places -- a figure's own page and a split pane beside the live viewer -- and the split pane is gone: composing a figure and looking down a microscope are different activities, and half a window was not enough room for either. What is left is a page whose dominant element is the figure. The permanent chrome is deliberately thin: a narrow tool rail, a tray of panels, and a topbar. Everything that ACTS on a selection is built in JavaScript into #fb_overlay_layer and floats beside what it acts on (figureContextBar.js) -- a fixed properties column would take three hundred pixels away from the thing the user is looking at, permanently, to show controls that are relevant some of the time. #fb_text_panel is not a return of that column, and the distinction is the word "permanently": it is CONTEXTUAL, present only while a text object is selected or being typed into, and gone the rest of the time. Text carries far more formatting than any other object here -- family, size, colour, weight, leading, two alignments -- and a popover deep enough to hold all of it is a popover nobody can work in. It holds formatting only; anything that can be done to any OBJECT stays on the floating bar. That bar renders from figureActions.js, one declaration of what each action is and when it applies, which the right-click menu renders from as well. It used to be four hand-built lists and they had drifted -- the menu disabled "Bring to front" where the bar offered it live on a text box and it did nothing at all. #fb_overlay_layer is the one part of this the canvas renderer never touches. FigureCanvas.render() replaces the whole of #fb_page_surface on every change, so anything that has to survive a render -- the context bar, an open text editor -- lives out here instead. #}
{# Clusters on the desk, not a strip across it. The bar itself paints nothing: what floats is the controls, in the same card as the rail and the tray. The gap between two clusters is what says which controls belong together, which is the job the grey pill inside a solid bar was doing -- without a box inside a box. #}
{# The library is where this goes by default and where it goes if anything is uncertain. It is retargeted at the VIEWER, in JavaScript, when the note left by figureSidebarController says that is where the user came from -- because the commonest trip there is is capture a few fields, look at the figure, go back to the slide for one more, and an arrow that always went to the library made the way back a search. #} {# contenteditable would be fewer elements and the wrong control: it accepts pasted markup, and this value is rendered back into a list of cards. A plain input cannot carry anything but text. #} {# The way IN, beside the name of the thing it fills. A figure with nothing in it is the state this page opens in, and the only route out of it used to be a drawer on the left and a menu inside it. It leaves for the project page, because that is where images are: this page has no datasource, and a figure legitimately spans several. THIS figure is remembered as the capture destination first, so whatever is captured over there lands back here. #}
{# History, pages and View in one card: three ways of moving around what already exists. Export is not one of those, and does not share it. #}
{# Zoom is not up here. It changes where the eye is, not what the figure is, and sitting in a row with Undo and Export it looked like the same kind of control. It lives in the status bar at the foot of the canvas, beside the readout it moves. #} {# In the corner, on the desk, and in no card at all -- the same argument the status bar's count and hint make at the other end of the page. It is a thing to read and never a thing to press, and it sat between the title and the first control, which is where the eye goes when it is looking for the title. #}
{# A native : modal, focus-trapped and Esc-dismissible without a line of script, and it cannot end up behind the canvas the way a positioned div can. #}

Export figure

Panels are re-rendered from the source images at the resolution you ask for — not from what is on screen.

{# Stated up front rather than discovered in the file. Only PNG has an alpha channel; a transparent page rendered to PDF or TIFF is drawn on white, which is a decision the author should make knowingly. #}

A transparent page keeps its transparency in PNG only. PDF and TIFF render it white.

{# Filled by the preflight, before anything is rendered: a warning attached to a file that is already written is a warning nobody acts on. #}
{# The row this dialog ENDS with, so .fb-dialog-footer and not .fb-banner-actions -- which is a banner's class, has no `justify-content`, and was leaving four buttons ranged LEFT with the primary one third of the way along. Answers run left to right in order of consequence with Export last, and the status stays on the left where it is read. #}
{# Nothing in here is a column. The canvas runs the full width of the body and the rail and the tray are cards lying on top of it -- which is why .fb-main comes FIRST: it is the only flex child that takes space, and the two cards are positioned against the body and out of the flow. Quick Edit is the exception, and takes its 420px from the canvas, because reframing a panel means watching the figure change as you do it. #}
{# Optional, off by default and remembered per browser. Two strips rather than a wall of positioned ticks: a ruler at 1 mm resolution across an A4 page is 210 elements that have to be rebuilt on every zoom and every scroll. #}
{# The sheet and the two things that belong to it, shrink-wrapped and centred as one block: centred independently, the caption and the button would drift off the page edges they are supposed to line up with. #}
{# Under the panels, and children of the page so they scale with it: a grid drawn in screen pixels drifts off the millimetres it is supposed to represent the moment the zoom changes. #} {# A listbox, and focusable. Nothing on this sheet was reachable without a pointer: the objects carried no role, no label and no tab stop, so a keyboard user could not select a panel at all -- and every control this workspace has acts on a selection, which made the whole page unusable rather than merely awkward. Tab reaches the sheet, the arrows walk it, Enter takes what is under the cursor. See FigureCanvas.describeObjects. #}
{# Guides and the marquee live above the panels and take no pointer events, so a snap line can never be what a drag grabs. #}
{# Under the page and as wide as it. Inside the scroll surface rather than in the status bar, so it scrolls away with the sheet it follows: it is part of the document, not part of the window. #}
{# Never re-rendered by the canvas. See the file comment. #}
{# Level 1: the only controls that are always visible, and there are four of them. Everything else is contextual, in a menu, or on the right-click. There is no Select tool. Selecting is what the pointer does when it is not doing anything else: the drawing tools are one-shot and hand the pointer back the moment they have placed something, and clicking the desk drops one armed by mistake. A button for "no tool" would be a light that is on almost always, and a click nobody needs to make. The scale bar and the colour bar are not here either. They act on a SELECTION, they have real settings behind them, and both live in the image sidebar next to the panels they change -- up here they were a second, blunter copy of the same switch, dimmed most of the time. Labelled, at the cost of twenty pixels of width: four icons in a stack with nothing under them is four things to hover before starting, every session, because "a square" is not a word -- and this rail is the first thing a new user has to read. #} {# The text sidebar. CONTEXTUAL, and that is the whole distinction from the fixed properties column this workspace deleted: it is present only while a text object is selected or being typed into, so the canvas keeps the full width for everything else anyone does here. It carries text FORMATTING and nothing else. Actions that apply to any object -- arrange, align, group, duplicate, delete -- belong to the bar that floats over the selection, which is one shared component for every object kind rather than a list rebuilt per type. `.fb-side-panel` is what it shares with the tray below: ONE strip beside the rail, holding one panel at a time, at one size and in one place. `.fb-object-panel` is what the four OBJECT panels share and the tray does not: the look of a card full of controls -- square corners, 4px between them, a width that hugs its own widest row. The tray is a grid of pictures and wants none of it. Which of them is in it is FigureWorkspace.showSidebar's to say, and neither hides or shows itself -- two panels each answering that for themselves is what drew this one underneath the tray, where it was invisible and still took every click on the overlap. #} {# The same strip, for the other kind of object with properties of its own. It carries the point tools too while Edit Points is open -- see figureShapePanel.js. #} {# And the third: a line has two ends, and everything that makes it an arrow is a property of one of them -- see figureLinePanel.js. #} {# The fourth, and the one the other three were the rehearsal for: a placed panel's own properties -- Quick Edit, the scale bar, the colour bar, the captions on the image, the rendering. These were six buttons on the floating bar, each opening a popover that covered the panel it was about. See figureImagePanel.js. #} {# What this figure is made of. Panels arrive here from the viewer and are dragged onto the page; nothing is ever placed automatically at capture time, because composition is a different sitting from exploration. A card the rail opens, with its own title and its own way out. Open on arrival: a figure page whose panels were behind a closed drawer would look, on the day it is reopened, like a figure that had lost them. #} {# Quick Edit: the microscopy view behind one panel, adjusted without leaving the canvas. The channel controls below the preview are CORE's -- a second ViewerSidebar instance driving the markup below, which carries core's own classes and `fbqe_`-prefixed ids so the two instances can never find each other's elements. Writing a second channel widget here would be two implementations of colour, contrast and ordering that agree until the day one of them is fixed, and a user who has to learn the second one. Deliberately NOT a second scientific viewer: there is no OSD, no tile stack, no overlays and no plugins in here. Anything past reframing and channels is what "Open in Main Viewer" is for. #}
{# What is on the page, and what the pointer can do to it. The topbar acts on the figure; this acts on the view of it. #}
-scroll to zoom · Space-drag to pan
{# The only thing down here anyone clicks, so it is the only thing down here in a card. The count and the hint stay on the desk. #}
{# The accessible name is the CONTROL, not its value: without it a screen reader announces the button as "100%", which is what it says and not what it does. The value is still the button's text, so it is read after the name. #}