Public
Edited
Oct 26, 2023
7 stars
Also listed in…
Arty
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
// source: https://observablehq.com/@saneef/rams-palette
rams = ({
DR01: ["#AAB7BF", "#736356", "#BFB1A8", "#AD1D1D", "#261201"],
DR02: ["#84754A", "#3A3124", "#96937D", "#B9ADA4", "#0D0000"],
DR03: ["#BF7C2A", "#C09C6F", "#5F503E", "#9C9C9C", "#E1E4E1"],
DR04: ["#84764B", "#B7B183", "#372E2D", "#ВСВЗА6", "#DBD7D3"],
DR05: ["#AF2E1B", "#CC6324", "#3B4B59", "#BFA07A", "#D9C3B0"],
DR06: ["#ED8008", "#ED3F1C", "#BF1B1B", "#736B1E", "#D9D2C6"],
})
Insert cell
fills = rams[controls.palette]
Insert cell
brAun = [1, 6, 12, 20, 24, 32, 36]
Insert cell
ring = d3.range(7)
Insert cell
patterns = [
["brAun", brAun],
["clocky", [1, 6, 12, 12, 12, 12, 12]],
["fib", [1, 5, 8, 13, 21, 34, 55]],
["3s", [1, 3, 3, 3, 3, 3, 3]],
["4s", [1, 4, 4, 4, 4, 4, 4]],
["5s", [1, 5, 5, 5, 5, 5, 5]],
["6s", [1, 6, 6, 6, 6, 6, 6]],
["161616", [1, 4, 8, 16, 16, 16, 16]],
["twobands", [0, 8, 0, 18, 26, 32, 26]],
["2×n", ring.map(x => 2 * x)],
["2^n", ring.map(x => 2 ** x)],
["3^n", ring.map(x => 3 ** x)],
]
Insert cell
presets = patterns.map(([label, values]) => [label, () => values])
Insert cell
// this cell runs whenever preset[] changes
// preset[] changes whenever a preset button is clicked
{
rings.forEach((ring, i) => set(ring, preset[i]));
return preset;
}
Insert cell
grill = griller(grillR)(holes.map(d => d3.range(d)))
Insert cell
aspect = ({
tall: 9 * 5,
wide: 9 * 4,
})
Insert cell
w = 36 * 12 // multiple of abundant number 36
Insert cell
R = 15 // radius of buttons in px
Insert cell
rings = [
viewof ring0,
viewof ring1,
viewof ring2,
viewof ring3,
viewof ring4,
viewof ring5,
viewof ring6,
]
Insert cell
domain = ({
x: [0, aspect.wide].map(x => (x - 2) / 4 - 4),
y: [0, aspect.tall].map(x => (x - 3) / 4 - 6),
})
Insert cell
holes = [ring0, ring1, ring2, ring3, ring4, ring5, ring6]
Insert cell
settings = ({
...controls,
aspect,
size: {width: w, height: w * aspect.tall / aspect.wide},
domain,
margin: 36,
R,
})
Insert cell
DieterRamsPalette =
(settings) =>
({
holes, // number of holes per ring
grill, // list of (x, y) coordinates of holes, derived from holes above
fills, // list of colors of current palette
}) =>
{

const {aspect, size, margin, domain, axis, grid, interval, R, palette} = settings;
const {width, height} = size;
const gridSetting = ({interval: 1 / interval, stroke: "black", strokeOpacity: 0.1})
const dom = (d) => ({ // set up equal domains for x and y
domain: domain[d],
ticks: Math.abs(domain[d][1] - domain[d][0]),
label: null,
});
const [x, y] = ["x", "y"].map(dom);

return Plot.plot({
axis,
grid,
width,
height,
margin,
x,
y,

marks: [

Plot.rect([0], {fill: "#EEEFE9"}), // background

// grid lines
grid ? Plot.gridX(gridSetting) : null,
grid ? Plot.gridY(gridSetting) : null,

// holes
Plot.text([0], { // holes configuration
y: +5,
fill: "gray",
text: () => holes.join(", "),
}),
Plot.dot(grill, {fill: "black", r}), // grill: holes per ring

// color palette buttons
Plot.dot(fills, { // color palette
x: (_, i, {length}) => i * 6/(length - 1) - 3,
y: -5,
r: R,
fill: fills,
stroke: "dimgray",
}),
Plot.text(fills, { // color hex codes
text: d => d.slice(1),
x: (_, i) => i * 1.35 - 2.7,
x: (_, i, {length}) => i * 6/(length - 1) - 3,
y: -4.0,
fontSize: "smaller",
lineAnchor: "top",
}),

// footer
Plot.text([null], { // palette artist
text: () => "Dieter Rams Palette",
x: -4, y: -6.5,
fontWeight: "bold",
fontSize: "larger",
lineAnchor: "bottom",
textAnchor: "start",
}),
Plot.text([null], { // palette name
text: () => palette,
x: 4, y: -6.5,
fontSize: "larger",
lineAnchor: "bottom",
textAnchor: "end",
}),

]
})
}
Insert cell
griller = (R = 2) => (holes) => d3
.range(holes.length)
.map((r) => holes[r].map(coord(r * R / 3 / 2)))
.flat()
;
Insert cell
coord = (r) => (x, _, a) => [
sin(x, a) * r,
cos(x, a) * r,
]
Insert cell
sin = xy(Math.sin)
Insert cell
cos = xy(Math.cos)
Insert cell
xy = (tri) => (x, {length}) => tri(TAU * x / length)
Insert cell
TAU = 2 * Math.PI
Insert cell
// kudos Mike Bostock https://observablehq.com/@observablehq/synchronized-inputs
set = (input, value) => {
input.value = value;
input.dispatchEvent(new Event("input"));
return value
}
Insert cell
Insert cell
// generates an object literal for us in Inputs.form
ringers = (rings) =>
rings.reduce(
(accu, ring, i) =>
({
...accu,
[`ring${i}`]: Inputs.range([0, 55], {label: `ring ${i}`, value: ring, step: 1})
}),
{})
Insert cell
ringers(rings)
Insert cell
Insert cell
// import {columns} from "@martien/inputs"
columns = (count = 2) => (inputs) => htl.html`<div class="styled">${Object.values(inputs)}</div>
<style>
div.styled { column-count: ${count}; }
</style>`
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