diff --git a/src/editor/assets/css/contextmenu/contextmenu.css b/src/editor/assets/css/contextmenu/contextmenu.css
index 346004f..8ad16bc 100644
--- a/src/editor/assets/css/contextmenu/contextmenu.css
+++ b/src/editor/assets/css/contextmenu/contextmenu.css
@@ -129,4 +129,20 @@
.ce-contextmenu-merge-cancel-cell {
background-image: url(../../../assets/images/merge-cancel-cell.svg);
+}
+
+.ce-contextmenu-vertical-align {
+ background-image: url(../../../assets/images/vertical-align.svg);
+}
+
+.ce-contextmenu-vertical-align-top {
+ background-image: url(../../../assets/images/vertical-align-top.svg);
+}
+
+.ce-contextmenu-vertical-align-middle {
+ background-image: url(../../../assets/images/vertical-align-middle.svg);
+}
+
+.ce-contextmenu-vertical-align-bottom {
+ background-image: url(../../../assets/images/vertical-align-bottom.svg);
}
\ No newline at end of file
diff --git a/src/editor/assets/images/vertical-align-bottom.svg b/src/editor/assets/images/vertical-align-bottom.svg
new file mode 100644
index 0000000..b4b8f01
--- /dev/null
+++ b/src/editor/assets/images/vertical-align-bottom.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/editor/assets/images/vertical-align-middle.svg b/src/editor/assets/images/vertical-align-middle.svg
new file mode 100644
index 0000000..9fc9f0b
--- /dev/null
+++ b/src/editor/assets/images/vertical-align-middle.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/editor/assets/images/vertical-align-top.svg b/src/editor/assets/images/vertical-align-top.svg
new file mode 100644
index 0000000..447ed06
--- /dev/null
+++ b/src/editor/assets/images/vertical-align-top.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/editor/assets/images/vertical-align.svg b/src/editor/assets/images/vertical-align.svg
new file mode 100644
index 0000000..b41d2b2
--- /dev/null
+++ b/src/editor/assets/images/vertical-align.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/editor/core/command/Command.ts b/src/editor/core/command/Command.ts
index 062afb8..09ab135 100644
--- a/src/editor/core/command/Command.ts
+++ b/src/editor/core/command/Command.ts
@@ -1,4 +1,4 @@
-import { IElement, ImageDisplay, INavigateInfo } from '../..'
+import { IElement, ImageDisplay, INavigateInfo, VerticalAlign } from '../..'
import { EditorMode, PageMode, PaperDirection } from '../../dataset/enum/Editor'
import { RowFlex } from '../../dataset/enum/Row'
import { IDrawImagePayload, IPainterOptions } from '../../interface/Draw'
@@ -47,6 +47,7 @@ export class Command {
private static deleteTable: CommandAdapt['deleteTable']
private static mergeTableCell: CommandAdapt['mergeTableCell']
private static cancelMergeTableCell: CommandAdapt['cancelMergeTableCell']
+ private static tableTdVerticalAlign: CommandAdapt['tableTdVerticalAlign']
private static image: CommandAdapt['image']
private static hyperlink: CommandAdapt['hyperlink']
private static deleteHyperlink: CommandAdapt['deleteHyperlink']
@@ -120,6 +121,7 @@ export class Command {
Command.deleteTable = adapt.deleteTable.bind(adapt)
Command.mergeTableCell = adapt.mergeTableCell.bind(adapt)
Command.cancelMergeTableCell = adapt.cancelMergeTableCell.bind(adapt)
+ Command.tableTdVerticalAlign = adapt.tableTdVerticalAlign.bind(adapt)
Command.image = adapt.image.bind(adapt)
Command.hyperlink = adapt.hyperlink.bind(adapt)
Command.deleteHyperlink = adapt.deleteHyperlink.bind(adapt)
@@ -311,6 +313,10 @@ export class Command {
return Command.cancelMergeTableCell()
}
+ public executeTableTdVerticalAlign(payload: VerticalAlign) {
+ return Command.tableTdVerticalAlign(payload)
+ }
+
public executeHyperlink(payload: IElement) {
return Command.hyperlink(payload)
}
diff --git a/src/editor/core/command/CommandAdapt.ts b/src/editor/core/command/CommandAdapt.ts
index 2b32b27..663b5f0 100644
--- a/src/editor/core/command/CommandAdapt.ts
+++ b/src/editor/core/command/CommandAdapt.ts
@@ -6,6 +6,7 @@ import { EditorContext, EditorMode, PageMode, PaperDirection } from '../../datas
import { ElementType } from '../../dataset/enum/Element'
import { ElementStyleKey } from '../../dataset/enum/ElementStyle'
import { RowFlex } from '../../dataset/enum/Row'
+import { VerticalAlign } from '../../dataset/enum/VerticalAlign'
import { IDrawImagePayload, IPainterOptions } from '../../interface/Draw'
import { IEditorOption, IEditorResult } from '../../interface/Editor'
import { IElement, IElementStyle } from '../../interface/Element'
@@ -997,6 +998,30 @@ export class CommandAdapt {
this.tableTool.render(element, position[index!])
}
+ public tableTdVerticalAlign(payload: VerticalAlign) {
+ const isReadonly = this.draw.isReadonly()
+ if (isReadonly) return
+ const positionContext = this.position.getPositionContext()
+ if (!positionContext.isTable) return
+ const { index, trIndex, tdIndex } = positionContext
+ const originalElementList = this.draw.getOriginalElementList()
+ const element = originalElementList[index!]
+ const curTd = element?.trList?.[trIndex!]?.tdList?.[tdIndex!]
+ if (
+ !curTd
+ || curTd.verticalAlign === payload
+ || (!curTd.verticalAlign && payload === VerticalAlign.TOP)
+ ) {
+ return
+ }
+ // 重设垂直对齐方式
+ curTd.verticalAlign = payload
+ const { endIndex } = this.range.getRange()
+ this.draw.render({
+ curIndex: endIndex
+ })
+ }
+
public hyperlink(payload: IElement) {
const isReadonly = this.draw.isReadonly()
if (isReadonly) return
diff --git a/src/editor/core/contextmenu/menus/tableMenus.ts b/src/editor/core/contextmenu/menus/tableMenus.ts
index 1974f52..0aa15f8 100644
--- a/src/editor/core/contextmenu/menus/tableMenus.ts
+++ b/src/editor/core/contextmenu/menus/tableMenus.ts
@@ -1,3 +1,4 @@
+import { VerticalAlign } from '../../../dataset/enum/VerticalAlign'
import { IRegisterContextMenu } from '../../../interface/contextmenu/ContextMenu'
import { Command } from '../../command/Command'
@@ -5,6 +6,39 @@ export const tableMenus: IRegisterContextMenu[] = [
{
isDivider: true
},
+ {
+ i18nPath: 'contextmenu.table.verticalAlign',
+ icon: 'vertical-align',
+ when: (payload) => {
+ return !payload.isReadonly && payload.isInTable
+ },
+ childMenus: [
+ {
+ i18nPath: 'contextmenu.table.verticalAlignTop',
+ icon: 'vertical-align-top',
+ when: () => true,
+ callback: (command: Command) => {
+ command.executeTableTdVerticalAlign(VerticalAlign.TOP)
+ }
+ },
+ {
+ i18nPath: 'contextmenu.table.verticalAlignMiddle',
+ icon: 'vertical-align-middle',
+ when: () => true,
+ callback: (command: Command) => {
+ command.executeTableTdVerticalAlign(VerticalAlign.MIDDLE)
+ }
+ },
+ {
+ i18nPath: 'contextmenu.table.verticalAlignBottom',
+ icon: 'vertical-align-bottom',
+ when: () => true,
+ callback: (command: Command) => {
+ command.executeTableTdVerticalAlign(VerticalAlign.BOTTOM)
+ }
+ }
+ ]
+ },
{
i18nPath: 'contextmenu.table.insertRowCol',
icon: 'insert-row-col',
diff --git a/src/editor/core/i18n/lang/en.json b/src/editor/core/i18n/lang/en.json
index 165b2c5..c7c9785 100644
--- a/src/editor/core/i18n/lang/en.json
+++ b/src/editor/core/i18n/lang/en.json
@@ -35,7 +35,11 @@
"deleteCol": "Delete 1 col",
"deleteTable": "Delete table",
"mergeCell": "Merge cell",
- "mergeCancelCell": "Cancel merge cell"
+ "mergeCancelCell": "Cancel merge cell",
+ "verticalAlign": "Vertical align",
+ "verticalAlignTop": "top",
+ "verticalAlignMiddle": "middle",
+ "verticalAlignBottom": "bottom"
}
},
"datePicker": {
diff --git a/src/editor/core/i18n/lang/zh-CN.json b/src/editor/core/i18n/lang/zh-CN.json
index d2e7b6b..67be634 100644
--- a/src/editor/core/i18n/lang/zh-CN.json
+++ b/src/editor/core/i18n/lang/zh-CN.json
@@ -35,7 +35,11 @@
"deleteCol": "删除1列",
"deleteTable": "删除整个表格",
"mergeCell": "合并单元格",
- "mergeCancelCell": "取消合并"
+ "mergeCancelCell": "取消合并",
+ "verticalAlign": "垂直对齐",
+ "verticalAlignTop": "顶端对齐",
+ "verticalAlignMiddle": "垂直居中",
+ "verticalAlignBottom": "底端对齐"
}
},
"datePicker": {
diff --git a/src/editor/core/position/Position.ts b/src/editor/core/position/Position.ts
index b4b9f0b..16e830b 100644
--- a/src/editor/core/position/Position.ts
+++ b/src/editor/core/position/Position.ts
@@ -1,4 +1,4 @@
-import { ElementType, RowFlex } from '../..'
+import { ElementType, RowFlex, VerticalAlign } from '../..'
import { ZERO } from '../../dataset/constant/Common'
import { ControlComponent, ImageDisplay } from '../../dataset/enum/Control'
import { IComputePageRowPositionPayload, IComputePageRowPositionResult } from '../../interface/Position'
@@ -112,15 +112,34 @@ export class Position {
for (let d = 0; d < tr.tdList!.length; d++) {
const td = tr.tdList[d]
td.positionList = []
+ const rowList = td.rowList!
const drawRowResult = this.computePageRowPosition({
positionList: td.positionList,
- rowList: td.rowList!,
+ rowList,
pageNo,
startIndex: 0,
startX: (td.x! + tdPadding) * scale + tablePreX,
startY: td.y! * scale + tablePreY,
innerWidth: (td.width! - tdGap) * scale
})
+ // 垂直对齐方式
+ if (
+ td.verticalAlign === VerticalAlign.MIDDLE
+ || td.verticalAlign == VerticalAlign.BOTTOM
+ ) {
+ const rowsHeight = rowList.reduce((pre, cur) => pre + cur.height, 0)
+ const blankHeight = td.height! - tdGap - rowsHeight
+ const offsetHeight = td.verticalAlign === VerticalAlign.MIDDLE ? blankHeight / 2 : blankHeight
+ if (Math.floor(offsetHeight) > 0) {
+ td.positionList.forEach(tdPosition => {
+ const { coordinate: { leftTop, leftBottom, rightBottom, rightTop } } = tdPosition
+ leftTop[1] += offsetHeight
+ leftBottom[1] += offsetHeight
+ rightBottom[1] += offsetHeight
+ rightTop[1] += offsetHeight
+ })
+ }
+ }
x = drawRowResult.x
y = drawRowResult.y
}
diff --git a/src/editor/dataset/enum/VerticalAlign.ts b/src/editor/dataset/enum/VerticalAlign.ts
new file mode 100644
index 0000000..8793426
--- /dev/null
+++ b/src/editor/dataset/enum/VerticalAlign.ts
@@ -0,0 +1,5 @@
+export enum VerticalAlign {
+ TOP = 'top',
+ MIDDLE = 'middle',
+ BOTTOM = 'bottom'
+}
\ No newline at end of file
diff --git a/src/editor/index.ts b/src/editor/index.ts
index 81c3586..e8515ab 100644
--- a/src/editor/index.ts
+++ b/src/editor/index.ts
@@ -33,6 +33,7 @@ import { ICursorOption } from './interface/Cursor'
import { defaultCursorOption } from './dataset/constant/Cursor'
import { IPageNumber } from './interface/PageNumber'
import { defaultPageNumberOption } from './dataset/constant/PageNumber'
+import { VerticalAlign } from './dataset/enum/VerticalAlign'
export default class Editor {
@@ -161,6 +162,7 @@ export default class Editor {
export {
Editor,
RowFlex,
+ VerticalAlign,
EditorZone,
EditorMode,
ElementType,
diff --git a/src/editor/interface/table/Td.ts b/src/editor/interface/table/Td.ts
index 57f3d90..c411920 100644
--- a/src/editor/interface/table/Td.ts
+++ b/src/editor/interface/table/Td.ts
@@ -1,3 +1,4 @@
+import { VerticalAlign } from '../../dataset/enum/VerticalAlign'
import { IElement, IElementPosition } from '../Element'
import { IRow } from '../Row'
@@ -17,4 +18,5 @@ export interface ITd {
colIndex?: number;
rowList?: IRow[];
positionList?: IElementPosition[];
+ verticalAlign?: VerticalAlign;
}
\ No newline at end of file
diff --git a/src/editor/utils/element.ts b/src/editor/utils/element.ts
index 095300d..1907959 100644
--- a/src/editor/utils/element.ts
+++ b/src/editor/utils/element.ts
@@ -6,6 +6,7 @@ import { ZERO } from '../dataset/constant/Common'
import { defaultControlOption } from '../dataset/constant/Control'
import { EDITOR_ELEMENT_ZIP_ATTR } from '../dataset/constant/Element'
import { ControlComponent, ControlType } from '../dataset/enum/Control'
+import { ITd } from '../interface/table/Td'
interface IFormatElementListOption {
isHandleFirstElement?: boolean;
@@ -308,11 +309,15 @@ export function zipElementList(payload: IElement[]): IElement[] {
delete tr.id
for (let d = 0; d < tr.tdList.length; d++) {
const td = tr.tdList[d]
- tr.tdList[d] = {
+ const zipTd: ITd = {
colspan: td.colspan,
rowspan: td.rowspan,
value: zipElementList(td.value)
}
+ if (td.verticalAlign) {
+ zipTd.verticalAlign = td.verticalAlign
+ }
+ tr.tdList[d] = zipTd
}
}
}