【问题标题】:Responsive canvas with fixed line width具有固定线宽的响应式画布
【发布时间】:2016-06-05 05:51:24
【问题描述】:

我正在用画布绘制折线图。图表是响应式的,但线条必须具有固定的宽度。

我用 css 让它响应

    #myCanvas{
        width: 80%;
    }

,所以笔画被缩放了。

我找到的唯一解决方案是通过画布的宽度属性与其实际宽度之间的比例来获取 lineWidth 的值。 要应用它,我会在调整大小时清除并绘制画布。

    <canvas id="myCanvas" width="510" height="210"></canvas>

<script type="text/javascript">
    var c = document.getElementById("myCanvas");
    var ctx = c.getContext("2d");   
    function draw(){
        var canvasattrwidth = $('#myCanvas').attr('width');
        var canvasrealwidth = $('#myCanvas').width();
        // n sets the line width
        var n = 4;
        var widthStroke = n * (canvasattrwidth / canvasrealwidth) ;
        ctx.lineWidth = widthStroke;
        ctx.beginPath();
        ctx.moveTo( 0 , 10 );
        ctx.lineTo( 200 , 100 );
        ctx.stroke();
    }
    $(window).on('resize', function(){
        ctx.clearRect(0, 0, c.width, c.height);
        draw();
    });
    draw();
</script>

这是我的第一个画布,我认为有一种更简单的方法可以固定 lineWidth(不是在每次调整大小时都清除和绘制),但我找不到它。

有一个类似问题的问题

html5 canvas prevent linewidth scaling 但是使用 scale() 方法,所以我不能使用该解决方案。

【问题讨论】:

  • 不,重绘是要走的路。如果您正在以任何方式更改在画布上绘制的内容(并且不想在已有的内容之上绘制),则需要重新绘制。您希望线条在调整大小时保持相同的像素宽度,如果不重绘​​,这将无法正确完成。无论如何,重绘对于图表之类的东西并不是很费力。

标签: javascript css html canvas


【解决方案1】:

无法获得画布细节的真实世界尺寸,例如毫米或英寸,因此您必须以像素为单位。

随着画布分辨率的降低,线条的像素宽度也需要减小。线宽的限制属性是像素。渲染比像素更窄的线只会通过降低不透明度来近似更窄线的外观(这是自动完成的)

您需要根据您期望的最低分辨率来定义线宽,当然,并在画布分辨率相对于所选理想分辨率发生变化时调整该宽度。

如果您在 x 和 y 方向以不同的量缩放图表,则必须使用 ctx.scalectx.setTransform 方法。正如您所说您不想这样做,我会假设您的缩放始终是方形的。

所以我们可以选择可接受的最低分辨率。将画布的宽度或高度设为 512 像素,然后为该分辨率选择 lineWidth(以像素为单位)。

因此我们可以创建两个常量

const NATIVE_RES = 512; // the minimum resolution we reasonably expect
const LINE_WIDTH = 1;   // pixel width of the line at that resolution
                        // Note I Capitalize constants, This is non standard in Javascript

然后计算实际线宽只需将实际canvas.width 除以NATIVE_RES,然后将结果乘以LINE_WIDTH

var actualLineWidth = LINE_WIDTH * (canvas.width / NATIVE_RES);
ctx.lineWidth = actualLineWidth;

您可能希望将该尺寸限制为最小的画布尺寸。您可以使用Math.min 执行此操作,也可以使用Math.max 将其限制在最大维度

用于最小尺寸。

var actualLineWidth = LINE_WIDTH * (Math.min(canvas.width, canvas.height) / NATIVE_RES);
ctx.lineWidth = actualLineWidth;

最大尺寸

var actualLineWidth = LINE_WIDTH * (Math.max(canvas.width, canvas.height) / NATIVE_RES);
ctx.lineWidth = actualLineWidth;

您还可以将对角线视为调整因素,将 x 和 y 维度中的最佳值结合起来。

// get the diagonal resolution
var diagonalRes = Math.sqrt(canvas.width * canvas.width + canvas.height * canvas.height)
var actualLineWidth = LINE_WIDTH * (diagonalRes / NATIVE_RES);
ctx.lineWidth = actualLineWidth;

最后,当线条小于 1 像素时,您可能希望限制线条的下限以阻止奇怪的伪影。

使用对角线设置下限

var diagonalRes = Math.sqrt(canvas.width * canvas.width + canvas.height * canvas.height)
var actualLineWidth = Math.max(1, LINE_WIDTH * (diagonalRes / NATIVE_RES));
ctx.lineWidth = actualLineWidth;

如果画布对角线分辨率低于 512,这将创建一个不会低于 1 像素的响应式线宽。

您使用的方法取决于您。试试看你最喜欢什么。我选择“512”的NATIVE_RES 也是任意的,可以是你想要的任何东西。你只需要试验一下价值观和方法,看看你最喜欢哪一种。

如果您的缩放方面正在发生变化,那么有一种完全不同的技术可以解决该问题,我将留给另一个问题。

希望这有帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-01-26
    • 1970-01-01
    • 2017-08-07
    • 2018-08-09
    • 1970-01-01
    • 2020-11-21
    • 2017-01-19
    • 1970-01-01
    相关资源
    最近更新 更多