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 {
|
export interface ShapePoolItem {
|
||||||
viewBox: [number, number];
|
viewBox: [number, number];
|
||||||
path: string;
|
path: string;
|
||||||
special?: boolean;
|
special?: boolean;
|
||||||
|
pathFormula?: ShapePathFormulasKeys;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ShapeListItem {
|
interface ShapeListItem {
|
||||||
@ -9,6 +12,37 @@ interface ShapeListItem {
|
|||||||
children: ShapePoolItem[];
|
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[] = [
|
export const SHAPE_LIST: ShapeListItem[] = [
|
||||||
{
|
{
|
||||||
type: '矩形',
|
type: '矩形',
|
||||||
@ -19,31 +53,38 @@ export const SHAPE_LIST: ShapeListItem[] = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
viewBox: [200, 200],
|
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],
|
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],
|
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],
|
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],
|
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],
|
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],
|
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 { getImageSize } from '@/utils/image'
|
||||||
import { VIEWPORT_SIZE } from '@/configs/canvas'
|
import { VIEWPORT_SIZE } from '@/configs/canvas'
|
||||||
import { PPTLineElement, ChartType, PPTElement, TableCell, TableCellStyle, PPTShapeElement } from '@/types/slides'
|
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 { LinePoolItem } from '@/configs/lines'
|
||||||
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
||||||
|
|
||||||
@ -195,6 +195,11 @@ export default () => {
|
|||||||
rotate: 0,
|
rotate: 0,
|
||||||
}
|
}
|
||||||
if (data.special) newElement.special = true
|
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)
|
createElement(newElement)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,15 @@
|
|||||||
import { IBarChartOptions, ILineChartOptions, IPieChartOptions } from 'chartist'
|
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 {
|
export const enum ElementTypes {
|
||||||
TEXT = 'text',
|
TEXT = 'text',
|
||||||
IMAGE = 'image',
|
IMAGE = 'image',
|
||||||
@ -277,6 +287,10 @@ export interface ShapeText {
|
|||||||
* special?: 特殊形状(标记一些难以解析的形状,例如路径使用了 L Q C A 以外的类型,该类形状在导出后将变为图片的形式)
|
* special?: 特殊形状(标记一些难以解析的形状,例如路径使用了 L Q C A 以外的类型,该类形状在导出后将变为图片的形式)
|
||||||
*
|
*
|
||||||
* text?: 形状内文本
|
* text?: 形状内文本
|
||||||
|
*
|
||||||
|
* pathFormula?: 形状路径计算公式
|
||||||
|
* 一般情况下,形状的大小变化时仅由宽高基于 viewBox 的缩放比例来调整形状,而 viewBox 本身和 path 不会变化,
|
||||||
|
* 但也有一些形状希望能更精确的控制一些关键点的位置,此时就需要提供路径计算公式,通过在缩放时更新 viewBox 并重新计算 path 来重新绘制形状
|
||||||
*/
|
*/
|
||||||
export interface PPTShapeElement extends PPTBaseElement {
|
export interface PPTShapeElement extends PPTBaseElement {
|
||||||
type: 'shape';
|
type: 'shape';
|
||||||
@ -292,6 +306,7 @@ export interface PPTShapeElement extends PPTBaseElement {
|
|||||||
shadow?: PPTElementShadow;
|
shadow?: PPTElementShadow;
|
||||||
special?: boolean;
|
special?: boolean;
|
||||||
text?: ShapeText;
|
text?: ShapeText;
|
||||||
|
pathFormula?: ShapePathFormulasKeys;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ import { PPTElement, PPTImageElement, PPTLineElement, PPTShapeElement } from '@/
|
|||||||
import { OperateResizeHandlers, OperateResizeHandler, AlignmentLineProps, MultiSelectRange } from '@/types/edit'
|
import { OperateResizeHandlers, OperateResizeHandler, AlignmentLineProps, MultiSelectRange } from '@/types/edit'
|
||||||
import { VIEWPORT_SIZE } from '@/configs/canvas'
|
import { VIEWPORT_SIZE } from '@/configs/canvas'
|
||||||
import { MIN_SIZE } from '@/configs/element'
|
import { MIN_SIZE } from '@/configs/element'
|
||||||
|
import { SHAPE_PATH_FORMULAS } from '@/configs/shapes'
|
||||||
import { AlignLine, uniqAlignLines } from '@/utils/element'
|
import { AlignLine, uniqAlignLines } from '@/utils/element'
|
||||||
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
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 => {
|
document.onmouseup = e => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user