坐标
理解坐标系对于构建交互式可视化至关重要。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])),
];
}
提示
- 鼠标事件:处理鼠标事件时,始终将屏幕坐标转换为场景坐标
- 约束:在场景坐标中定义约束
- 调试:使用坐标显示功能来验证位置
- 边界:约束移动时考虑画布边界