260719_10
This commit is contained in:
+32
-21
@@ -1,16 +1,10 @@
|
||||
import { Point, type Vector } from '@flatten-js/core';
|
||||
import { CANVAS_BACKGROUND_COLOR, MOUSE_ZOOM_MULTIPLIER } from '../App.consts';
|
||||
import { containRectangle } from '../helpers/contain-rect.ts';
|
||||
import { getAngleWithXAxis } from '../helpers/get-angle-with-x-axis.ts';
|
||||
import { getBoundingBoxOfMultipleEntities } from '../helpers/get-bounding-box-of-multiple-entities.ts';
|
||||
import { mapNumberRange } from '../helpers/map-number-range.ts';
|
||||
import { StateVariable } from '../helpers/undo-stack.ts';
|
||||
import {
|
||||
getEntities,
|
||||
getGridEnabled,
|
||||
getScreenCanvasDrawController,
|
||||
triggerReactUpdate,
|
||||
} from '../state.ts';
|
||||
import { getEntities, getGridEnabled, triggerReactUpdate } from '../state.ts';
|
||||
import { DEFAULT_TEXT_OPTIONS, type DrawController } from './DrawController';
|
||||
|
||||
/**
|
||||
@@ -122,23 +116,40 @@ export class ScreenCanvasDrawController implements DrawController {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 전체 도면(모든 엔티티)을 화면 중심에 여백을 두고 배치한다.
|
||||
* 가로/세로 중 더 제약이 큰 축에 맞춰 배율을 정하고, 도면 중심이 화면 중심에
|
||||
* 오도록 screenOffset(월드 좌표)을 역산한다. (기존 구현은 화면 픽셀 여백값을
|
||||
* 월드 좌표 offset에 그대로 대입해 중심 배치가 어긋나는 문제가 있었다.)
|
||||
*/
|
||||
public zoomToFitScreen() {
|
||||
const boundingBox = getBoundingBoxOfMultipleEntities(getEntities());
|
||||
const entities = getEntities();
|
||||
if (!entities.length) return;
|
||||
const boundingBox = getBoundingBoxOfMultipleEntities(entities);
|
||||
const boundingWidth = boundingBox.maxX - boundingBox.minX;
|
||||
const fittedRect = containRectangle(
|
||||
boundingBox.minX,
|
||||
boundingBox.minY,
|
||||
boundingBox.maxX,
|
||||
boundingBox.maxY,
|
||||
0,
|
||||
0,
|
||||
getScreenCanvasDrawController().getCanvasSize().x,
|
||||
getScreenCanvasDrawController().getCanvasSize().y
|
||||
const boundingHeight = boundingBox.maxY - boundingBox.minY;
|
||||
const canvasSize = this.getCanvasSize();
|
||||
|
||||
// 10% 여백을 남기고 두 축 중 더 빡빡한 쪽에 맞춘다 (종횡비 유지)
|
||||
const FIT_MARGIN = 0.9;
|
||||
const scaleX =
|
||||
boundingWidth > 0 ? (canvasSize.x * FIT_MARGIN) / boundingWidth : Number.POSITIVE_INFINITY;
|
||||
const scaleY =
|
||||
boundingHeight > 0 ? (canvasSize.y * FIT_MARGIN) / boundingHeight : Number.POSITIVE_INFINITY;
|
||||
let zoomLevel = Math.min(scaleX, scaleY);
|
||||
if (!Number.isFinite(zoomLevel) || zoomLevel <= 0) zoomLevel = 1;
|
||||
this.setScreenScale(zoomLevel);
|
||||
|
||||
// screen = (world - offset) * zoom 이므로, 도면 중심을 화면 중심에 맞추려면
|
||||
// offset = worldCenter - (화면 절반 픽셀) / zoom
|
||||
const worldCenterX = (boundingBox.minX + boundingBox.maxX) / 2;
|
||||
const worldCenterY = (boundingBox.minY + boundingBox.maxY) / 2;
|
||||
this.setScreenOffset(
|
||||
new Point(
|
||||
worldCenterX - canvasSize.x / 2 / zoomLevel,
|
||||
worldCenterY - canvasSize.y / 2 / zoomLevel
|
||||
)
|
||||
);
|
||||
const fittedWidth = fittedRect.maxX - fittedRect.minX;
|
||||
const zoomLevel = fittedWidth / boundingWidth;
|
||||
getScreenCanvasDrawController().setScreenScale(zoomLevel);
|
||||
getScreenCanvasDrawController().setScreenOffset(new Point(fittedRect.minX, fittedRect.minY));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user