Canvas painting

Asked

Viewed 335 times

0

I have this code below in HTML, CSS and Javascript, and I’m using a Javascript library called Three.js. I am having a problem to perform an insertion in the code. This code makes paintings on Planes and I needed to put a checkboxin HTML so that when activated, instead of painting, it would become an eraser, so that I could erase the already made drawing or a part of the drawing. It would look like the wipe button all over the screen, but instead of cleaning the whole screen, I would pass the mouse where I intend to delete and it would erase that part. (I hope I’ve been clear with my problem).

Follows HTML code:

<script src="https://code.jquery.com/jquery-1.11.2.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r77/three.min.js"></script>
<div id="container">
<div overflow="hidden">
<input id="pinta" name="pintar" type="checkbox"/>
<label for="pintar">Bloquear</label>
<input id="limpar" type="button" value="limpar"/>
</div>
</div>

Follows CSS code:

#container {
overflow: hidden;
position: absolute;
width: 300px;
height: 150px;
outline: 1px dashed grey;
margin-left: -150px;
margin-top: -75px;
left: 50%;
top: 50%;
}

.balloon {
position: absolute;
color: white;
background: black;
border-radius: 100px;
font-family: sans-serif;
font-size: 20px;
width: 100px;
height: 30px;
text-align: center;
padding-top: 10px;
}

.balloon .text {
overflow: hidden;
white-space: nowrap;
width: 80px;
margin-left: 10px;
/* fix chrome gap */
height: 21px;
}

.balloon .arrow {
left: 40px;
margin-top: 9px;
border-width: 10px 10px 0px;
border-color: black transparent transparent;
position: absolute;
width: 0px;
height: 0px;
border-style: solid;
}

Follow Javascript code:

var mouse = {
    x: 0,
    y: 0,
    down: false,
    pinta: true
};

var scene, camera, renderer, raycaster = new THREE.Raycaster(),mesh;

var canvas = document.createElement('canvas');
canvas.width = 256;
canvas.height = 256;

var texture = new THREE.Texture(canvas);
texture.needsUpdate = true;

var context = canvas.getContext('2d');
limpar();

scene = new THREE.Scene();

camera = new THREE.PerspectiveCamera(50, container.offsetWidth / 
container.offsetHeight, 1, 10000);
camera.position.y = -400;
camera.position.z = 1000;
camera.lookAt(scene.position);

mesh = new THREE.Mesh(
    new THREE.PlaneGeometry(1000, 1000),
    new THREE.MeshBasicMaterial({
        map: texture
    })
);
scene.add(mesh);

renderer = new THREE.WebGLRenderer();
renderer.setClearColor(0xffffff);
renderer.setSize(container.offsetWidth, container.offsetHeight);

container.appendChild(renderer.domElement);

var handler = function(e) {
    mouse.down = (e.buttons != 0);
    mouse.x = e.clientX;
    mouse.y = e.clientY;
}

document.body.addEventListener('mousemove', handler);
document.body.addEventListener('mousedown', handler);
document.getElementById("pinta").onchange = function() {
    pintar()
};
document.getElementById("limpar").onclick = function() {
    limpar()
};

function limpar() {
    context.rect(0, 0, canvas.width, canvas.height);
    context.clearRect(0, 0, canvas.width, canvas.height);
    context.fillStyle = 'aliceblue';
    context.fill();
    texture.needsUpdate = true;
}

function pintar() {
    mouse.pinta = !document.getElementById("pinta").checked;
}

function animate() {

    requestAnimationFrame(animate);

    mesh.rotation.y = (2 * mouse.x - document.body.offsetWidth) * 1e-3;

    if (mouse.down && mouse.pinta) {
        var canvasRect = renderer.domElement.getBoundingClientRect();

        raycaster.ray.origin.set(0, 0, 0);
        camera.localToWorld(raycaster.ray.origin);
        raycaster.ray.direction.set(
            ((mouse.x - canvasRect.left) / canvasRect.width) * 2 - 1,
            ((canvasRect.top - mouse.y) / canvasRect.height) * 2 + 1,
            0.5).unproject(camera).sub(raycaster.ray.origin).normalize();

        var intersects = raycaster.intersectObject(scene, true);
        if (intersects && intersects[0]) {
            var x = intersects[0].uv.x * canvas.width;
            var y = (1 - intersects[0].uv.y) * canvas.height;

            context.beginPath();
            context.rect(x - 4, y - 4, 8, 8);
            context.fillStyle = 'black';
            context.fill();

            texture.needsUpdate = true;
        }
    }

    renderer.render(scene, camera);

}

animate();

1 answer

0


An easy way to do this, taking into account that your program is still quite simple, is to paint with the background color.

So in the code where the painting takes place:

context.beginPath();
context.rect(x - 4, y - 4, 8, 8);
context.fillStyle = 'black';
context.fill();

We can put a if to check if we are using the eraser or brush, and if it is the eraser, we use the background color to paint:

if (document.getElementById("apaga").checked) {
    context.fillStyle = 'aliceblue'; // cor do fundo
} else {
    context.fillStyle = 'black';
}

Take a look at the example working below:

var mouse = {
    x: 0,
    y: 0,
    down: false,
    pinta: true
};

var scene, camera, renderer, raycaster = new THREE.Raycaster(),mesh;

var canvas = document.createElement('canvas');
canvas.width = 256;
canvas.height = 256;

var texture = new THREE.Texture(canvas);
texture.needsUpdate = true;

var context = canvas.getContext('2d');
limpar();

scene = new THREE.Scene();

camera = new THREE.PerspectiveCamera(50, container.offsetWidth / 
container.offsetHeight, 1, 10000);
camera.position.y = -400;
camera.position.z = 1000;
camera.lookAt(scene.position);

mesh = new THREE.Mesh(
    new THREE.PlaneGeometry(1000, 1000),
    new THREE.MeshBasicMaterial({
        map: texture
    })
);
scene.add(mesh);

renderer = new THREE.WebGLRenderer();
renderer.setClearColor(0xffffff);
renderer.setSize(container.offsetWidth, container.offsetHeight);

container.appendChild(renderer.domElement);

var handler = function(e) {
    mouse.down = (e.buttons != 0);
    mouse.x = e.clientX;
    mouse.y = e.clientY;
}

document.body.addEventListener('mousemove', handler);
document.body.addEventListener('mousedown', handler);
document.getElementById("pinta").onchange = function() {
    pintar()
};
document.getElementById("limpar").onclick = function() {
    limpar()
};

function limpar() {
    context.rect(0, 0, canvas.width, canvas.height);
    context.clearRect(0, 0, canvas.width, canvas.height);
    context.fillStyle = 'aliceblue';
    context.fill();
    texture.needsUpdate = true;
}

function pintar() {
    mouse.pinta = !document.getElementById("pinta").checked;
}

function animate() {

    requestAnimationFrame(animate);

    mesh.rotation.y = (2 * mouse.x - document.body.offsetWidth) * 1e-3;

    if (mouse.down && mouse.pinta) {
        var canvasRect = renderer.domElement.getBoundingClientRect();

        raycaster.ray.origin.set(0, 0, 0);
        camera.localToWorld(raycaster.ray.origin);
        raycaster.ray.direction.set(
            ((mouse.x - canvasRect.left) / canvasRect.width) * 2 - 1,
            ((canvasRect.top - mouse.y) / canvasRect.height) * 2 + 1,
            0.5).unproject(camera).sub(raycaster.ray.origin).normalize();

        var intersects = raycaster.intersectObject(scene, true);
        if (intersects && intersects[0]) {
            var x = intersects[0].uv.x * canvas.width;
            var y = (1 - intersects[0].uv.y) * canvas.height;

            context.beginPath();
            context.rect(x - 4, y - 4, 8, 8);
            if (document.getElementById("apaga").checked) {
            context.fillStyle = 'aliceblue';
            } else {
            context.fillStyle = 'black';
            }
            context.fill();
            texture.needsUpdate = true;
        }
    }

    renderer.render(scene, camera);

}

animate();
#container {
overflow: hidden;
position: absolute;
width: 300px;
height: 150px;
outline: 1px dashed grey;
margin-left: -150px;
margin-top: -75px;
left: 50%;
top: 50%;
}

.balloon {
position: absolute;
color: white;
background: black;
border-radius: 100px;
font-family: sans-serif;
font-size: 20px;
width: 100px;
height: 30px;
text-align: center;
padding-top: 10px;
}

.balloon .text {
overflow: hidden;
white-space: nowrap;
width: 80px;
margin-left: 10px;
/* fix chrome gap */
height: 21px;
}

.balloon .arrow {
left: 40px;
margin-top: 9px;
border-width: 10px 10px 0px;
border-color: black transparent transparent;
position: absolute;
width: 0px;
height: 0px;
border-style: solid;
}
<script src="https://code.jquery.com/jquery-1.11.2.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r77/three.min.js"></script>
<div id="container">
<div overflow="hidden">
<input id="pinta" name="pintar" type="checkbox"/>
<label for="pintar">Bloquear</label>
<input id="apaga" name="apagar" type="checkbox"/>
<label for="apagar">Apagar</label>
<input id="limpar" type="button" value="limpar"/>
</div>
</div>

  • Thanks again @Blogger, but I really needed a "eraser", because within the canvas I intend to open images, pdf, videos and web pages, the background of a specific color is just for testing

  • @Giovannidesiró understood - and when delete these images/pdfs, what would be underneath? I think it’s nice to implement this part of opening images first, and then think about the question of how to delete, because if the problem is different, the solution will probably be different, I think...

  • then is that this painting system will be enabled, IE, most of the time this painting will not be used, it is as if it was something more in the system, to be able to use if you need to highlight something or even present something. The opening part of the image, video, website and pdf is almost ready. I’m having trouble even in this part of the painting. But thank you for your great help...

Browser other questions tagged

You are not signed in. Login or sign up in order to post.