html5 - องค์ประกอบผ้าใบ - หลายชั้น


176

หากไม่มีไลบรารีส่วนขยายเป็นไปได้หรือไม่ที่จะมีหลายชั้นในองค์ประกอบ Canvas เดียวกัน

ดังนั้นถ้าฉันทำ clearRect ที่ชั้นบนสุดมันจะไม่ลบชั้นล่างสุด?

ขอบคุณ


คุณอาจต้องการที่จะดูที่radikalfx.com/2009/10/16/canvas-collage เขาใช้เทคนิค "เลเยอร์"
แมทธิว

2
ตรวจสอบนี้ .. html5.litten.com/using-multiple-html5-canvases-as-layersนี้จะช่วยให้คุณในการแก้ไขปัญหาของคุณในทางที่เหมาะสม
Dakshika

@Dakshika ขอบคุณสำหรับการเชื่อมโยงมันอธิบายปัญหาที่ฉันใช้ผ้าใบเมื่อไม่กี่ปีก่อนที่ห้องสมุดดูแลฉัน
Fering

คำตอบ:


267

ไม่อย่างไรก็ตามคุณสามารถเลเยอร์<canvas>องค์ประกอบหลายรายการซ้อนทับกันและทำสิ่งที่คล้ายกันได้

<div style="position: relative;">
 <canvas id="layer1" width="100" height="100" 
   style="position: absolute; left: 0; top: 0; z-index: 0;"></canvas>
 <canvas id="layer2" width="100" height="100" 
   style="position: absolute; left: 0; top: 0; z-index: 1;"></canvas>
</div>

วาดเลเยอร์แรกของคุณบนlayer1ผืนผ้าใบและเลเยอร์ที่สองบนlayer2ผืนผ้าใบ จากนั้นเมื่อคุณclearRectอยู่ที่ชั้นบนสุดสิ่งที่อยู่บนผืนผ้าใบด้านล่างจะแสดงผ่าน


มีวิธีซ่อน / ปลดเลเยอร์ .. หรือไม่เช่นนั้นฉันสามารถซ่อน layer1 และแสดง layer2 และทำกลับกันได้เมื่อจำเป็น .. ?
ซารากิ

4
คุณสามารถซ่อนมันไว้ด้วย CSS - display: none;คือ หรือแค่เคลียร์ผืนผ้าใบถ้ามันไม่แพงเกินกว่าที่จะวาดใหม่อีกครั้งเมื่อชั้นควรจะแสดง
jimr

ค่าที่กำหนดให้กับ 'left' และ 'top' จะต้องเป็น '0px' ไม่ใช่ '0'
ไบรอันกรีน

6
@BryanGreen ไม่เป็นความจริง "อย่างไรก็ตามสำหรับความยาวเป็นศูนย์ตัวระบุหน่วยเป็นตัวเลือก (เช่นสามารถแสดง syntactically เป็น <number> 0)" w3.org/TR/css3-values/#lengths
xehpuk

ฉันสามารถควบคุมประเภทองค์ประกอบสำหรับผืนผ้าใบหลาย ๆ ผืนได้หรือไม่
ziyuang

40

เกี่ยวข้องกับเรื่องนี้:

หากคุณมีบางอย่างบนผืนผ้าใบของคุณและคุณต้องการวาดบางสิ่งที่ด้านหลัง - คุณสามารถทำได้โดยเปลี่ยนการตั้งค่าบริบท เสร็จสิ้นอีกครั้ง

   var context = document.getElementById('cvs').getContext('2d');

    // Draw a red square
    context.fillStyle = 'red';
    context.fillRect(50,50,100,100);



    // Change the globalCompositeOperation to destination-over so that anything
    // that is drawn on to the canvas from this point on is drawn at the back
    // of what's already on the canvas
    context.globalCompositeOperation = 'destination-over';



    // Draw a big yellow rectangle
    context.fillStyle = 'yellow';
    context.fillRect(0,0,600,250);


    // Now return the globalCompositeOperation to source-over and draw a
    // blue rectangle
    context.globalCompositeOperation = 'source-over';

    // Draw a blue rectangle
    context.fillStyle = 'blue';
    context.fillRect(75,75,100,100);
<canvas id="cvs" />


ใช่ว่าใช้ได้ แต่ในกรณีของการลบตามที่ถามในคำถาม สิ่งนี้จะลบทั้งสองชั้นคล้ายคลึงกัน ซึ่งไม่ถูกต้องอีกครั้ง
Pardeep Jain

27

คุณสามารถสร้างcanvasองค์ประกอบหลายรายการโดยไม่ต้องผนวกเข้ากับเอกสาร สิ่งเหล่านี้จะเป็นเลเยอร์ของคุณ :

จากนั้นทำสิ่งที่คุณต้องการกับพวกเขาและในตอนท้ายเพียงแสดงเนื้อหาของพวกเขาตามลำดับที่ถูกต้องบนผืนผ้าใบปลายทางที่ใช้drawImageบนcontextใน

ตัวอย่าง:

/* using canvas from DOM */
var domCanvas = document.getElementById('some-canvas');
var domContext = domCanvas.getContext('2d');
domContext.fillRect(50,50,150,50);

/* virtual canvase 1 - not appended to the DOM */
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
ctx.fillStyle = 'blue';
ctx.fillRect(50,50,150,150);

/* virtual canvase 2 - not appended to the DOM */    
var canvas2 = document.createElement('canvas')
var ctx2 = canvas2.getContext('2d');
ctx2.fillStyle = 'yellow';
ctx2.fillRect(50,50,100,50)

/* render virtual canvases on DOM canvas */
domContext.drawImage(canvas, 0, 0, 200, 200);
domContext.drawImage(canvas2, 0, 0, 200, 200);

และนี่คือ codepen บางส่วน: https://codepen.io/anon/pen/mQWMMW


4
@ SCLeo คุณพูดว่า "Performance killer ประมาณ ~ 10 ครั้งช้าลง" ผิดทั้งหมด ขึ้นอยู่กับกรณีการใช้งานที่ใช้ผ้าใบ DOM เดียวและการแสดงผลผ้าใบหน้าจอไปที่เร็วกว่าผ้าใบซ้อนใน DOM ข้อผิดพลาดทั่วไปคือการเปรียบเทียบการโทรการเรนเดอร์การโทรแบบดึงออกสามารถกำหนดเวลาการเรนเดอร์ DOM อยู่นอกบริบทของ Javascripts และไม่สามารถกำหนดเวลาได้ ผลลัพธ์ก็คือผ้าใบผ้าใบแบบกองซ้อน DOM ไม่ได้รับการเรนเดอร์แบบเรียงซ้อน (ทำโดย DOM) ที่รวมอยู่ในเกณฑ์มาตรฐาน ..
Blindman67

@ Blindman67 ฉันรู้ว่าคุณหมายถึงอะไร เพียงชำระเงินมาตรฐานนี้: jsfiddle.net/9a9L8k7k/1 ในกรณีที่คุณเข้าใจผิดมีผ้าใบสามผืนผ้าใบ 1 (ctx1) เป็นผืนผ้าใบจริง Canvas 2 (ctx2) และ canvas 3 (ctx) ปิดหน้าจอ ก่อนหน้านี้มีการสร้างภาพลงบน ctx3 ในการทดสอบ 1 ของเกณฑ์มาตรฐานนี้ฉันแสดง ctx3 ลงบน ctx1 โดยตรง ในการทดสอบ 2 ฉันแสดง ctx3 บน ctx2 แล้ว ctx2 ถึง ctx1 การทดสอบ 2 ช้ากว่าการทดสอบ 1 1 ถึง 30 ในคอมพิวเตอร์ของฉัน นั่นคือเหตุผลที่ฉันพูดว่าการใช้ผ้าใบกลางนั้นช้ากว่ามาก
SCLeo

@ Blindman67 เคล็ดลับของผืนผ้าใบนอกหน้าจอจะใช้งานได้เมื่อผ้าใบนอกหน้าจอคงที่เท่านั้น การใช้ผืนผ้าใบแบบไดนามิกจะทำให้ประสิทธิภาพเสียหายอย่างมาก (อีกครั้งสิ่งที่ฉันพยายามจะพูดคือผ้าใบแบบไดนามิกนอกจอช้ามากดังนั้นจึงสันนิษฐานว่าเทคนิคนี้ (เลเยอร์จำลองโดยผ้าใบหลายหน้าจอ) จะไม่เป็นที่ต้องการ)
SCLeo

@ Blindman67 สำคัญ: ที่อยู่มาตรฐานคือhttps://jsfiddle.net/9a9L8k7k/3ฉันลืมบันทึกหลังจากแก้ไขและ Stack Overflow ไม่อนุญาตให้ฉันเปลี่ยนความคิดเห็นก่อนหน้านี้อีกต่อไป ...
SCLeo

4
@ Blindman67 ฉันขอโทษมันเป็นความผิดพลาดของฉัน ฉันทดสอบและพบว่าการใช้ผ้าใบหลายหน้าจอนั้นราบรื่นมาก ฉันยังคงไม่แน่ใจว่าทำไมเกณฑ์มาตรฐานดังกล่าวแสดงให้เห็นว่าการใช้พื้นที่หน้าจอปิดนั้นช้า
SCLeo

6

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

ดังนั้นฉันจึงไปข้างหน้าและใช้ "ระบบ" เลเยอร์ง่ายๆในการเขียนโค้ดราวกับว่าแต่ละเลเยอร์มีรหัสของตัวเอง แต่ทุกอย่างจะแสดงผลเป็นองค์ประกอบเดียวกัน

https://github.com/federicojacobi/layeredCanvas

ฉันตั้งใจจะเพิ่มความสามารถพิเศษ แต่ตอนนี้มันจะทำ

คุณสามารถทำหลายฟังก์ชั่นและเรียกมันเพื่อเลเยอร์ "ปลอม"


อันนี้สมบูรณ์แบบ
ขีดตกต่ำสุด

4

นอกจากนี้คุณยังสามารถเช็คเอาต์http://www.concretejs.comซึ่งเป็นเฟรมเวิร์คผ้าใบที่ทันสมัยน้ำหนักเบา Html5 ที่ช่วยให้การตรวจจับการโจมตีการเลเยอร์และสิ่งต่อพ่วงอื่น ๆ อีกมากมาย คุณสามารถทำสิ่งนี้:

var wrapper = new Concrete.Wrapper({
  width: 500,
  height: 300,
  container: el
});

var layer1 = new Concrete.Layer();
var layer2 = new Concrete.Layer();

wrapper.add(layer1).add(layer2);

// draw stuff
layer1.sceneCanvas.context.fillStyle = 'red';
layer1.sceneCanvas.context.fillRect(0, 0, 100, 100);

// reorder layers
layer1.moveUp();

// destroy a layer
layer1.destroy();

เลเยอร์เหล่านั้นจะจบลงที่ DOM อย่างไร แต่ละคนสามารถเข้าถึงได้ผ่าน CSS หรือไม่
Garavani

0

ฉันเข้าใจว่า Q ไม่ต้องการใช้ห้องสมุด แต่ฉันจะให้สิ่งนี้กับคนอื่น ๆ ที่มาจากการค้นหาของ Google @EricRowell พูดถึงปลั๊กอินที่ดี แต่ยังมีปลั๊กอินอื่นที่คุณสามารถลองได้html2canvas html2canvas

ในกรณีของเราเราใช้ PNG โปร่งใสแบบเลเยอร์ z-indexเป็นเครื่องมือ "ตัวสร้างผลิตภัณฑ์" Html2canvas ทำงานได้อย่างยอดเยี่ยมในการต้มกองซ้อนโดยไม่ต้องกดภาพหรือใช้ความซับซ้อนการแก้ปัญหาและผืนผ้าใบ "ที่ไม่ตอบสนอง" เราไม่สามารถทำสิ่งนี้ได้อย่างราบรื่น / มีสติด้วยผ้าใบวานิลลา + JS

ใช้งานครั้งแรกz-indexบน divs แบบสัมบูรณ์เพื่อสร้างเนื้อหาแบบเลเยอร์ภายใน wrapper ตำแหน่งที่สัมพันธ์กัน จากนั้นไพพ์เสื้อคลุมผ่าน html2canvas เพื่อให้ผืนผ้าใบเรนเดอร์เรนเดอร์ซึ่งคุณอาจปล่อยให้เป็นไปตามที่เป็นอยู่หรือเอาท์พุทเป็นรูปภาพเพื่อให้ลูกค้าสามารถบันทึกได้


หากคุณมีภาพที่หนักกว่านี้จะต้องใช้เวลาพอสมควรในการแปลง HTML เป็นผืนผ้าใบเราต้องย้ายออกจากนี้เพียงเพราะการเรนเดอร์ใช้เวลานาน
Vilius

@Vilius ใช่ดีโทรภาพใหญ่ / ใหญ่ เราพยายามที่จะยึดรูปภาพขนาด 300K หรือน้อยกว่าที่มีไม่เกิน 4 เลเยอร์มิฉะนั้นไคลเอนต์ที่ประสบปัญหาจะรู้สึกแสบร้อนเมื่อดาวน์โหลดภาพที่ได้ทำการหมัก อยากรู้อยากเห็นคุณย้ายไปที่เวลาที่ลดลงคืออะไร?
dhaupin

เราทำผิดพลาดครั้งใหญ่โดยใช้องค์ประกอบ html เพื่อวาดบางอย่างตั้งแต่แรก เนื่องจาก api ของเราคืนค่า x, y, ความกว้างและความสูงเราจึงย้ายไปที่ jscanavs เพื่อวาดภาพแทนที่จะใช้องค์ประกอบ html ในใจคุณเรามีปัญหาสองสามอย่างเกี่ยวกับการหมุน (จุดเริ่มต้นนั้นค่อนข้างอึดอัดและคาดเดาไม่ได้) และการใช้รูปภาพกับมิตินั้นโดยเฉพาะ แต่ทุกอย่างก็ถูกแก้ไขในที่สุด นอกจากนี้เรายังพบว่าแอปพลิเคชันการประมวลผลภาพของเราใช้ทรัพยากรจำนวนมากดังนั้นเราจึงย้ายออกไปจากที่นั้น
Vilius

0

แต่เลเยอร์ 02 จะครอบคลุมภาพวาดทั้งหมดในเลเยอร์ 01 ฉันใช้สิ่งนี้เพื่อแสดงภาพวาดในเลเยอร์ทั้งสอง ใช้ (พื้นหลังสี: โปร่งใส;) อย่างมีสไตล์

    <div style="position: relative;"> 
      <canvas id="lay01" width="500" height="500" style="position: absolute; left: 0; top: 0; z-index: 0; background-color: transparent;">
      </canvas> 
      <canvas id="lay02" width="500" height="500" style="position: absolute; left: 0; top: 0; z-index: 1; background-color: transparent;">
      </canvas>
</div>

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