HTML 无限可平移画布

Posted

技术标签:

【中文标题】HTML 无限可平移画布【英文标题】:HTML infinite pan-able canvas 【发布时间】:2018-05-02 11:14:45 【问题描述】:

我需要创建一个带有文本框的“无限”画布。

喜欢 Desmos 网站上的这个:

https://www.desmos.com/calculator

我自己没有设法实现它。

问题

谁能帮我解决这个问题?

【问题讨论】:

让我们知道您自己尝试了什么。 对画布没有太多经验,但你能像谷歌地图使用小地图瓦片一样使用多个画布吗? 【参考方案1】:

可平移画布的最简单方法是绘制相对于偏移量的所有内容,在此示例中,我将其称为 panX 和 panY。将其想象为您用来移动视口(画布中当前可见的无限板区域)的坐标。

<!doctype html>
<html>
	<head>
		<meta charset="utf-8">
		<style>
			body 
				background-color: black;
			
			
			canvas 
				position: absolute;
				margin-left: auto;
				margin-right: auto;
				left: 0;
				right: 0;
				border: solid 1px white;
				border-radius: 10px;
			
		</style>
	</head>
	
	<body>
		<canvas id="canvas"></canvas>
		<script type="application/javascript">
			
			var imageWidth = 180;
			var imageHeight = 160;
			var canvas = null;
			var ctx = null;
			var bounds = null;
			var selectedBox = null;
			var panX = 0;
			var panY = 0;
			var mouseX = 0;
			var mouseY = 0;
			var oldMouseX = 0;
			var oldMouseY = 0;
			var mouseHeld = false;
			var boxArray = [];
			
			function DraggableBox(x,y,width,height,text) 
				this.x = x;
				this.y = y;
				this.width = width;
				this.height = height;
				this.text = text;
				this.isSelected = false;
			
			
			DraggableBox.prototype.isCollidingWidthPoint = function(x,y) 
				return (x > this.x && x < this.x + this.width)
					&& (y > this.y && y < this.y + this.height);
			
			
			DraggableBox.prototype.drag = function(newX,newY) 
				this.x = newX - this.width * 0.5;
				this.y = newY - this.height * 0.5;
			
			
			DraggableBox.prototype.draw = function() 
				if (this.isSelected) 
					ctx.fillStyle = "darkcyan";
					ctx.fillRect(
						this.x - panX,
						this.y - panY,
						this.width,
						this.height
					);
					ctx.fillStyle = "black";
				 else 			
					ctx.fillRect(
						this.x - panX,
						this.y - panY,
						this.width,
						this.height
					);
				
				
				ctx.fillStyle = "white";
				ctx.fillText(
					this.text,
					this.x + this.width * 0.5 - panX,
					this.y + this.height * 0.5 - panY,
					this.width
				);
				ctx.fillStyle = "black";
			
			
			window.onmousedown = function(e) 
				mouseHeld = true;
			
				if (!selectedBox) 
					for (var i = boxArray.length - 1; i > -1; --i) 
						if (boxArray[i].isCollidingWidthPoint(mouseX + panX,mouseY + panY)) 
							selectedBox = boxArray[i];
							selectedBox.isSelected = true;
							requestAnimationFrame(draw);
							return;
						
					
				
			
			
			window.onmousemove = function(e) 
				mouseX = e.clientX - bounds.left;
				mouseY = e.clientY - bounds.top;
				
				if (mouseHeld) 
					if (!selectedBox) 
						panX += oldMouseX - mouseX;
						panY += oldMouseY - mouseY;
					 else 
						selectedBox.x = mouseX - selectedBox.width * 0.5 + panX;
						selectedBox.y = mouseY - selectedBox.height * 0.5 + panY;
					
				
				
				oldMouseX = mouseX;
				oldMouseY = mouseY;
				
				requestAnimationFrame(draw);
			
			
			window.onmouseup = function(e) 
				mouseHeld = false;
				
				if (selectedBox) 
					selectedBox.isSelected = false;
					selectedBox = null;
					requestAnimationFrame(draw);
				
			
			
			function draw() 
				ctx.fillStyle = "gray";
				ctx.fillRect(0,0,imageWidth,imageHeight);
				
				var box = null;
				var xMin = 0;
				var xMax = 0;
				var yMin = 0;
				var yMax = 0;
				
				ctx.fillStyle = "black";
				
				for (var i = 0; i < boxArray.length; ++i) 
					box = boxArray[i];
					
					xMin = box.x - panX;
					xMax = box.x + box.width - panX;
					yMin = box.y - panY;
					yMax = box.y + box.height - panY;
					
					if (xMax > 0 && xMin < imageWidth && yMax > 0 && yMin < imageHeight) 
						box.draw();
					
				
			
			
			window.onload = function() 
				canvas = document.getElementById("canvas");
				canvas.width = imageWidth;
				canvas.height = imageHeight;
				
				bounds = canvas.getBoundingClientRect();
				ctx = canvas.getContext("2d");
				ctx.textAlign = "center";
				ctx.font = "15px Arial"
				
				boxArray.push(new DraggableBox(Math.random() * 320,Math.random() * 240,100,25,"This is a draggable text box"));
				boxArray.push(new DraggableBox(Math.random() * 320,Math.random() * 240,100,50,"Another text box"));
				boxArray.push(new DraggableBox(Math.random() * 320,Math.random() * 240,100,50,"Text in a box"));
				boxArray.push(new DraggableBox(Math.random() * 320,Math.random() * 240,100,50,"I find this box quite texing"));
				boxArray.push(new DraggableBox(Math.random() * 320,Math.random() * 240,150,50,"You weren't supposed to find this box"));
				requestAnimationFrame(draw);
			
			
			window.onunload = function() 
				canvas = null;
				ctx = null;
				bounds = null;
				selectedBox = null;
				boxArray = null;
			
			
		</script>
	</body>
</html>

【讨论】:

【参考方案2】:

我自己研究了这个功能,发现了这个项目,它提供了一个完整的功能实现。

https://www.infinite-canvas.org/

【讨论】:

以上是关于HTML 无限可平移画布的主要内容,如果未能解决你的问题,请参考以下文章

缩放和平移 HTML5 画布 - 库

缩放和平移画布后鼠标坐标不匹配

画布可绘制对象和居中缩放

使用 raphael.js 直接进行画布平移

画布上的水平滚动。 HTML5

Android UICanvas 画布 ⑨ ( Canvas 绘图坐标系平移实例 )