Steffen Peters: Canvas über MouseWheel skalieren funktioniert nicht

Beitrag lesen

Hallo Leute,

ich versuche mich gerade an einem kleinen Canvas-Projekt. Irgendwann soll damit ein einfaches Organigramm angezeigt (und vielleicht auch noch bearbeitet) werden.

Alles funktioniert in meinem Test soweit schonmal, aber das Vergrößern/Verkleinern über das Mausrad leider nicht so ganz.

Die ursprüngliche Canvas-Anzeige bleibt stehen und die skalierte Version wird erst bei Drag&Drop "mit" angezeigt.

Wieso bleibt das alte Teil stehen und wird nicht durch das clearRect gelöscht?

Hier der aktuelle Source-Code:

<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>Canvas</title>
<style>
.canvas-container {
	text-align: center;
}
.canvas {
	border: 5px solid black;
	background-color: #fff;
}
</style>
</head>
<body>
<div class="canvas-container">
	<canvas id="canvas" class="canvas"></canvas>
</div>
<script>
let canvas = document.getElementById("canvas");
let sizeX = window.innerWidth - 30 ;
let sizeY = window.innerHeight - 60 ;
canvas.style.width = sizeX + "px";
canvas.style.height = sizeY + "px";
let scale = window.devicePixelRatio;
canvas.width = sizeX * scale;
canvas.height = sizeY * scale;
let canvas_width = canvas.width;
let canvas_height = canvas.height;

let ctx = canvas.getContext("2d");
ctx.scale(scale, scale);

let shapes = [];
let current_shape_index = null;
let is_dragging = false;
let startX;
let startY;
let lastX = canvas.width/2
let lastY = canvas.height/2;
let scaleFactor = 0.2;
let originx = 0;
let originy = 0;

shapes.push( { id: "1", form: 'rect', x:50, y:50, width: 180, height: 100, color: 'blue'} );
shapes.push( { id: "2", form: 'rect', x:150, y:250, width: 180, height: 100, color: 'red'} );
shapes.push( { id: "3", form: 'connector', from: "1", to: "2", from_point: "B", to_point: "T", color: 'black'} );
shapes.push( { id: "4", form: 'rect', x:350, y:150, width: 180, height: 100, color: 'lightblue'} );
shapes.push( { id: "5", form: 'connector', from: "2", to: "4", from_point: "R", to_point: "L", color: 'black'} );

let offset_x;
let offset_y;
let get_offset = function() {
	let canvas_offsets = canvas.getBoundingClientRect();
	offset_x = canvas_offsets.left;
	offset_y = canvas_offsets.top;
}

get_offset();
window.onscroll = function() {
	get_offset();
}
window.onresize = function() {
	get_offset();
}
window.onscroll = function() {
	get_offset();
}
canvas.onresize = function() {
	get_offset();
}

let is_mouse_in_shape = function(x, y, shape) {
	let shape_left = shape.x;
	let shape_right = shape.x + shape.width;
	let shape_top = shape.y;
	let shape_bottom = shape.y + shape.height;
	if (x > shape_left && x < shape_right && y > shape_top && y < shape_bottom) {
		return true;
	}
	return false;
}

let mouse_down = function(event) {
	event.preventDefault();

	startX = parseInt(event.clientX) - offset_x;
	startY = parseInt(event.clientY) - offset_y;

	let index = 0;
	for (let shape of shapes) {
		if (is_mouse_in_shape(startX, startY, shape)) {
			current_shape_index = index;
			is_dragging = true;
			return;
		}
		index ++;
	}
}

let mouse_out = function(event) {
	if (!is_dragging) {
		return;
	}
	event.preventDefault();
	is_dragging = false;
}

let mouse_up = function(event) {
	if (!is_dragging) {
		return;
	}
	event.preventDefault();
	is_dragging = false;
}

let mouse_move = function(event) {
	if (!is_dragging) {
		return;
	}
	event.preventDefault();
	let mouseX = parseInt(event.clientX) - offset_x;
	let mouseY = parseInt(event.clientY) - offset_y;
	let dx = mouseX - startX;
	let dy = mouseY - startY;

	let current_shape = shapes[current_shape_index];
	current_shape.x += dx;
	current_shape.y += dy;

	draw_shapes();

	startX = mouseX;
	startY = mouseY;
}

let mouse_wheel = function(event) {
	event.preventDefault();
	let mouseX = parseInt(event.clientX) - offset_x;
	let mouseY = parseInt(event.clientY) - offset_y;
	let wheel = event.deltaY < 0 ? 1 : -1;

	let zoom = Math.exp(wheel * scaleFactor);

	ctx.translate(originx, originy);
	ctx.scale(zoom,zoom);
	originx -= mouseX / (scale * zoom) - mouseX / scale;
	originy -= mouseY / (scale * zoom) - mouseY / scale;
	ctx.translate(-originx, -originy);
	scale *= zoom;

	draw_shapes();
	return false;
}

canvas.onmousedown = mouse_down;
canvas.onmouseup = mouse_up;
canvas.onmouseout = mouse_out;
canvas.onmousemove = mouse_move;
canvas.onwheel = mouse_wheel;

let getCoords = function(shape,point) {
    var _x = 0;
    var _y = 0;
	switch (point) {
	case "B":
		_x = shape.x + ( shape.width / 2 );
		_y = shape.y + shape.height;
		break;
	case "T":
		_x = shape.x + ( shape.width / 2 );
		_y = shape.y;
		break;
	case "L":
		_x = shape.x;
		_y = shape.y + ( shape.height / 2 );
		break;
	case "R":
		_x = shape.x + shape.width;
		_y = shape.y + ( shape.height / 2 );
		break;
	}
    return { y: _y, x: _x };
}

let draw_shapes = function() {
	ctx.clearRect(0, 0, canvas_width, canvas_height);

	for (let shape of shapes) {
		switch (shape.form) {
		case "rect":
			ctx.fillStyle = shape.color;
			ctx.fillRect(shape.x, shape.y, shape.width, shape.height);
			break;
		case "connector":
			let from_shape = shapes.filter(s => s.id == shape.from);
			let to_shape = shapes.filter(s => s.id == shape.to);
			let from_shape_point = shape.from_point;
			let to_shape_point = shape.to_point;
			ctx.beginPath();
			let a = getCoords(from_shape[0],from_shape_point);
			ctx.moveTo(a.x,a.y);
			let b = getCoords(to_shape[0],to_shape_point);
			ctx.lineTo(b.x,b.y);
			ctx.lineWidth = 1;
			ctx.strokeStyle = shape.color;
			ctx.stroke();
			break;
		}
	}
}

draw_shapes();

</script>
</body>
</html>