HTML5 Canvas 100 ความกว้างความสูงของวิวพอร์ต


151

ฉันกำลังพยายามสร้างองค์ประกอบผ้าใบที่ใช้ความกว้างและความสูงของวิวพอร์ตได้ 100%

คุณสามารถเห็นในตัวอย่างของฉันที่นี่ที่เกิดขึ้นอย่างไรก็ตามมันคือการเพิ่มแถบเลื่อนทั้งใน Chrome และ FireFox ฉันจะป้องกันแถบเลื่อนพิเศษและเพียงแค่กำหนดความกว้างและความสูงของหน้าต่างให้เท่ากับขนาดของผืนผ้าใบได้อย่างไร


1
ดูเพิ่มเติมที่: stackoverflow.com/questions/4037212
hippietrail

เตือนให้ฉันนึกถึงภาพร่างตลก Fonejacker ที่ค่อนข้างสนุก: youtu.be/6oj_oLMD688?t=22s
ฟรานซิสบูธ

คำตอบ:


258

ในการทำให้ผืนผ้าใบเต็มความกว้างและความสูงเสมอหมายถึงแม้ว่าเบราว์เซอร์จะถูกปรับขนาดคุณจำเป็นต้องเรียกใช้ลูปการวาดภายในฟังก์ชันที่ปรับขนาดผ้าใบเป็นหน้าต่างด้านในความสูงและหน้าต่างด้านในความกว้าง

ตัวอย่าง: http://jsfiddle.net/jaredwilli/qFuDr/

HTML

<canvas id="canvas"></canvas>

JavaScript

(function() {
    var canvas = document.getElementById('canvas'),
            context = canvas.getContext('2d');

    // resize the canvas to fill browser window dynamically
    window.addEventListener('resize', resizeCanvas, false);

    function resizeCanvas() {
            canvas.width = window.innerWidth;
            canvas.height = window.innerHeight;

            /**
             * Your drawings need to be inside this function otherwise they will be reset when 
             * you resize the browser window and the canvas goes will be cleared.
             */
            drawStuff(); 
    }
    resizeCanvas();

    function drawStuff() {
            // do your drawing stuff here
    }
})();

CSS

* { margin:0; padding:0; } /* to remove the top and left whitespace */

html, body { width:100%; height:100%; } /* just to be sure these are full screen*/

canvas { display:block; } /* To remove the scrollbars */

นั่นคือวิธีที่คุณทำ Canvas ให้เต็มความกว้างและความสูงของเบราว์เซอร์ คุณเพียงแค่ใส่รหัสทั้งหมดสำหรับการวาดลงบนผืนผ้าใบในฟังก์ชัน drawStuff ()


2
ทำไมจึงจำเป็นต้องลบการขยายและตั้งค่าความกว้างความสูงเป็น 100%
Kos

3
ฉันเชื่อว่าส่วนใหญ่จะมาจากการแทนที่สไตล์ผู้ใช้ซึ่งเบราว์เซอร์มีค่าเริ่มต้น หากคุณกำลังใช้งานไฟล์ Normalize หรือ Reset css บางประเภทสิ่งนี้ไม่จำเป็นเพราะจะได้รับการดูแลอยู่แล้ว
jaredwilli

2
หากคุณคาดว่าจะมีการปรับขนาดค่อนข้างมาก เช่นบนอุปกรณ์แนวตั้ง / แนวนอนคุณต้องการdebounceปรับขนาดมิฉะนั้นคุณจะเบราว์เซอร์ท่วม
dooburt

24
display: block: ไม่เพียง แต่จะลบแถบเลื่อนออกเท่านั้น แต่ยังลบ 2px ออกจากความสูงของตัวเอกสารซึ่งโดยปกติจะถูกเพิ่มภายใต้บรรทัดข้อความในบล็อก +1 ดังนั้นสำหรับ
Neptilo

2
บวกหนึ่งสำหรับ no jQuery
Félix Gagnon-Grenier

26

คุณสามารถลองใช้หน่วย viewport (CSS3):

canvas { 
  height: 100vh; 
  width: 100vw; 
  display: block;
}

5
เพิ่มdisplay: block;และมันจะทำงาน
superlukas

18
ฉันลองสิ่งนี้และพบว่าใน Chrome และ Firefox ผ้าใบจะแสดงภาพที่ขยายไปยังวิวพอร์ตแบบเต็ม แม้กระทั่งองค์ประกอบที่เพิ่งวาดใหม่ก็จะถูกยืดออกเช่นกัน
Vivian River

8
@ Daniel เป็นสิทธิ - คำตอบนี้เป็นที่ไม่ถูกต้อง มันจะไม่ตั้งค่ามิติภายในของบริบทผ้าใบ แต่เป็นการกำหนดขนาดขององค์ประกอบ DOM สำหรับความแตกต่างให้ดูคำตอบของฉันคำถามที่เกี่ยวข้อง
Dan Dascalescu

19
วิธีนี้ใช้ไม่ได้ผลมันยืดข้อความ คุณ ต้อง ใช้ JS
i336_

16

ฉันจะตอบคำถามทั่วไปเพิ่มเติมเกี่ยวกับวิธีปรับขนาดผ้าใบแบบไดนามิกเมื่อปรับขนาดหน้าต่าง คำตอบที่ได้รับการยอมรับอย่างเหมาะสมจะจัดการกับกรณีที่ทั้งความกว้างและความสูงควรเป็น 100% ซึ่งเป็นสิ่งที่ถูกถาม แต่จะเปลี่ยนอัตราส่วนภาพของผืนผ้าใบด้วย ผู้ใช้หลายคนต้องการให้ Canvas ปรับขนาดบนปรับขนาดหน้าต่าง แต่ในขณะที่รักษาอัตราส่วนกว้างยาวไว้ มันไม่ใช่คำถามที่แน่นอน แต่มัน "พอดีกับ" เพียงใส่คำถามในบริบททั่วไปที่กว้างขึ้นเล็กน้อย

หน้าต่างจะมีอัตราส่วนกว้างยาว (กว้าง / สูง) และวัตถุผ้าใบจะทำเช่นนั้น คุณต้องการให้อัตราส่วนทั้งสองนี้เกี่ยวข้องกันอย่างไรเป็นสิ่งหนึ่งที่คุณจะต้องชัดเจนไม่มี "คำตอบที่เหมาะกับทุกขนาด" สำหรับคำถามนั้น - ฉันจะพูดถึงกรณีทั่วไปของสิ่งที่คุณอาจจะรู้ ต้องการ.

สิ่งที่สำคัญที่สุดที่คุณต้องมีความชัดเจนเกี่ยวกับ: วัตถุผ้าใบ html มีคุณลักษณะความกว้างและคุณลักษณะความสูง; จากนั้น css ของวัตถุเดียวกันก็มีแอตทริบิวต์ width และ height ความกว้างและความสูงทั้งสองนั้นต่างกันทั้งสองมีประโยชน์สำหรับสิ่งต่าง ๆ

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

ฉันเห็น 4 กรณีของสิ่งที่คุณอาจต้องการให้เกิดขึ้นในการปรับขนาดหน้าต่าง (ทั้งหมดเริ่มต้นด้วย Canvas แบบเต็มหน้าจอ)

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

$(ctx.canvas).css("width", "100%");

โดยที่ ctx คือบริบทผ้าใบของคุณ ซอ: ปรับขนาดโดยไวด์ ธ

2: คุณต้องการให้ทั้งความกว้างและความสูงอยู่ที่ 100% และคุณต้องการให้การเปลี่ยนแปลงอัตราส่วนภาพมีผลต่อภาพที่ขยายออก ตอนนี้คุณยังไม่จำเป็นต้องวาดภาพวาดผ้าใบอีกต่อไป แต่คุณต้องมีตัวปรับขนาดหน้าต่าง ในตัวจัดการคุณทำ

$(ctx.canvas).css("height", window.innerHeight);

ซอ: messWithAspectratio

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

ซอ: วาดใหม่

4: คุณต้องการให้ความกว้างและความสูงเท่ากับ 100% สำหรับการโหลดหน้า แต่คงที่หลังจากนั้น (คงที่ไม่ตอบสนองต่อการปรับขนาดหน้าต่าง

ซอ: แก้ไขแล้ว

ซอทั้งหมดมีรหัสเหมือนกันยกเว้นบรรทัดที่ 63 ซึ่งตั้งโหมดไว้ นอกจากนี้คุณยังสามารถคัดลอกรหัสซอเพื่อเรียกใช้บนเครื่องท้องถิ่นของคุณซึ่งในกรณีนี้คุณสามารถเลือกโหมดผ่านการโต้แย้งสตริงการสืบค้นเป็น? mode = redraw


1
fyi: $(ctx.canvas).css("width", "100%");เทียบเท่ากับ$(canvas).css("width", "100%"); (ผืนผ้าใบของบริบทเป็นเพียงผืนผ้าใบ)
แบรดเคนต์

@BradKent เมื่อคุณเรียกใช้ฟังก์ชั่นตัวช่วยซึ่งทำหน้าที่ "canvas-things" ที่คุณต้องการคุณสามารถทำได้อย่างใดอย่างหนึ่งตามที่อาร์กิวเมนต์ 1) ส่งต่อวัตถุ canvas, 2) ผ่านบริบท Canvas, 3) ทั้งคู่ ฉันไม่ชอบ 3) และctx.canvasสั้นกว่ามากcanvas.getContext('2d')- นั่นเป็นเหตุผลที่ฉันทำ 2) ดังนั้นจึงไม่มีตัวแปรที่เรียกว่า canvas แต่มี ctx.canvas นั่นคือที่มาของ ctx.canvas
mathheadinclouds

9

http://jsfiddle.net/mqFdk/10/

<!DOCTYPE html>
<html>
<head>
    <title>aj</title>
</head>
<body>

    <canvas id="c"></canvas>

</body>
</html>

ด้วย CSS

body { 
       margin: 0; 
       padding: 0
     }
#c { 
     position: absolute; 
     width: 100%; 
     height: 100%; 
     overflow: hidden
   }

ใช้งานได้ แต่มันทำให้ผ้าใบของฉันไม่มีความกว้างและความสูงที่กำหนดไว้ ต้องกำหนดความกว้างและความสูงของผืนผ้าใบในองค์ประกอบที่ฉันเชื่อ
aherrick

@Aherrick: ไม่คุณไม่จำเป็นต้องตั้งค่าความกว้าง / ความสูงอย่างชัดเจนบนองค์ประกอบ Canvas เพื่อให้ทำงานได้ รหัสนี้ควรจะทำงานได้ดี
Jon Adams

18
ใช่จริงองค์ประกอบผ้าใบต้องมีชุดความกว้าง / ความสูงที่ชัดเจน หากไม่มีพวกเขาจะตั้งค่าเริ่มต้นเป็นเบราว์เซอร์ที่ตั้งไว้ล่วงหน้า (เป็น Chrome ฉันคิดว่าขนาด 300x150px) การวาดภาพทั้งหมดลงบนผืนผ้าใบจะถูกตีความที่ขนาดนี้จากนั้นปรับสัดส่วนเป็น 100% ของขนาดวิวพอร์ต ลองวาดภาพอะไรในผืนผ้าใบของคุณเพื่อดูสิ่งที่ผมหมายถึง - มันจะถูกบิดเบือน
Mark Kahn

หากคุณพยายามทำให้ผืนผ้าใบมีความกว้างและความสูง 100% นั่นก็ไม่ได้สำคัญอะไร คุณเพียงแค่ปรับขนาด anyways
jaredwilli

1
ขนาดที่แท้จริงขององค์ประกอบผ้าใบเท่ากับขนาดของพื้นที่พิกัดโดยที่ตัวเลขตีความใน CSS พิกเซล อย่างไรก็ตามองค์ประกอบสามารถปรับขนาดได้ตามสไตล์ชีต ในระหว่างการเรนเดอร์รูปภาพจะถูกปรับอัตราส่วนให้พอดีกับขนาดเค้าโครงนี้
jaredwilli

8

ฉันกำลังหาคำตอบสำหรับคำถามนี้เช่นกัน แต่คำตอบที่ได้รับการตอบรับก็ไม่ดีสำหรับฉัน เห็นได้ชัดว่าใช้ window.innerWidth ไม่ใช่แบบพกพา มันใช้งานได้ในบางเบราว์เซอร์ แต่ฉันสังเกตว่า Firefox ไม่ชอบ

Gregg Tavares โพสต์แหล่งข้อมูลที่ดีที่นี่เพื่อแก้ไขปัญหานี้โดยตรง: http://webglfundamentals.org/webgl/lessons/webgl-anti-patterns.html (ดู 3 และ 4 ของ anti-pattern #)

การใช้ canvas.clientWidth แทนที่จะเป็น window.innerWidth ดูเหมือนว่าจะทำงานได้ดี

นี่คือลูปการเรนเดอร์ที่แนะนำของ Gregg:

function resize() {
  var width = gl.canvas.clientWidth;
  var height = gl.canvas.clientHeight;
  if (gl.canvas.width != width ||
      gl.canvas.height != height) {
     gl.canvas.width = width;
     gl.canvas.height = height;
     return true;
  }
  return false;
}

var needToRender = true;  // draw at least once
function checkRender() {
   if (resize() || needToRender) {
     needToRender = false;
     drawStuff();
   }
   requestAnimationFrame(checkRender);
}
checkRender();

2

(ขยายคำตอบของ動靜能量)

จัดแต่งทรงผ้าใบเพื่อเติมเต็มร่างกาย เมื่อเรนเดอร์ไปยังผืนผ้าใบคำนึงถึงขนาดของมัน

http://jsfiddle.net/mqFdk/356/

<!DOCTYPE html>
<html>
<head>
    <title>aj</title>
</head>
<body>

    <canvas id="c"></canvas>

</body>
</html>

CSS:

body { 
       margin: 0; 
       padding: 0
     }
#c { 
     position: absolute; 
     width: 100%; 
     height: 100%; 
     overflow: hidden
   }

javascript:

function redraw() {
    var cc = c.getContext("2d");
    c.width = c.clientWidth;
    c.height = c.clientHeight;
    cc.scale(c.width, c.height);

    // Draw a circle filling the canvas.
    cc.beginPath();
    cc.arc(0.5, 0.5, .5, 0, 2*Math.PI);
    cc.fill();
}

// update on any window size change.
window.addEventListener("resize", redraw);

// first draw
redraw();

1

สำหรับโทรศัพท์มือถือมันจะดีกว่าที่จะใช้

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

เพราะมันจะแสดงอย่างไม่ถูกต้องหลังจากเปลี่ยนการวางแนว“ วิวพอร์ต” จะเพิ่มขึ้นเมื่อเปลี่ยนการวางแนวเป็นแนวตั้งดู ตัวอย่างทั้งหมด

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