canvas圖片、文字在移動端顯示模糊問題

項目需要畫一個餅圖,個插件沒找到符合要求的,于是自己手動畫了一個??墒堑揭苿佣说臅r候,或出現(xiàn)模糊不清的情況,研究了一下是高清屏的問題。

因為 canvas 不是矢量圖,而是像圖片一樣是位圖模式的。高 dpi 顯示設(shè)備意味著每平方英寸有更多的像素。也就是說二倍屏,瀏覽器就會以2個像素點的寬度來渲染一個像素,該 canvas 在 Retina 屏幕下相當(dāng)于占據(jù)了2倍的空間,相當(dāng)于圖片被放大了一倍,因此繪制出來的圖片文字等會變模糊。

因此,要做 Retina 屏適配,關(guān)鍵是知道當(dāng)前屏幕的設(shè)備像素比,然后將 canvas 放大到該設(shè)備像素比來繪制,然后將 canvas 壓縮到一倍來展示。

所以只要加上以下代碼即可:

        // *****************解決移動端糊的問題
        let dpr = window.devicePixelRatio; // 假設(shè)dpr為2
        // 獲取css的寬高
        let { width: cssWidth, height: cssHeight } = canvas.getBoundingClientRect();
        // 根據(jù)dpr,擴(kuò)大canvas畫布的像素,使1個canvas像素和1個物理像素相等
        canvas.style.width = canvas.width + 'px';
        canvas.style.height = canvas.height + 'px';
     
        canvas.width = dpr * cssWidth;
        canvas.height = dpr * cssHeight;
        // 由于畫布擴(kuò)大,canvas的坐標(biāo)系也跟著擴(kuò)大,如果按照原先的坐標(biāo)系繪圖內(nèi)容會縮小
        // 所以需要將繪制比例放大
        ctx.scale(dpr,dpr);
        // **************************

下面開始進(jìn)行畫圖,填充文字就可以了,出來的效果就非常清晰了。
解決前:


image.png

解決后:


image.png

下面貼出來我的完整代碼:

<canvas id="canvas" width={200} height={200} />

 let canvas = document.getElementById('canvas');
      if(canvas.getContext) {
        let ctx = canvas.getContext('2d');
        // *****************解決移動端糊的問題
        let dpr = window.devicePixelRatio; // 假設(shè)dpr為2
        // 獲取css的寬高
        let { width: cssWidth, height: cssHeight } = canvas.getBoundingClientRect();
        // 根據(jù)dpr,擴(kuò)大canvas畫布的像素,使1個canvas像素和1個物理像素相等
        canvas.style.width = canvas.width + 'px';
        canvas.style.height = canvas.height + 'px';
     
        canvas.width = dpr * cssWidth;
        canvas.height = dpr * cssHeight;
        // 由于畫布擴(kuò)大,canvas的坐標(biāo)系也跟著擴(kuò)大,如果按照原先的坐標(biāo)系繪圖內(nèi)容會縮小
        // 所以需要將繪制比例放大
        ctx.scale(dpr,dpr);
        // **************************

        for(let i = 0; i < listSubPercent.length; i++) {
          ctx.beginPath();
          let startAngle = listSubPercent[i] * Math.PI / 180;
          let endAngle = listSubPercent[i + 1] * Math.PI / 180;
          ctx.arc(pointX, pointY, sectorR, startAngle, endAngle, false);
          ctx.lineTo(pointX, pointY); //轉(zhuǎn)折點
          ctx.fillStyle = colorList[i];
          ctx.fill(); //扇形填充
        }
        //繪制圓形
        ctx.beginPath();
        ctx.moveTo(pointX, pointY); //起始點中心坐標(biāo)點
        let startAngle = 0; // 開始點
        let endAngle = 2 * Math.PI;
        ctx.arc(pointX, pointY, circleR, startAngle, endAngle, true);
        
        ctx.fillStyle = fillColor; //作對比  暫用此顏色  需要改為黑色才能和三角拼接  rgba(255,165,0,1)類也可以
        ctx.fill(); //圓形填充

        //中間位置的度數(shù)
        let middleDegree = (listSubPercent[num + 1] - listSubPercent[num]) / 2 + listSubPercent[num];
        middleDegree = 90 - middleDegree;
        //三角形底邊的另一個點的位置
        let X1 = Math.sin((middleDegree + 90) * Math.PI / 180) * 30 + pointX;
        let Y1 = Math.cos((middleDegree + 90) * Math.PI / 180) * 30 + pointY;
        //三角形底邊的一個點的位置
        let X = Math.sin((middleDegree + 270) * Math.PI / 180) * 30 + pointX;
        let Y = Math.cos((middleDegree + 270) * Math.PI / 180) * 30 + pointY;
        //三角形頂點的位置
        let RX = Math.sin(middleDegree * Math.PI / 180) * 60 + pointX;
        let RY = Math.cos(middleDegree * Math.PI / 180) * 60 + pointY;
        ctx.beginPath();
        ctx.moveTo(X1, Y1); //起始點
        ctx.lineTo(X, Y); //轉(zhuǎn)折點
        ctx.lineTo(RX, RY); //結(jié)束點
        ctx.fillStyle = fillColor;
        ctx.fill(); //三角形填充

        // 繪制文字
        ctx.font = "16px sans-serif";
        ctx.fillStyle = textColor;
        ctx.fillText(data[0].ratingagency, 70, 95);
        ctx.font = "14px sans-serif";
        ctx.fillStyle = textColor;
        ctx.fillText(`${data[0].percentage}%`, 80, 115);
      }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容