Skip to main content

Coordinates

Understanding the coordinate system is essential for building interactive visualizations. Locus uses a Cartesian coordinate system with some specific conventions.

Coordinate System

By default, Locus uses a standard screen coordinate system:

  • Origin (0, 0): Center of the canvas
  • X-axis: Positive values extend to the right
  • Y-axis: Positive values extend downward (screen coordinates)
        -Y
|
-X ----+---- +X
|
+Y

Canvas vs Scene Coordinates

When working with interactive elements, you'll encounter two coordinate systems:

Scene Coordinates

Used internally by nodes and shapes:

  • Origin at canvas center
  • Standard mathematical directions

Screen Coordinates

Used for mouse events:

  • Origin at top-left corner
  • Y increases downward

Coordinate Conversion

Convert between coordinate systems:

import { Vector2 } from '@wangyaoshen/locus-core';

// Canvas dimensions
const canvasWidth = 800;
const canvasHeight = 600;

// Screen to Scene
function screenToScene(screenX: number, screenY: number): Vector2 {
return new Vector2(
screenX - canvasWidth / 2,
screenY - canvasHeight / 2
);
}

// Scene to Screen
function sceneToScreen(sceneX: number, sceneY: number): [number, number] {
return [
sceneX + canvasWidth / 2,
sceneY + canvasHeight / 2
];
}

Interactive Coordinate Display

The InteractiveDemo components display coordinates in real-time as you drag points:

const point = new InteractivePoint({
position: [100, 50],
onMove: (pos) => {
// pos is in scene coordinates
console.log(`Position: (${pos[0]}, ${pos[1]})`);
},
});

Grid System

Interactive demos use a grid overlay to help visualize coordinates:

function drawGrid(ctx: CanvasRenderingContext2D, spacing: number = 50) {
ctx.strokeStyle = '#e0e0e0';
ctx.lineWidth = 1;

// Vertical lines
for (let x = 0; x <= ctx.canvas.width; x += spacing) {
ctx.beginPath();
ctx.moveTo(x, 0);
ctx.lineTo(x, ctx.canvas.height);
ctx.stroke();
}

// Horizontal lines
for (let y = 0; y <= ctx.canvas.height; y += spacing) {
ctx.beginPath();
ctx.moveTo(0, y);
ctx.lineTo(ctx.canvas.width, y);
ctx.stroke();
}
}

Working with Constraints

Constraints operate in scene coordinates:

import { horizontal, vertical, circle } from '@wangyaoshen/locus-interaction';

// Horizontal line at y = 100 (in scene coords)
const hConstraint = horizontal(100);

// Vertical line at x = 0 (center of canvas)
const vConstraint = vertical(0);

// Circle centered at (100, 100) with radius 50
const cConstraint = circle([100, 100], 50);

Coordinate Ranges

When setting up interactive elements, consider the visible coordinate range:

// For a 500x300 canvas:
const bounds = {
minX: -250, maxX: 250, // x range
minY: -150, maxY: 150, // y range
};

// Clamp position to bounds
function clampToBounds(pos: Vector2): Vector2 {
return [
Math.max(bounds.minX, Math.min(bounds.maxX, pos[0])),
Math.max(bounds.minY, Math.min(bounds.maxY, pos[1])),
];
}

Tips

  1. Mouse Events: Always convert screen coordinates to scene coordinates when handling mouse events
  2. Constraints: Define constraints in scene coordinates
  3. Debugging: Use the coordinate display feature to verify positions
  4. Bounds: Consider canvas bounds when constraining movement