Public
Edited
Jan 20, 2023
Paused
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function simulate() {
// PARAMETERS
// ===

const spacing = 6;
const debug = false;
const antigravity = 0.4;

// HELPER FUNCTIONS
// ===

function distBetween(a, b) {
return (
Math.sqrt(
Math.pow(b.pos.x - a.pos.x, 2) + Math.pow(b.pos.y - a.pos.y, 2)
) -
a.size / 2 -
b.size / 2 -
spacing
);
}

function calcPos(s, R) {
let rd = s.size * antigravity;
let y = Math.sin(s.p + 0.5 * Math.PI) * (R + rd);
let x = Math.cos(s.p + 0.5 * Math.PI) * (R + rd);
return { x, y };
}

function assertStillValid(state) {
for (let i = 0; i < 6; i++) {
let a = state[i];
let b = state[i + 1];
if (b.p < a.p) {
throw new Error(
`no longer valid at circle ${i}. State: ${JSON.stringify(
state.map((s) => s.p)
)}`
);
}
}
}

function totalDistBetween(state) {
let total = 0;
for (let i = 0; i < 7; i++) {
let a = state[i];
let b = state[(i + 1) % 7];
total += distBetween(a, b);
}

return total;
}

function thread({ state, R }) {
let totalSteps = 0;

for (let i = 0; i < 6; i++) {
debug && console.log(" thread", i);
let a = state[i];
let b = state[i + 1];

let d,
steps = 0;
while (
((d = distBetween(a, b)),
++totalSteps,
++steps < 1000 && Math.abs(d) > 0.1)
) {
for (let j = i + 1; j < 7; j++) {
let b = state[j];
b.p = Math.min(
2 * Math.PI - 0.05, // 2 * Math.PI - 0.1,
b.p + -Math.sign(d) * 0.0001 * Math.PI
);
b.pos = calcPos(b, R);
}

debug &&
console.log(" ", state.map((s) => s.p.toFixed(2)).join(", "));

debug && assertStillValid(state);
}
}

return { state, R, totalSteps };
}

// THE SIMULATION
// ===

let R = 150;
let steps = 0;

let state = emotions.map((emotion, i) => {
const size = diameter[values[emotions[i]]];
const color = colors[emotions[i]];
const p = (i / 7) * 2 * Math.PI;

let s = { i, emotion, size, color, p };
s.pos = calcPos(s, R);

return s;
});

debug && assertStillValid(state);

let totalDist,
iterations = 0;
while (
((totalDist = totalDistBetween(state)),
++iterations < 10_000 && Math.abs(totalDist) > 1)
) {
R += -Math.sign(totalDist) * 0.05;

state = state.map((s) => {
s.pos = calcPos(s, R);
return s;
});

debug && assertStillValid(state);

let r = thread({ state, R });
state = r.state;
steps += r.totalSteps;

debug && assertStillValid(state);
}

return { state, iterations, steps };
}
Insert cell
Insert cell
Insert cell
Insert cell
xlen = ({
sad: 3,
stressed: 7,
frustrated: 8,
energetic: 7.5,
happy: 5,
relaxed: 6.5,
fatigued: 6.5
})
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