วิธีที่ดีที่สุดในการตั้งค่าพิกเซลเดียวในผืนผ้าใบ HTML5 คืออะไร


184

ผ้าใบ HTML5 ไม่มีวิธีการตั้งค่าพิกเซลเดียวอย่างชัดเจน

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

อีกวิธีหนึ่งคือการสร้างImageDataวัตถุขนาดเล็กและการใช้:

context.putImageData(data, x, y)

ที่จะวางไว้ในสถานที่

ใครสามารถอธิบายวิธีที่มีประสิทธิภาพและเชื่อถือได้ในการทำเช่นนี้?

คำตอบ:


292

มีผู้เข้าแข่งขันที่ดีที่สุดสองคน:

  1. สร้างข้อมูลรูปภาพขนาด 1x1 ตั้งค่าสีและputImageDataที่ตำแหน่ง:

    var id = myContext.createImageData(1,1); // only do this once per page
    var d  = id.data;                        // only do this once per page
    d[0]   = r;
    d[1]   = g;
    d[2]   = b;
    d[3]   = a;
    myContext.putImageData( id, x, y );     
  2. ใช้fillRect()เพื่อวาดพิกเซล (ไม่ควรมีปัญหาเรื่องนามแฝง):

    ctx.fillStyle = "rgba("+r+","+g+","+b+","+(a/255)+")";
    ctx.fillRect( x, y, 1, 1 );

คุณสามารถทดสอบความเร็วของสิ่งเหล่านี้ได้ที่นี่: http://jsperf.com/setting-canvas-pixel/9หรือที่นี่https://www.measurethat.net/Benchmarks/Show/1664/1

ฉันแนะนำให้ทดสอบกับเบราว์เซอร์ที่คุณสนใจเพื่อความเร็วสูงสุด ตั้งแต่เดือนกรกฎาคม 2017 fillRect()มีความเร็ว 5-6 ×เร็วใน Firefox v54 และ Chrome v59 (Win7x64)

อื่น ๆ ทางเลือกที่ sillier คือ:

  • ใช้getImageData()/putImageData()บนผืนผ้าใบทั้งหมด นี่คือประมาณ 100 ×ช้ากว่าตัวเลือกอื่น ๆ

  • การสร้างภาพที่กำหนดเองโดยใช้ URL ข้อมูลและการใช้drawImage()เพื่อแสดง:

    var img = new Image;
    img.src = "data:image/png;base64," + myPNGEncoder(r,g,b,a);
    // Writing the PNGEncoder is left as an exercise for the reader
  • การสร้าง img หรือผืนผ้าใบอื่นที่เต็มไปด้วยพิกเซลทั้งหมดที่คุณต้องการและใช้drawImage()เพื่อแยกพิกเซลที่คุณต้องการ นี่อาจจะเร็วมาก แต่มีข้อ จำกัด ที่คุณต้องคำนวณล่วงหน้าพิกเซลที่คุณต้องการ

โปรดทราบว่าการทดสอบของฉันไม่ได้พยายามที่จะบันทึกและเรียกคืนบริบทผ้าใบfillStyle; นี่จะทำให้fillRect()ประสิทธิภาพลดลง โปรดทราบว่าฉันไม่ได้เริ่มต้นด้วยกระดานชนวนที่สะอาดหรือทดสอบพิกเซลชุดเดียวกันสำหรับการทดสอบแต่ละครั้ง


2
ฉันจะให้อีก +10 ถ้าฉันสามารถทำรายงานข้อผิดพลาด! :)
— Alnitak

51
โปรดทราบว่าในเครื่องของฉันที่มีไดรเวอร์ GPU และกราฟิกของฉันfillRect()กึ่งเร็ว ๆ นี้กลายเป็นเกือบ 10 เท่าเร็วกว่า 1x1 putimagedata ใน Chromev24 ดังนั้น ... หากความเร็วมีความสำคัญและคุณรู้จักกลุ่มเป้าหมายของคุณอย่าใช้คำตอบที่ล้าสมัย (แม้แต่ของฉัน) แทน: ทดสอบ!
— Phrogz

3
โปรดอัปเดตคำตอบ วิธีการเติมนั้นเร็วกว่ามากในเบราว์เซอร์สมัยใหม่
— Buzzy

10
"การเขียน PNGEncoder นั้นเป็นแบบฝึกหัดสำหรับผู้อ่าน" ทำให้ฉันหัวเราะออกมาดัง ๆ
— Pascal Ganaye

2
ทำไมผ้าใบคำตอบที่ยอดเยี่ยมทั้งหมดที่ฉันได้พบก็คือคุณ :)
— Domino

19

วิธีการหนึ่งที่ไม่ได้กล่าวถึงคือการใช้ getImageData จากนั้น putImageData
วิธีนี้เหมาะสำหรับเมื่อคุณต้องการวาดภาพจำนวนมากในครั้งเดียวอย่างรวดเร็ว
http://next.plnkr.co/edit/mfNyalsAR2MWkccr

  var canvas = document.getElementById('canvas');
  var ctx = canvas.getContext('2d');
  var canvasWidth = canvas.width;
  var canvasHeight = canvas.height;
  ctx.clearRect(0, 0, canvasWidth, canvasHeight);
  var id = ctx.getImageData(0, 0, canvasWidth, canvasHeight);
  var pixels = id.data;

    var x = Math.floor(Math.random() * canvasWidth);
    var y = Math.floor(Math.random() * canvasHeight);
    var r = Math.floor(Math.random() * 256);
    var g = Math.floor(Math.random() * 256);
    var b = Math.floor(Math.random() * 256);
    var off = (y * id.width + x) * 4;
    pixels[off] = r;
    pixels[off + 1] = g;
    pixels[off + 2] = b;
    pixels[off + 3] = 255;

  ctx.putImageData(id, 0, 0);

13
@Alnitak ทำให้ฉันไม่เห็นด้วยที่จะไม่สามารถอ่านความคิดของคุณได้ต่ำ ... คนอื่น ๆ อาจมาที่นี่เพื่อให้สามารถพล็อตพิกเซลจำนวนมากได้ ฉันทำแล้วจำวิธีที่มีประสิทธิภาพมากขึ้น
— PAEz

นี่เป็นวิธีการที่สมเหตุสมผลเมื่อกระตุ้นพิกเซลจำนวนมากสำหรับการสาธิตกราฟิกที่คำนวณแต่ละพิกเซลหรือคล้ายกัน มันเร็วกว่าการใช้ fillRect สิบเท่าสำหรับแต่ละพิกเซล
— Sam Watkins

ใช่มันบอกฉันเสมอว่าคำตอบที่ยกเว้นบอกว่าวิธีนี้ช้ากว่าวิธีอื่น 100 เท่า สิ่งนี้อาจเป็นจริงได้หากการวางแผนของคุณน้อยกว่า 1,000 แต่จากนั้นเป็นต้นไปวิธีการนี้จะเริ่มชนะและจากนั้นจะฆ่าวิธีอื่น ๆ นี่คือกรณีทดสอบ .... measurethat.net/Benchmarks/Show/8386/0/…
— PAEz

17

ฉันไม่ได้พิจารณาfillRect()แต่คำตอบก็กระตุ้นให้ฉันเปรียบเทียบกับมันputImage()แต่คำตอบที่กระตุ้นให้ฉันไปมันกับมาตรฐาน

วาง 100,000 พิกเซลสีแบบสุ่มในสถานที่สุ่มด้วย Chrome 9.0.597.84 บน (เดิม) MacBook Pro, ใช้เวลาน้อยกว่า 100 มิลลิวินาทีมีputImage()แต่เกือบ 900ms fillRect()ใช้ (รหัสมาตรฐานที่http://pastebin.com/4ijVKJcC )

ถ้าฉันเลือกสีเดียวนอกลูปและเพียงแค่พล็อตสีนั้นในสถานที่สุ่มให้putImage()ใช้เวลา 59ms เทียบกับ 102 มิลลิวินาทีfillRect()สำหรับ

ดูเหมือนว่าค่าใช้จ่ายในการสร้างและแยกวิเคราะห์ข้อกำหนดสี CSS ใน rgb(...)ไวยากรณ์นั้นรับผิดชอบส่วนใหญ่ของความแตกต่าง

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


2
ฉันได้เพิ่มพลั่วเกอร์ที่คุณสามารถคลิกปุ่มและทดสอบแต่ละวิธี (PutImage, FillRect) และเพิ่มเติมจากวิธี LineTo มันแสดงให้เห็นว่า PutImage และ FillRect อยู่ใกล้มากในเวลา แต่ LineTo ช้ามาก ตรวจสอบได้ที่: plnkr.co/edit/tww6e1VY2OCVY4c4ECy3?p=previewมันขึ้นอยู่กับรหัสPastebinที่ดีของคุณ ขอบคุณ
— raddevus

สำหรับผู้รวบรวมเสียงดังกล่าวฉันเห็นว่า PutImage ช้ากว่า FillRect เล็กน้อย (ใน Chrome 63 ล่าสุด) เล็กน้อย แต่หลังจากฉันลอง LineTo แล้ว PutImage นั้นเร็วกว่า FillRect อย่างมาก อย่างใดพวกเขาดูเหมือนจะรบกวน
— mlepage

13
function setPixel(imageData, x, y, r, g, b, a) {
    var index = 4 * (x + y * imageData.width);
    imageData.data[index+0] = r;
    imageData.data[index+1] = g;
    imageData.data[index+2] = b;
    imageData.data[index+3] = a;
}

var index = (x + y * imageData.width) * 4;
— user889030

1
ควรเรียกputImageData() หลังจากฟังก์ชันนั้นหรือบริบทจะอัปเดตตามการอ้างอิงหรือไม่
— Lucas Sousa

7

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


5

ดูเหมือนว่าแปลก แต่ HTML5 ยังรองรับการวาดเส้นวงกลมสี่เหลี่ยมและรูปร่างพื้นฐานอื่น ๆ อีกมากมายมันไม่มีอะไรเหมาะสำหรับการวาดจุดพื้นฐาน วิธีเดียวที่จะทำเช่นนั้นคือการจำลองจุดด้วยสิ่งที่คุณมี

ดังนั้นโดยทั่วไปมีวิธีแก้ปัญหา 3 ประการที่เป็นไปได้:

  • วาดจุดเป็นเส้น
  • วาดจุดเป็นรูปหลายเหลี่ยม
  • วาดจุดเป็นวงกลม

แต่ละคนมีข้อเสีย


ไลน์

function point(x, y, canvas){
  canvas.beginPath();
  canvas.moveTo(x, y);
  canvas.lineTo(x+1, y+1);
  canvas.stroke();
}

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


สี่เหลี่ยมผืนผ้า

function point(x, y, canvas){
  canvas.strokeRect(x,y,1,1);
}

หรือในวิธีที่เร็วกว่าการใช้ fillRect เพราะโปรแกรมแสดงผลจะเติมหนึ่งพิกเซล

function point(x, y, canvas){
  canvas.fillRect(x,y,1,1);
}

วงกลม


ปัญหาอย่างหนึ่งของวงการคือมันยากกว่าสำหรับเครื่องยนต์ที่จะแสดงผล

function point(x, y, canvas){
  canvas.beginPath();
  canvas.arc(x, y, 1, 0, 2 * Math.PI, true);
  canvas.stroke();
}

ความคิดเช่นเดียวกับสี่เหลี่ยมคุณสามารถบรรลุด้วยการเติม

function point(x, y, canvas){
  canvas.beginPath();
  canvas.arc(x, y, 1, 0, 2 * Math.PI, true);
  canvas.fill();
}

ปัญหาเกี่ยวกับวิธีแก้ไขปัญหาทั้งหมด:

  • มันยากที่จะติดตามคะแนนทั้งหมดที่คุณจะวาด
  • เมื่อคุณซูมเข้ามันดูน่าเกลียด

หากคุณสงสัยว่า " วิธีที่ดีที่สุดในการวาดจุดคืออะไร " ฉันจะไปกับสี่เหลี่ยมที่เต็มไปด้วย ท่านสามารถเข้าดูของฉันjsperf นี่กับการทดสอบเปรียบเทียบ


ทิศทางตะวันออกเฉียงใต้? อะไร?
— LoganDark

4

สี่เหลี่ยมผืนผ้าล่ะ นั่นจะต้องมีประสิทธิภาพมากกว่าการสร้างImageDataวัตถุ


3
คุณอาจคิดอย่างนั้นและอาจเป็นพิกเซลเดียว แต่ถ้าคุณสร้างข้อมูลภาพล่วงหน้าและตั้งค่า 1 พิกเซลจากนั้นใช้putImageDataมันเร็วกว่า 10x fillRectใน Chrome (ดูคำตอบของฉันมากขึ้น)
— Phrogz

2

วาดสี่เหลี่ยมเหมือน sdleihssirhc พูด!

ctx.fillRect (10, 10, 1, 1);

^ - ควรวาดสี่เหลี่ยม 1x1 ที่ x: 10, y: 10


1

อืมคุณสามารถสร้างเส้นกว้าง 1 พิกเซลด้วยความยาว 1 พิกเซลและทำให้ทิศทางเคลื่อนที่ไปตามแกนเดียว

            ctx.beginPath();
            ctx.lineWidth = 1; // one pixel wide
            ctx.strokeStyle = rgba(...);
            ctx.moveTo(50,25); // positioned at 50,25
            ctx.lineTo(51,25); // one pixel long
            ctx.stroke();

1
ฉันใช้การวาดพิกเซลเป็น FillRect, PutImage และ LineTo และสร้างตัวเรียงลำดับที่: plnkr.co/edit/tww6e1VY2OCVY4c4ECy3?p=preview ลองดูเพราะ LineTo ช้าลงอย่างมาก สามารถทำ 100,000 คะแนน w อีก 2 วิธีใน 0.25 วินาที แต่ 10,000 คะแนนกับ LineTo ใช้เวลา 5 วินาที
— raddevus

1
โอเคฉันทำผิดพลาดและฉันต้องการปิดลูป รหัส LineTo ขาดหายไปหนึ่งบรรทัดสำคัญมากซึ่งมีลักษณะดังนี้: ctx.beginPath (); ฉันอัปเดตพลั่วเกอร์ (ที่ลิงก์จากความคิดเห็นอื่นของฉัน) และเพิ่มที่หนึ่งบรรทัดตอนนี้อนุญาตให้วิธี LineTo สร้าง 100,000 ใน 0.5 วินาทีโดยเฉลี่ย น่าทึ่งทีเดียว ดังนั้นหากคุณจะแก้ไขคำตอบของคุณและเพิ่มบรรทัดนั้นในรหัสของคุณ (ก่อนหน้าบรรทัด ctx.lineWidth) ฉันจะลงคะแนนให้คุณ ฉันหวังว่าคุณจะพบสิ่งที่น่าสนใจและฉันขอโทษสำหรับรหัสรถบั๊กกี้ดั้งเดิมของฉัน
— raddevus

1

ให้เสร็จสมบูรณ์ Phrogz คำตอบอย่างมากมีความแตกต่างที่สำคัญระหว่างและ fillRect() บริบทการใช้ครั้งแรกในการวาดมากกว่าโดยการเพิ่มรูปสี่เหลี่ยมผืนผ้า (ไม่พิกเซล) โดยใช้สไตล์การเติมสีค่าอัลฟาและบริบทglobalAlphaและเมทริกซ์การเปลี่ยนแปลง , หมวกบรรทัด ฯลฯ ..แทนที่ทั้งสองชุดของพิกเซล (อาจจะเป็นหนึ่ง แต่ทำไม ?) ผลที่ได้จะแตกต่างกันที่คุณสามารถดูบนjsperfputImageData()



ไม่มีใครต้องการตั้งค่าหนึ่งพิกเซลในแต่ละครั้ง (หมายถึงการวาดภาพบนหน้าจอ) นั่นคือเหตุผลที่ไม่มี API เฉพาะที่จะทำ (และถูกต้อง)
ผลการดำเนินงานที่ชาญฉลาดถ้าเป้าหมายคือการสร้างภาพ (ตัวอย่างเช่นซอฟต์แวร์ ray ติดตาม), คุณมักจะต้องการที่จะใช้อาร์เรย์ที่ได้จากการgetImageData()ซึ่งเป็นที่ดีที่สุด Uint8Array แล้วคุณโทรครั้งเดียวหรือไม่กี่ครั้งต่อวินาทีโดยใช้putImageData()setTimeout/seTInterval


ฉันมีกรณีที่ฉันต้องการวางบล็อกขนาด 100k ลงในภาพ แต่ไม่ได้มีขนาด 1: 1 พิกเซล การใช้งานfillRectนั้นเจ็บปวดเพราะการเร่งความเร็ว h / w ของ Chrome ไม่สามารถรับมือกับการเรียก GPU แต่ละตัวได้ ในที่สุดฉันก็ต้องใช้ข้อมูลพิกเซลที่ 1: 1 แล้วใช้การปรับขนาด CSS เพื่อให้ได้ผลลัพธ์ที่ต้องการ มันน่าเกลียด :(
— Alnitak

การใช้เกณฑ์มาตรฐานที่เชื่อมโยงกับ Firefox 42 ฉันได้รับเพียง 168 Ops / วินาทีget/putImageDataแต่ 194,893 สำหรับfillRectแต่สำหรับ1x1 image dataคือ 125,102 Ops / วินาที ดังนั้นfillRectชนะโดยไกลใน Firefox ดังนั้นสิ่งต่าง ๆ จึงเปลี่ยนไปมากระหว่างปี 2012 และวันนี้ และเช่นเคยอย่าพึ่งพาผลการวัดประสิทธิภาพเก่า
— Mecki

12
ฉันต้องการตั้งค่าครั้งละหนึ่งพิกเซล ฉันคาดเดาด้วยชื่อของคำถามนี้ที่คนอื่นทำได้เช่นกัน
— chasmani

1

รหัสการสาธิต HTML แบบเร็ว: ขึ้นอยู่กับสิ่งที่ฉันรู้เกี่ยวกับไลบรารีกราฟิก SFML C ++:

บันทึกเป็นไฟล์ HTML ด้วยการเข้ารหัส UTF-8 และเรียกใช้ รู้สึกอิสระที่จะ refactor ฉันก็เหมือนกับการใช้ตัวแปรญี่ปุ่นเพราะพวกเขามีความกระชับและไม่ใช้พื้นที่มาก

คุณจะต้องการตั้งค่าพิกเซลแบบกำหนดเองจำนวนหนึ่งแล้วค่อยแสดงบนหน้าจอ ดังนั้นใช้

PutPix(x,y, r,g,b,a) 

วิธีการวาดพิกเซลโดยพลการจำนวนมากเพื่อ back-buffer (โทรราคาถูก)

จากนั้นเมื่อพร้อมที่จะแสดงให้โทรไปที่

Apply() 

วิธีการแสดงการเปลี่ยนแปลง (โทรแพง)

รหัสไฟล์. HTML แบบเต็มด้านล่าง:

<!DOCTYPE HTML >
<html lang="en">
<head>
    <title> back-buffer demo </title>
</head>
<body>

</body>

<script>
//Main function to execute once 
//all script is loaded:
function main(){

    //Create a canvas:
    var canvas;
    canvas = attachCanvasToDom();

    //Do the pixel setting test:
    var test_type = FAST_TEST;
    backBufferTest(canvas, test_type);
}

//Constants:
var SLOW_TEST = 1;
var FAST_TEST = 2;


function attachCanvasToDom(){
    //Canvas Creation:
    //cccccccccccccccccccccccccccccccccccccccccc//
    //Create Canvas and append to body:
    var can = document.createElement('canvas');
    document.body.appendChild(can);

    //Make canvas non-zero in size, 
    //so we can see it:
    can.width = 800;
    can.height= 600;

    //Get the context, fill canvas to get visual:
    var ctx = can.getContext("2d");
    ctx.fillStyle = "rgba(0, 0, 200, 0.5)";
    ctx.fillRect(0,0,can.width-1, can.height-1);
    //cccccccccccccccccccccccccccccccccccccccccc//

    //Return the canvas that was created:
    return can;
}

//THIS OBJECT IS SLOOOOOWW!
// 筆 == "pen"
//T筆 == "Type:Pen"
function T筆(canvas){


    //Publicly Exposed Functions
    //PEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPE//
    this.PutPix = _putPix;
    //PEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPE//

    if(!canvas){
        throw("[NilCanvasGivenToPenConstruct]");
    }

    var _ctx = canvas.getContext("2d");

    //Pixel Setting Test:
    // only do this once per page
    //絵  =="image"
    //資  =="data"
    //絵資=="image data"
    //筆  =="pen"
    var _絵資 = _ctx.createImageData(1,1); 
    // only do this once per page
    var _筆  = _絵資.data;   


    function _putPix(x,y,  r,g,b,a){
        _筆[0]   = r;
        _筆[1]   = g;
        _筆[2]   = b;
        _筆[3]   = a;
        _ctx.putImageData( _絵資, x, y );  
    }
}

//Back-buffer object, for fast pixel setting:
//尻 =="butt,rear" using to mean "back-buffer"
//T尻=="type: back-buffer"
function T尻(canvas){

    //Publicly Exposed Functions
    //PEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPE//
    this.PutPix = _putPix;
    this.Apply  = _apply;
    //PEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPE//

    if(!canvas){
        throw("[NilCanvasGivenToPenConstruct]");
    }

    var _can = canvas;
    var _ctx = canvas.getContext("2d");

    //Pixel Setting Test:
    // only do this once per page
    //絵  =="image"
    //資  =="data"
    //絵資=="image data"
    //筆  =="pen"
    var _w = _can.width;
    var _h = _can.height;
    var _絵資 = _ctx.createImageData(_w,_h); 
    // only do this once per page
    var _筆  = _絵資.data;   


    function _putPix(x,y,  r,g,b,a){

        //Convert XY to index:
        var dex = ( (y*4) *_w) + (x*4);

        _筆[dex+0]   = r;
        _筆[dex+1]   = g;
        _筆[dex+2]   = b;
        _筆[dex+3]   = a;

    }

    function _apply(){
        _ctx.putImageData( _絵資, 0,0 );  
    }

}

function backBufferTest(canvas_input, test_type){
    var can = canvas_input; //shorthand var.

    if(test_type==SLOW_TEST){
        var t筆 = new T筆( can );

        //Iterate over entire canvas, 
        //and set pixels:
        var x0 = 0;
        var x1 = can.width - 1;

        var y0 = 0;
        var y1 = can.height -1;

        for(var x = x0; x <= x1; x++){
        for(var y = y0; y <= y1; y++){
            t筆.PutPix(
                x,y, 
                x%256, y%256,(x+y)%256, 255
            );
        }}//next X/Y

    }else
    if(test_type==FAST_TEST){
        var t尻 = new T尻( can );

        //Iterate over entire canvas, 
        //and set pixels:
        var x0 = 0;
        var x1 = can.width - 1;

        var y0 = 0;
        var y1 = can.height -1;

        for(var x = x0; x <= x1; x++){
        for(var y = y0; y <= y1; y++){
            t尻.PutPix(
                x,y, 
                x%256, y%256,(x+y)%256, 255
            );
        }}//next X/Y

        //When done setting arbitrary pixels,
        //use the apply method to show them 
        //on screen:
        t尻.Apply();

    }
}


main();
</script>
</html>


-1

มีประโยชน์และนำเสนอฟังก์ชั่นใส่พิกเซล (pp) (ES6) (อ่านค่าพิกเซลที่นี่ ):

let pp= ((s='.myCanvas',c=document.querySelector(s),ctx=c.getContext('2d'),id=ctx.createImageData(1,1)) => (x,y,r=0,g=0,b=0,a=255)=>(id.data.set([r,g,b,a]),ctx.putImageData(id, x, y),c))()

pp(10,30,0,0,255,255);    // x,y,r,g,b,a ; return canvas object

ฟังก์ชั่นนี้ใช้putImageDataและมีส่วนเริ่มต้น (บรรทัดแรกยาว) ที่จุดเริ่มต้นแทนที่จะs='.myCanvas'ใช้ตัวเลือก CSS กับ Canvas ของคุณ

ฉันต้องการเปลี่ยนค่าพารามิเตอร์เป็นมาตรฐานตั้งแต่ 0-1 คุณควรเปลี่ยนค่าเริ่มต้นa=255เป็นa=1และสอดคล้องกับ: id.data.set([r,g,b,a]),ctx.putImageData(id, x, y)เป็น id.data.set([r*255,g*255,b*255,a*255]),ctx.putImageData(id, x*c.width, y*c.height)

โค้ดที่มีประโยชน์ด้านบนนั้นดีสำหรับอัลกอริธึมการทดสอบแบบ ad-hoc หรือพิสูจน์แนวคิด แต่มันก็ไม่ดีที่จะใช้ในการผลิตที่โค้ดควรอ่านและชัดเจน


1
ลงคะแนนสำหรับภาษาอังกฤษที่ไม่ดีและซับหนึ่งที่รก
— ซาเวียร์

1
@xavier - ภาษาอังกฤษไม่ใช่ภาษาแม่ของฉันและฉันไม่เก่งในการเรียนรู้ภาษา foregin แต่คุณสามารถแก้ไขคำตอบและแก้ไขข้อบกพร่องด้านภาษาได้ (มันจะเป็นผลดีจากคุณ) ฉันใส่ซับในอันนี้เพราะสะดวกและใช้งานง่าย - และสามารถเป็นตัวอย่างที่ดีสำหรับนักเรียนที่จะทดสอบอัลกอริธึมกราฟิกบางอย่าง แต่มันก็ไม่ใช่วิธีแก้ปัญหาที่ดีที่จะใช้ในการผลิตที่ควรอ่านโค้ดได้ชัดเจน
— Kamil Kiełczewski

3
@ KamilKiełczewski Code การอ่านและชัดเจนเป็นสิ่งสำคัญสำหรับนักเรียนเช่นเดียวกับสำหรับมืออาชีพ
— รถกระบะโลแกน

-2

putImageData อาจเร็วกว่า fillRectโดยกำเนิด ฉันคิดว่านี่เป็นเพราะพารามิเตอร์ที่ห้าสามารถมีวิธีที่แตกต่างกันที่จะได้รับมอบหมาย (สีสี่เหลี่ยมผืนผ้า) โดยใช้สตริงที่ต้องตีความ

สมมติว่าคุณทำเช่นนั้น:

context.fillRect(x, y, 1, 1, "#fff")
context.fillRect(x, y, 1, 1, "rgba(255, 255, 255, 0.5)")`
context.fillRect(x, y, 1, 1, "rgb(255,255,255)")`
context.fillRect(x, y, 1, 1, "blue")`

ดังนั้นสาย

context.fillRect(x, y, 1, 1, "rgba(255, 255, 255, 0.5)")`

หนักที่สุดระหว่างทั้งหมด อาร์กิวเมนต์ที่ห้าในการfillRectโทรเป็นสายยาวขึ้นอีกเล็กน้อย


1
เบราว์เซอร์ใดที่สนับสนุนการส่งผ่านสีเป็นอาร์กิวเมนต์ที่ 5 สำหรับ Chrome ฉันต้องใช้context.fillStyle = ...แทน developer.mozilla.org/en-US/docs/Web/API/…
— iX3
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.