Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Canvas Drawing Over HTML and Preserving Aspect on Screen Resize

Background

This is a pretty hard problem that I have been struggling with for a few days now. I am trying to display lessons in a slide-show format. So a lesson is made up of different slides. Now overlayed on top of each slide is a canvas element which is fit to the size of the screen.

canvas.width  = document.body.clientWidth;
canvas.height = document.body.clientHeight;

This allows the teacher to draw notes and highlight parts of the lesson on the canvas.

Problem

The content of the slide is made up of HTML it looks like this when the slide is loaded.

When I resize the page however...

enter image description here

So the problem here is that the canvas 'image' is resized according to the aspect ratio of the page with CSS.

#theCanvas {
    position:fixed;
    top:0;
    right:0;
    bottom:0;
    left:0;
}

But the actual HTML stays the same size, but re-arranges its line-wrap points, bad.

What I have Tried

First, I am making all my HTML elements resize according to the width and height of the window using CSS:

h1 {
    font-family: 'Open Sans Condensed', sans-serif;
    color: #222222;
    font-weight: 200;
    font-size: 5.9vw;
}

h2 {
    font-family: 'Open Sans Condensed', sans-serif;
    color: #222222;
    font-weight: 200;
    font-size: 3.0vh;
}

h4 {
    font-family: 'Open Sans Condensed', sans-serif;
    color: #444444;
    font-weight: 200;
    font-size: 2vmin;
}

p {
    font-family: 'Open Sans Condensed';
    font-size: 2vmin;
    font-weight: 200;
}

Next I am saving and resizing the canvas image using:

window.onresize = function(event) {

    var data = canvas.toDataURL();

    // resize the canvas
    canvas.width = document.body.clientWidth;
    canvas.height = document.body.clientHeight;
    //alert($(container).width());

    // scale and redraw the canvas content
    var img=new Image();

    img.width = document.body.clientWidth;
    img.height = document.body.clientHeight;

    img.onload=function(){
        context.drawImage(img,0,0,img.width,img.height);
    }
    img.src=data;

};

The result in full screen (1920px width)

enter image description here

When a click the resize window button (1200px)

enter image description here

That's pretty close.

Problem

Now when I drag the corner of the window to resize this happens:

enter image description here

Question

1 - Why is the window.onresize function not triggering when I manually resize the corner of the window?

(bonus question) Am I going about this the right way, or is it going to be more trouble then its worth to overlay canvas on HTML elements for interactive lessons?

like image 678
Jethro Hazelhurst Avatar asked Jan 21 '17 13:01

Jethro Hazelhurst


People also ask

How do I make my canvas fit the screen in HTML?

to set the canvas's width and height both to 100%. We also set the position to absolute and top , left , right , and bottom to 0 to make the canvas fill the screen. Also, we make the html and body elements fill the screen by setting the width and height to 100%.

How do you dynamically resize canvas?

Resizing the canvas on the fly is quite easy. To do it, simply set the width and height properties of the Canvas object, and then redraw the canvas contents: Canvas . width = 600 ; Canvas .


1 Answers

I think I mis-understood your problem.

If you want the hand drawn stuff to match the html elements then you need to make sure the HTML elements never change layout and always keep the same relative sizes. In your example that's already NOT the case. You've got that "🕑25m" in the top left and "Welcome" in the middle and as you drag the page taller those 2 elements are separating by an amount not proportional to the other sizes of elements so you're already asking for something that's basically impossible.

You could maybe use SVG for all your text, that way it can be scaled to arbitrary sizes where as normal HTML text can't. In other words if you make the page really tall and thin with SVG you'll get tall and thin text and all the positions and sizes will be proportional to their original positions and size where as with HTML the text will not stretch, you set the size to various settings of vh but that just means the browser is going to pick the size, not non-proportionally scale the text.

Example: Original desired display

enter image description here

Change the window to tall and thin (font-size: 10vh;)

enter image description here

Notice the font is not stretched and so the relative sizes and distance between the "25m" and the "welcome" no longer match

Do the same with SVG with preserveAspectRatio="none"

enter image description here

Notice now the both the "25m" and "Welcome" are also tall and thin. This means if you had drawn a box around both in your canvas both boxes would still match after scaling. Without that something is not going to match.

Here's the HTML version of the above

body { margin: 0; }
.center {
  position: absolute;
  left: 0;
  top: 0;
  width: 100vw;
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 20vh;
}
<div id="time">25m</div>
<div class="center">
  <div>Welcome</div>
</div>

And the SVG version

body { margin: 0; }
#foo {
  width: 100vw;
  height: 100vh;
  display: block;
}
<svg 
     id="foo" 
     width="100%" 
     height="100%" 
     viewBox="0 0 640 480" 
     version="1.1" 
     xmlns="http://www.w3.org/2000/svg" 
     preserveAspectRatio="none" 
     xmlns:xlink="http://www.w3.org/1999/xlink" 
     xml:space="preserve" 
     style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;">
    <text x="187px" y="240px" style="font-family:'ArialMT', 'Arial', sans-serif;font-size:64px;">W<tspan x="246px 282px " y="240px 240.084px ">el</tspan>come</text>
    <text x="19px" y="35px" style="font-family:'ArialMT', 'Arial', sans-serif;font-size:16px;">25m</text>
</svg>
like image 155
gman Avatar answered Sep 22 '22 12:09

gman