Alexander Farber
Alexander Farber

Reputation: 23008

How to give a canvas max space and place left (scrollable) and right "menu" divs on it?

I have prepared a complete and simple jsFiddle for my question.

My word game currently uses an HTML table for laying out HTML canvas and jQuery UI buttons.

I would like to get rid of the HTML table and instead use HTML div elements, which I have written out in the red/yellow boxes with arrows at the screenshot:

screenshot

I would like to have the following structure of the div elements:

- fullDiv (should occupy 100% width and height of browser window)
-- hintDiv (100% width, min height, visible on top)
-- mainDiv (100% width, max height)
--- gameDiv (100% width, max height)
---- myCanvas (100% width, max height)
-- leftDiv (min width, same height as mainDiv, scrollable) <- relative position
-- rightDiv (min width, same height as mainDiv) <- relative position
-- totalDiv (100% width, min height, visible on bottom)

The idea is to give myCanvas as much space as possible and place leftDiv and rightDiv as kind of "menus" of both sides of it. The leftDiv would be a navigational menu with a scrollable list of games and have the same max possible height as myCanvas and rightDiv.

So I have tried the following code -

$(function () {
  $(':button').button();
  $('#fullCheck').checkboxradio();

  var gamesMenu = $('#gamesMenu').menu({
    items: '> :not(.ui-widget-header)'
  });

  for (var game = 1; game <= 50; game++) {
    gamesMenu.append('<LI VALUE="' + game + '">GAME ' + game + '</LI>');
  }
    gamesMenu.menu('refresh');
});
body {
  margin: 0;
  padding: 0;
}

#fullDiv {
  width: 100%;
  height: 100vh;
  background: #FFF;
}

#hintDiv,
#totalDiv {
  text-align: center;
}

#mainDiv,
#gameDiv {
  width: 100%;
  height: 100%;
}

#myCanvas {
  width: 100%;
  height: 100%;
  border: 4px red dotted;
  background: #CCF;
}

#leftDiv {
  position: relative;
  left: 0;
  top: 0;
  /* bottom: 0; */
  text-align: center;
  background: #FCC;
}

#rightDiv {
  position: relative;
  right: 0;
  top: 0;
  /* bottom: 0; */
  text-align: center;
  background: #CFC;
}

#gamesMenu {
  overflow-y: scroll;
}

#hintDiv {
  font-style: italic;
}
<div id="fullDiv">
  <div id="hintDiv">Hint</div>
  <div id="mainDiv">
    <div id="gameDiv">
      <canvas id="myCanvas"></canvas>
    </div>

    <div id="leftDiv">
      <button id="newBtn">New game</button>
      <ul id="gamesMenu"></ul>
    </div>

    <div id="rightDiv">
      <input id="fullCheck" type="checkbox">
      <label for="fullCheck">Full screen</label><br>
      <button id="recallBtn">Recall</button><br>
      <button id="shuffleBtn">Shuffle</button><br>
      <button id="swapBtn">Swap</button><br>
      <button id="skipBtn">Skip</button><br>
      <button id="resignBtn">Resign</button><br>
      <button id="pileBtn">Pile</button><br>
      <button id="movesBtn">Moves history</button><br>
      <button id="shareBtn">Share</button><br>
      <button id="playBtn">Play</button>
    </div>
  </div>
  <div id="totalDiv">Total</div>
</div>

<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script> 
<script src="//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>

However, my screen is totally messed up now:

screenshot

UPDATE:

Here the solution by Derek (thank you!)

$(function () {
  $(':button').button();
  $('#fullCheck').checkboxradio();

  var gamesMenu = $('#gamesMenu').menu({
    items: '> :not(.ui-widget-header)'
  });

  for (var game = 1; game <= 50; game++) {
    gamesMenu.append('<LI VALUE="' + game + '">GAME ' + game + '</LI>');
  }

    gamesMenu.menu('refresh');
});
body {
  margin: 0;
  padding: 0;
}

#fullDiv {
  width: 100%;
  height: 100vh;
  background: #FFF;
  display: flex;
  flex-direction: column;
}

#hintDiv,
#totalDiv {
  text-align: center;
  background: yellow;
}

#leftDiv {
  text-align: center;
  background: #FCC;
  display: flex;
  flex-direction: column;
}

#gamesMenu {
  overflow-y: auto;
}

#mainDiv {
  flex-grow: 1;
  display: flex;
  justify-content: space-between;
  overflow: hidden;
}

#gameDiv {
  flex-grow: 1;
}

#myCanvas {
  width: 100%;
  height: 100%;
  box-sizing: border-box;
  border: 4px red dotted;
  background: #CCF;
}

#rightDiv {
  text-align: center;
  background: #CFC;
  overflow-y: auto;
}

#hintDiv {
  font-style: italic;
}
<div id="fullDiv">
  <div id="hintDiv">Hint</div>
  <div id="mainDiv">
    <div id="leftDiv">
      <button id="newBtn">New game</button>
      <ul id="gamesMenu"></ul>
    </div>

    <div id="gameDiv">
      <canvas id="myCanvas"></canvas>
    </div>

    <div id="rightDiv">
      <input id="fullCheck" type="checkbox">
      <label for="fullCheck">Full screen</label><br>
      <button id="recallBtn">Recall</button><br>
      <button id="shuffleBtn">Shuffle</button><br>
      <button id="swapBtn">Swap</button><br>
      <button id="skipBtn">Skip</button><br>
      <button id="resignBtn">Resign</button><br>
      <button id="pileBtn">Pile</button><br>
      <button id="movesBtn">Moves history</button><br>
      <button id="shareBtn">Share</button><br>
      <button id="playBtn">Play</button>
    </div>
  </div>
  <div id="totalDiv">Total</div>
</div>

<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script> 
<script src="//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>

UPDATE 2:

For some reason jQuery UI menu is not hoverable (eventhough in the official demo it is)...

My workaround sofar is (to at least see the selected item):

li.selected {
  font-weight: bold;
  background-color: yellow;
}

var gamesMenu = $('#gamesMenu').menu({
  items: '> :not(.ui-widget-header)',
  select: function(ev, ui) {
    ui.item.addClass('selected').siblings().removeClass('selected');
  }
});

Upvotes: 1

Views: 118

Answers (1)

Derek Wang
Derek Wang

Reputation: 10204

This can be accomplished using flex layout.

  • Make the #fullDiv to use flex layout with flex-direction: column so that it can be aligned on columns.
  • Set flex: 1 1 auto to #mainDiv so that it can take the space except the #hintDiv and #totalDiv on #fullDiv.
  • Set #mainDiv to flex layout too with justify-content: space-between. You will know about that on this guide.
  • Due to that guide, exchange the #leftDiv and #gameDiv.
  • On #gameDiv, I have updated the canvas width and height as calc(100% - 8px) because the border size will be added to the real canvas size. So now, canvas border width is 4px so the canvas width will be (100% - 8px) + 8px(border size) = 100%.

/*$(function () {
  $(':button').button();
  $('#fullCheck').checkboxradio();

  var gamesMenu = $('#gamesMenu').menu({
    items: '> :not(.ui-widget-header)'
  });

  for (var game = 1; game <= 50; game++) {
    gamesMenu.append('<LI VALUE="' + game + '">GAME ' + game + '</LI>');
  }
});*/
body {
  font-family: Arial, Helvetica, sans-serif;
  margin: 0;
  padding: 0;
}

#fullDiv {
  width: 100%;
  height: 100vh;
  background: #FFF;
}

#hintDiv,
#totalDiv {
  text-align: center;
}

#myCanvas {
  width: calc(100% - 8px);
  height: calc(100% - 8px);
  border: 4px red dotted;
  background: #CCF;
}

#leftDiv {
  text-align: center;
  background: #FCC;
}

#rightDiv {
  text-align: center;
  background: #CFC;
}

#gamesMenu {
  overflow-y: scroll;
}

#publishBtn {
  max-width: 200px;
}

#timer1,
#timer2 {
  color: red;
}

#hintDiv {
  font-style: italic;
}


/*** Additional Codes ***/
#fullDiv {
  display: flex;
  flex-direction: column;
}

#mainDiv {
  flex: 1 1 auto;
  display: flex;
  justify-content: space-between;
}

#gameDiv {
  flex: 1 1 auto;
}
<div id="fullDiv">
  <div id="hintDiv">Hint</div>
  <div id="mainDiv">
    <div id="leftDiv">
      <button id="newBtn">New game</button>
      <ul id="gamesMenu"></ul>
    </div>
    
    <div id="gameDiv">
      <canvas id="myCanvas"></canvas>
    </div>

    <div id="rightDiv">
      <input id="fullCheck" type="checkbox">
      <label for="fullCheck">Full screen</label><br>
      <button id="recallBtn">Recall</button><br>
      <button id="shuffleBtn">Shuffle</button><br>
      <button id="swapBtn">Swap</button><br>
      <button id="skipBtn">Skip</button><br>
      <button id="resignBtn">Resign</button><br>
      <button id="pileBtn">Pile</button><br>
      <button id="movesBtn">Moves history</button><br>
      <button id="shareBtn">Share</button><br>
      <button id="playBtn">Play</button>
    </div>
  </div>
  <div id="totalDiv">Total</div>
</div>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

Upvotes: 3

Related Questions