html5画布在调整大小时重绘
Posted
技术标签:
【中文标题】html5画布在调整大小时重绘【英文标题】:html5 canvas redraw on resize 【发布时间】:2015-07-24 21:24:06 【问题描述】:我有两个画布元素,需要在单击按钮时调整它们的大小。
<div class="sDetails"><div>
<div id="canvasDiv" style="width: 310px;"><canvas id="canvasGraph"></canvas></div></div>
<div class="kDetails"><div><div>
<div id="canvasDiv" style="width: 310px; height: 240px;"><canvas id="canvasGraph"></canvas></div></div>
和脚本:
var sketch;var sketch_sl;var onPaint;var canvas=null;var ctx=null;var tmp_ctx=null;
function drawCanvas(div)
canvas = document.querySelector(div + " #canvasGraph");
ctx = canvas.getContext('2d');
sketch = document.querySelector(div + " #canvasDiv");
sketch_sl = getComputedStyle(sketch);
canvas.width = parseInt(sketch_style.getPropertyValue('width'));
canvas.height = parseInt(sketch_style.getPropertyValue('height'));
tmp_canvas = document.createElement('canvas');
tmp_ctx = tmp_canvas.getContext('2d');
tmp_canvas.id = 'tmp_canvas';
tmp_canvas.width = canvas.width;
tmp_canvas.height = canvas.height;
sketch.appendChild(tmp_canvas);
重绘功能:
// here I must redraw my lines resized 2 times ( *cScale ) where cScale=2 or =1
function drawScales(ctx, canvas)
ctx.strokeStyle = 'green';
ctx.fillStyle = 'green';
ctx.beginPath();
ctx.moveTo(5, 0);
ctx.lineTo(0, canvas.height);
scaleStep = 24*cScale;
由于某种原因,它的效果非常糟糕,旧职位仍然存在。 有没有办法完全删除整个画布并附加它或完全重绘它?
我试过canvas.width=canvas.width
,试过ctx.clearRect(0, 0, canvas.width, canvas.height);tmp_ctx.clearRect(0, 0, canvas.width, canvas.height);
,试过$(".sDetails #canvasGraph")[0].reset();
从逻辑上讲,drawCanvas(".sDetails");drawLines(ctx, canvas);
应该从头开始重新绘制它,但它不会。
【问题讨论】:
为什么在调整大小时需要重绘画布?它的尺寸真的取决于窗口大小吗?如果是这样,你为什么要在画布上用 css 样式设置固定尺寸(宽度/高度)? @hindmost 我有一个坐标系统,当按下按钮时,画布会变宽两倍,从而在用户绘制时更精确地捕获 x 坐标。.. 【参考方案1】:调整画布元素的width
和height
的大小并使用context.scale
以新缩放的大小重新绘制原始绘图。
调整画布元素的大小会自动清除画布上的所有绘图。
调整大小还会自动将所有上下文属性重置为其默认值。
使用context.scale
很有用,因为这样画布会自动重新缩放原始绘图以适应新大小的画布。
重要提示:Canvas 不会自动重绘原始绘图...您必须重新发出原始绘图命令。
两个相同大小的画布的插图(它们的大小由范围控件控制)
左画布放大后的插图
右画布放大后的插图
这是示例代码和演示。此演示使用范围元素来控制调整大小,但您也可以在window.onresize
中进行调整大小+重绘
var canvas1=document.getElementById("canvas1");
var ctx1=canvas1.getContext("2d");
var canvas2=document.getElementById("canvas2");
var ctx2=canvas2.getContext("2d");
var originalWidth=canvas1.width;
var originalHeight=canvas1.height;
var scale1=1;
var scale2=1;
$myslider1=$('#myslider1');
$myslider1.attr(min:50,max:200).val(100);
$myslider1.on('input change',function()
var scale=parseInt($(this).val())/100;
scale1=scale;
redraw(ctx1,scale);
);
$myslider2=$('#myslider2');
$myslider2.attr(min:50,max:200).val(100);
$myslider2.on('input change',function()
var scale=parseInt($(this).val())/100;
scale2=scale;
redraw(ctx2,scale);
);
draw(ctx1);
draw(ctx2);
function redraw(ctx,scale)
// Resizing the canvas will clear all drawings off the canvas
// Resizing will also automatically clear the context
// of all its current values and set default context values
ctx.canvas.width=originalWidth*scale;
ctx.canvas.height=originalHeight*scale;
// context.scale will scale the original drawings to fit on
// the newly resized canvas
ctx.scale(scale,scale);
draw(ctx);
// always clean up! Reverse the scale
ctx.scale(-scale,-scale);
function draw(ctx)
// note: context.scale causes canvas to do all the rescaling
// math for us, so we can always just draw using the
// original sizes and x,y coordinates
ctx.beginPath();
ctx.moveTo(150,50);
ctx.lineTo(250,150);
ctx.lineTo(50,150);
ctx.closePath();
ctx.stroke();
ctx.fillStyle='skyblue';
ctx.beginPath();
ctx.arc(150,50,20,0,Math.PI*2);
ctx.closePath();
ctx.fill();
ctx.stroke();
ctx.beginPath();
ctx.arc(250,150,20,0,Math.PI*2);
ctx.closePath();
ctx.fill();
ctx.stroke();
ctx.beginPath();;
ctx.arc(50,150,20,0,Math.PI*2);
ctx.fill();
ctx.stroke();
$("#canvas1, #canvas2").mousemove(function(e)handleMouseMove(e););
var $mouse=$('#mouse');
function handleMouseMove(e)
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
var bb=e.target.getBoundingClientRect();
mouseX=parseInt(e.clientX-bb.left);
mouseY=parseInt(e.clientY-bb.top);
if(e.target.id=='canvas1')
$mouse.text('Mouse1: '+mouseX/scale1+' / '+mouseY/scale1+' (scale:'+scale1+')');
else
$mouse.text('Mouse2: '+mouseX/scale2+' / '+mouseY/scale2+' (scale:'+scale2+')');
body background-color: ivory;
canvasborder:1px solid red;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div>Resize left canvas</div>
<input id=myslider1 type=range><br>
<div>Resize right canvas</div>
<input id=myslider2 type=range><br>
<h4 id=mouse>Mouse coordinates:</h4>
<canvas id="canvas1" width=300 height=300></canvas>
<canvas id="canvas2" width=300 height=300></canvas>
【讨论】:
谢谢!虽然我不确定缩放是否适合我。我有一个坐标系统,当按下按钮时,画布会变宽两倍,从而在用户在其上绘制时更精确地捕获 x 坐标。如果我缩放它,它会根据缩放的画布获取坐标吗?也就是说,如果 x 值为 3,并且捕获的点为 12px,则缩放后它必须是 3 和 24px。它会像缩放一样工作吗? 当然!浏览器总是以未缩放的值报告鼠标坐标。要调整缩放的画布,只需将浏览器的鼠标坐标除以当前画布缩放因子。这为您提供了缩放画布术语中的鼠标坐标。 mouseX/=缩放;和 mouseY/=scale; @CodeGust。我在上面的评论中说错了。我的意思是 除 浏览器报告的鼠标坐标除以缩放因子。我已添加到我的演示中,以展示即使从缩放的画布中如何正确计算鼠标坐标。【参考方案2】:如果您需要与比例无关的位置,您可以改用标准化值 ([0, 1]),并使用画布的大小作为比例因子。通过这种方式,您可以缩放和存储值,而无需过多关注实际目标大小。
您还可以几乎按原样使用鼠标位置,并通过将它们按画布大小划分来进行标准化。
例如:
渲染时,(1,1) 点将始终绘制在右下角,就像您在(1 * canvas.width, 1 * canvas.height)
所做的那样。
当您存储一个点时,您将使用鼠标位置并将其按画布尺寸划分,例如,如果我单击大小为 400x200 的画布的右下角,这些点将为 400/400 = 1, 200/200 = 1。
请注意,宽度和高度将是互斥的(即 width-1 等),但为了简单起见...
示例
在此示例中,您可以从任何大小的画布开始,绘制标准化的点,更改画布的大小并相对于原始位置按比例重新绘制点。
var rng = document.querySelector("input"),
c = document.querySelector("canvas"),
ctx = c.getContext("2d"),
points = [];
// change canvas size and redraw all points
rng.onchange = function()
c.width = +this.value;
render();
;
// add a new normalized point to array
c.onclick = function(e)
var r = this.getBoundingClientRect(), // to adjust mouse position
x = e.clientX - r.left,
y = e.clientY - r.top;
points.push(
x: x / c.width, // normalize value to range [0, 1]
y: y / c.height
); // store point
render(); // redraw (for demo)
;
function render()
ctx.clearRect(0, 0, c.width, c.height); // clear canvas
ctx.beginPath(); // clear path
for(var i = 0, p; p = points[i]; i++) // draw points as fixed-size circles
var x = p.x * c.width, // normalized to absolute values
y = p.y * c.height;
ctx.moveTo(x + 5, y);
ctx.arc(x, y, 5, 0, 6.28);
ctx.closePath();
ctx.stroke();
canvas background:#ddd
<h3>Click on canvas to add points, then resize</h3>
<label>Width: <input type="range" min=50 max=600 value=300></label><br>
<canvas></canvas>
【讨论】:
【参考方案3】:我决定使用比例变量来调整我的比例。我调整了画布canvas.width *= 2;
的大小,然后重新绘制了我的比例。
var scaleStep;
并使用将其添加到代码中:ctx.lineTo(12*24*cScale+12, canvas.height-24);
需要进行缩放的地方。
最大化画布时 scaleStep 为 2,返回原始大小时为 1。
【讨论】:
以上是关于html5画布在调整大小时重绘的主要内容,如果未能解决你的问题,请参考以下文章