mirror of
https://github.com/pipipi-pikachu/PPTist.git
synced 2025-04-15 02:20:00 +08:00
feat: 形状支持缩放重新计算路径
This commit is contained in:
parent
47234085da
commit
14c6965153
@ -1,7 +1,10 @@
|
||||
import { ShapePathFormulasKeys } from '@/types/slides'
|
||||
|
||||
export interface ShapePoolItem {
|
||||
viewBox: [number, number];
|
||||
path: string;
|
||||
special?: boolean;
|
||||
pathFormula?: ShapePathFormulasKeys;
|
||||
}
|
||||
|
||||
interface ShapeListItem {
|
||||
@ -9,6 +12,37 @@ interface ShapeListItem {
|
||||
children: ShapePoolItem[];
|
||||
}
|
||||
|
||||
export const SHAPE_PATH_FORMULAS = {
|
||||
[ShapePathFormulasKeys.ROUND_RECT]: (width: number, height: number) => {
|
||||
const radius = Math.min(width, height) / 8
|
||||
return `M ${radius} 0 L ${width - radius} 0 Q ${width} 0 ${width} ${radius} L ${width} ${height - radius} Q ${width} ${height} ${width - radius} ${height} L ${radius} ${height} Q 0 ${height} 0 ${height - radius} L 0 ${radius} Q 0 0 ${radius} 0 Z`
|
||||
},
|
||||
[ShapePathFormulasKeys.CUT_RECT_DIAGONAL]: (width: number, height: number) => {
|
||||
const radius = Math.min(width, height) / 5
|
||||
return `M 0 ${height - radius} L 0 0 L ${width - radius} 0 L ${width} ${radius} L ${width} ${height} L ${radius} ${height} Z`
|
||||
},
|
||||
[ShapePathFormulasKeys.CUT_RECT_SINGLE]: (width: number, height: number) => {
|
||||
const radius = Math.min(width, height) / 5
|
||||
return `M 0 ${height} L 0 0 L ${width - radius} 0 L ${width} ${radius} L ${width} ${height} Z`
|
||||
},
|
||||
[ShapePathFormulasKeys.CUT_RECT_SAMESIDE]: (width: number, height: number) => {
|
||||
const radius = Math.min(width, height) / 5
|
||||
return `M 0 ${radius} L ${radius} 0 L ${width - radius} 0 L ${width} ${radius} L ${width} ${height} L 0 ${height} Z`
|
||||
},
|
||||
[ShapePathFormulasKeys.ROUND_RECT_DIAGONAL]: (width: number, height: number) => {
|
||||
const radius = Math.min(width, height) / 8
|
||||
return `M 0 0 L ${width - radius} 0 Q ${width} 0 ${width} ${radius} L ${width} ${height} L ${radius} ${height} Q 0 ${height} 0 ${height - radius} L 0 0 Z`
|
||||
},
|
||||
[ShapePathFormulasKeys.ROUND_RECT_SINGLE]: (width: number, height: number) => {
|
||||
const radius = Math.min(width, height) / 8
|
||||
return `M 0 0 L ${width - radius} 0 Q ${width} 0 ${width} ${radius} L ${width} ${height} L 0 ${height} L 0 0 Z`
|
||||
},
|
||||
[ShapePathFormulasKeys.ROUND_RECT_SAMESIDE]: (width: number, height: number) => {
|
||||
const radius = Math.min(width, height) / 8
|
||||
return `M 0 ${radius} Q 0 0 ${radius} 0 L ${width - radius} 0 Q ${width} 0 ${width} ${radius} L ${width} ${height} L 0 ${height} Z`
|
||||
},
|
||||
}
|
||||
|
||||
export const SHAPE_LIST: ShapeListItem[] = [
|
||||
{
|
||||
type: '矩形',
|
||||
@ -19,31 +53,38 @@ export const SHAPE_LIST: ShapeListItem[] = [
|
||||
},
|
||||
{
|
||||
viewBox: [200, 200],
|
||||
path: 'M 20 0 L 180 0 Q 200 0 200 20 L 200 180 Q 200 200 180 200 L 20 200 Q 0 200 0 180 L 0 20 Q 0 0 20 0 Z'
|
||||
path: 'M 50 0 L 150 0 Q 200 0 200 50 L 200 150 Q 200 200 150 200 L 50 200 Q 0 200 0 150 L 0 50 Q 0 0 50 0 Z',
|
||||
pathFormula: ShapePathFormulasKeys.ROUND_RECT,
|
||||
},
|
||||
{
|
||||
viewBox: [200, 200],
|
||||
path: 'M 0 150 L 0 0 L 150 0 L 200 50 L 200 200 L 50 200 L 0 150 Z'
|
||||
path: 'M 0 150 L 0 0 L 150 0 L 200 50 L 200 200 L 50 200 Z',
|
||||
pathFormula: ShapePathFormulasKeys.CUT_RECT_DIAGONAL,
|
||||
},
|
||||
{
|
||||
viewBox: [200, 200],
|
||||
path: 'M 0 200 L 0 0 L 150 0 L 200 50 L 200 200 L 0 200'
|
||||
path: 'M 0 200 L 0 0 L 150 0 L 200 50 L 200 200 Z',
|
||||
pathFormula: ShapePathFormulasKeys.CUT_RECT_SINGLE,
|
||||
},
|
||||
{
|
||||
viewBox: [200, 200],
|
||||
path: 'M 0 50 L 50 0 L 150 0 L 200 50 L 200 200 L 0 200 L 0 50 Z'
|
||||
path: 'M 0 50 L 50 0 L 150 0 L 200 50 L 200 200 L 0 200 Z',
|
||||
pathFormula: ShapePathFormulasKeys.CUT_RECT_SAMESIDE,
|
||||
},
|
||||
{
|
||||
viewBox: [200, 200],
|
||||
path: 'M 0 0 L 140 0 Q 200 0 200 60 L 200 200 L 60 200 Q 0 200 0 140 L 0 0 Z'
|
||||
path: 'M 0 0 L 150 0 Q 200 0 200 50 L 200 200 L 50 200 Q 0 200 0 150 L 0 0 Z',
|
||||
pathFormula: ShapePathFormulasKeys.ROUND_RECT_DIAGONAL,
|
||||
},
|
||||
{
|
||||
viewBox: [200, 200],
|
||||
path: 'M 0 0 L 140 0 Q 200 0 200 60 L 200 200 L 0 200 L 0 0 Z'
|
||||
path: 'M 0 0 L 150 0 Q 200 0 200 50 L 200 200 L 0 200 L 0 0 Z',
|
||||
pathFormula: ShapePathFormulasKeys.ROUND_RECT_SINGLE,
|
||||
},
|
||||
{
|
||||
viewBox: [200, 200],
|
||||
path: 'M 0 50 Q 0 0 50 0 L 150 0 Q 200 0 200 50 L 200 200 L 0 200 L 0 50 Z'
|
||||
path: 'M 0 50 Q 0 0 50 0 L 150 0 Q 200 0 200 50 L 200 200 L 0 200 Z',
|
||||
pathFormula: ShapePathFormulasKeys.ROUND_RECT_SAMESIDE,
|
||||
},
|
||||
]
|
||||
},
|
||||
|
@ -4,7 +4,7 @@ import { createRandomCode } from '@/utils/common'
|
||||
import { getImageSize } from '@/utils/image'
|
||||
import { VIEWPORT_SIZE } from '@/configs/canvas'
|
||||
import { PPTLineElement, ChartType, PPTElement, TableCell, TableCellStyle, PPTShapeElement } from '@/types/slides'
|
||||
import { ShapePoolItem } from '@/configs/shapes'
|
||||
import { ShapePoolItem, SHAPE_PATH_FORMULAS } from '@/configs/shapes'
|
||||
import { LinePoolItem } from '@/configs/lines'
|
||||
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
||||
|
||||
@ -195,6 +195,11 @@ export default () => {
|
||||
rotate: 0,
|
||||
}
|
||||
if (data.special) newElement.special = true
|
||||
if (data.pathFormula) {
|
||||
newElement.pathFormula = data.pathFormula
|
||||
newElement.viewBox = [width, height]
|
||||
newElement.path = SHAPE_PATH_FORMULAS[data.pathFormula](width, height)
|
||||
}
|
||||
createElement(newElement)
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,15 @@
|
||||
import { IBarChartOptions, ILineChartOptions, IPieChartOptions } from 'chartist'
|
||||
|
||||
export const enum ShapePathFormulasKeys {
|
||||
ROUND_RECT = 'roundRect',
|
||||
ROUND_RECT_DIAGONAL = 'roundRectDiagonal',
|
||||
ROUND_RECT_SINGLE = 'roundRectSingle',
|
||||
ROUND_RECT_SAMESIDE = 'roundRectSameSide',
|
||||
CUT_RECT_DIAGONAL = 'cutRectDiagonal',
|
||||
CUT_RECT_SINGLE = 'cutRectSingle',
|
||||
CUT_RECT_SAMESIDE = 'cutRectSameSide',
|
||||
}
|
||||
|
||||
export const enum ElementTypes {
|
||||
TEXT = 'text',
|
||||
IMAGE = 'image',
|
||||
@ -277,6 +287,10 @@ export interface ShapeText {
|
||||
* special?: 特殊形状(标记一些难以解析的形状,例如路径使用了 L Q C A 以外的类型,该类形状在导出后将变为图片的形式)
|
||||
*
|
||||
* text?: 形状内文本
|
||||
*
|
||||
* pathFormula?: 形状路径计算公式
|
||||
* 一般情况下,形状的大小变化时仅由宽高基于 viewBox 的缩放比例来调整形状,而 viewBox 本身和 path 不会变化,
|
||||
* 但也有一些形状希望能更精确的控制一些关键点的位置,此时就需要提供路径计算公式,通过在缩放时更新 viewBox 并重新计算 path 来重新绘制形状
|
||||
*/
|
||||
export interface PPTShapeElement extends PPTBaseElement {
|
||||
type: 'shape';
|
||||
@ -292,6 +306,7 @@ export interface PPTShapeElement extends PPTBaseElement {
|
||||
shadow?: PPTElementShadow;
|
||||
special?: boolean;
|
||||
text?: ShapeText;
|
||||
pathFormula?: ShapePathFormulasKeys;
|
||||
}
|
||||
|
||||
|
||||
|
@ -5,6 +5,7 @@ import { PPTElement, PPTImageElement, PPTLineElement, PPTShapeElement } from '@/
|
||||
import { OperateResizeHandlers, OperateResizeHandler, AlignmentLineProps, MultiSelectRange } from '@/types/edit'
|
||||
import { VIEWPORT_SIZE } from '@/configs/canvas'
|
||||
import { MIN_SIZE } from '@/configs/element'
|
||||
import { SHAPE_PATH_FORMULAS } from '@/configs/shapes'
|
||||
import { AlignLine, uniqAlignLines } from '@/utils/element'
|
||||
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
||||
|
||||
@ -393,7 +394,17 @@ export default (
|
||||
}
|
||||
}
|
||||
|
||||
elementList.value = elementList.value.map(el => element.id === el.id ? { ...el, left, top, width, height } : el)
|
||||
elementList.value = elementList.value.map(el => {
|
||||
if (element.id !== el.id) return el
|
||||
if (el.type === 'shape' && 'pathFormula' in el && el.pathFormula) {
|
||||
return {
|
||||
...el, left, top, width, height,
|
||||
viewBox: [width, height],
|
||||
path: SHAPE_PATH_FORMULAS[el.pathFormula](width, height),
|
||||
}
|
||||
}
|
||||
return { ...el, left, top, width, height }
|
||||
})
|
||||
}
|
||||
|
||||
document.onmouseup = e => {
|
||||
|
Loading…
x
Reference in New Issue
Block a user