Public
Edited
Oct 19, 2023
1 fork
Insert cell
Insert cell
viewof depth = Inputs.range([0, 13], { label: "Depth", step: 1, value: 11 })
Insert cell
Insert cell
maskBoundary = {
const numberOfObjects = 1; // Change this to the number of objects you want in the array

const objectsArray = Array.from({ length: numberOfObjects }, () => ({
x: 0,
y: 0,
radius: 900
}));

function getRandomCoordinate(min, max) {
return Math.random() * (max - min) + min;
}
return objectsArray;
}
Insert cell
maskedTriangles = {
const result = [];
const boundaries = maskBoundary;
const triangles = tris;

let palettes = [
// ["#c19e82", "#302128", "#646368", "#aa9e9a", "#79483b"],
["#ccc7b4", "#5b534c", "#a7755d", "#97b9ac"],
["#bf9978", "#3a282c", "#d4c5bf", "#728d82"],
// ["#b88272", "#7e3d35", "#432728", "#868375", "#e0b0a3"],
["#c69f92", "#65685f", "#9a7261", "#7e3d2d"] //intruder
// ["#8ea6b4", "#e7eff3", "#ff8f56"]
];

for (let i = 0; i < boundaries.length; ++i) {
let kyc = someColor();
let lyc = someColor();

const paletteCurrent = random(palettes);

// let kyc = random(paletteCurrent);
// let lyc = random(paletteCurrent);

palettes = palettes.filter((palette) => palette !== paletteCurrent);
// for (const triangle of triangles) {
for (let j = 0; j < triangles.length; ++j) {
const triangle = triangles[j];

const points = triangle.points;
let allTrue = true;
let trueCount = 0;

// clr
// let kyc = random(["pink", "pink"]);
// let lyc = random(["steelblue", "blue"]);

points.forEach((point) => {
const x = Math.floor(point.x);
const y = Math.floor(point.y);
const cx = Math.floor(boundaries[i].x);
const cy = Math.floor(boundaries[i].y);
const r = Math.floor(boundaries[i].radius);

if (isPointInsideCircle(x, y, cx, cy, r)) {
trueCount = trueCount + 1;
if (trueCount === 2) {
result.push(triangle);
trueCount = 0;
if (triangle.subbed) {
triangle.colorr = "none";
} else {
// Gimmecolor
// if (random(1) < 0.005)
// kyc = random(paletteCurrent.filter((col) => col !== kyc));
// if (random(1) < 0.005)
// lyc = random(paletteCurrent.filter((col) => col !== lyc));

// Pollock
if (random(1) < 0.001) kyc = someColor();
if (random(1) < 0.001) lyc = someColor();
triangle.type === "acute"
? (triangle.colorr = kyc)
: (triangle.colorr = lyc);
}
return;
}
}
});
}
}
return result;
}
Insert cell
Insert cell
{
const decaRadius = TAU * 0.9;
const height = 500;

const data = maskedTriangles; // tris; //*.reverse();

const svg = d3
.create("svg")
.style("border", "1px solid black")
.attr("height", height)
.attr("viewBox", "-1000 -750 2000 1500");
//.style("background", "black");
// .attr("stroke-width", 1);
// Person as path
const inside = svg
.selectAll("path")
.data(data) // maskedTriangles // dec.triangles
.enter()
.append("path")
.attr("stroke", "none")
//.attr("stroke-width", 0.2)
.attr("d", (d) => lineGen(d.points))
.attr("fill", (d) => d.colorr);
// .attr("fill", (d) => (d.gen < depth - 1 ? "none" : d.color));

// Person as gorup
const parentSelection = svg
.selectAll("g")
.data(data)
.enter()
.append("g")
.attr(
"fill",
() => `rgb(${random(1, 256)}, ${random(100, 156)} ,${random(1, 6)}`
);

// // Penrose stroke tessellation
const gPaths = parentSelection
.append("path")
.attr("d", (d) => lineGen(d.points))
.attr("stroke-width", 0.1)
.attr("fill", "none");
// .attr("stroke", "black");

//Circles added at points[x,y] by using gContainer's selection
// const gCircles = parentSelection
// .selectAll("circle")
// .data((d) => d.points)
// .enter()
// .append("circle")
// .attr("cx", (d) => d.x)
// .attr("cy", (d) => d.y)
// .attr("r", 5);

// personBoundaries
// const colorContainers = svg
// .selectAll(".container")
// .data(maskBoundary)
// .join("circle")
// .attr("cx", (d) => d.x)
// .attr("cy", (d) => d.y)
// .attr("r", (d) => d.radius)
// .attr("fill", "none")
// .attr("stroke", "black")
// .attr("stroke-width", 2);

return svg.node();
}
Insert cell
seed = {
let size = 3000;
let firstTris = Array.from(
{ length: 10 },
(d, i) =>
new RobinsonTriangle({
type: "acute",
maxGen: depth,
ayc: ayc,
byc: byc,
points: [
{ x: 0, y: 0 },
{
x: Math.cos((TAU / 10) * i) * size,
y: Math.sin((TAU / 10) * i) * size
},
{
x: Math.cos((TAU / 10) * (i + 1)) * size,
y: Math.sin((TAU / 10) * (i + 1)) * size
}
]
})
).map((s, i) => (i % 2 ? s.flip() : s));
tris.push(...firstTris);
// console.log("tris", tris);
return firstTris;
}
Insert cell
mutable ayc = someColor();

Insert cell
mutable byc = someColor();
Insert cell
class RobinsonTriangle {
constructor({ points, type, gen = 0, subbed }) {
this.type = type;
this.points = points;
this.gen = gen;
this.subbed = false;
// this.ayc = ayc;
// this.byc = byc;

if (this.gen < depth) this.subdivide();

// this.type === "acute" ? (this.col = ayc) : (this.col = byc);
}
// get color() {
// //if (this.gen < depth - 2) return "none";
// if (this.subbed) return "none";
// if (random(1) < 0.01) mutable ayc = someColor();
// if (random(1) < 0.01) mutable byc = someColor();
// return this.type === "acute" ? mutable ayc : mutable byc;
// }

subdivide() {
if (this.subbed) return;
let [a, b, c] = this.points;

if (this.type === "acute") {
let p = lerpxy(a, b, 1 / PHI);
// console.log("sub1");
this.subbed = true;

let triA = new RobinsonTriangle({
type: "acute",
points: [c, p, b],
gen: this.gen + 1,
maxGen: this.maxGen
// ayc: this.ayc,
// byc: this.byc
});
let triB = new RobinsonTriangle({
type: "obtuse",
points: [p, c, a],
gen: this.gen + 1,
maxGen: this.maxGen
// ayc: this.ayc,
// byc: this.byc
});
mutable tris.push(...[triA, triB]);
// return [triA, triB];
} else {
let q = lerpxy(b, a, 1 / PHI);
let r = lerpxy(b, c, 1 / PHI);
const triA = new RobinsonTriangle({
type: "obtuse",
points: [r, c, a],
gen: this.gen + 1,
maxGen: this.maxGen
// ayc: this.ayc,
// byc: this.byc
});

const triB = new RobinsonTriangle({
type: "obtuse",
points: [q, r, b],
gen: this.gen + 1,
maxGen: this.maxGen
// ayc: this.ayc,
// byc: this.byc
});

const triC = new RobinsonTriangle({
type: "acute",
points: [r, q, a],
gen: this.gen + 1,
maxGen: this.maxGen
// ayc: this.ayc,
// byc: this.byc
});
// console.log("sub2");
// this.subbed = true;

mutable tris.push(...[triA, triB, triC]);
// return [triA, triB, triC];
}
this.subbed = true;
}
get path() {
let [a, b, c] = this.points;
return lineGen([b, a, c]);
}

get svg() {
let [a, b, c] = this.points;
// let strokeWidth = 0.1 * Math.pow(0.87, this.gen);
return htl.svg`<g>
<path d="${lineGen([b, a, c])}" fill="${this.color}"></path>
</g>`;
}

flip() {
let [a, b, c] = this.points;
return new RobinsonTriangle({ type: this.type, points: [a, c, b] });
}
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
draw = d3
.line()
.curve(d3.curveLinearClosed)
.x((d) => d[0])
.y((d) => d[1])
Insert cell
lineGen = d3
.line()
.curve(d3.curveLinearClosed)
.x((d) => d.x)
.y((d) => d.y)
Insert cell
Insert cell
Insert cell
Insert cell
deg = (d) => d / 360 * TAU
Insert cell
TAU = Math.PI * 2
Insert cell
lerp = (a, b, t) => a + (b - a) * t
Insert cell
lerpxy = (p1, p2, t) => ({ x: lerp(p1.x, p2.x, t), y: lerp(p1.y, p2.y, t) })
Insert cell
PHI = (1 + Math.sqrt(5)) / 2
Insert cell
Insert cell
function changeColors(ayc, byc) {
// periodically switch up the colors
if (random(1.0) < 0.5) ayc = someColor();
if (random(1.0) < 0.5) byc = someColor();
}
Insert cell
function someColor() {
return pollock[Math.floor(random(pollock.length))];
}
Insert cell
{
const width = 800;
const height = 400;
const gridStep = width / 16;
let p = 0;
let grids = [];
// console.log("--------");
// console.log("gridStep initial", gridStep);

const svg = d3
.create("svg")
.style("border", "1px solid black")
.attr("width", width)
.attr("height", height);
//while (p < pollock.length) {
for (let i = 0; i < height; i += gridStep) {
for (let j = 0; j < width; j += gridStep) {
grids.push([j, i]);
}
}
// }
for (let c = 0; c < simplePalette.length; ++c) {
svg
.append("rect")
.attr("width", gridStep)
.attr("height", gridStep)
.attr("x", grids[c][0])
.attr("y", grids[c][1])
.attr("fill", simplePalette[c])
.attr("stroke", "black");
}

return svg.node();
}
Insert cell
simplePalette = pollock.slice(0, 10)
Insert cell
Insert cell
Insert cell
Insert cell
d3 = require("d3@6")
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