feat: add table td border type
This commit is contained in:
@@ -419,6 +419,16 @@ Usage:
|
||||
instance.command.executeTableBorderType(payload: TableBorder)
|
||||
```
|
||||
|
||||
## executeTableTdBorderType
|
||||
|
||||
Feature: Table td border type
|
||||
|
||||
Usage:
|
||||
|
||||
```javascript
|
||||
instance.command.executeTableTdBorderType(payload: TableBorder)
|
||||
```
|
||||
|
||||
## executeTableTdBackgroundColor
|
||||
|
||||
Feature: Table cell background color
|
||||
|
||||
@@ -63,6 +63,8 @@ interface ILang {
|
||||
borderAll: string
|
||||
borderEmpty: string
|
||||
borderExternal: string
|
||||
borderTd: string
|
||||
borderTdBottom: string
|
||||
}
|
||||
}
|
||||
datePicker: {
|
||||
|
||||
@@ -54,6 +54,7 @@ interface IElement {
|
||||
rowspan: number;
|
||||
verticalAlign?: VerticalAlign;
|
||||
backgroundColor?: string;
|
||||
borderType?: TdBorder;
|
||||
value: IElement[];
|
||||
}[];
|
||||
}[];
|
||||
|
||||
@@ -419,6 +419,16 @@ instance.command.executeTableTdVerticalAlign(payload: VerticalAlign)
|
||||
instance.command.executeTableBorderType(payload: TableBorder)
|
||||
```
|
||||
|
||||
## executeTableTdBorderType
|
||||
|
||||
功能:表格单元格边框类型
|
||||
|
||||
用法:
|
||||
|
||||
```javascript
|
||||
instance.command.executeTableTdBorderType(payload: TdBorder)
|
||||
```
|
||||
|
||||
## executeTableTdBackgroundColor
|
||||
|
||||
功能:表格单元格背景色
|
||||
|
||||
@@ -63,6 +63,8 @@ interface ILang {
|
||||
borderAll: string
|
||||
borderEmpty: string
|
||||
borderExternal: string
|
||||
borderTd: string
|
||||
borderTdBottom: string
|
||||
}
|
||||
}
|
||||
datePicker: {
|
||||
|
||||
@@ -54,6 +54,7 @@ interface IElement {
|
||||
rowspan: number;
|
||||
verticalAlign?: VerticalAlign;
|
||||
backgroundColor?: string;
|
||||
borderType?: TdBorder;
|
||||
value: IElement[];
|
||||
}[];
|
||||
}[];
|
||||
|
||||
@@ -157,4 +157,12 @@
|
||||
|
||||
.ce-contextmenu-border-external {
|
||||
background-image: url(../../../assets/images/table-border-external.svg);
|
||||
}
|
||||
|
||||
.ce-contextmenu-border-td {
|
||||
background-image: url(../../../assets/images/table-border-td.svg);
|
||||
}
|
||||
|
||||
.ce-contextmenu-border-td-bottom {
|
||||
background-image: url(../../../assets/images/table-border-td-bottom.svg);
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<svg width="16" height="16" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M2.5 3a.5.5 0 01.5-.5h11a.5.5 0 01.5.5v11a.5.5 0 01-.5.5H3a.5.5 0 01-.5-.5V3z" stroke="#AAACB0"/><path stroke="#3D4757" d="M2.5 8.5 h12"/></svg>
|
||||
|
After Width: | Height: | Size: 228 B |
@@ -0,0 +1 @@
|
||||
<svg width="16" height="16" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M2.5 3a.5.5 0 01.5-.5h11a.5.5 0 01.5.5v11a.5.5 0 01-.5.5H3a.5.5 0 01-.5-.5V3z" stroke="#AAACB0"/><path stroke="#3D4757" d="M8.5 2.5 v6 h-6"/></svg>
|
||||
|
After Width: | Height: | Size: 231 B |
@@ -43,6 +43,7 @@ export class Command {
|
||||
public executeCancelMergeTableCell: CommandAdapt['cancelMergeTableCell']
|
||||
public executeTableTdVerticalAlign: CommandAdapt['tableTdVerticalAlign']
|
||||
public executeTableBorderType: CommandAdapt['tableBorderType']
|
||||
public executeTableTdBorderType: CommandAdapt['tableTdBorderType']
|
||||
public executeTableTdBackgroundColor: CommandAdapt['tableTdBackgroundColor']
|
||||
public executeTableSelectAll: CommandAdapt['tableSelectAll']
|
||||
public executeImage: CommandAdapt['image']
|
||||
@@ -143,6 +144,7 @@ export class Command {
|
||||
this.executeCancelMergeTableCell = adapt.cancelMergeTableCell.bind(adapt)
|
||||
this.executeTableTdVerticalAlign = adapt.tableTdVerticalAlign.bind(adapt)
|
||||
this.executeTableBorderType = adapt.tableBorderType.bind(adapt)
|
||||
this.executeTableTdBorderType = adapt.tableTdBorderType.bind(adapt)
|
||||
this.executeTableTdBackgroundColor =
|
||||
adapt.tableTdBackgroundColor.bind(adapt)
|
||||
this.executeTableSelectAll = adapt.tableSelectAll.bind(adapt)
|
||||
|
||||
@@ -13,7 +13,7 @@ import { ElementType } from '../../dataset/enum/Element'
|
||||
import { ElementStyleKey } from '../../dataset/enum/ElementStyle'
|
||||
import { ListStyle, ListType } from '../../dataset/enum/List'
|
||||
import { RowFlex } from '../../dataset/enum/Row'
|
||||
import { TableBorder } from '../../dataset/enum/table/Table'
|
||||
import { TableBorder, TdBorder } from '../../dataset/enum/table/Table'
|
||||
import { TitleLevel } from '../../dataset/enum/Title'
|
||||
import { VerticalAlign } from '../../dataset/enum/VerticalAlign'
|
||||
import { ICatalog } from '../../interface/Catalog'
|
||||
@@ -1227,6 +1227,27 @@ export class CommandAdapt {
|
||||
})
|
||||
}
|
||||
|
||||
public tableTdBorderType(payload: TdBorder) {
|
||||
const isReadonly = this.draw.isReadonly()
|
||||
if (isReadonly) return
|
||||
const rowCol = this.draw.getTableParticle().getRangeRowCol()
|
||||
if (!rowCol) return
|
||||
const tdList = rowCol.flat()
|
||||
// 存在则设置边框类型,否则取消设置
|
||||
const isSetBorderType = tdList.some(td => td.borderType !== payload)
|
||||
tdList.forEach(td => {
|
||||
if (isSetBorderType) {
|
||||
td.borderType = payload
|
||||
} else {
|
||||
delete td.borderType
|
||||
}
|
||||
})
|
||||
const { endIndex } = this.range.getRange()
|
||||
this.draw.render({
|
||||
curIndex: endIndex
|
||||
})
|
||||
}
|
||||
|
||||
public tableTdBackgroundColor(payload: string) {
|
||||
const isReadonly = this.draw.isReadonly()
|
||||
if (isReadonly) return
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { VerticalAlign } from '../../../dataset/enum/VerticalAlign'
|
||||
import { TableBorder } from '../../../dataset/enum/table/Table'
|
||||
import { TableBorder, TdBorder } from '../../../dataset/enum/table/Table'
|
||||
import { IRegisterContextMenu } from '../../../interface/contextmenu/ContextMenu'
|
||||
import { Command } from '../../command/Command'
|
||||
|
||||
@@ -37,6 +37,21 @@ export const tableMenus: IRegisterContextMenu[] = [
|
||||
callback: (command: Command) => {
|
||||
command.executeTableBorderType(TableBorder.EXTERNAL)
|
||||
}
|
||||
},
|
||||
{
|
||||
i18nPath: 'contextmenu.table.borderTd',
|
||||
icon: 'border-td',
|
||||
when: () => true,
|
||||
childMenus: [
|
||||
{
|
||||
i18nPath: 'contextmenu.table.borderTdBottom',
|
||||
icon: 'border-td-bottom',
|
||||
when: () => true,
|
||||
callback: (command: Command) => {
|
||||
command.executeTableTdBorderType(TdBorder.BOTTOM)
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { ElementType, IElement, TableBorder } from '../../../..'
|
||||
import { TdBorder } from '../../../../dataset/enum/table/Table'
|
||||
import { IEditorOption } from '../../../../interface/Editor'
|
||||
import { ITd } from '../../../../interface/table/Td'
|
||||
import { ITr } from '../../../../interface/table/Tr'
|
||||
@@ -122,40 +123,55 @@ export class TableParticle {
|
||||
startY: number
|
||||
) {
|
||||
const { colgroup, trList, borderType } = element
|
||||
if (!colgroup || !trList || borderType === TableBorder.EMPTY) return
|
||||
if (!colgroup || !trList) return
|
||||
const { scale } = this.options
|
||||
const tableWidth = element.width! * scale
|
||||
const tableHeight = element.height! * scale
|
||||
// 无边框
|
||||
const isEmptyBorderType = borderType === TableBorder.EMPTY
|
||||
// 仅外边框
|
||||
const isExternalBorderType = borderType === TableBorder.EXTERNAL
|
||||
ctx.save()
|
||||
// 渲染边框
|
||||
this._drawOuterBorder({
|
||||
ctx,
|
||||
startX,
|
||||
startY,
|
||||
width: tableWidth,
|
||||
height: tableHeight,
|
||||
isDrawFullBorder: isExternalBorderType
|
||||
})
|
||||
if (!isExternalBorderType) {
|
||||
// 渲染表格
|
||||
for (let t = 0; t < trList.length; t++) {
|
||||
const tr = trList[t]
|
||||
for (let d = 0; d < tr.tdList.length; d++) {
|
||||
const td = tr.tdList[d]
|
||||
const width = td.width! * scale
|
||||
const height = td.height! * scale
|
||||
const x = Math.round(td.x! * scale + startX + width)
|
||||
const y = Math.round(td.y! * scale + startY)
|
||||
ctx.translate(0.5, 0.5)
|
||||
// 绘制线条
|
||||
ctx.beginPath()
|
||||
if (!isEmptyBorderType) {
|
||||
this._drawOuterBorder({
|
||||
ctx,
|
||||
startX,
|
||||
startY,
|
||||
width: tableWidth,
|
||||
height: tableHeight,
|
||||
isDrawFullBorder: isExternalBorderType
|
||||
})
|
||||
}
|
||||
// 渲染单元格
|
||||
for (let t = 0; t < trList.length; t++) {
|
||||
const tr = trList[t]
|
||||
for (let d = 0; d < tr.tdList.length; d++) {
|
||||
const td = tr.tdList[d]
|
||||
// 没有设置单元格边框 && 没有设置表格边框则忽略
|
||||
if (!td.borderType && (isEmptyBorderType || isExternalBorderType)) {
|
||||
continue
|
||||
}
|
||||
const width = td.width! * scale
|
||||
const height = td.height! * scale
|
||||
const x = Math.round(td.x! * scale + startX + width)
|
||||
const y = Math.round(td.y! * scale + startY)
|
||||
ctx.translate(0.5, 0.5)
|
||||
// 绘制线条
|
||||
ctx.beginPath()
|
||||
if (td.borderType === TdBorder.BOTTOM) {
|
||||
ctx.moveTo(x, y + height)
|
||||
ctx.lineTo(x - width, y + height)
|
||||
ctx.stroke()
|
||||
}
|
||||
if (!isEmptyBorderType && !isExternalBorderType) {
|
||||
ctx.moveTo(x, y + height)
|
||||
ctx.moveTo(x, y)
|
||||
ctx.lineTo(x, y + height)
|
||||
ctx.lineTo(x - width, y + height)
|
||||
ctx.stroke()
|
||||
ctx.translate(-0.5, -0.5)
|
||||
}
|
||||
ctx.translate(-0.5, -0.5)
|
||||
}
|
||||
}
|
||||
ctx.restore()
|
||||
|
||||
@@ -43,7 +43,9 @@
|
||||
"border": "Table border",
|
||||
"borderAll": "All",
|
||||
"borderEmpty": "Empty",
|
||||
"borderExternal": "External"
|
||||
"borderExternal": "External",
|
||||
"borderTd": "Table cell border",
|
||||
"borderTdBottom": "Bottom"
|
||||
}
|
||||
},
|
||||
"datePicker": {
|
||||
|
||||
@@ -43,7 +43,9 @@
|
||||
"border": "表格边框",
|
||||
"borderAll": "所有框线",
|
||||
"borderEmpty": "无框线",
|
||||
"borderExternal": "外侧框线"
|
||||
"borderExternal": "外侧框线",
|
||||
"borderTd": "单元格边框",
|
||||
"borderTdBottom": "下边框"
|
||||
}
|
||||
},
|
||||
"datePicker": {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { ElementType } from '../enum/Element'
|
||||
import { IElement } from '../../interface/Element'
|
||||
import { ITd } from '../../interface/table/Td'
|
||||
|
||||
export const EDITOR_ELEMENT_STYLE_ATTR: Array<keyof IElement> = [
|
||||
'bold',
|
||||
@@ -61,6 +62,12 @@ export const EDITOR_ELEMENT_ZIP_ATTR: Array<keyof IElement> = [
|
||||
'groupIds'
|
||||
]
|
||||
|
||||
export const TABLE_TD_ZIP_ATTR: Array<keyof ITd> = [
|
||||
'verticalAlign',
|
||||
'backgroundColor',
|
||||
'borderType'
|
||||
]
|
||||
|
||||
export const TABLE_CONTEXT_ATTR: Array<keyof IElement> = [
|
||||
'tdId',
|
||||
'trId',
|
||||
|
||||
@@ -3,3 +3,7 @@ export enum TableBorder {
|
||||
EMPTY = 'empty',
|
||||
EXTERNAL = 'external'
|
||||
}
|
||||
|
||||
export enum TdBorder {
|
||||
BOTTOM = 'bottom'
|
||||
}
|
||||
|
||||
+2
-1
@@ -44,7 +44,7 @@ import { defaultCursorOption } from './dataset/constant/Cursor'
|
||||
import { IPageNumber } from './interface/PageNumber'
|
||||
import { defaultPageNumberOption } from './dataset/constant/PageNumber'
|
||||
import { VerticalAlign } from './dataset/enum/VerticalAlign'
|
||||
import { TableBorder } from './dataset/enum/table/Table'
|
||||
import { TableBorder, TdBorder } from './dataset/enum/table/Table'
|
||||
import { IFooter } from './interface/Footer'
|
||||
import { defaultFooterOption } from './dataset/constant/Footer'
|
||||
import { MaxHeightRatio, NumberType } from './dataset/enum/Common'
|
||||
@@ -259,6 +259,7 @@ export {
|
||||
BlockType,
|
||||
PaperDirection,
|
||||
TableBorder,
|
||||
TdBorder,
|
||||
MaxHeightRatio,
|
||||
NumberType,
|
||||
TitleLevel,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { VerticalAlign } from '../../dataset/enum/VerticalAlign'
|
||||
import { TdBorder } from '../../dataset/enum/table/Table'
|
||||
import { IElement, IElementPosition } from '../Element'
|
||||
import { IRow } from '../Row'
|
||||
|
||||
@@ -20,6 +21,7 @@ export interface ITd {
|
||||
positionList?: IElementPosition[]
|
||||
verticalAlign?: VerticalAlign
|
||||
backgroundColor?: string
|
||||
borderType?: TdBorder
|
||||
mainHeight?: number // 内容 + 内边距高度
|
||||
realHeight?: number // 真实高度(包含跨列)
|
||||
realMinHeight?: number // 真实最小高度(包含跨列)
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
EDITOR_ELEMENT_ZIP_ATTR,
|
||||
INLINE_NODE_NAME,
|
||||
TABLE_CONTEXT_ATTR,
|
||||
TABLE_TD_ZIP_ATTR,
|
||||
TEXTLIKE_ELEMENT_TYPE
|
||||
} from '../dataset/constant/Element'
|
||||
import {
|
||||
@@ -483,12 +484,13 @@ export function zipElementList(payload: IElement[]): IElement[] {
|
||||
rowspan: td.rowspan,
|
||||
value: zipElementList(td.value)
|
||||
}
|
||||
if (td.verticalAlign) {
|
||||
zipTd.verticalAlign = td.verticalAlign
|
||||
}
|
||||
if (td.backgroundColor) {
|
||||
zipTd.backgroundColor = td.backgroundColor
|
||||
}
|
||||
// 压缩单元格属性
|
||||
TABLE_TD_ZIP_ATTR.forEach(attr => {
|
||||
const value = td[attr] as never
|
||||
if (value !== undefined) {
|
||||
zipTd[attr] = value
|
||||
}
|
||||
})
|
||||
tr.tdList[d] = zipTd
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user