Published
Edited
Feb 13, 2022
1 fork
5 stars
Also listed in…
Computer Graphics
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
bigTriangle = new Float32Array([-5, -5, 5, -5, 0, 5])
Insert cell
### Function to map transfer functions to a fragment shader color array
Insert cell
function smoothStep(edge0, edge1, x) {
// Scale, bias and saturate x to 0..1 range
x = Math.min(Math.max((x - edge0) / (edge1 - edge0), 0.0), 1.0);
// Evaluate polynomial
return x * x * (3 - 2 * x);
}
Insert cell
function tfToColors(tf, options = {}) {
const { xdomain = [-1, 1], sharpen = 0, n = 256 } = options;
const smooth = sharpen - 2;
const s = smooth > -2 ? Math.pow(10, smooth) : 1e-10;
const colors = d3.range(n).map((i) => {
let v = -1.0 + (2 * i) / (n - 1);
for (let { x1, x2, y, color } of tf) {
if (v >= x1 && v < x2) {
let alpha = smooth
? smoothStep((x2 - x1) / 2, 0, Math.abs(v - (x2 + x1) / 2)) ** s
: 1;
return { color, y: y * alpha };
}
}
return { color: 0, y: 0 };
});
return colors;
}
Insert cell
Insert cell
Insert cell
{
let colors = tfToColors(tf, { sharpen, n: 512 });
return Plot.plot({
width,
height: 300,
margin: 40,
style: {
userSelect: "none",
background: "black",
color: "white",
fontSize: "14px"
},
x: {
grid: true,
tickFormat: (d, i) => (i % ~~(colors.length / 10) == 0 ? d : ""),
label: "Field value →"
},
y: {
grid: true,
label: "↑ alpha",
domain: [0, 1]
},
color: {
domain: [0, 1, 2, 3, 4],
range: palette
},
marks: [
Plot.barY(colors, {
x: (d, i) => i,
y: (d, i) => d.y,
fill: "color"
}),
Plot.ruleY([0])
]
});
}
Insert cell
Insert cell
palette = ["white", "orange", "#77ff77", "cyan", "#aa11ff"]
Insert cell
Insert cell
Insert cell
Insert cell
canvasSize = ({ width: 800, height: 600 })
Insert cell
Insert cell
class Arcball {
constructor(canvas) {
this.canvas = canvas;
this.center = [canvas.width / 2, canvas.height / 2];
this.radius = (Math.min(canvas.width, canvas.height) / 2) * 0.9;
this.prev = [];
this.transform = mat4.create();
this.mouseIsDown = false;
}
ballPos(p) {
let u = vec2.sub([], p, this.center);
if (vec2.len(u) >= this.radius) return vec3.normalize([], [...u, 0]);
let z = Math.sqrt(this.radius ** 2 - u[0] ** 2 - u[1] ** 2);
return vec3.normalize([], [...u, z]);
}
mousedown(x, y) {
this.mouseIsDown = true;
this.prev = [x, y];
}
mousemove(x, y) {
if (!this.mouseIsDown) return this.transform;
let mouse = [x, y];
let u = this.ballPos(this.prev);
let v = this.ballPos(mouse);
this.prev = mouse;
let axis = vec3.cross([], v, u);
let ang = Math.asin(vec3.len(axis));
let rot = mat4.fromRotation([], ang, vec3.normalize([], axis));
[this.u, this.v, this.ang, this.axis] = [u, v, ang, axis];
return mat4.mul(this.transform, this.transform, rot);
}
mouseup(x, y) {
this.mouseIsDown = false;
}
}
Insert cell
Insert cell
headBuffer = {
const zip = await FileAttachment("head256x256x109.zip").zip();
const file = zip.file("head256x256x109");
const buffer = await file.arrayBuffer();
const byteArray = new Uint8Array(buffer);
return byteArray;
}
Insert cell
Insert cell
headAspect = [1, -1, 1 / 1.65]
Insert cell
Insert cell
Insert cell
import { TransferFunctionInput } from "@esperanc/transfer-function-input"
Insert cell
Insert cell
mat4 = glmatrix.mat4
Insert cell
vec2 = glmatrix.vec2
Insert cell
vec3 = glmatrix.vec3
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