Public
Edited
May 29, 2023
Insert cell
Insert cell
Insert cell
{
const groups = [];
// create a circle at 100 250
const circle = `<circle id="camera" cx="100" cy="250" r="4" fill="white" stroke="black" />`;

// create a line at 100 250 to 600 250
const line = `<line x1="100" y1="250" x2="1000" y2="250" stroke="black" />`;

// second circle at the center
const circle2 = `<circle id="origin" cx="350" cy="250" r="4" fill="white" stroke="black" />`;

const debugText = `<text id="debug" x="10" y="20" fill="black">Interactive control</text>`;

const w = 700;
const h = 500;

const svgRef = svg`<svg style="background-color: white;" width="${w}" height="${h}" viewBox="0 0 ${w} ${h}">
${line}
${circle}
${circle2}
${debugText}
</svg>`;

const debugRef = svgRef.querySelector("#debug");

let ref = svgRef.querySelector("#camera");
let refLine = svgRef.querySelector("line");
let refOrigin = svgRef.querySelector("#origin");
function getCamera() {
return [ref.getAttribute("cx"), ref.getAttribute("cy")];
}
function getOrigin() {
return [refOrigin.getAttribute("cx"), refOrigin.getAttribute("cy")];
}
draggableElement({
element: ref,
callback: ([x, y]) => {
// min 0 0 w h

let p = 10;
x = Math.max(10, Math.min(700, x));
y = Math.max(0, Math.min(500, y));
ref.setAttribute("cx", x);
ref.setAttribute("cy", y);

// set x1 and y1 of the line
refLine.setAttribute("x1", x);
refLine.setAttribute("y1", y);

const [ox, oy] = getOrigin();
let dx = ox - x;
let dy = oy - y;
// make sure it's out of the bounds
dx *= 1000;
dy *= 1000;

refLine.setAttribute("x2", x + dx);
refLine.setAttribute("y2", y + dy);
},
defaultValue: [100, 250]
});
// make circle darker when the mouse is over it or while dragging
ref.addEventListener("mouseover", () => {
ref.setAttribute("fill", "lightgray");
ref.setAttribute("stroke-width", "2");
});
ref.addEventListener("mouseout", () => {
ref.setAttribute("fill", "white");
ref.setAttribute("stroke-width", "1");
});

return svgRef;
}
Insert cell
draggableElement = ({ element, callback, defaultValue = [0, 0] }) => {
let isDown = false;
let offset = [0, 0];
let transform = defaultValue;
let start = [0, 0];
let mouseStart = [0, 0];
const mouseup = () => {
isDown = false;
// remove
document.removeEventListener("mouseup", mouseup);
document.removeEventListener("mousemove", mousemove);
};
const mousemove = (event) => {
event.preventDefault();
if (isDown) {
// update transform
const [x, y] = transform;
const [mx, my] = mouseStart;
const [dx, dy] = [event.clientX - mx, event.clientY - my];
const [sx, sy] = start;
const [tx, ty] = [sx + dx, sy + dy];
transform = [tx, ty];

callback(transform);
}
};
element.addEventListener(
"mousedown",
(e) => {
isDown = true;
start = transform;
mouseStart = [e.clientX, e.clientY];
// add the event listeners
document.addEventListener("mouseup", mouseup);
document.addEventListener("mousemove", mousemove);
},
true
);
}
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