跳到主要内容

坐标

理解坐标系对于构建交互式可视化至关重要。Locus 使用笛卡尔坐标系,并遵循一些特定的约定。

坐标系

默认情况下,Locus 使用标准屏幕坐标系:

  • 原点 (0, 0):画布中心
  • X 轴:正值向右延伸
  • Y 轴:正值向下延伸(屏幕坐标)
        -Y
|
-X ----+---- +X
|
+Y

画布坐标与场景坐标

在使用交互元素时,您会遇到两个坐标系:

场景坐标

由节点和形状内部使用:

  • 原点位于画布中心
  • 标准数学方向

屏幕坐标

用于鼠标事件:

  • 原点位于左上角
  • Y 向下增加

坐标转换

在坐标系之间进行转换:

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

// 画布尺寸
const canvasWidth = 800;
const canvasHeight = 600;

// 屏幕到场景
function screenToScene(screenX: number, screenY: number): Vector2 {
return new Vector2(
screenX - canvasWidth / 2,
screenY - canvasHeight / 2
);
}

// 场景到屏幕
function sceneToScreen(sceneX: number, sceneY: number): [number, number] {
return [
sceneX + canvasWidth / 2,
sceneY + canvasHeight / 2
];
}

交互式坐标显示

InteractiveDemo 组件在您拖动点时实时显示坐标:

const point = new InteractivePoint({
position: [100, 50],
onMove: (pos) => {
// pos 位于场景坐标中
console.log(`位置: (${pos[0]}, ${pos[1]})`);
},
});

网格系统

交互式演示使用网格叠加来帮助可视化坐标:

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

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

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

使用约束

约束在场景坐标中操作:

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

// y = 100 处的水平线(场景坐标)
const hConstraint = horizontal(100);

// x = 0 处的垂直线(画布中心)
const vConstraint = vertical(0);

// 以 (100, 100) 为中心,半径为 50 的圆
const cConstraint = circle([100, 100], 50);

坐标范围

设置交互元素时,请考虑可见的坐标范围:

// 对于 500x300 的画布:
const bounds = {
minX: -250, maxX: 250, // x 范围
minY: -150, maxY: 150, // y 范围
};

// 将位置限制在边界内
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])),
];
}

提示

  1. 鼠标事件:处理鼠标事件时,始终将屏幕坐标转换为场景坐标
  2. 约束:在场景坐标中定义约束
  3. 调试:使用坐标显示功能来验证位置
  4. 边界:约束移动时考虑画布边界