2

My project needs to print out a canvas image that can be smaller or greater than the page width. I want the printout to maintain the canvas size if it is smaller than page width and scale if the canvas image is larger than page width. How do I accomplish this?

Here is an example of the canvas image being too big for the printed page (It needs to be shrunk to fit):

var canvas = document.getElementById("canvas1");

var ctx = canvas.getContext("2d");
ctx.fillStyle = "blue";
ctx.fillRect(0, 0, canvas.width, canvas.height);
html {height:100%; overflow:hidden;}
#main-container {height:100%; padding:; margin:0;
display: flex;
flex-direction: column;
}


body {height:100%; padding:0; margin:0; 
display: flex;
flex-direction: column;
}

header {
  background:aqua;
flex: 0 0 100px;
}
section {background:blue;
flex: 1;
display: flex;
flex-direction: row;
  overflow:auto;
}
article {
  background:blanchedalmond;
flex: 3;
}
nav {
  background:coral;
flex: 1;
order: -1;
  /*start flex settings*/
  display:flex;
  flex-direction: column;
  justify-content: space-betweeen;
  -webkit-justify-content: space-between;
  
 /*end flex settings*/
}

.nav-bottom-container {
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  align-items: flex-start;
}

.nav-item-top{
  overflow-y:auto;
}

.nav-bottom-item-left {
  background:deeppink;
  order:1;
  border-color:red;
  border-style: solid;
  flex-grow:1;
  cursor: pointer;
  text-align:center;
}
.nav-bottom-item-right {
  background:dodgerblue;
  order:0;
  border-color:blue;
  border-style: solid;
  flex-grow:1;
  cursor: pointer;
  text-align:center;
}

aside {background:#ddd;
flex: 0 0 200px;
}
footer {background:#888;
flex: 0 0 100px;
}

.item-text{
  font-size:1vmax;
  padding:1em;
}
canvas{ border: 1px solid black; }

#container {
    display: flex;           /* establish flex container */
    flex-direction: column;  /* make main axis vertical */
    justify-content: center; /* center items vertically, in this case */
    align-items: center;     /* center items horizontally, in this case */
  cursor:move;
}

.print-this-only{
  
}



@media print {
  html,
  body {
    height:100%;
    overflow:hidden;
   display:block;
    background-color: yellow;
  }
  .print-this-only {
    background-color: yellow;
    /*
            height: 100%;
    
            width: 100%;
            position: fixed;*/
    top: 0;
    left: 0;
    margin: 0;
  }
  .no-print,
  .no-print * {
    display: none !important;
  }
  .printOnly {
    display: block;
  }
}
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title> Shrink Canvas to Fit Printed Page </title>
</head>

<body ng-app="ui.bootstrap.demo" ng-controller="DropdownController as vm">
  
  <div id="main-container">
  
	<header class="no-print">fixed height header <button onclick="window.print();" class="no-print">Print Canvas</button></header>
	<section>
		<article id="id"><div id="container" >
  <div id="container"  class="print-this-only"style="position:relative">
    
<canvas height="1000px" width="2000px" id="canvas1">
</canvas>
     
        <img src="http://s.cdpn.io/3/kiwi.svg" 
       style="position: absolute; 
              left: 0px; 
              top:0px;
              z-index: 2;
              width: 100px;
       " />
      
        <img src="http://s.cdpn.io/3/kiwi.svg" 
       style="position: absolute; 
              left: 150px; 
              top:0px;
              z-index: 2;
              width: 100px;
       " />
      
      
        <img src="http://s.cdpn.io/3/kiwi.svg" 
       style="position: absolute; 
              left: 1700px; 
              top:150px;
              z-index: 2;
              width: 100px;
       " />
      </>
      
</div></article>
		<nav class="no-print">
     
      
      <div class="nav-item-top">
        <div class="item-text">
          sample
        </div>
         <div class="item-text">
         sample this is a much longer sample text it goes on for a little bit here and there.
        </div>
        
          <div class="item-text">
          this is the end of the line and the end of the universe.
        </div>
        <div ng-show=vm.showNav>Right</div>
        <div ng-hide=vm.showNav>Left</div>
      
      
      </div>
      <div class="nav-bottom-container">
         <div class="nav-bottom-item-right" ng-click="vm.showNav=!vm.showNav">Right</div>
      <div class="nav-bottom-item-left" ng-click="vm.showNav=!vm.showNav">Left</div>
   
      </div>
    </nav>
	
	</section>
  </div>


</body>
</html>

Here is an example of the canvas being smaller than page width and appropriately scaled:

var canvas = document.getElementById("canvas1");

var ctx = canvas.getContext("2d");
ctx.fillStyle = "blue";
ctx.fillRect(0, 0, canvas.width, canvas.height);
html {height:100%; overflow:hidden;}
#main-container {height:100%; padding:; margin:0;
display: flex;
flex-direction: column;
}


body {height:100%; padding:0; margin:0; 
display: flex;
flex-direction: column;
}

header {
  background:aqua;
flex: 0 0 100px;
}
section {background:blue;
flex: 1;
display: flex;
flex-direction: row;
  overflow:auto;
}
article {
  background:blanchedalmond;
flex: 3;
}
nav {
  background:coral;
flex: 1;
order: -1;
  /*start flex settings*/
  display:flex;
  flex-direction: column;
  justify-content: space-betweeen;
  -webkit-justify-content: space-between;
  
 /*end flex settings*/
}

.nav-bottom-container {
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  align-items: flex-start;
}

.nav-item-top{
  overflow-y:auto;
}

.nav-bottom-item-left {
  background:deeppink;
  order:1;
  border-color:red;
  border-style: solid;
  flex-grow:1;
  cursor: pointer;
  text-align:center;
}
.nav-bottom-item-right {
  background:dodgerblue;
  order:0;
  border-color:blue;
  border-style: solid;
  flex-grow:1;
  cursor: pointer;
  text-align:center;
}

aside {background:#ddd;
flex: 0 0 200px;
}
footer {background:#888;
flex: 0 0 100px;
}

.item-text{
  font-size:1vmax;
  padding:1em;
}
canvas{ border: 1px solid black; }

#container {
    display: flex;           /* establish flex container */
    flex-direction: column;  /* make main axis vertical */
    justify-content: center; /* center items vertically, in this case */
    align-items: center;     /* center items horizontally, in this case */
  cursor:move;
}

.print-this-only{
  
}



@media print {
  html,
  body {
    height:100%;
    overflow:hidden;
   display:block;
    background-color: yellow;
  }
  .print-this-only {
    background-color: yellow;
    /*
            height: 100%;
    
            width: 100%;
            position: fixed;*/
    top: 0;
    left: 0;
    margin: 0;
  }
  .no-print,
  .no-print * {
    display: none !important;
  }
  .printOnly {
    display: block;
  }
}
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title> Shrink Canvas to Fit Printed Page </title>
</head>

<body ng-app="ui.bootstrap.demo" ng-controller="DropdownController as vm">
  
  <div id="main-container">
  
	<header class="no-print">fixed height header <button onclick="window.print();" class="no-print">Print Canvas</button></header>
	<section>
		<article id="id"><div id="container" >
  <div id="container"  class="print-this-only"style="position:relative">
    
<canvas height="400px" width="400px" id="canvas1">
</canvas>
     
        <img src="http://s.cdpn.io/3/kiwi.svg" 
       style="position: absolute; 
              left: 0px; 
              top:0px;
              z-index: 2;
              width: 100px;
       " />
      
        <img src="http://s.cdpn.io/3/kiwi.svg" 
       style="position: absolute; 
              left: 150px; 
              top:0px;
              z-index: 2;
              width: 100px;
       " />
      
      
        <img src="http://s.cdpn.io/3/kiwi.svg" 
       style="position: absolute; 
              left: 200px; 
              top:150px;
              z-index: 2;
              width: 100px;
       " />
      </>
      
</div></article>
		<nav class="no-print">
     
      
      <div class="nav-item-top">
        <div class="item-text">
          sample
        </div>
         <div class="item-text">
         sample this is a much longer sample text it goes on for a little bit here and there.
        </div>
        
          <div class="item-text">
          this is the end of the line and the end of the universe.
        </div>
        <div ng-show=vm.showNav>Right</div>
        <div ng-hide=vm.showNav>Left</div>
      
      
      </div>
      <div class="nav-bottom-container">
         <div class="nav-bottom-item-right" ng-click="vm.showNav=!vm.showNav">Right</div>
      <div class="nav-bottom-item-left" ng-click="vm.showNav=!vm.showNav">Left</div>
   
      </div>
    </nav>
	
	</section>
  </div>


</body>
</html>

2 Answers 2

3
+50

One way to do it is to wrap the canvas into container, than calculate everything in percents of parent element width. So first in HTML:

<div class="canvas_container">
    <canvas height="1000px" width="2000px" id="canvas1"></canvas>
</div>

Than add in CSS:

@media print {
    #container {
        display: block; /* Cannot be flex here */
    }
    .canvas_container {
        max-width: 100%;
        padding-bottom: 50%; /* Canvas is 2000x1000, this will set the height to 50% of width */
        position: relative;
    }
    canvas{
        position: absolute;
        left: 0;
        top: 0;
        right: 0;
        bottom: 0;
        width: 100%;
    }
}

Than each of your images position gotta be in percent, also the width gotta be in percents:

<img src="http://s.cdpn.io/3/kiwi.svg" 
    style="
        position: absolute; 
        left: 0; 
        top: 0;
        z-index: 2;
        width: 5%;
    "
/>

<img src="http://s.cdpn.io/3/kiwi.svg" 
    style="
        position: absolute; 
        left: 7%; 
        top: 0;
        z-index: 2;
        width: 5%;
    "
/>

<img src="http://s.cdpn.io/3/kiwi.svg" 
    style="
        position: absolute; 
        left: 85%; 
        top: 15%;
        z-index: 2;
        width: 5%;
    "
/>

Complete code below:

<html xmlns="http://www.w3.org/1999/xhtml">

    <head>
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
        <title> Shrink Canvas to Fit Printed Page </title>
        <style>
            html {
                height: 100%;
                overflow: hidden;
            }
            
            #main-container {
                height: 100%;
                padding: ;
                margin: 0;
                display: flex;
                flex-direction: column;
            }
            
            * {
                box-sizing: border-box;
            }
            
            body {
                height: 100%;
                padding: 0;
                margin: 0;
                display: flex;
                flex-direction: column;
            }
            
            header {
                background: aqua;
                flex: 0 0 100px;
            }
            
            section {
                background: blue;
                flex: 1;
                display: flex;
                flex-direction: row;
                overflow: auto;
            }
            
            article {
                background: blanchedalmond;
                flex: 3;
            }
            
            nav {
                background: coral;
                flex: 1;
                order: -1;
                /*start flex settings*/
                display: flex;
                flex-direction: column;
                justify-content: space-betweeen;
                -webkit-justify-content: space-between;
                /*end flex settings*/
            }
            
            .nav-bottom-container {
                display: flex;
                flex-direction: row;
                flex-wrap: nowrap;
                align-items: flex-start;
            }
            
            .nav-item-top {
                overflow-y: auto;
            }
            
            .nav-bottom-item-left {
                background: deeppink;
                order: 1;
                border-color: red;
                border-style: solid;
                flex-grow: 1;
                cursor: pointer;
                text-align: center;
            }
            
            .nav-bottom-item-right {
                background: dodgerblue;
                order: 0;
                border-color: blue;
                border-style: solid;
                flex-grow: 1;
                cursor: pointer;
                text-align: center;
            }
            
            aside {
                background: #ddd;
                flex: 0 0 200px;
            }
            
            footer {
                background: #888;
                flex: 0 0 100px;
            }
            
            .item-text {
                font-size: 1vmax;
                padding: 1em;
            }
            
            canvas {
                border: 1px solid black;
            }
            
            #container {
                display: flex;
                /* establish flex container */
                flex-direction: column;
                /* make main axis vertical */
                justify-content: center;
                /* center items vertically, in this case */
                align-items: center;
                /* center items horizontally, in this case */
                cursor: move;
            }
            
            .print-this-only {}
            
            @media print {
                html,
                body {
                    height: 100%;
                    overflow: hidden;
                    display: block;
                    background-color: yellow;
                }
                #container {
                    display: block;
                }
                .canvas_container {
                    max-width: 100%;
                    padding-bottom: 50%;
                    position: relative;
                }
                canvas {
                    position: absolute;
                    left: 0;
                    top: 0;
                    right: 0;
                    bottom: 0;
                    width: 100%;
                }
                .print-this-only {
                    background-color: yellow;
                    /*
            height: 100%;
    
            width: 100%;
            position: fixed;*/
                    top: 0;
                    left: 0;
                    margin: 0;
                }
                .no-print,
                .no-print * {
                    display: none !important;
                }
                .printOnly {
                    display: block;
                }
            }

        </style>

    </head>

    <body ng-app="ui.bootstrap.demo" ng-controller="DropdownController as vm">

        <div id="main-container">

            <header class="no-print">fixed height header
                <button onclick="window.print();" class="no-print">Print Canvas</button>
            </header>
            <section>
                <article id="id">
                    <div id="container">
                        <div id="container" class="print-this-only" style="position:relative">

                            <div class="canvas_container">
                                <canvas height="1000px" width="2000px" id="canvas1"></canvas>
                            </div>

                            <img src="http://s.cdpn.io/3/kiwi.svg" style="
			position: absolute; 
			left: 0; 
			top: 0;
			z-index: 2;
			width: 5%;
		" />

                            <img src="http://s.cdpn.io/3/kiwi.svg" style="
			position: absolute; 
			left: 7%; 
			top: 0;
			z-index: 2;
			width: 5%;
		" />

                            <img src="http://s.cdpn.io/3/kiwi.svg" style="
			position: absolute; 
			left: 85%; 
			top: 15%;
			z-index: 2;
			width: 5%;
		" />


                        </div>
                </article>
                <nav class="no-print">


                    <div class="nav-item-top">
                        <div class="item-text">
                            sample
                        </div>
                        <div class="item-text">
                            sample this is a much longer sample text it goes on for a little bit here and there.
                        </div>

                        <div class="item-text">
                            this is the end of the line and the end of the universe.
                        </div>
                        <div ng-show=vm.showNav>Right</div>
                        <div ng-hide=vm.showNav>Left</div>


                    </div>
                    <div class="nav-bottom-container">
                        <div class="nav-bottom-item-right" ng-click="vm.showNav=!vm.showNav">Right</div>
                        <div class="nav-bottom-item-left" ng-click="vm.showNav=!vm.showNav">Left</div>

                    </div>
                </nav>

            </section>
            </div>

            <script>
                var canvas = document.getElementById("canvas1");

                var ctx = canvas.getContext("2d");
                ctx.fillStyle = "blue";
                ctx.fillRect(0, 0, canvas.width, canvas.height);

            </script>
    </body>

</html>

1

In your print styles, you can add overflow: hidden to .print-this-only and add this to the canvas:

.print-this-only canvas {
    max-width:100%;
    max-height: 100%;
    display: block;
}

Now you can constrain the canvas. Note that for the third image in the canvas you have left: 1700px (changed it to right: 0 for the demo below) - the position values for these images need to be in percentages for the scaling to be proper.

var canvas = document.getElementById("canvas1");

var ctx = canvas.getContext("2d");
ctx.fillStyle = "blue";
ctx.fillRect(0, 0, canvas.width, canvas.height);
html {
  height: 100%;
  overflow: hidden;
}

#main-container {
  height: 100%;
  padding: ;
  margin: 0;
  display: flex;
  flex-direction: column;
}

body {
  height: 100%;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
}

header {
  background: aqua;
  flex: 0 0 100px;
}

section {
  background: blue;
  flex: 1;
  display: flex;
  flex-direction: row;
  overflow: auto;
}

article {
  background: blanchedalmond;
  flex: 3;
}

nav {
  background: coral;
  flex: 1;
  order: -1;
  /*start flex settings*/
  display: flex;
  flex-direction: column;
  justify-content: space-betweeen;
  -webkit-justify-content: space-between;
  /*end flex settings*/
}

.nav-bottom-container {
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  align-items: flex-start;
}

.nav-item-top {
  overflow-y: auto;
}

.nav-bottom-item-left {
  background: deeppink;
  order: 1;
  border-color: red;
  border-style: solid;
  flex-grow: 1;
  cursor: pointer;
  text-align: center;
}

.nav-bottom-item-right {
  background: dodgerblue;
  order: 0;
  border-color: blue;
  border-style: solid;
  flex-grow: 1;
  cursor: pointer;
  text-align: center;
}

aside {
  background: #ddd;
  flex: 0 0 200px;
}

footer {
  background: #888;
  flex: 0 0 100px;
}

.item-text {
  font-size: 1vmax;
  padding: 1em;
}

canvas {
  border: 1px solid black;
}

#container {
  display: flex;
  /* establish flex container */
  flex-direction: column;
  /* make main axis vertical */
  justify-content: center;
  /* center items vertically, in this case */
  align-items: center;
  /* center items horizontally, in this case */
  cursor: move;
}

.print-this-only {}

@media print {
  html,
  body {
    height: 100%;
    width: 100%;
    margin: 0;
    overflow: hidden;
    display: block;
    background-color: yellow;
  }
  .print-this-only {
    background-color: yellow;
    top: 0;
    left: 0;
    margin: 0;
    overflow: hidden;
    /* ADDED */
  }
  /* ADDED */
  .print-this-only canvas {
    max-width: 100%;
    max-height: 100%;
    display: block;
  }
  .no-print,
  .no-print * {
    display: none !important;
  }
  .printOnly {
    display: block;
  }
}
<html xmlns="http://www.w3.org/1999/xhtml">

<head>
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  <title> Shrink Canvas to Fit Printed Page </title>
</head>

<body ng-app="ui.bootstrap.demo" ng-controller="DropdownController as vm">

  <div id="main-container">

    <header class="no-print">fixed height header <button onclick="window.print()" class="no-print">Print Canvas</button></header>
    <section>
      <article id="id">
        <div id="container">
          <div id="container" class="print-this-only" style="position:relative">

            <canvas height="1000px" width="2000px" id="canvas1">
</canvas>

            <img src="http://s.cdpn.io/3/kiwi.svg" style="position: absolute; 
              left: 0px; 
              top:0px;
              z-index: 2;
              width: 100px;
       " />

            <img src="http://s.cdpn.io/3/kiwi.svg" style="position: absolute; 
              left: 150px; 
              top:0px;
              z-index: 2;
              width: 100px;
       " />


            <img src="http://s.cdpn.io/3/kiwi.svg" style="position: absolute; 
              right: 0; 
              top:150px;
              z-index: 2;
              width: 100px;
       " />
          </div>

        </div>
      </article>
      <nav class="no-print">


        <div class="nav-item-top">
          <div class="item-text">
            sample
          </div>
          <div class="item-text">
            sample this is a much longer sample text it goes on for a little bit here and there.
          </div>

          <div class="item-text">
            this is the end of the line and the end of the universe.
          </div>
          <div ng-show=vm.showNav>Right</div>
          <div ng-hide=vm.showNav>Left</div>


        </div>
        <div class="nav-bottom-container">
          <div class="nav-bottom-item-right" ng-click="vm.showNav=!vm.showNav">Right</div>
          <div class="nav-bottom-item-left" ng-click="vm.showNav=!vm.showNav">Left</div>

        </div>
      </nav>

    </section>
  </div>
</body>

</html>

The same demo for a smaller canvas:

var canvas = document.getElementById("canvas1");

var ctx = canvas.getContext("2d");
ctx.fillStyle = "blue";
ctx.fillRect(0, 0, canvas.width, canvas.height);
html {
  height: 100%;
  overflow: hidden;
}

#main-container {
  height: 100%;
  padding: ;
  margin: 0;
  display: flex;
  flex-direction: column;
}

body {
  height: 100%;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
}

header {
  background: aqua;
  flex: 0 0 100px;
}

section {
  background: blue;
  flex: 1;
  display: flex;
  flex-direction: row;
  overflow: auto;
}

article {
  background: blanchedalmond;
  flex: 3;
}

nav {
  background: coral;
  flex: 1;
  order: -1;
  /*start flex settings*/
  display: flex;
  flex-direction: column;
  justify-content: space-betweeen;
  -webkit-justify-content: space-between;
  /*end flex settings*/
}

.nav-bottom-container {
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  align-items: flex-start;
}

.nav-item-top {
  overflow-y: auto;
}

.nav-bottom-item-left {
  background: deeppink;
  order: 1;
  border-color: red;
  border-style: solid;
  flex-grow: 1;
  cursor: pointer;
  text-align: center;
}

.nav-bottom-item-right {
  background: dodgerblue;
  order: 0;
  border-color: blue;
  border-style: solid;
  flex-grow: 1;
  cursor: pointer;
  text-align: center;
}

aside {
  background: #ddd;
  flex: 0 0 200px;
}

footer {
  background: #888;
  flex: 0 0 100px;
}

.item-text {
  font-size: 1vmax;
  padding: 1em;
}

canvas {
  border: 1px solid black;
}

#container {
  display: flex;
  /* establish flex container */
  flex-direction: column;
  /* make main axis vertical */
  justify-content: center;
  /* center items vertically, in this case */
  align-items: center;
  /* center items horizontally, in this case */
  cursor: move;
}

.print-this-only {}

@media print {
  html,
  body {
    height: 100%;
    width: 100%;
    margin: 0;
    overflow: hidden;
    display: block;
    background-color: yellow;
  }
  .print-this-only {
    background-color: yellow;
    top: 0;
    left: 0;
    margin: 0;
    overflow: hidden;
    /* ADDED */
  }
  /* ADDED */
  .print-this-only canvas {
    max-width: 100%;
    max-height: 100%;
    display: block;
  }
  .no-print,
  .no-print * {
    display: none !important;
  }
  .printOnly {
    display: block;
  }
}
<html xmlns="http://www.w3.org/1999/xhtml">

<head>
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  <title> Shrink Canvas to Fit Printed Page </title>
</head>

<body ng-app="ui.bootstrap.demo" ng-controller="DropdownController as vm">

  <div id="main-container">

    <header class="no-print">fixed height header <button onclick="window.print();" class="no-print">Print Canvas</button></header>
    <section>
      <article id="id">
        <div id="container">
          <div id="container" class="print-this-only" style="position:relative">

            <canvas height="400px" width="400px" id="canvas1">
</canvas>

            <img src="http://s.cdpn.io/3/kiwi.svg" style="position: absolute; 
              left: 0px; 
              top:0px;
              z-index: 2;
              width: 100px;
       " />

            <img src="http://s.cdpn.io/3/kiwi.svg" style="position: absolute; 
              left: 150px; 
              top:0px;
              z-index: 2;
              width: 100px;
       " />


            <img src="http://s.cdpn.io/3/kiwi.svg" style="position: absolute; 
              left: 200px; 
              top:150px;
              z-index: 2;
              width: 100px;
       " />
          </div>

        </div>
      </article>
      <nav class="no-print">


        <div class="nav-item-top">
          <div class="item-text">
            sample
          </div>
          <div class="item-text">
            sample this is a much longer sample text it goes on for a little bit here and there.
          </div>

          <div class="item-text">
            this is the end of the line and the end of the universe.
          </div>
          <div ng-show=vm.showNav>Right</div>
          <div ng-hide=vm.showNav>Left</div>


        </div>
        <div class="nav-bottom-container">
          <div class="nav-bottom-item-right" ng-click="vm.showNav=!vm.showNav">Right</div>
          <div class="nav-bottom-item-left" ng-click="vm.showNav=!vm.showNav">Left</div>

        </div>
      </nav>

    </section>
  </div>


</body>

</html>

0

Not the answer you're looking for? Browse other questions tagged or ask your own question.