Published
Edited
Aug 28, 2022
4 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function drag(g, svg, size) {
let x, y, free;

g.each((d, i) => {
d.slot = i;
d.x = placeX(d.slot, size);
d.y = placeY(d.slot, size);
})
.attr(
"transform",
(d) => `translate(${placeX(d.slot, size)},${placeY(d.slot, size)})`
);

function dragstart(e, d) {
d3.select(this).raise().classed("active", true);

x = +d.x - e.x;
y = +d.y - e.y;
free = d.slot;
}

function dragged(e, d) {
console.log(e.x, e.y);
const xx = Math.max(0, e.x),
yy = Math.max(0, e.y);

d.x = xx;
d.y = yy;

d3.select(this).attr("transform", (d) => `translate(${xx},${yy})`);

let p = Math.round(xx / size) + cols * Math.round(yy / size);

svg.value = g.data().map((d) => d.slot);
svg.dispatchEvent(new CustomEvent("input"));

if (p === d.slot) return;

g.each(function (e) {
if (e !== d && e.slot === p) {
e.slot = free;
d.slot = free = p;

d3.select(this)
.transition()
.attr(
"transform",
(d) => `translate(${placeX(e.slot, size)},${placeY(e.slot, size)})`
);
}
});
}

function dragend(e, d) {
d.slot = free;
d3.select(this)
.transition()
.attr(
"transform",
(d) => `translate(${placeX(d.slot, size)},${placeY(d.slot, size)})`
);

free = -1;
d3.select(this).classed("active", false);
}

const d = d3
.drag()
.on("start", dragstart)
.on("drag", dragged)
.on("end", dragend);

svg.value = g.data().map((d) => d.slot);
svg.dispatchEvent(new CustomEvent("input"));

return d(g);
}
Insert cell
placeX = (slot, size) => (slot % cols) * size
Insert cell
placeY = (slot, size) => Math.floor(slot / cols) * size
Insert cell
numOfCells = cols * rows
Insert cell
cells = d3.range(numOfCells).map((_) => ({}))
Insert cell
width = 640
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