0

Previously I made this question. I try the solution linked in the similar question already made (using grid instead of flex) but I have some problems.

I have to build a grid of plots (bar charts). My dataset could be aggregated by Day or by Month. Obviously if the data is aggregated by months, the number of bars is much smaller than the number of bars in case the data is aggregated by day. The width of the plot is proportional to the number of bars.

To show my problem I created these simple images: each rectangle represents a bar chart (is like a placeholder). The larger rectangles represent the bar charts in the case in which the data are aggregated by Day, the narrower bar charts instead represent the bar charts when the data are aggregated by Month.

In this example I suppose that my dataset is composed by 6 chart. I know the width of the graph because it is simply the number of bars for the width of the bar. I would like the data to be positioned automatically.

In each row there cannot be more than two graphs, between a graph and the other there must be some space and the final row (if it is not complete) must have the charts aligned to the left. The last request is the reason why use Flex is not correct, so I switched to Grid.

So, I want that if data are aggregated by Day, charts would like:

enter image description here

If data are aggregated by Month, charts would like:

enter image description here

I try CSS grid using this code:

<div
  className="relative ba b--black"
  style={{
    display: 'grid',
    gridTemplateColumns: `repeat(auto-fit, minmax(45%, 1fr))`,
    gridAutoRows: SVG_HEIGHT,
    gridGap: '10px 5px', // space h, space v
  }}
>
  {
    data.map((plot, plotIdx) => {
      return (
        <div
          key={plotIdx}
          className="ba b--black overflow-x-auto"
          onScroll={this.handleHorizontalScroll(plotIdx)}
        >
          <svg
            width={SVG_WIDTH}
            height={CHART_HEIGHT + MARGINS.bottom + MARGINS.top}
          >
            // other code...
          </svg>
        </div>
      )
    })
  }
</div>

(Each chart can have a large width so there is a horizontal scroll).

The problem now is that the cell of each plot is always the same even if the real dimension if the chart is smaller than the container.

Data aggregated by Day:

enter image description here

Data aggregated by Month:

enter image description here


If I use SVG_WIDTH in place of 45% in the minmax statement, I get:

enter image description here

in case data are aggregated by day, and this one in case data are aggregated my month:

enter image description here


I didn't use px, thanks! Now it works in the case of aggregation by month but not the case of aggregation by day.

by day (doesn't work):

enter image description here

by month (works):

enter image description here

The problem is that every graph should have a horizontal scroll in fact if the SVG_WIDTH is greater than the size of the father div, then I need to add a scroll.

Here is the code I used:

<div
  className="relative ba b--black"
  style={{
    display: 'grid',
    gridTemplateColumns: `repeat(auto-fit, minmax(${SVG_WIDTH}px, 1fr))`,
    gridAutoRows: PLOT_HEIGHT,
    gridGap: '10px 5px', // space h, space v
  }}
>
  {data.map((plot, plotIdx) => {
    const yScale = this.yScale(plot)
    const yAxisTicks = yScale.ticks(4)

    return (
      <div
        key={plotIdx}
        ref={plotElem => (this.plots[plotIdx] = plotElem)}
        className="ba b--black overflow-x-auto"
        onScroll={this.handleHorizontalScroll(plotIdx)}
      >
      // ...
      </div>
    )}
  )}
</div>
  • Please clarify your specific problem or add additional details to highlight exactly what you need. As it's currently written, it’s hard to tell exactly what you're asking. – Paulie_D Mar 22 '19 at 16:32
  • 1
    @Paulie_D Sure! I edit my main message adding a lot of information. Thanks –  Mar 22 '19 at 20:07
  • personally, I would use two different styles for this, one with 2 columns and one with 4 columns and set a different class name depending on the source being daily or monthly. – arieljuod Mar 23 '19 at 14:20
  • 1
    @arieljuod Thanks for your advice but my data are really variable, I prefer not to use a hard coded solution –  Mar 24 '19 at 09:45
  • What do you mean by "really variable"? you said there was 2 sources: daily, monthy and you gave 2 examples: 2 columns, 4 columns. It sounds like you have 2 different layouts. It's not clear. I don't understand why you want a grid instead of a flex, it sound like a flexbox fits your need better but, again, it's not clear. – arieljuod Mar 24 '19 at 13:04
  • 1
    @arieljuod Yes, there are two possible sources: daily and monthly. The data may vary, which means that the number of bars on the graph can vary a lot (from 2 to 3000, or more) so the number of layout columns can also vary, at least there must be two graphs per line but they can there are also 3, 4, 5, 6, etc. `flex` is not good for this reason: https://stackoverflow.com/questions/42176419/targeting-flex-items-on-the-last-row –  Mar 24 '19 at 13:35
  • You would probably be receiving more answers if you provided a way to replicate the problem. Because the code you posted is so limited, the best we can do is offer guesses and suggestions, which isn't really that helpful. Please try to provide enough code so that the problem can be reproduced. Thank you. – Michael Benjamin Mar 26 '19 at 17:48

1 Answers1

0

Use SVG_WIDTH in place of 45% in the minmax statement.

As for the overflow problem that show up for big values, there is a workaround described here, although it is a bit hacky. Adapted to your case, minimum two columns:

@media (max-width: ${SVG_WIDTH * 2 + 10}px) {
  .container { grid-template-columns: repeat(2, 1fr); }
}

Where 10 is your grid-gap. And the .container takes full width of the page with body margin reset to 0. Otherwise also add the default margin of the body tag (8px left and right) and the sidebar width if you have one. You can also use CSS calc() if your sidebar or layout is adaptive, but the support for calc() in media queries is limited to very recent browsers currently.

user
  • 23,260
  • 9
  • 113
  • 101
  • I edit my main question adding details about using your advice. It doesn't work –  Mar 26 '19 at 08:03
  • @beth, are you sure it applied correctly? Probably need to add `px` after the number if it isn't there. – user Mar 26 '19 at 08:12
  • @beth: you can check it in the Inspector in the browser developer tools. Find the `div` element and make sure that the property is there, it isn't struckthrough and its value is correct. It should have `100px` (or whatever the width is) in place of `45%`. – user Mar 26 '19 at 08:39
  • Thanks, there are still problems. I hope you can help me. I changed the main message again –  Mar 26 '19 at 08:52
  • Thanks for the updates. I'm using React so how can I use your code? I can't put it in the css file because in that file I haven't the `SVG_WIDTH ` variable. Normally I create in the component js file a variable `const style = {something in css}` and then I use it in this way `
    `. In this case how can I use a media query style rule?
    –  Mar 27 '19 at 07:39
  • @beth: so, have you found a way to do it? I believe you could add a `style` tag as part of the element's html, [like here](https://stackoverflow.com/a/49878074). – user Mar 28 '19 at 15:05