วิธีที่ดีที่สุดในการตั้งค่าพิกเซลเดียวในผืนผ้าใบ 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.