Published
Edited
Jul 15, 2021
2 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
mutable contours_ = []
Insert cell
Insert cell
viewof columns = Inputs.range([10, 200], { step: 10 })
Insert cell
viewof maxLines = Inputs.range([3, 20], { step: 1 })
Insert cell
{
const context = DOM.context2d(imageWidth, imageHeight, 1);
context.drawImage(image, 0, 0, imageWidth, imageHeight);

context.canvas.style.width = "400px";
context.canvas.style.border = "1px solid black";

// const columns = 100;

const grid = getCells(columns).map((cell) => {
const { x, y, width, height } = cell;
const pixels = getPixels2({
context,
x,
y,
width,
height
});
const maxLightness = d3.max(pixels, (d) => d.lightness);
const meanLightness = d3.mean(pixels, (d) => d.lightness);
return {
...cell,
maxLightness,
meanLightness
};
});

// const maxDots = 1500 / columns;
// const maxDots = 10;

// // const maxDots = 20;
// const numDotsScale = d3.scaleLinear([0, 255], [0, maxDots]);

// const allDots = grid
// .map((cell) => {
// const numDots = Math.ceil(numDotsScale(cell.meanLightness));
// const dots = d3.range(numDots).map(() => {
// const x = cell.x + Math.random() * cell.width;
// const y = cell.y + Math.random() * cell.height;
// return { x, y };
// });
// return dots;
// })
// .flat(1)
// .map((d) => htl.svg`<circle r="1" cx=${d.x} cy=${d.y} />`);

// const maxLines = 200 / columns;
// const maxLines = d3.scaleLinear([10, 200], [15, 5])(columns);

const numLinesScale = d3.scaleLinear([0, 255], [1, maxLines]);

const hatching = grid
.map((cell) => {
const numLines = Math.ceil(numLinesScale(cell.meanLightness));
const hatchLines = hatchDiagonal({
...cell,
n: numLines,
stroke: `rgba(0, 0, 0, 0.5)`
});
console.log("hatchlines", hatchLines);
return hatchLines;
})
.flat(1);

const children = hatching;

return htl.html`
<svg viewBox="0 0 ${imageWidth} ${imageHeight}" style="width: 400px; border: 1px dashed red;">
${children}
</svg>
`;
}
Insert cell
{
const context = DOM.context2d(imageWidth, imageHeight, 1);
context.drawImage(image, 0, 0, imageWidth, imageHeight);

context.canvas.style.width = "400px";
context.canvas.style.border = "1px solid black";

const cells = getCells(200).map((cell) => {
const { x, y, width, height } = cell;
const pixels = getPixels2({
context,
x,
y,
width,
height
});
const average = d3.mean(pixels, (d) => d.lightness);
return [x, y, average];
});

const bumpMax = 20;
const bumpScale = d3.scaleLinear([0, 255], [0, bumpMax]);

const lines = d3
.groups(cells, (d) => d[1])
.map(([rowY, values]) => {
const chunks = values
.map(([x, y, lightness]) => {
const bump = bumpScale(lightness);
return `L ${x} ${y - bump}`;
})
.join(" ");
return `M 0 ${rowY} ${chunks}`;
})
.map((pathDef) => {
return htl.svg`<path fill="none" stroke="black" d=${pathDef} />`;
})
.filter((d, i) => i % 2 === 0);

const children = lines;
return htl.html`<svg viewBox=${`0 0 ${imageWidth} ${imageHeight}`} style="border: 1px dashed black; width: 400px">${children}</svg>`;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
import { hatchDiagonal, hatchHorizontal } from "@plmrry/diy-svg-hatching"
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