JSFiddle - React, Tailwind, and code Playground

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.4.4/d3.min.js"></script>

JavaScript

// Part 1

viewof image1 = imageInput({
  height: 350,
  crossOrigin: "anonymous",
  initialUrl: rioMoscovaUrl,
})


// Part 2

html`
${image} ${image.src === rioMoscovaUrl ? rioMoscovaAttribution : ""}
`


// Part 3

{
  const height = width / 4;
  const margin = 2;
  
  const x = d3.scaleLinear()
    .domain([0, 256])
    .range([0 + margin, width - margin])
  const y = d3.scaleLinear()
    .domain([0, d3.max(histogram.map(x => d3.max(x.data)))])
    .range([height - margin, 0 + margin])
  
  const area = d3.area()
    .x((_, i) => x(i))
    .y0(y(0))
    .y1((d, _) => y(d))
    .curve(d3.curveStepAfter)
  
  const svg = d3.create("svg")
    .attr("width", width)
    .attr("height", height)
    .attr("class", "histogram")
    .style("background-color", "#333")
    .style("isolation", "isolate");
    
  for (const channel of histogram) {
    svg.append("path")
      .attr("class", channel.name)
      // duplicate the last data point so that the right-most step is drawn correctly
      .attr("d", area([...channel.data, channel.data.slice(-1)]))
      .attr("fill", channel.color)
      .attr("stroke", channel.color)
      .style("mix-blend-mode", "screen")
  }
  
  return svg.node()
}


// Part 4

{
  // dividing the histogram into channels like this is @lemonnish's idea
  const histogram = [
    { name: "red",   color: "#ff0000", data: new Uint32Array(256) },
    { name: "green", color: "#00ff00", data: new Uint32Array(256) },
    { name: "blue",  color: "#0000ff", data: new Uint32Array(256) },
  ];

  const { data } = getImageData(image);
    
  for (let i = 0; i < data.length; i += 4) {
    let pixel = data.slice(i, i + 3);
    ++histogram[0].data[pixel[0]];
    ++histogram[1].data[pixel[1]];
    ++histogram[2].data[pixel[2]];
  }
  
  return histogram;
}


// Part 5

getImageData = ƒ(…)

function getImageData(image, width = image.naturalWidth, height = image.naturalHeight) {
  const context = DOM.context2d(width, height, 1);
  context.drawImage(image, 0, 0,...