Published
Edited
Sep 6, 2022
Importers
8 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function raster_grid(config = {}) {
// Parse arguments
let { value, grid_width=width, grid_height = 100, verticalUp = true, size, numberH, numberV, grid = true, centers = true, mousedown, title, description } = config;
// How big is the grid? Use size if given; otherwise, largest number horizontally or vertically
if(size == null && numberH == null && numberV == null) size = "10%";
if(size != null)
{
numberH = null; numberV = null;
size = pixelSize(size, grid_width, grid_height);
}
else
{
if(numberH != null && numberV != null) if(numberH > numberV) numberV = null; else numberH = null;
size = numberH != null ? grid_width / Math.max(1, numberH) : grid_height / Math.max(1, numberV);
}
if(size < 8)
// No centers info if pixels too small
centers = false;
if(size < 3)
grid = false; // No grid if pixels too small.

// Generate mouse handler if there is none
const i_max = Math.round(grid_width / size);
const j_max = Math.round(grid_height / size);
if(mousedown == null)
{
mousedown = function([i,j])
{
if(value[(i_max * j + i) * 4 + 3])
{
// Turn off
value[(i_max * j + i) * 4 + 3] = 0;
d3.select(this).attr("fill", "none");
}
else
{
// Turn on
value[(i_max * j + i) * 4 + 3] = 255;
d3.select(this).attr("fill", "rgba(" + value[(i_max * j + i) * 4] +
"," + value[(i_max * j + i) * 4 + 1] +
"," + value[(i_max * j + i) * 4 + 2] +
"," + value[(i_max * j + i) * 4 + 3] / 255 + ")");
}
d3.event && d3.event.preventDefault();
form.dispatchEvent(new CustomEvent("input"));
}
}
// Build the raster
if(value == null) value = new Uint8ClampedArray(i_max * j_max * 4);
const raster = d3.select(html`<svg width="${grid_width}" height="${grid_height}"></svg>`)
const svg_grid = raster.selectAll("g")
.data(d3.range(i_max * j_max).map( (idx) => [idx % i_max, Math.floor(idx / i_max)]))
.enter().append("g");
if(centers) svg_grid.append("circle")
.attr("class", "raster_center")
.attr("stroke", "none")
.attr("fill", "steelblue")
.attr("r", 2)
.attr("cx", ([i,j]) => (i + 0.5) * size)
.attr("cy", ([i,j]) => verticalUp ? grid_height - (j + 0.5) * size : (j + 0.5) * size);
svg_grid.append("rect")
.attr("class", "raster_grid")
.attr("id", ([i,j]) => "grid" + i + "_" + j)
.attr("stroke", `${grid ? "steelblue" : "none" }`)
.attr("fill", ([i,j]) => "rgba(" + value[(i_max * j + i) * 4] +
"," + value[(i_max * j + i) * 4 + 1] +
"," + value[(i_max * j + i) * 4 + 2] +
"," + value[(i_max * j + i) * 4 + 3] / 255 + ")")
.attr("x", ([i,j]) => i * size)
.attr("y", ([i,j]) => verticalUp ? grid_height - (j + 1) * size : j * size)
.attr("width", ([i,j]) => size)
.attr("height", ([i,j]) => size)
.attr("pointer-events", "fill")
.on("mousedown", mousedown);

// Generate form using Inputs library; trim what we don't need and return.
const form = input({
type: "hidden",
title,
description,
action: (form) => null,
form: html`<form>${raster.node()}</form>`
});
form.output.remove();
form.value = value;
return form;
}
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more