Question

I was trying to create some kind of canvas with a menu on the right. The canvas should use some part of the screen hopefully a constant ratio on all devices and the menu should have a fixed width.

I succeeded at doing something that looks a lot like what I want but when the mouse move, the clientX and clientY are innacurate. I believe it's because the flexbox has align center and it looks like the offset I see in clientX and clientY is the one created by the alignment. I'd like the mouse to draw where the pointer is located.

The interface is targetted for mobile browsers. I don't want the page to scroll and it should use 100% of the viewport and no more. I don't mind not using flexbox.

http://jsfiddle.net/F8YBf/

Css:

   body {
        width: 100%;
        height: 100%;
        margin: 0;
        padding: 0;
        display: flex;
    }

    ul[role="layout"] {
        display: flex;
        list-style: none;
        padding: 0;
        margin: 0;
        flex: 1 1 0%;
        background: pink;
    }

    ul[role="layout"] .canvas canvas {
        outline: 1px solid #000;
        width: 96%;
        margin: 2%;
    }

    ul[role="layout"] .canvas {
        flex: 1 1 0%;
        align-self: center;
    }

    ul[role="layout"] .menu {
        background: green;
        flex: 0 0 12rem;
    }

Javascript

var canvas = window.paint_zone;
var ctx = canvas.getContext("2d");

//canvas.style.height = window.body.scrollHeight - 32;
var width = canvas.scrollWidth;
var height = canvas.scrollHeight;
canvas.width = width;
canvas.height = height;

canvas.addEventListener("mousemove", function(e){
    ctx.beginPath();

    var radius = 10;
    ctx.fillStyle = "rgb(200,0,0)";
    ctx.arc(e.clientX, e.clientY, radius, 0, 2 * Math.PI, false);
    ctx.fill();
    ctx.closePath();

    e.preventDefault();
});

And html inside the <body>.

<ul role="layout">
    <li class="canvas">
        <canvas id="paint_zone"></canvas>
    </li>
    <li class="menu">
        <ul class="buttons">
            <li>Menu1</li>
            <li>Menu1</li>
            <li>Menu1</li>
            <li>Menu1</li>
            <li>Menu1</li>             
            <li>Menu1</li>
            <li>Menu1</li>
            <li>Menu1</li>             
            <li>Menu1</li>
            <li>Menu1</li>                   
            <li>Menu1</li>
            <li>Menu1</li>             
            <li>Menu1</li>
            <li>Menu1</li>
        </ul>
    </li>
</ul>
Was it helpful?

Solution

coordinates are accurate but:

event.client* behavior isn't actually defined for flexbox (what is the client area?)

therefore you should use absolute coordinates like pageX & pageY and getBoundingClientRect() to calc the relative ones

also you were right, the align-self:center contributed to (but wasn't the only) issue

you are also stretching the canvas, so document:canvas pixel ratio is not 1:1

here's the math:

var actualX = e.pageX - canvas.getBoundingClientRect().left;
var actualY = e.pageY - canvas.getBoundingClientRect().top;

var currentWidth = this.scrollWidth;
var currentHeight = this.scrollHeight;

var the_x = canvas.width * actualX / currentWidth; // a simple proportion
var the_y = canvas.height * actualY / currentHeight;

ctx.arc(the_x, the_y, radius, 0, 2 * Math.PI, false);

and here's the working demo: http://jsfiddle.net/qtkyw/

hth!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top