elementColour = ({C: "#7f8c9d", N: "#3b6fb6", O: "#d9733b", F: "#2a9d8f", I: "#8e5bb5", Cl: "#2a9d8f", Br: "#a0522d"})
kindColour = ({C: "#d9733b", S: "#3b6fb6", P: "#9aa5b1"})
extent = {
const xs = mol.atoms.map(a => a[0]), ys = mol.atoms.map(a => a[1]), pad = 0.15;
return {x: [d3.min(xs) - pad, d3.max(xs) + pad], y: [d3.min(ys) - pad, d3.max(ys) + pad]};
}
atomPlot = {
const chosen = pick === null ? new Set() : new Set(mol.primitives[pick].atoms);
const bonds = mol.bonds.map(([u, v]) => ({x1: mol.atoms[u][0], y1: mol.atoms[u][1], x2: mol.atoms[v][0], y2: mol.atoms[v][1],
on: chosen.has(u) && chosen.has(v)}));
const atoms = mol.atoms.map(([x, y, el], i) => ({x, y, el, on: chosen.has(i)}));
const fade = d => (pick === null || d.on ? 1 : 0.3);
return Plot.plot({
width: 400, height: 400, inset: 18, x: {domain: extent.x, axis: null}, y: {domain: extent.y, axis: null},
marks: [
Plot.link(bonds, {x1: "x1", y1: "y1", x2: "x2", y2: "y2", stroke: d => (d.on ? "#c2541b" : "currentColor"),
strokeOpacity: d => (d.on ? 1 : 0.35), strokeWidth: d => (d.on ? 4 : 1.5)}),
Plot.dot(atoms.filter(d => d.on), {x: "x", y: "y", r: 15, fill: "#c2541b", fillOpacity: 0.25}),
Plot.dot(atoms, {x: "x", y: "y", r: 10, fill: d => elementColour[d.el], fillOpacity: fade}),
Plot.text(atoms, {x: "x", y: "y", text: "el", fill: "white", fontSize: 10, fontWeight: 700, fillOpacity: fade})
]
});
}
primPlot = {
const ps = mol.primitives.map((p, i) => ({...p, i, on: i === pick}));
const fade = d => (pick === null || d.on ? 0.95 : 0.3);
const links = mol.links.map(([u, v]) => ({x1: ps[u].x, y1: ps[u].y, x2: ps[v].x, y2: ps[v].y}));
const plot = Plot.plot({
width: 400, height: 400, inset: 18, x: {domain: extent.x, axis: null}, y: {domain: extent.y, axis: null},
r: {type: "identity"},
marks: [
Plot.link(links, {x1: "x1", y1: "y1", x2: "x2", y2: "y2", stroke: "currentColor", strokeOpacity: 0.35, strokeWidth: 1.5}),
Plot.dot(ps, {x: "x", y: "y", r: d => ({C: 17, S: 12, P: 8})[d.kind] + (d.on ? 4 : 0), fill: d => kindColour[d.kind],
stroke: d => (d.on ? "currentColor" : "none"), strokeWidth: 3, fillOpacity: fade,
title: d => `${d.label}: atoms ${d.atoms.join(", ")} (click to highlight)`}),
Plot.text(ps.filter(d => d.kind !== "P"), {x: "x", y: "y", text: "label", fill: "white", fontSize: 9, fontWeight: 700})
]
});
// clicking a primitive selects it in the "Highlight primitive" menu (clicking it again clears it)
d3.select(plot).selectAll("text").style("pointer-events", "none"); // labels must not swallow clicks
d3.select(plot).selectAll("circle").style("cursor", "pointer").each(function (_, i) {
this.addEventListener("click", () => {
viewof pick.value = pick === i ? null : i;
viewof pick.dispatchEvent(new Event("input", {bubbles: true}));
});
});
return plot;
}