ฉันจะแก้ไขข้อความที่ไม่ชัดเจนในผ้าใบ HTML5 ของฉันได้อย่างไร


89

ผมรวมn00bด้วยHTML5และกำลังทำงานร่วมกับcanvasการแสดงผลรูปทรงสีและข้อความ ในแอปของฉันฉันมีอะแดปเตอร์มุมมองที่สร้างผืนผ้าใบแบบไดนามิกและเติมเต็มด้วยเนื้อหา สิ่งนี้ใช้งานได้ดีจริงๆยกเว้นว่าข้อความของฉันแสดงผลไม่ชัดเจน / เบลอ / ยืดมาก ฉันได้เห็นจำนวนมากของการโพสต์อื่น ๆ เกี่ยวกับเหตุผลที่กำหนดความกว้างและความสูงในการCSSที่จะทำให้เกิดปัญหานี้ javascriptแต่ฉันกำหนดทุกอย่างไว้ใน

รหัสที่เกี่ยวข้อง (ดูFiddle ):

var width  = 500;//FIXME:size.w;
var height = 500;//FIXME:size.h;
    
var canvas = document.createElement("canvas");
//canvas.className="singleUserCanvas";
canvas.width=width;
canvas.height=height;
canvas.border = "3px solid #999999";
canvas.bgcolor = "#999999";
canvas.margin = "(0, 2%, 0, 2%)";
    
var context = canvas.getContext("2d");

//////////////////
////  SHAPES  ////
//////////////////
    
var left = 0;

//draw zone 1 rect
context.fillStyle = "#8bacbe";
context.fillRect(0, (canvas.height*5/6)+1, canvas.width*1.5/8.5, canvas.height*1/6);

left = left + canvas.width*1.5/8.5;

//draw zone 2 rect
context.fillStyle = "#ffe381";
context.fillRect(left+1, (canvas.height*5/6)+1, canvas.width*2.75/8.5, canvas.height*1/6);

left = left + canvas.width*2.75/8.5 + 1;

//draw zone 3 rect
context.fillStyle = "#fbbd36";
context.fillRect(left+1, (canvas.height*5/6)+1, canvas.width*1.25/8.5, canvas.height*1/6);

left = left + canvas.width*1.25/8.5;

//draw target zone rect
context.fillStyle = "#004880";
context.fillRect(left+1, (canvas.height*5/6)+1, canvas.width*0.25/8.5, canvas.height*1/6);

left = left + canvas.width*0.25/8.5;
    
//draw zone 4 rect
context.fillStyle = "#f8961d";
context.fillRect(left+1, (canvas.height*5/6)+1, canvas.width*1.25/8.5, canvas.height*1/6);

left = left + canvas.width*1.25/8.5 + 1;

//draw zone 5 rect
context.fillStyle = "#8a1002";
context.fillRect(left+1, (canvas.height*5/6)+1, canvas.width-left, canvas.height*1/6);

////////////////
////  TEXT  ////
////////////////

//user name
context.fillStyle = "black";
context.font = "bold 18px sans-serif";
context.textAlign = 'right';
context.fillText("User Name", canvas.width, canvas.height*.05);

//AT:
context.font = "bold 12px sans-serif";
context.fillText("AT: 140", canvas.width, canvas.height*.1);

//AB:
context.fillText("AB: 94", canvas.width, canvas.height*.15);
       
//this part is done after the callback from the view adapter, but is relevant here to add the view back into the layout.
var parent = document.getElementById("layout-content");
parent.appendChild(canvas);
<div id="layout-content"></div>

ผลลัพธ์ที่ฉันเห็น (ในSafari ) มีความเบ้มากกว่าที่แสดงใน Fiddle:

ของฉัน

ผลลัพธ์ที่แสดงผลใน Safari

ซอ

ผลลัพธ์ที่แสดงผลบน JSFiddle

ฉันทำอะไรไม่ถูกต้อง ฉันต้องการผืนผ้าใบแยกต่างหากสำหรับแต่ละองค์ประกอบข้อความหรือไม่ มันเป็นแบบอักษร? ฉันต้องกำหนดผ้าใบในเค้าโครง HTML5 ก่อนหรือไม่ มีพิมพ์ผิดหรือเปล่า ฉันหลงทาง.


ดูเหมือนว่าคุณไม่ได้โทรclearRectมา
David

1
โพลีฟิลล์นี้แก้ไขการทำงานของแคนวาสขั้นพื้นฐานส่วนใหญ่ด้วยเบราว์เซอร์ HiDPI ที่ไม่
อัป

ฉันได้พัฒนาเฟรมเวิร์ก JS ที่แก้ปัญหาผ้าใบเบลอด้วย DIV mosaic ฉันสร้างภาพที่ชัดเจนและคมชัดขึ้นด้วยค่าใช้จ่ายบางส่วนในแง่ของ mem / cpu js2dx.com
Gonki

คำตอบ:


160

องค์ประกอบผ้าใบทำงานเป็นอิสระจากอัตราส่วนพิกเซลของอุปกรณ์หรือจอภาพ

บน iPad 3+ อัตราส่วนนี้คือ 2 ซึ่งโดยพื้นฐานแล้วหมายความว่าตอนนี้ผืนผ้าใบที่มีความกว้าง 1000px ของคุณจะต้องเติม 2000px เพื่อให้ตรงกับความกว้างที่ระบุไว้บนจอแสดงผลของ iPad โชคดีสำหรับเราการดำเนินการนี้โดยอัตโนมัติโดยเบราว์เซอร์ ในทางกลับกันนี่เป็นสาเหตุที่ทำให้คุณเห็นความคมชัดน้อยลงบนรูปภาพและองค์ประกอบผ้าใบที่สร้างขึ้นเพื่อให้พอดีกับพื้นที่ที่มองเห็นได้โดยตรง เนื่องจากผืนผ้าใบของคุณรู้วิธีเติม 1,000px แต่ถูกขอให้วาดเป็น 2000px ตอนนี้เบราว์เซอร์จึงต้องเติมช่องว่างระหว่างพิกเซลอย่างชาญฉลาดเพื่อแสดงองค์ประกอบในขนาดที่เหมาะสม

ฉันขอแนะนำให้คุณอ่านบทความนี้จากHTML5Rocksซึ่งอธิบายรายละเอียดเพิ่มเติมเกี่ยวกับวิธีสร้างองค์ประกอบความคมชัดสูง

tl; dr? นี่คือตัวอย่าง (ตามบทเรียนข้างต้น) ที่ฉันใช้ในโครงการของตัวเองเพื่อพ่นผ้าใบด้วยความละเอียดที่เหมาะสม:

var PIXEL_RATIO = (function () {
    var ctx = document.createElement("canvas").getContext("2d"),
        dpr = window.devicePixelRatio || 1,
        bsr = ctx.webkitBackingStorePixelRatio ||
              ctx.mozBackingStorePixelRatio ||
              ctx.msBackingStorePixelRatio ||
              ctx.oBackingStorePixelRatio ||
              ctx.backingStorePixelRatio || 1;

    return dpr / bsr;
})();


createHiDPICanvas = function(w, h, ratio) {
    if (!ratio) { ratio = PIXEL_RATIO; }
    var can = document.createElement("canvas");
    can.width = w * ratio;
    can.height = h * ratio;
    can.style.width = w + "px";
    can.style.height = h + "px";
    can.getContext("2d").setTransform(ratio, 0, 0, ratio, 0, 0);
    return can;
}

//Create canvas with the device resolution.
var myCanvas = createHiDPICanvas(500, 250);

//Create canvas with a custom resolution.
var myCustomCanvas = createHiDPICanvas(500, 200, 4);

หวังว่านี่จะช่วยได้!


2
คิดว่ามันจะคุ้มค่าที่จะกล่าวถึงเมธอด createHiDPI () ของฉันมีชื่อค่อนข้างไม่ดี DPI เป็นคำศัพท์สำหรับการพิมพ์เท่านั้นและ PPI เป็นคำย่อที่เหมาะสมกว่าเนื่องจากจอภาพแสดงภาพโดยใช้พิกเซลซึ่งต่างจากจุด
MyNameIsKo

3
โปรดทราบว่าอัตราส่วนนี้สามารถเปลี่ยนแปลงได้ตลอดอายุการใช้งานของเพจ ตัวอย่างเช่นถ้าฉันลากหน้าต่าง Chrome จากจอภาพภายนอก res "มาตรฐาน" รุ่นเก่าไปยังหน้าจอเรตินาในตัวของ macbook รหัสจะคำนวณอัตราส่วนที่แตกต่างกัน เพียงแค่ FYI หากคุณวางแผนที่จะแคชค่านี้ (ภายนอกคืออัตราส่วน 1 จอเรตินา 2 ในกรณีที่คุณอยากรู้อยากเห็น)
Aardvark

1
ขอบคุณสำหรับคำอธิบายนี้ แต่เนื้อหารูปภาพล่ะ เราจำเป็นต้องจัดหาภาพแคนวาสทุกภาพด้วยความละเอียดสองเท่าและลดขนาดด้วยตนเองหรือไม่?
Kokodoko

1
เรื่องไม่สำคัญเพิ่มเติม: IE ของ Windows Phone 8 จะรายงาน 1 เสมอสำหรับ window.devicePixelRatio (และการเรียกพิกเซลสำรองไม่ทำงาน) ดูแย่มากที่ 1 แต่อัตราส่วน 2 ดูดี สำหรับตอนนี้การคำนวณอัตราส่วนของฉันยังคงส่งกลับอย่างน้อย 2 (วิธีแก้ปัญหาแบบเส็งเคร็ง แต่แพลตฟอร์มเป้าหมายของฉันเป็นโทรศัพท์ที่ทันสมัยซึ่งเกือบทั้งหมดดูเหมือนจะมีหน้าจอ DPI สูง) ทดสอบกับ HTC 8X และ Lumia 1020
Aardvark

1
@Aardvark: ดูเหมือนว่า msBackingStorePixelRatio จะไม่ได้กำหนดไว้เสมอ ถามคำถามใหม่เกี่ยวกับเรื่องนี้ที่นี่stackoverflow.com/questions/22483296/…
Frank ของ TV

29

แก้ไขแล้ว!

ฉันตัดสินใจที่จะดูว่าการเปลี่ยนแปลงแอตทริบิวต์ความกว้างและความสูงที่ฉันตั้งค่าไว้javascriptเพื่อดูว่าสิ่งนั้นส่งผลต่อขนาดผ้าใบอย่างไร แต่ก็ไม่ได้ มันเปลี่ยนความละเอียด

เพื่อให้ได้ผลลัพธ์ที่ฉันต้องการฉันต้องตั้งค่าcanvas.style.widthแอตทริบิวต์ซึ่งจะเปลี่ยนขนาดทางกายภาพของcanvas:

canvas.width=1000;//horizontal resolution (?) - increase for better looking text
canvas.height=500;//vertical resolution (?) - increase for better looking text
canvas.style.width=width;//actual width of canvas
canvas.style.height=height;//actual height of canvas

1
เพื่อให้ได้ผลลัพธ์ที่ดีที่สุดคุณไม่ควรแตะแอตทริบิวต์สไตล์ของผืนผ้าใบเลยและควบคุมขนาดด้วยแอตทริบิวต์ความกว้างและความสูงของผืนผ้าใบเท่านั้น วิธีนี้จะช่วยให้คุณแน่ใจว่าหนึ่งพิกเซลบนผืนผ้าใบเท่ากับหนึ่งพิกเซลบนหน้าจอ
Philipp

7
ฉันไม่เห็นด้วย. การเปลี่ยนแอตทริบิวต์ style.width / height เป็นวิธีที่คุณสร้างผ้าใบ HiDPI
MyNameIsKo

2
ในคำตอบของคุณคุณตั้งค่า canvas.width เป็น 1,000 และ canvas.style.width เป็นครึ่งหนึ่งที่ 500 ซึ่งใช้ได้กับอุปกรณ์ที่มีอัตราส่วนพิกเซลเท่ากับ 2 เท่านั้นสำหรับสิ่งที่อยู่ด้านล่างเช่นจอภาพเดสก์ท็อปของคุณตอนนี้พื้นที่ทำงานจะเป็น วาดเป็นพิกเซลที่ไม่จำเป็น สำหรับอัตราส่วนที่สูงขึ้นคุณจะกลับมาที่จุดเริ่มต้นด้วยเนื้อหา / องค์ประกอบที่มีความละเอียดต่ำและพร่ามัว อีกประเด็นหนึ่งที่ฟิลิปป์ดูเหมือนจะพาดพิงถึงคือตอนนี้ทุกสิ่งที่คุณวาดเข้ากับบริบทของคุณจะต้องถูกดึงให้มีความกว้าง / ความสูงเพิ่มขึ้นเป็นสองเท่าแม้ว่าจะแสดงค่าครึ่งหนึ่งก็ตาม การแก้ไขนี้คือการตั้งค่าบริบทผ้าใบของคุณเป็นสองเท่า
MyNameIsKo

3
มีwindow.devicePixelRatioและใช้งานได้ดีในเบราว์เซอร์สมัยใหม่ส่วนใหญ่
เฉิน

6

ฉันปรับขนาดองค์ประกอบผ้าใบผ่าน css เพื่อรับความกว้างทั้งหมดขององค์ประกอบหลัก ฉันสังเกตเห็นว่าความกว้างและความสูงขององค์ประกอบของฉันไม่มีการปรับขนาด ฉันกำลังมองหาวิธีที่ดีที่สุดในการกำหนดขนาดที่ควรจะเป็น

canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;

วิธีง่ายๆนี้จะตั้งค่าผืนผ้าใบของคุณอย่างสมบูรณ์แบบไม่ว่าคุณจะใช้หน้าจอใด


5

สิ่งนี้แก้ไขได้ 100% สำหรับฉัน:

var canvas = document.getElementById('canvas');
canvas.width = canvas.getBoundingClientRect().width;
canvas.height = canvas.getBoundingClientRect().height;

(อยู่ใกล้กับวิธีแก้ปัญหาของ Adam Mańkowski)


4

ฉันสังเกตเห็นรายละเอียดที่ไม่ได้กล่าวถึงในคำตอบอื่น ๆ ความละเอียดแคนวาสจะตัดทอนเป็นค่าจำนวนเต็ม

ขนาดความละเอียดผ้าใบเริ่มต้นและcanvas.width: 300canvas.height: 150

window.devicePixelRatio: 1.75บนหน้าจอของฉัน

ดังนั้นเมื่อผมตั้งcanvas.height = 1.75 * 150ค่าที่ถูกตัดทอนจากที่ต้องการลงไป262.5262

วิธีแก้ปัญหาคือการเลือกขนาดเค้าโครง CSS สำหรับค่าที่กำหนดwindow.devicePixelRatioซึ่งการตัดทอนจะไม่เกิดขึ้นในการปรับขนาดความละเอียด

ตัวอย่างเช่นผมสามารถใช้width: 300pxและซึ่งจะให้ผลผลิตจำนวนทั้งหมดเมื่อคูณด้วยheight: 152px1.75

แก้ไข : อีกวิธีหนึ่งคือการใช้ประโยชน์จากความจริงที่พิกเซล CSS สามารถเป็นเศษส่วนได้เพื่อต่อต้านการตัดทอนของพิกเซลแคนวาส

ด้านล่างนี้เป็นการสาธิตโดยใช้กลยุทธ์นี้

แก้ไข : ที่นี่เป็นซอ OP ของการปรับปรุงเพื่อใช้กลยุทธ์นี้: http://jsfiddle.net/65maD/83/

main();

// Rerun on window resize.
window.addEventListener('resize', main);


function main() {
  // Prepare canvas with properly scaled dimensions.
  scaleCanvas();

  // Test scaling calculations by rendering some text.
  testRender();
}


function scaleCanvas() {
  const container = document.querySelector('#container');
  const canvas = document.querySelector('#canvas');

  // Get desired dimensions for canvas from container.
  let {width, height} = container.getBoundingClientRect();

  // Get pixel ratio.
  const dpr = window.devicePixelRatio;
  
  // (Optional) Report the dpr.
  document.querySelector('#dpr').innerHTML = dpr.toFixed(4);

  // Size the canvas a bit bigger than desired.
  // Use exaggeration = 0 in real code.
  const exaggeration = 20;
  width = Math.ceil (width * dpr + exaggeration);
  height = Math.ceil (height * dpr + exaggeration);

  // Set the canvas resolution dimensions (integer values).
  canvas.width = width;
  canvas.height = height;

  /*-----------------------------------------------------------
                         - KEY STEP -
   Set the canvas layout dimensions with respect to the canvas
   resolution dimensions. (Not necessarily integer values!)
   -----------------------------------------------------------*/
  canvas.style.width = `${width / dpr}px`;
  canvas.style.height = `${height / dpr}px`;

  // Adjust canvas coordinates to use CSS pixel coordinates.
  const ctx = canvas.getContext('2d');
  ctx.scale(dpr, dpr);
}


function testRender() {
  const canvas = document.querySelector('#canvas');
  const ctx = canvas.getContext('2d');
  
  // fontBaseline is the location of the baseline of the serif font
  // written as a fraction of line-height and calculated from the top
  // of the line downwards. (Measured by trial and error.)
  const fontBaseline = 0.83;
  
  // Start at the top of the box.
  let baseline = 0;

  // 50px font text
  ctx.font = `50px serif`;
  ctx.fillText("Hello World", 0, baseline + fontBaseline * 50);
  baseline += 50;

  // 25px font text
  ctx.font = `25px serif`;
  ctx.fillText("Hello World", 0, baseline + fontBaseline * 25);
  baseline += 25;

  // 12.5px font text
  ctx.font = `12.5px serif`;
  ctx.fillText("Hello World", 0, baseline + fontBaseline * 12.5);
}
/* HTML is red */

#container
{
  background-color: red;
  position: relative;
  /* Setting a border will mess up scaling calculations. */
  
  /* Hide canvas overflow (if any) in real code. */
  /* overflow: hidden; */
}

/* Canvas is green */ 

#canvas
{
  background-color: rgba(0,255,0,.8);
  animation: 2s ease-in-out infinite alternate both comparison;
}

/* animate to compare HTML and Canvas renderings */

@keyframes comparison
{
  33% {opacity:1; transform: translate(0,0);}
  100% {opacity:.7; transform: translate(7.5%,15%);}
}

/* hover to pause */

#canvas:hover, #container:hover > #canvas
{
  animation-play-state: paused;
}

/* click to translate Canvas by (1px, 1px) */

#canvas:active
{
  transform: translate(1px,1px) !important;
  animation: none;
}

/* HTML text */

.text
{
  position: absolute;
  color: white;
}

.text:nth-child(1)
{
  top: 0px;
  font-size: 50px;
  line-height: 50px;
}

.text:nth-child(2)
{
  top: 50px;
  font-size: 25px;
  line-height: 25px;
}

.text:nth-child(3)
{
  top: 75px;
  font-size: 12.5px;
  line-height: 12.5px;
}
<!-- Make the desired dimensions strange to guarantee truncation. -->
<div id="container" style="width: 313.235px; height: 157.122px">
  <!-- Render text in HTML. -->
  <div class="text">Hello World</div>
  <div class="text">Hello World</div>
  <div class="text">Hello World</div>
  
  <!-- Render text in Canvas. -->
  <canvas id="canvas"></canvas>
</div>

<!-- Interaction instructions. -->
<p>Hover to pause the animation.<br>
Click to translate the green box by (1px, 1px).</p>

<!-- Color key. -->
<p><em style="color:red">red</em> = HTML rendered<br>
<em style="color:green">green</em> = Canvas rendered</p>

<!-- Report pixel ratio. -->
<p>Device pixel ratio: <code id="dpr"></code>
<em>(physical pixels per CSS pixel)</em></p>

<!-- Info. -->
<p>Zoom your browser to re-run the scaling calculations.
(<code>Ctrl+</code> or <code>Ctrl-</code>)</p>


3

ฉันปรับโค้ดMyNameIsKoเล็กน้อยภายใต้canvg (SVG เป็นไลบรารี Canvas js) ฉันสับสนอยู่พักหนึ่งและใช้เวลาเพื่อสิ่งนี้ หวังว่านี่จะช่วยใครสักคน

HTML

<div id="chart"><canvas></canvas><svg>Your SVG here</svg></div>

Javascript

window.onload = function() {

var PIXEL_RATIO = (function () {
    var ctx = document.createElement("canvas").getContext("2d"),
        dpr = window.devicePixelRatio || 1,
        bsr = ctx.webkitBackingStorePixelRatio ||
              ctx.mozBackingStorePixelRatio ||
              ctx.msBackingStorePixelRatio ||
              ctx.oBackingStorePixelRatio ||
              ctx.backingStorePixelRatio || 1;

    return dpr / bsr;
})();

setHiDPICanvas = function(canvas, w, h, ratio) {
    if (!ratio) { ratio = PIXEL_RATIO; }
    var can = canvas;
    can.width = w * ratio;
    can.height = h * ratio;
    can.style.width = w + "px";
    can.style.height = h + "px";
    can.getContext("2d").setTransform(ratio, 0, 0, ratio, 0, 0);
}

var svg = document.querySelector('#chart svg'),
    canvas = document.querySelector('#chart canvas');

var svgSize = svg.getBoundingClientRect();
var w = svgSize.width, h = svgSize.height;
setHiDPICanvas(canvas, w, h);

var svgString = (new XMLSerializer).serializeToString(svg);
var ctx = canvas.getContext('2d');
ctx.drawSvg(svgString, 0, 0, w, h);

}

2

สำหรับคนที่คุณทำงานใน reactjs ฉันปรับคำตอบของ MyNameIsKo และมันก็ใช้ได้ดี นี่คือรหัส

import React from 'react'

export default class CanvasComponent extends React.Component {
    constructor(props) {
        this.calcRatio = this.calcRatio.bind(this);
    } 

    // Use componentDidMount to draw on the canvas
    componentDidMount() {  
        this.updateChart();
    }

    calcRatio() {
        let ctx = document.createElement("canvas").getContext("2d"),
        dpr = window.devicePixelRatio || 1,
        bsr = ctx.webkitBackingStorePixelRatio ||
          ctx.mozBackingStorePixelRatio ||
          ctx.msBackingStorePixelRatio ||
          ctx.oBackingStorePixelRatio ||
          ctx.backingStorePixelRatio || 1;
        return dpr / bsr;
    }

    // Draw on the canvas
    updateChart() {

        // Adjust resolution
        const ratio = this.calcRatio();
        this.canvas.width = this.props.width * ratio;
        this.canvas.height = this.props.height * ratio;
        this.canvas.style.width = this.props.width + "px";
        this.canvas.style.height = this.props.height + "px";
        this.canvas.getContext("2d").setTransform(ratio, 0, 0, ratio, 0, 0);
        const ctx = this.canvas.getContext('2d');

       // now use ctx to draw on the canvas
    }


    render() {
        return (
            <canvas ref={el=>this.canvas=el} width={this.props.width} height {this.props.height}/>
        )
    }
}

ในตัวอย่างนี้ฉันส่งผ่านความกว้างและความสูงของผืนผ้าใบเป็นอุปกรณ์ประกอบฉาก


2

ลองใช้ CSS บรรทัดเดียวบนผ้าใบของคุณ: image-rendering: pixelated

ตามMDN :

เมื่อปรับขนาดภาพขึ้นต้องใช้อัลกอริทึมเพื่อนบ้านที่ใกล้ที่สุดเพื่อให้ภาพมีพิกเซลขนาดใหญ่

ดังนั้นจึงป้องกันการลบรอยหยักอย่างสิ้นเชิง


2

แม้ว่าคำตอบของ @ MyNameIsKo จะยังคงใช้งานได้ แต่ตอนนี้มันล้าสมัยไปเล็กน้อยในปี 2020 และสามารถปรับปรุงได้:

function createHiPPICanvas(w, h) {
    let ratio = window.devicePixelRatio;
    let cv = document.createElement("canvas");
    cv.width = w * ratio;
    cv.height = h * ratio;
    cv.style.width = w + "px";
    cv.style.height = h + "px";
    cv.getContext("2d").scale(ratio, ratio);
    return cv;
}

โดยทั่วไปเราทำการปรับปรุงดังต่อไปนี้:

  • เราลบการbackingStorePixelRatioอ้างอิงออกเนื่องจากสิ่งเหล่านี้ไม่ได้ถูกนำไปใช้ในเบราว์เซอร์ใด ๆ ในทางที่สำคัญ (อันที่จริงมีเพียง Safari เท่านั้นที่ส่งคืนสิ่งอื่นที่ไม่ใช่undefinedและเวอร์ชันนี้ยังคงทำงานได้อย่างสมบูรณ์ใน Safari)
  • เราแทนที่ทั้งหมดของรหัสอัตราส่วนที่มีwindow.devicePixelRatio, ซึ่งได้รับการสนับสนุนที่ยอดเยี่ยม
  • นอกจากนี้ยังหมายความว่าเราประกาศทรัพย์สินทั่วโลกน้อยกว่าหนึ่งรายการ --- ไชโย !!
  • นอกจากนี้เรายังสามารถลบทาง|| 1เลือกwindow.devicePixelRatioออกได้เนื่องจากไม่มีจุดหมาย: เบราว์เซอร์ทั้งหมดที่ไม่รองรับคุณสมบัตินี้ไม่รองรับ.setTransformหรือ.scaleอย่างใดอย่างหนึ่งดังนั้นฟังก์ชันนี้จะไม่ทำงานกับพวกเขาทางเลือกหรือไม่
  • เราสามารถแทนที่.setTransformโดย.scaleขณะที่ผ่านในความกว้างและความสูงเป็นเล็ก ๆ น้อย ๆ ที่ใช้งานง่ายกว่าผ่านในเมทริกซ์การเปลี่ยนแปลง
  • ฟังก์ชั่นได้รับการเปลี่ยนชื่อจากไปcreateHiDPICanvas createHiPPICanvasตามที่ @MyNameIsKo พูดถึงในความคิดเห็นของคำตอบ DPI (Dots per Inch) คือคำศัพท์ในการพิมพ์ (เนื่องจากเครื่องพิมพ์ประกอบขึ้นจากภาพจากหมึกสีจุดเล็ก ๆ ) ในขณะเดียวกันจอภาพจะแสดงภาพโดยใช้พิกเซลและ PPI (พิกเซลต่อนิ้ว) ดังกล่าวเป็นตัวย่อที่ดีกว่าสำหรับกรณีการใช้งานของเรา

ข้อดีอย่างหนึ่งของการทำให้เข้าใจง่ายเหล่านี้คือตอนนี้คำตอบนี้สามารถใช้ใน TypeScript ได้โดยไม่ต้องใช้// @ts-ignore(เนื่องจาก TS ไม่มีประเภทสำหรับbackingStorePixelRatio)


0

สำหรับฉันมีเพียงเทคนิค 'พิกเซลที่สมบูรณ์แบบ' ที่แตกต่างกันเท่านั้นที่ช่วยเก็บผลลัพธ์

  1. รับและปรับขนาดด้วยอัตราส่วนพิกเซลตามที่ @MyNameIsKo แนะนำ

    pixelRatio = window.devicePixelRatio / ctx.backingStorePixelRatio

  2. ปรับขนาดผืนผ้าใบตามการปรับขนาด (หลีกเลี่ยงการขยายขนาดเริ่มต้นของผ้าใบ)

  3. ทวีคูณ lineWidth ด้วย pixelRatio เพื่อค้นหาความหนาของเส้นพิกเซล 'จริง' ที่เหมาะสม:

    context.lineWidth = ความหนา * pixelRatio;

  4. ตรวจสอบว่าความหนาของเส้นเป็นเลขคี่หรือคู่ เพิ่มครึ่งหนึ่งของ pixelRatio ลงในตำแหน่งเส้นสำหรับค่าความหนาที่แปลก

    x = x + pixelRatio / 2;

เส้นคี่จะวางไว้ตรงกลางพิกเซล บรรทัดด้านบนใช้เพื่อเลื่อนมันเล็กน้อย

function getPixelRatio(context) {
  dpr = window.devicePixelRatio || 1,
    bsr = context.webkitBackingStorePixelRatio ||
    context.mozBackingStorePixelRatio ||
    context.msBackingStorePixelRatio ||
    context.oBackingStorePixelRatio ||
    context.backingStorePixelRatio || 1;

  return dpr / bsr;
}


var canvas = document.getElementById('canvas');
var context = canvas.getContext("2d");
var pixelRatio = getPixelRatio(context);
var initialWidth = canvas.clientWidth * pixelRatio;
var initialHeight = canvas.clientHeight * pixelRatio;


window.addEventListener('resize', function(args) {
  rescale();
  redraw();
}, false);

function rescale() {
  var width = initialWidth * pixelRatio;
  var height = initialHeight * pixelRatio;
  if (width != context.canvas.width)
    context.canvas.width = width;
  if (height != context.canvas.height)
    context.canvas.height = height;

  context.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
}

function pixelPerfectLine(x) {

  context.save();
  context.beginPath();
  thickness = 1;
  // Multiple your stroke thickness  by a pixel ratio!
  context.lineWidth = thickness * pixelRatio;

  context.strokeStyle = "Black";
  context.moveTo(getSharpPixel(thickness, x), getSharpPixel(thickness, 0));
  context.lineTo(getSharpPixel(thickness, x), getSharpPixel(thickness, 200));
  context.stroke();
  context.restore();
}

function pixelPerfectRectangle(x, y, w, h, thickness, useDash) {
  context.save();
  // Pixel perfect rectange:
  context.beginPath();

  // Multiple your stroke thickness by a pixel ratio!
  context.lineWidth = thickness * pixelRatio;
  context.strokeStyle = "Red";
  if (useDash) {
    context.setLineDash([4]);
  }
  // use sharp x,y and integer w,h!
  context.strokeRect(
    getSharpPixel(thickness, x),
    getSharpPixel(thickness, y),
    Math.floor(w),
    Math.floor(h));
  context.restore();
}

function redraw() {
  context.clearRect(0, 0, canvas.width, canvas.height);
  pixelPerfectLine(50);
  pixelPerfectLine(120);
  pixelPerfectLine(122);
  pixelPerfectLine(130);
  pixelPerfectLine(132);
  pixelPerfectRectangle();
  pixelPerfectRectangle(10, 11, 200.3, 443.2, 1, false);
  pixelPerfectRectangle(41, 42, 150.3, 443.2, 1, true);
  pixelPerfectRectangle(102, 100, 150.3, 243.2, 2, true);
}

function getSharpPixel(thickness, pos) {

  if (thickness % 2 == 0) {
    return pos;
  }
  return pos + pixelRatio / 2;

}

rescale();
redraw();
canvas {
  image-rendering: -moz-crisp-edges;
  image-rendering: -webkit-crisp-edges;
  image-rendering: pixelated;
  image-rendering: crisp-edges;
  width: 100vh;
  height: 100vh;
}
<canvas id="canvas"></canvas>

เหตุการณ์การปรับขนาดจะไม่เริ่มทำงานในสนิปดังนั้นคุณสามารถลองไฟล์บนgithub


0

สำหรับฉันมันไม่ใช่แค่รูปภาพ แต่ข้อความมีคุณภาพไม่ดี โซลูชันการทำงานของเบราว์เซอร์ข้ามเบราว์เซอร์ที่ง่ายที่สุดสำหรับการแสดงเรตินา / ไม่ใช่เรตินาคือการแสดงภาพให้ใหญ่เป็นสองเท่าของที่ต้องการและปรับขนาดบริบทผ้าใบตามที่ผู้ชายคนนี้แนะนำ: https://stackoverflow.com/a/53921030/4837965

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.