feat: manually mirror opencoze's code from bytedance
Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
type Canvas,
|
||||
type FabricObject,
|
||||
type Point,
|
||||
type TMat2D,
|
||||
type Textbox,
|
||||
} from 'fabric';
|
||||
|
||||
import { Mode, type FabricObjectWithCustomProps } from '../typings';
|
||||
|
||||
/**
|
||||
* 缩放到指定点
|
||||
*/
|
||||
export const zoomToPoint = ({
|
||||
canvas,
|
||||
point,
|
||||
zoomLevel,
|
||||
minZoom,
|
||||
maxZoom,
|
||||
}: {
|
||||
point: Point;
|
||||
zoomLevel: number;
|
||||
canvas?: Canvas;
|
||||
minZoom: number;
|
||||
maxZoom: number;
|
||||
}): TMat2D => {
|
||||
// 设置缩放级别的限制
|
||||
zoomLevel = Math.max(zoomLevel, minZoom); // 最小缩放级别
|
||||
zoomLevel = Math.min(zoomLevel, maxZoom); // 最大缩放级别
|
||||
|
||||
// 以鼠标位置为中心进行缩放
|
||||
canvas?.zoomToPoint(point, zoomLevel);
|
||||
return [...(canvas?.viewportTransform as TMat2D)];
|
||||
};
|
||||
|
||||
/**
|
||||
* 设置 canvas 视图
|
||||
*/
|
||||
export const setViewport = ({
|
||||
canvas,
|
||||
vpt,
|
||||
}: {
|
||||
vpt: TMat2D;
|
||||
canvas?: Canvas;
|
||||
}): TMat2D => {
|
||||
canvas?.setViewportTransform(vpt);
|
||||
canvas?.requestRenderAll();
|
||||
return [...(canvas?.viewportTransform as TMat2D)];
|
||||
};
|
||||
|
||||
/**
|
||||
* 画布坐标点距离画布左上角距离(单位:px)
|
||||
*/
|
||||
export const canvasXYToScreen = ({
|
||||
canvas,
|
||||
scale,
|
||||
point,
|
||||
}: {
|
||||
canvas: Canvas;
|
||||
scale: number;
|
||||
point: { x: number; y: number };
|
||||
}) => {
|
||||
// 获取画布的变换矩阵
|
||||
const transform = canvas.viewportTransform;
|
||||
|
||||
// 应用缩放和平移
|
||||
const zoomX = transform[0];
|
||||
const zoomY = transform[3];
|
||||
const translateX = transform[4];
|
||||
const translateY = transform[5];
|
||||
|
||||
const screenX = (point.x * zoomX + translateX) * scale;
|
||||
const screenY = (point.y * zoomY + translateY) * scale;
|
||||
|
||||
// 获取画布在屏幕上的位置
|
||||
const x = screenX;
|
||||
const y = screenY;
|
||||
|
||||
// 不做限制
|
||||
return {
|
||||
x,
|
||||
y,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* 得到选中元素的屏幕坐标(左上 tl、右下 br)
|
||||
*/
|
||||
export const getPopPosition = ({
|
||||
canvas,
|
||||
scale,
|
||||
}: {
|
||||
canvas: Canvas;
|
||||
scale: number;
|
||||
}) => {
|
||||
const selection = canvas?.getActiveObject();
|
||||
if (canvas && selection) {
|
||||
const boundingRect = selection.getBoundingRect();
|
||||
|
||||
// 左上角坐标
|
||||
const tl = {
|
||||
x: boundingRect.left,
|
||||
y: boundingRect.top,
|
||||
};
|
||||
|
||||
// 右下角坐标
|
||||
const br = {
|
||||
x: boundingRect.left + boundingRect.width,
|
||||
y: boundingRect.top + boundingRect.height,
|
||||
};
|
||||
|
||||
return {
|
||||
tl: canvasXYToScreen({ canvas, scale, point: tl }),
|
||||
br: canvasXYToScreen({ canvas, scale, point: br }),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
tl: {
|
||||
x: -9999,
|
||||
y: -9999,
|
||||
},
|
||||
br: {
|
||||
x: -9999,
|
||||
y: -9999,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export const resetElementClip = ({ element }: { element: FabricObject }) => {
|
||||
if (!element.clipPath) {
|
||||
return;
|
||||
}
|
||||
|
||||
const clipRect = element.clipPath;
|
||||
const padding = (element as Textbox).padding ?? 0;
|
||||
|
||||
const { height, width } = element as FabricObject;
|
||||
|
||||
const _height = height + padding * 2;
|
||||
const _width = width + padding * 2;
|
||||
|
||||
const newPosition = {
|
||||
originX: 'left',
|
||||
originY: 'top',
|
||||
left: -_width / 2,
|
||||
top: -_height / 2,
|
||||
height: _height,
|
||||
width: _width,
|
||||
absolutePositioned: false,
|
||||
};
|
||||
|
||||
clipRect?.set(newPosition);
|
||||
};
|
||||
|
||||
export const isGroupElement = (obj?: FabricObject) =>
|
||||
(obj as FabricObjectWithCustomProps)?.customType === Mode.GROUP;
|
||||
Reference in New Issue
Block a user