HTML5画布防止线宽缩放

19
如果我绘制一个线宽为2的矩形,然后将其缩放到原来大小的两倍,那么得到的矩形边框的大小也会是初始线宽的两倍。
有没有方法可以使线宽保持在感知大小2或原始大小?
简而言之,我想只缩放矩形的大小,但保持边框线宽视觉上为2。
我尝试在scale(2,2)命令之前和之后设置线宽,但边框宽度也会增加。
一种选项是将线宽除以比例因子,如果x和y比例因子相同,则这将起作用。
我无法选择缩放矩形的宽度和高度,并且我需要使用scale命令,因为矩形内还有其他对象需要缩放。
3个回答

23
您可以使用转换定义路径,并在没有转换的情况下描边它。这样,线宽就不会被转换。
示例:

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.save(); //save context without transformation
ctx.scale(2, 0.5); //make transformation
ctx.beginPath(); //define path
ctx.arc(100, 75, 50, 0, 2 * Math.PI);
ctx.restore(); //restore context without transformation
ctx.stroke(); //stroke path
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;">


你测试过哪些浏览器?在Chrome 38上似乎无法工作。 - b0fh
太棒了!在Chrome 44、FF 39和IE 9+中都能正常工作。 - Alexey Lebedev
这个很好用。但是如果在恢复之前有clip()区域,它就会丢失;如果在描边之前添加了clip()区域,则clip路径会被描边。还有其他解决方案吗? - PeterT
您可以重置转换矩阵,这样就可以正常工作。ctx.setTransform(1, 0, 0, 1, 0, 0); ctx.stroke();。您也可以像这样保存和恢复:ctx.save(); ctx.setTransform(1, 0, 0, 1, 0, 0); ctx.stroke(); ctx.restore();,以便只影响描边但保留其他所有内容。不知道这会如何影响剪辑。 - gman
你能否通过已经设置的Path2D对象来完成这个操作? - Polygon

5

在此之前应该先缩小lineWidth。

ctx.lineWidth = 2 / Math.max(scaleX, scaleY);
ctx.scale(scaleX, scaleY);
ctx.fillRect(50, 50, 50, 50);

1
但这并不防止行宽度缩放,只是确保行宽度不超过一个值。 - Calmarius

1

好的,你有几个选项:

你可以自己缩放坐标和尺寸,例如:

ctx.strokeRect( scaleX * x, scaleY * y, scaleX * width, scaleY * height) ;

你需要将缩放应用到所有其他对象上。

或者,你可以应用缩放,但不依赖于线宽来绘制矩形的边框。一个简单的方法是通过填充正确的区域来绘制矩形,然后移除内部,减去边框,就像这样:

var scaleX = 1.5, scaleY = 2;
var lineWidth = 2;

ctx.scale(scaleX, scaleY);

ctx.fillStyle = "#000";
ctx.fillRect(100, 50, 100, 
ctx.clearRect(100+lineWidth/scaleX, 50+lineWidth/scaleY, 100-(2*lineWidth)/scaleX, 60-(2*lineWidth)/scaleY);

OP似乎正在经历完全相反的情况... lineWidth受到缩放的影响? - MrWhite
天啊!我这阅读理解能力也太差了吧!而且亲测,它确实受到影响。 - andrewmu
w3d 是正确的,我的线宽受到缩放的影响。我的解决方案是通过缩放因子除以线宽,如果缩放因子为2,则线宽=原始线宽/缩放因子。这对于感知厚度来说效果很好。 - Nilesh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接