feat(canvas): 100% 显示时实际渲染 0.6 倍,整体视图缩小一档
This commit is contained in:
@@ -11,6 +11,9 @@ import {
|
||||
zoomAt,
|
||||
rectsIntersect,
|
||||
nodeRect,
|
||||
BASE_SCALE,
|
||||
MIN_SCALE,
|
||||
MAX_SCALE,
|
||||
} from '../../utils/canvas'
|
||||
import CanvasNodeView from './CanvasNodeView.vue'
|
||||
|
||||
@@ -216,11 +219,11 @@ const edgePaths = computed(() => {
|
||||
})
|
||||
|
||||
const worldStyle = computed(() => ({
|
||||
transform: `translate3d(${vp.x}px, ${vp.y}px, 0) scale(${vp.scale})`,
|
||||
transform: `translate3d(${vp.x}px, ${vp.y}px, 0) scale(${vp.scale * BASE_SCALE})`,
|
||||
}))
|
||||
|
||||
const gridStyle = computed(() => {
|
||||
const cell = Math.max(14, 24 * vp.scale)
|
||||
const cell = Math.max(14, 24 * vp.scale * BASE_SCALE)
|
||||
return {
|
||||
backgroundSize: `${cell}px ${cell}px`,
|
||||
backgroundPosition: `${vp.x}px ${vp.y}px`,
|
||||
@@ -645,8 +648,9 @@ function zoomTo(scale) {
|
||||
}
|
||||
function centerOn(x, y) {
|
||||
const r = stageEl.value?.getBoundingClientRect()
|
||||
vp.x = (r ? r.width / 2 : 400) - x * vp.scale
|
||||
vp.y = (r ? r.height / 2 : 300) - y * vp.scale
|
||||
const s = vp.scale * BASE_SCALE
|
||||
vp.x = (r ? r.width / 2 : 400) - x * s
|
||||
vp.y = (r ? r.height / 2 : 300) - y * s
|
||||
notifyViewport()
|
||||
}
|
||||
function clearSelection() {
|
||||
@@ -677,8 +681,8 @@ function fitToContent() {
|
||||
const pad = 80
|
||||
const bw = Math.max(1, x2 - x1 + pad * 2)
|
||||
const bh = Math.max(1, y2 - y1 + pad * 2)
|
||||
const s = Math.min(sw / bw, sh / bh, 1.2)
|
||||
vp.scale = s
|
||||
const s = Math.min(sw / bw, sh / bh, 1.2) // 期望的有效缩放
|
||||
vp.scale = Math.min(MAX_SCALE, Math.max(MIN_SCALE, s / BASE_SCALE))
|
||||
vp.x = sw / 2 - (x1 - pad + bw / 2) * s
|
||||
vp.y = sh / 2 - (y1 - pad + bh / 2) * s
|
||||
notifyViewport()
|
||||
|
||||
@@ -7,17 +7,21 @@ let idSeq = 0
|
||||
|
||||
/** 世界→屏幕 */
|
||||
export function worldToScreen(x, y, vp) {
|
||||
return { x: x * vp.scale + vp.x, y: y * vp.scale + vp.y }
|
||||
const s = vp.scale * BASE_SCALE
|
||||
return { x: x * s + vp.x, y: y * s + vp.y }
|
||||
}
|
||||
|
||||
/** 屏幕→世界 */
|
||||
export function screenToWorld(sx, sy, vp) {
|
||||
return { x: (sx - vp.x) / vp.scale, y: (sy - vp.y) / vp.scale }
|
||||
const s = vp.scale * BASE_SCALE
|
||||
return { x: (sx - vp.x) / s, y: (sy - vp.y) / s }
|
||||
}
|
||||
|
||||
export const MIN_SCALE = 0.05
|
||||
export const MAX_SCALE = 4
|
||||
export const DEFAULT_SCALE = 0.6 // 新画布/重置视图的默认缩放
|
||||
export const DEFAULT_SCALE = 1 // 新画布/重置视图的逻辑缩放(BASE_SCALE 已整体缩小)
|
||||
// 视觉基准:显示 100% 时实际渲染 0.6×,全部屏幕换算统一走它
|
||||
export const BASE_SCALE = 0.6
|
||||
|
||||
/** 以屏幕点 m 为锚缩放到 newScale,返回新 viewport(平移量按锚点保持不动) */
|
||||
export function zoomAt(vp, mx, my, newScale) {
|
||||
@@ -41,11 +45,12 @@ export function pointInRect(px, py, r) {
|
||||
|
||||
/** 视口剔除:返回与可见世界矩形(含 margin)相交的节点。纯几何,千级节点也是微秒。 */
|
||||
export function nodesInViewport(nodes, vp, stageW, stageH, margin = 240) {
|
||||
const s = vp.scale * BASE_SCALE
|
||||
const vis = {
|
||||
x: -vp.x / vp.scale - margin,
|
||||
y: -vp.y / vp.scale - margin,
|
||||
w: stageW / vp.scale + margin * 2,
|
||||
h: stageH / vp.scale + margin * 2,
|
||||
x: -vp.x / s - margin,
|
||||
y: -vp.y / s - margin,
|
||||
w: stageW / s + margin * 2,
|
||||
h: stageH / s + margin * 2,
|
||||
}
|
||||
return nodes.filter((n) => rectsIntersect(nodeRect(n), vis))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user