worldInspector = function*(
world,
forces = () => {},
onContact = (handle1, handle2, contactStarted) => {},
onIntersection = (handle1, handle2, intersecting) => {},
height = 600
) {
const dx = 12;
const dy = 24;
const marginLeft = 40;
const cxnInitials = cxnId => cxnId.match(/^.|[A-Z]/g).join("");
let matchingCxnId = null;
const canvas = DOM.canvas(width, height);
const interactionCanvas = DOM.canvas(width, height);
const context = canvas.getContext('2d');
const interactionContext = interactionCanvas.getContext('2d');
const pixelRatio = window.devicePixelRatio;
canvas.width = width * pixelRatio;
canvas.height = height * pixelRatio;
interactionCanvas.width = width * pixelRatio;
interactionCanvas.height = height * pixelRatio;
canvas.style.width = `${width}px`;
canvas.style.height = `${height}px`;
canvas.style.cursor = 'move';
interactionCanvas.style.width = `${width}px`;
interactionCanvas.style.height = `${height}px`;
const draw = () => {
const transform = d3.zoomTransform(canvas);
context.save();
context.clearRect(0, 0, canvas.width, canvas.height);
context.translate(0, canvas.height);
context.translate(transform.x, transform.y);
context.scale(transform.k, transform.k);
context.scale(pixelRatio, pixelRatio);
context.scale(100, -100); // 1px = 1cm
context.lineWidth = 0.01;
context.fillStyle = context.strokeStyle = "#000";
world.colliders.forEachCollider(collider => {
const { x, y } = collider.translation();
const r = collider.rotation();
context.save();
context.translate(x, y);
context.rotate(r);
drawCollider(context, collider);
context.restore();
});
context.restore();
// Draw interaction segmentation.
interactionContext.save();
interactionContext.clearRect(0, 0, canvas.width, canvas.height);
interactionContext.translate(0, canvas.height);
interactionContext.translate(transform.x, transform.y);
interactionContext.scale(transform.k, transform.k);
interactionContext.scale(pixelRatio, pixelRatio);
interactionContext.scale(100, -100); // 1px = 1cm
interactionContext.lineWidth = 0.01;
world.colliders.forEachCollider(collider => {
const { x, y } = collider.translation();
const r = collider.rotation();
interactionContext.save();
interactionContext.fillStyle = idToColor(collider.parent());
interactionContext.translate(x, y);
interactionContext.rotate(r);
drawCollider(interactionContext, collider, true);
interactionContext.restore();
});
interactionContext.restore();
};
const zoom = d3
.zoom()
.scaleExtent([0.05, 2])
.on("zoom", e => draw());
function dragsubject(event) {
const [x, y] = [event.x * pixelRatio, event.y * pixelRatio];
const colorData = interactionContext.getImageData(x, y, 1, 1).data;
if (colorData[3] === 255) {
const transform = d3.zoomTransform(canvas);
const bodyId = colorToId(colorData);
const body = world.getRigidBody(bodyId);
body.sleep();
const { x, y } = body.translation();
return {
x: transform.applyX(x * 100),
y: transform.applyY(y * -100) + height,
bodyId
};
}
}
function dragged(event) {
const transform = d3.zoomTransform(canvas);
const body = world.getRigidBody(event.subject.bodyId);
body.sleep();
body.setTranslation(
new rapier2d.Vector2(
transform.invertX(event.x) / 100,
transform.invertY(event.y - height) / -100
)
);
}
function dragended(event) {
const body = world.getRigidBody(event.subject.bodyId);
body.setLinvel(new rapier2d.Vector2(0, 0));
body.setAngvel(0);
body.wakeUp();
}
const drag = d3
.drag()
.container(canvas)
.subject(dragsubject)
// .on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended);
d3.select(canvas)
.call(drag)
.call(zoom);
let eventQueue = new rapier2d.EventQueue(true);
while (true) {
forces();
world.step(eventQueue);
eventQueue.drainContactEvents(onContact);
eventQueue.drainIntersectionEvents(onIntersection);
draw();
yield canvas;
}
}