1

I want to make canvas-based uPlot plots responsive in width.

The ResizeObserver observes the parent div width and changes the plot/canvas width accordingly.

It works for simple layouts. If the parent div is part of a flexbox layout, growing works, but shrinking doesn't. Why?

const plotContainer1 = document.getElementById("plot-container1");
const plotContainer2 = document.getElementById("plot-container2");
const plot1 = document.getElementById("plot1");
const plot2 = document.getElementById("plot2");

const resizeObserver1 = new ResizeObserver(() => {
  plot1.width = plotContainer1.clientWidth;
});
resizeObserver1.observe(plotContainer1);

const resizeObserver2 = new ResizeObserver(() => {
  plot2.width = plotContainer2.clientWidth;
});
resizeObserver2.observe(plotContainer2);
.container {
  display: flex;
}

.left {
  width: 300px;
  flex-grow: 0;
  flex-shrink: 0;
}

.main {
  width: 100%;
  flex-grow: 0;
  flex-shrink: 1;
}

.plot-container {
  background: red;
}

.plot {
  display: flex !important;
  background: black;
}
<h1>Plot full width</h1>
<div class="plot-container" id="plot-container1">
  Plot 1
  <canvas class="plot" id="plot1"></canvas>
</div>

<h1>Plot in flexbox layout</h1>
<div class="container">
  <div class="left">Navigation</div>
  <div class="main">
    <div class="plot-container" id="plot-container2">
      Plot 2
      <canvas class="plot" id="plot2"></canvas>
    </div>
  </div>
</div>

Example on codepen: https://codepen.io/lukasberbuer/pen/LYjLmdE

luxderfux
  • 151
  • 1
  • 9
  • Please add more details like HTML and CSS in a [minimal reproducable example](https://stackoverflow.com/help/minimal-reproducible-example) at best in a [stack snippet](https://meta.stackoverflow.com/questions/358992/ive-been-told-to-create-a-runnable-example-with-stack-snippets-how-do-i-do). See [how to ask](https://stackoverflow.com/help/how-to-ask) – biberman Oct 28 '21 at 11:34

2 Answers2

1

Because as it seems, display:block and display:flex have a slightly different behaviour when it comes to their width. By default, both their width is 100% that of their parent. When the parent grows, they grow with it. Now when the parent shrinks, they are both trying to keep their width 100% that of their parents, BUT they contain something. They contain a canvas whose witdh has been constrained. So there's a conflict between the parent shrinking from the outside and the canvas pushing from the inside.

I believe display:block prioritizes the parent and shrinks, allowing in return the canvas to be resized down.

But display:flex seems to prioritize the canvas and is prevented from shrinking.

Jeremy Thille
  • 26,047
  • 12
  • 43
  • 63
  • Thanks! Adding `.plot { display: flex; }` does not change the behaviour. Any ideas? – luxderfux Oct 28 '21 at 11:36
  • What? I never suggested to add `.plot { display: flex; }` – Jeremy Thille Oct 28 '21 at 11:39
  • Well your question is "Why?", not "How to fix it?" – Jeremy Thille Oct 28 '21 at 11:41
  • Ok I misunderstood your answer. Is there any way to achieve similar behaviour as with `block` display (prioritize parent) in a flexbox layout? – luxderfux Oct 28 '21 at 11:48
  • I'm not sure. I tried to leave the canvas with `with:auto`, to let the CSS manage its width, and by doing so, it does shrink with its parent. What's wrong with that? Apparently you don't need a JS observer to force the canvas to be 100%, just stick with `width:auto` – Jeremy Thille Oct 28 '21 at 11:51
  • uPlot requires a fixed width/height of the canvas. Setting the width to auto will stretch and distort the plot. If the width of the parent container is changed, the JS observer will change the plot settings and therefore trigger redrawing. – luxderfux Oct 28 '21 at 12:01
0

A detailed answer can be found here: https://stackoverflow.com/a/36247448/9967707

Simply had to add min-width: 0 !important; to .main.

luxderfux
  • 151
  • 1
  • 9