11521 sujets

JavaScript, DOM et API Web HTML5

Bonjour,
Sur une image chargée dans un canvas via drawImage, je cherche à implémenter une fonction (JavaScript avec JQuery) permettant le tracé élastique d'un rectangle avec le clic de souris comme les Boîtes de sélections qu'on obtient sur le bureau de Windows 10.
En m'inspirant du Web, j'ai le code :

    <canvas id="canvas" width="1000" height="700"></canvas>
    <div id="output">output</div>
	
    <script>
	$(document).ready(function(){ 

		//Variables
		var last_mousex = last_mousey = 0;
		var mousex = mousey = 0;
		var derW = derH = 0;
		var mousedown = false;

        //Canvas
		var canvas = document.getElementById('canvas');
		var ctx = canvas.getContext('2d');
		ctx.drawStyle = "black";
		ctx.lineWidth = 1;
		ctx.globalCompositeOperation = 'xor';	
		
		// Fond
		var monimage = new Image();
		monimage.src = "./albums/une_photo.jpg";
		ctx.drawImage(monimage, 0, 0, 1000, 700);
		
		//Mousedown
		$(canvas).on('mousedown', function(e) {
			last_mousex = parseInt(e.pageX);
			last_mousey = parseInt(e.pageY);
			mousedown = true;
		});

		//Mouseup
		$(canvas).on('mouseup', function(e) {
			mousedown = false;
		});

		//Mousemove
		$(canvas).on('mousemove', function(e) {
			mousex = parseInt(e.pageX); 
			mousey = parseInt(e.pageY); 
		   if (mousedown) {
				var width = mousex-last_mousex;
				var height = mousey-last_mousey;
				ctx.strokeRect(last_mousex, last_mousey, derW, derH);
				derW = width;
				derH = height;
				ctx.strokeRect(last_mousex, last_mousey, width, height);
			}
			//Output
			$('#output').html('current: '+mousex+', '+mousey+' last: '+last_mousex+', '+last_mousey+' mousedown: '+mousedown);		});
		});
	</script>

Ce code ne me donne pas satisfaction !
Mon idée est, utilisant les événements souris, de tracer sur le fond du canvas par strokeRect, des rectangles au fur et à mesure du déplacement de la souris, événement mousemove.
Avec globalCompositeOperation = 'xor', je pense que deux tracés consécutifs du même rectangle devraient s'annuler, laissant réapparaître l'image de fond.
Ce n'est hélas pas ce qui se passe, comme si le xor ne fonctionnait pas ?
Merci de m'avoir lu jusqu'à ce point, et merci si vous avez une idée pour venir à mon aide.
Bien cordialement.
Yves
Modifié par goggi (10 Oct 2022 - 10:25)
Modérateur
Bonjour,

La doc pour xor (voir https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation ) dit : "Les formes sont rendues transparentes là où elles se chevauchent et dessinées normalement partout ailleurs."

Si tu appliques 2 fois ça, tu ne peux pas retrouver la forme d'origine.

EDIT: ce serait plus simple de dessiner un autre canvas avec un fond transparent par dessus le canvas qui contient ton image d'origine, et de n'y dessiner que ton rectangle.

Amicalement,
Modifié par parsimonhi (11 Oct 2022 - 23:01)
Merci pour l'idée.
Je suis en train de tester une solution consistant à réafficher la photo de fond à chaque déplacement du rectangle, mais c'est un peu lourd.
Je vais tester la surcharge de deux canvas comme proposé.
Merci à tous.
Yves
Bonjour,
J'ai testé la surcharge de deux canvas superposés, la photo dans le canvas du dessous par drawImage, la boîte de sélection (rectangle élastique) tracée sur le canvas transparent du dessus.
Le problème demeure que deux strokeRect l'un après l'autre en mode xor sur le canvas du dessus ne laissent pas convenablement voir les pixels de la photo du canvas inférieur ?
Je m'en tiendrai donc pour le moment à un seul canvas avec réaffichage de la photo et tracé du rectangle en mode 'source-over' :

	$(document).ready(function(){  

		//Variables
		let start_mousex = start_mousey = 0;
		let mousedown = false;

                //Canvas
		let canvas = document.getElementById('canvas'); 
		let ctx = canvas.getContext('2d');
		ctx.globalCompositeOperation = 'source-over';						

		// Fond
		let monimage = new Image();
		monimage.src = './album/monimage.jpg';
		ctx.drawImage(monimage, 0, 0, canvas.width, canvas.height);
		
		//Mousedown
		$("#canvas").on('mousedown', function(e) {
			start_mousex = parseInt(e.pageX, 10);
			start_mousey = parseInt(e.pageY, 10);
			mousedown = true;
		});

		//Mouseup
		$("#canvas").on('mouseup', function(e) {
			mousedown = false;
		});

		//Mousemove
		$("#canvas").on('mousemove', function(e) {
			mousex = parseInt(e.pageX, 10); 
			mousey = parseInt(e.pageY, 10); 
			if (mousedown) {
				ctx.drawImage(monimage, 0, 0, canvas.width, canvas.height);
				ctx.strokeRect(start_mousex, start_mousey, mousex-start_mousex, mousey-start_mousey);
			}
		});

J'ai essayé de ne sauvegarder à chaque mouvement de souris que la partie d'image concernée par getImageData et de ne restaurer que celle-ci (gain de temps par rapport au réaffichage complet, mais je ne m'en suis pas sorti (maladresse et manque de temps).
Bien cordialement.
Yves
Modifié par goggi (15 Oct 2022 - 09:19)