理解 Canvas的save和restore

理解 Canvas的save和restore

save()和restore()方法只会在有效范围内生效,它是绘制状态的存储器,并不是画布内容的存储器。它是基于状态记录的。

  • save:用来保存Canvas的状态。save之后,可以调用Canvas的平移、放缩、旋转、错切、裁剪等操作。
  • restore:用来恢复Canvas之前保存的状态。防止save后对Canvas执行的操作对后续的绘制有影响。

较为细致解释

save()和restore()方法只会在有效范围内生效,它是绘制状态的存储器,并不是画布内容的存储器。它是基于状态记录的。 Canvas Context维持着绘制状态的堆栈。区分绘制状态:

  • 当前矩阵变换例如:平移translate(),缩放scale(),以及旋转rotate()等
  • 剪切区域clip()
  • 以下属性值:
  • strokeStyle,fillStyle,globalAlpha,lineWidth,lineCap,lineJoin,miterLimit,shadowOffsetX,shadowOffsetY,shadowBlur,shadowColor,globalCompositeOperation,font,textAlign,textBaseline。
  • 路径和位图不是绘图状态的一部分,使用save()和restore()不会生效。路径是持久的,只能使用beginPath()方法重置,位图是画布的属性,而非上下文。
  • context.save()将当前状态压入堆栈。context.restore()弹出堆栈上的顶级状态,将上下文恢复到该状态。

实际代码应用

let processNum = 0
const process = () => {
    if (processNum < this.state.score) {
        processNum++
    }
    let canvas = document.getElementById("canvas");
    let ctx = canvas.getContext('2d');
    ctx.clearRect(0, 0, 600, 240)

    let x = 300
    let y = 170
    ctx.beginPath();
    ctx.arc(x, y, 122, Math.PI + Math.asin(10/66), 2 * Math.PI - Math.asin(10/66));
    ctx.strokeStyle = "rgba(0, 0, 0, 0.05)";
    ctx.lineWidth = 60;
    ctx.lineCap = "round";
    ctx.stroke();

    ctx.beginPath();
    let angle = processNum / 100 * (Math.PI - 2 * Math.asin(10/66)) + Math.PI + Math.asin(10/66)
    ctx.arc(x, y, 122, Math.PI + Math.asin(10/66), angle);

    // 渐变
    var gradient=ctx.createLinearGradient(0,0,400,0);
    gradient.addColorStop("0.5","rgba(85, 255, 234, 1)");
    gradient.addColorStop("1","rgba(38, 123, 255, 1)");
    ctx.strokeStyle = gradient;
    ctx.lineWidth = 60;
    ctx.lineCap = "round";
    ctx.stroke();

    ctx.save()
    ctx.translate(178, 160)
    ctx.rotate(5*Math.PI/180);
    ctx.font = `bold 20px DINAlternate-Bold,DINAlternate`
    ctx.fillStyle = '#FFFFFF'
    ctx.fillText(0, 0,0)
    ctx.restore()

    ctx.save()
    ctx.translate(422, 160)
    ctx.rotate(-10*Math.PI/180);
    ctx.font = `bold 20px DINAlternate-Bold,DINAlternate`
    ctx.fillStyle = '#FFFFFF'
    ctx.fillText(100, 0,0)
    ctx.restore()

    ctx.save()
    ctx.font = `bold 100px DINAlternate-Bold,DINAlternate`
    ctx.fillStyle = '#3AA7FF'
    ctx.textAlign = 'center'
    ctx.fillText(this.state.score, 300, 240)
    // ctx.restore()
    // ctx.save()

    if (processNum < 100) {
        requestAnimationFrame(process)
    }
}

process()

canvas 在高清屏绘制模糊问题

常规绘制大概参考 解决 canvas 在高清屏中绘制模糊的问题open in new window 就可以了

但我在这个是通过 antd 引入的高清屏设置,所以通过上述方案在模拟器中正常,但在移动端显示不太正常,大量错位产生。

解决方案

统一按2倍屏幕设置canvas宽高:

<canvas width="640" height="800" style="width:320px; height:400px"></canvas>

canvas中字体、位移、半径等都是二倍即可。

写在最后

其实大部分时间都是浪费在一个冒泡泡的动画上:

image

然鹅我并没有写好,交给了UI去写GIF了。

但大部分代码也写好了,主要考虑效果不尽如意

本来也想在这加上那段动画效果来着,毕竟又花了一晚上学习了以下初中圆的知识[滑稽],可惜回撤找不着了

参考

Last Updated 2024/12/27 14:02:06