@@ -35,6 +35,7 @@ use crate::CursorLinkGroups;
3535use crate :: GridInput ;
3636use crate :: GridMark ;
3737use crate :: GridSpacer ;
38+ use crate :: HPlacement ;
3839use crate :: LabelFormatter ;
3940use crate :: Legend ;
4041use crate :: LinkedBounds ;
@@ -46,6 +47,8 @@ use crate::PlotPoint;
4647use crate :: PlotResponse ;
4748use crate :: PlotTransform ;
4849use crate :: PlotUi ;
50+ use crate :: VPlacement ;
51+ use crate :: axis:: AxisWidget ;
4952use crate :: items;
5053use crate :: items:: horizontal_line;
5154use crate :: items:: rulers_color;
@@ -850,7 +853,7 @@ impl<'a> Plot<'a> {
850853
851854 let plot_id = id. unwrap_or_else ( || ui. make_persistent_id ( id_source) ) ;
852855
853- let ( [ x_axis_widgets, y_axis_widgets] , plot_rect) = crate :: axis_widgets (
856+ let ( [ x_axis_widgets, y_axis_widgets] , plot_rect) = axis_widgets (
854857 PlotMemory :: load ( ui. ctx ( ) , plot_id) . as_ref ( ) , // TODO #164: avoid loading plot memory twice
855858 show_axes,
856859 complete_rect,
@@ -1612,3 +1615,124 @@ impl PreparedPlot<'_> {
16121615 ( cursors, hovered_plot_item_id)
16131616 }
16141617}
1618+
1619+ /// Returns the rect left after adding axes.
1620+ fn axis_widgets < ' a > (
1621+ mem : Option < & PlotMemory > ,
1622+ show_axes : impl Into < Vec2b > ,
1623+ complete_rect : Rect ,
1624+ [ x_axes, y_axes] : [ & ' a [ AxisHints < ' a > ] ; 2 ] ,
1625+ ) -> ( [ Vec < AxisWidget < ' a > > ; 2 ] , Rect ) {
1626+ // Next we want to create this layout.
1627+ // Indices are only examples.
1628+ //
1629+ // left right
1630+ // +---+---------x----------+ +
1631+ // | | X-axis 3 |
1632+ // | +--------------------+ top
1633+ // | | X-axis 2 |
1634+ // +-+-+--------------------+-+-+
1635+ // |y|y| |y|y|
1636+ // |-|-| |-|-|
1637+ // |A|A| |A|A|
1638+ // y|x|x| Plot Window |x|x|
1639+ // |i|i| |i|i|
1640+ // |s|s| |s|s|
1641+ // |1|0| |2|3|
1642+ // +-+-+--------------------+-+-+
1643+ // | X-axis 0 | |
1644+ // +--------------------+ | bottom
1645+ // | X-axis 1 | |
1646+ // + +--------------------+---+
1647+ //
1648+ let show_axes = show_axes. into ( ) ;
1649+
1650+ let mut x_axis_widgets = Vec :: < AxisWidget < ' _ > > :: new ( ) ;
1651+ let mut y_axis_widgets = Vec :: < AxisWidget < ' _ > > :: new ( ) ;
1652+
1653+ // Will shrink as we add more axes.
1654+ let mut rect_left = complete_rect;
1655+
1656+ if show_axes. x {
1657+ // We will fix this later, once we know how much space the y axes take up.
1658+ let initial_x_range = complete_rect. x_range ( ) ;
1659+
1660+ for ( i, cfg) in x_axes. iter ( ) . enumerate ( ) . rev ( ) {
1661+ let mut height = cfg. min_thickness ;
1662+ if let Some ( mem) = mem {
1663+ // If the labels took up too much space the previous frame, give them more space
1664+ // now:
1665+ height = height. max ( mem. x_axis_thickness . get ( & i) . copied ( ) . unwrap_or_default ( ) ) ;
1666+ }
1667+
1668+ let rect = match VPlacement :: from ( cfg. placement ) {
1669+ VPlacement :: Bottom => {
1670+ let bottom = rect_left. bottom ( ) ;
1671+ * rect_left. bottom_mut ( ) -= height;
1672+ let top = rect_left. bottom ( ) ;
1673+ Rect :: from_x_y_ranges ( initial_x_range, top..=bottom)
1674+ }
1675+ VPlacement :: Top => {
1676+ let top = rect_left. top ( ) ;
1677+ * rect_left. top_mut ( ) += height;
1678+ let bottom = rect_left. top ( ) ;
1679+ Rect :: from_x_y_ranges ( initial_x_range, top..=bottom)
1680+ }
1681+ } ;
1682+ x_axis_widgets. push ( AxisWidget :: new ( cfg. clone ( ) , rect) ) ;
1683+ }
1684+ }
1685+ if show_axes. y {
1686+ // We know this, since we've already allocated space for the x axes.
1687+ let plot_y_range = rect_left. y_range ( ) ;
1688+
1689+ for ( i, cfg) in y_axes. iter ( ) . enumerate ( ) . rev ( ) {
1690+ let mut width = cfg. min_thickness ;
1691+ if let Some ( mem) = mem {
1692+ // If the labels took up too much space the previous frame, give them more space
1693+ // now:
1694+ width = width. max ( mem. y_axis_thickness . get ( & i) . copied ( ) . unwrap_or_default ( ) ) ;
1695+ }
1696+
1697+ let rect = match HPlacement :: from ( cfg. placement ) {
1698+ HPlacement :: Left => {
1699+ let left = rect_left. left ( ) ;
1700+ * rect_left. left_mut ( ) += width;
1701+ let right = rect_left. left ( ) ;
1702+ Rect :: from_x_y_ranges ( left..=right, plot_y_range)
1703+ }
1704+ HPlacement :: Right => {
1705+ let right = rect_left. right ( ) ;
1706+ * rect_left. right_mut ( ) -= width;
1707+ let left = rect_left. right ( ) ;
1708+ Rect :: from_x_y_ranges ( left..=right, plot_y_range)
1709+ }
1710+ } ;
1711+ y_axis_widgets. push ( AxisWidget :: new ( cfg. clone ( ) , rect) ) ;
1712+ }
1713+ }
1714+
1715+ // The loops iterated through {x,y}_axes in reverse order, so we have to reverse
1716+ // the {x,y}_axis_widgets vec as well. Otherwise, the indices are messed up
1717+ // and the plot memory (mem.{x,y}_axis_thickness) will access the wrong axis
1718+ // given an index.
1719+ x_axis_widgets. reverse ( ) ;
1720+ y_axis_widgets. reverse ( ) ;
1721+
1722+ let mut plot_rect = rect_left;
1723+
1724+ // If too little space, remove axis widgets
1725+ if plot_rect. width ( ) <= 0.0 || plot_rect. height ( ) <= 0.0 {
1726+ y_axis_widgets. clear ( ) ;
1727+ x_axis_widgets. clear ( ) ;
1728+ plot_rect = complete_rect;
1729+ }
1730+
1731+ // Now that we know the final x_range of the plot_rect,
1732+ // assign it to the x_axis_widgets (they are currently too wide):
1733+ for widget in & mut x_axis_widgets {
1734+ widget. rect = Rect :: from_x_y_ranges ( plot_rect. x_range ( ) , widget. rect . y_range ( ) ) ;
1735+ }
1736+
1737+ ( [ x_axis_widgets, y_axis_widgets] , plot_rect)
1738+ }
0 commit comments