feat: table border type #152

pr675
Hufe921 3 years ago
parent 756c706b9f
commit 48ad18bccb

@ -146,3 +146,15 @@
.ce-contextmenu-vertical-align-bottom { .ce-contextmenu-vertical-align-bottom {
background-image: url(../../../assets/images/vertical-align-bottom.svg); background-image: url(../../../assets/images/vertical-align-bottom.svg);
} }
.ce-contextmenu-border-all {
background-image: url(../../../assets/images/table-border-all.svg);
}
.ce-contextmenu-border-empty {
background-image: url(../../../assets/images/table-border-empty.svg);
}
.ce-contextmenu-border-external {
background-image: url(../../../assets/images/table-border-external.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="#3D4757"/><path fill="#3D4757" d="M3 8h11v1H3z"/><path fill="#3D4757" d="M9 3v11H8V3z"/></svg>

After

Width:  |  Height:  |  Size: 265 B

@ -0,0 +1 @@
<svg width="16" height="16" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M13 3h-1V2h1a1 1 0 011 1v1h-1V3zm-3-1v1H8.5v2h-1V3H6V2h4zM4 2v1H3v1H2V3a1 1 0 011-1h1zM2 6h1v1.5h2v1H3V10H2V6zm0 6h1v1h1v1H3a1 1 0 01-1-1v-1zm4 2v-1h1.5v-2h1v2H10v1H6zm6 0v-1h1v-1h1v1a1 1 0 01-1 1h-1zm2-4h-1V8.5h-2v-1h2V6h1v4zM8.5 7.5v-1h-1v1h-1v1h1v1h1v-1h1v-1h-1z" fill="#AAACB0"/></svg>

After

Width:  |  Height:  |  Size: 413 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="#3D4757"/><path fill-rule="evenodd" clip-rule="evenodd" d="M9 5V3H8v2h1zm0 9v-2H8v2h1zM5 8H3v1h2V8zm9 0h-2v1h2V8zM9 7v1h1v1H9v1H8V9H7V8h1V7h1z" fill="#AAACB0"/></svg>

After

Width:  |  Height:  |  Size: 337 B

@ -1,4 +1,4 @@
import { IElement, ImageDisplay, INavigateInfo, VerticalAlign } from '../..' import { IElement, ImageDisplay, INavigateInfo, TableBorder, VerticalAlign } from '../..'
import { EditorMode, PageMode, PaperDirection } from '../../dataset/enum/Editor' import { EditorMode, PageMode, PaperDirection } from '../../dataset/enum/Editor'
import { RowFlex } from '../../dataset/enum/Row' import { RowFlex } from '../../dataset/enum/Row'
import { IDrawImagePayload, IPainterOptions } from '../../interface/Draw' import { IDrawImagePayload, IPainterOptions } from '../../interface/Draw'
@ -49,6 +49,7 @@ export class Command {
private static mergeTableCell: CommandAdapt['mergeTableCell'] private static mergeTableCell: CommandAdapt['mergeTableCell']
private static cancelMergeTableCell: CommandAdapt['cancelMergeTableCell'] private static cancelMergeTableCell: CommandAdapt['cancelMergeTableCell']
private static tableTdVerticalAlign: CommandAdapt['tableTdVerticalAlign'] private static tableTdVerticalAlign: CommandAdapt['tableTdVerticalAlign']
private static tableBorderType: CommandAdapt['tableBorderType']
private static image: CommandAdapt['image'] private static image: CommandAdapt['image']
private static hyperlink: CommandAdapt['hyperlink'] private static hyperlink: CommandAdapt['hyperlink']
private static deleteHyperlink: CommandAdapt['deleteHyperlink'] private static deleteHyperlink: CommandAdapt['deleteHyperlink']
@ -124,6 +125,7 @@ export class Command {
Command.mergeTableCell = adapt.mergeTableCell.bind(adapt) Command.mergeTableCell = adapt.mergeTableCell.bind(adapt)
Command.cancelMergeTableCell = adapt.cancelMergeTableCell.bind(adapt) Command.cancelMergeTableCell = adapt.cancelMergeTableCell.bind(adapt)
Command.tableTdVerticalAlign = adapt.tableTdVerticalAlign.bind(adapt) Command.tableTdVerticalAlign = adapt.tableTdVerticalAlign.bind(adapt)
Command.tableBorderType = adapt.tableBorderType.bind(adapt)
Command.image = adapt.image.bind(adapt) Command.image = adapt.image.bind(adapt)
Command.hyperlink = adapt.hyperlink.bind(adapt) Command.hyperlink = adapt.hyperlink.bind(adapt)
Command.deleteHyperlink = adapt.deleteHyperlink.bind(adapt) Command.deleteHyperlink = adapt.deleteHyperlink.bind(adapt)
@ -323,6 +325,10 @@ export class Command {
return Command.tableTdVerticalAlign(payload) return Command.tableTdVerticalAlign(payload)
} }
public executeTableBorderType(payload: TableBorder) {
return Command.tableBorderType(payload)
}
public executeHyperlink(payload: IElement) { public executeHyperlink(payload: IElement) {
return Command.hyperlink(payload) return Command.hyperlink(payload)
} }

@ -6,6 +6,7 @@ import { EditorContext, EditorMode, PageMode, PaperDirection } from '../../datas
import { ElementType } from '../../dataset/enum/Element' import { ElementType } from '../../dataset/enum/Element'
import { ElementStyleKey } from '../../dataset/enum/ElementStyle' import { ElementStyleKey } from '../../dataset/enum/ElementStyle'
import { RowFlex } from '../../dataset/enum/Row' import { RowFlex } from '../../dataset/enum/Row'
import { TableBorder } from '../../dataset/enum/table/Table'
import { VerticalAlign } from '../../dataset/enum/VerticalAlign' import { VerticalAlign } from '../../dataset/enum/VerticalAlign'
import { IDrawImagePayload, IPainterOptions } from '../../interface/Draw' import { IDrawImagePayload, IPainterOptions } from '../../interface/Draw'
import { IEditorOption, IEditorResult } from '../../interface/Editor' import { IEditorOption, IEditorResult } from '../../interface/Editor'
@ -1032,9 +1033,9 @@ export class CommandAdapt {
const element = originalElementList[index!] const element = originalElementList[index!]
const curTd = element?.trList?.[trIndex!]?.tdList?.[tdIndex!] const curTd = element?.trList?.[trIndex!]?.tdList?.[tdIndex!]
if ( if (
!curTd !curTd ||
|| curTd.verticalAlign === payload curTd.verticalAlign === payload ||
|| (!curTd.verticalAlign && payload === VerticalAlign.TOP) (!curTd.verticalAlign && payload === VerticalAlign.TOP)
) { ) {
return return
} }
@ -1046,6 +1047,27 @@ export class CommandAdapt {
}) })
} }
public tableBorderType(payload: TableBorder) {
const isReadonly = this.draw.isReadonly()
if (isReadonly) return
const positionContext = this.position.getPositionContext()
if (!positionContext.isTable) return
const { index } = positionContext
const originalElementList = this.draw.getOriginalElementList()
const element = originalElementList[index!]
if (
(!element.borderType && payload === TableBorder.ALL) ||
element.borderType === payload
) {
return
}
element.borderType = payload
const { endIndex } = this.range.getRange()
this.draw.render({
curIndex: endIndex
})
}
public hyperlink(payload: IElement) { public hyperlink(payload: IElement) {
const isReadonly = this.draw.isReadonly() const isReadonly = this.draw.isReadonly()
if (isReadonly) return if (isReadonly) return

@ -1,4 +1,5 @@
import { VerticalAlign } from '../../../dataset/enum/VerticalAlign' import { VerticalAlign } from '../../../dataset/enum/VerticalAlign'
import { TableBorder } from '../../../dataset/enum/table/Table'
import { IRegisterContextMenu } from '../../../interface/contextmenu/ContextMenu' import { IRegisterContextMenu } from '../../../interface/contextmenu/ContextMenu'
import { Command } from '../../command/Command' import { Command } from '../../command/Command'
@ -6,6 +7,39 @@ export const tableMenus: IRegisterContextMenu[] = [
{ {
isDivider: true isDivider: true
}, },
{
i18nPath: 'contextmenu.table.border',
icon: 'border-all',
when: (payload) => {
return !payload.isReadonly && payload.isInTable
},
childMenus: [
{
i18nPath: 'contextmenu.table.borderAll',
icon: 'border-all',
when: () => true,
callback: (command: Command) => {
command.executeTableBorderType(TableBorder.ALL)
}
},
{
i18nPath: 'contextmenu.table.borderEmpty',
icon: 'border-empty',
when: () => true,
callback: (command: Command) => {
command.executeTableBorderType(TableBorder.EMPTY)
}
},
{
i18nPath: 'contextmenu.table.borderExternal',
icon: 'border-external',
when: () => true,
callback: (command: Command) => {
command.executeTableBorderType(TableBorder.EXTERNAL)
}
}
]
},
{ {
i18nPath: 'contextmenu.table.verticalAlign', i18nPath: 'contextmenu.table.verticalAlign',
icon: 'vertical-align', icon: 'vertical-align',

@ -1,8 +1,17 @@
import { ElementType, IElement } from '../../../..' import { ElementType, IElement, TableBorder } from '../../../..'
import { IEditorOption } from '../../../../interface/Editor' import { IEditorOption } from '../../../../interface/Editor'
import { RangeManager } from '../../../range/RangeManager' import { RangeManager } from '../../../range/RangeManager'
import { Draw } from '../../Draw' import { Draw } from '../../Draw'
interface IDrawTableBorderOption {
ctx: CanvasRenderingContext2D;
startX: number;
startY: number;
width: number;
height: number;
isDrawFullBorder?: boolean;
}
export class TableParticle { export class TableParticle {
private range: RangeManager private range: RangeManager
@ -13,14 +22,19 @@ export class TableParticle {
this.options = draw.getOptions() this.options = draw.getOptions()
} }
private _drawBorder(ctx: CanvasRenderingContext2D, startX: number, startY: number, width: number, height: number) { private _drawBorder(payload: IDrawTableBorderOption) {
const { ctx, startX, startY, width, height, isDrawFullBorder } = payload
ctx.beginPath() ctx.beginPath()
const x = Math.round(startX) const x = Math.round(startX)
const y = Math.round(startY) const y = Math.round(startY)
ctx.translate(0.5, 0.5) ctx.translate(0.5, 0.5)
ctx.moveTo(x, y + height) if (isDrawFullBorder) {
ctx.lineTo(x, y) ctx.rect(x, y, width, height)
ctx.lineTo(x + width, y) } else {
ctx.moveTo(x, y + height)
ctx.lineTo(x, y)
ctx.lineTo(x + width, y)
}
ctx.stroke() ctx.stroke()
ctx.translate(-0.5, -0.5) ctx.translate(-0.5, -0.5)
} }
@ -159,31 +173,41 @@ export class TableParticle {
} }
public render(ctx: CanvasRenderingContext2D, element: IElement, startX: number, startY: number) { public render(ctx: CanvasRenderingContext2D, element: IElement, startX: number, startY: number) {
const { colgroup, trList } = element const { colgroup, trList, borderType } = element
if (!colgroup || !trList) return if (!colgroup || !trList || borderType === TableBorder.EMPTY) return
const { scale } = this.options const { scale } = this.options
const tableWidth = element.width! * scale const tableWidth = element.width! * scale
const tableHeight = element.height! * scale const tableHeight = element.height! * scale
const isExternalBorderType = borderType === TableBorder.EXTERNAL
ctx.save() ctx.save()
// 渲染边框 // 渲染边框
this._drawBorder(ctx, startX, startY, tableWidth, tableHeight) this._drawBorder({
// 渲染表格 ctx,
for (let t = 0; t < trList.length; t++) { startX,
const tr = trList[t] startY,
for (let d = 0; d < tr.tdList.length; d++) { width: tableWidth,
const td = tr.tdList[d] height: tableHeight,
const width = td.width! * scale isDrawFullBorder: isExternalBorderType
const height = td.height! * scale })
const x = Math.round(td.x! * scale + startX + width) if (!isExternalBorderType) {
const y = Math.round(td.y! * scale + startY) // 渲染表格
ctx.translate(0.5, 0.5) for (let t = 0; t < trList.length; t++) {
// 绘制线条 const tr = trList[t]
ctx.beginPath() for (let d = 0; d < tr.tdList.length; d++) {
ctx.moveTo(x, y) const td = tr.tdList[d]
ctx.lineTo(x, y + height) const width = td.width! * scale
ctx.lineTo(x - width, y + height) const height = td.height! * scale
ctx.stroke() const x = Math.round(td.x! * scale + startX + width)
ctx.translate(-0.5, -0.5) const y = Math.round(td.y! * scale + startY)
ctx.translate(0.5, 0.5)
// 绘制线条
ctx.beginPath()
ctx.moveTo(x, y)
ctx.lineTo(x, y + height)
ctx.lineTo(x - width, y + height)
ctx.stroke()
ctx.translate(-0.5, -0.5)
}
} }
} }
ctx.restore() ctx.restore()

@ -39,7 +39,11 @@
"verticalAlign": "Vertical align", "verticalAlign": "Vertical align",
"verticalAlignTop": "Top", "verticalAlignTop": "Top",
"verticalAlignMiddle": "Middle", "verticalAlignMiddle": "Middle",
"verticalAlignBottom": "Bottom" "verticalAlignBottom": "Bottom",
"border": "Table border",
"borderAll": "All",
"borderEmpty": "Empty",
"borderExternal": "External"
} }
}, },
"datePicker": { "datePicker": {

@ -39,7 +39,11 @@
"verticalAlign": "垂直对齐", "verticalAlign": "垂直对齐",
"verticalAlignTop": "顶端对齐", "verticalAlignTop": "顶端对齐",
"verticalAlignMiddle": "垂直居中", "verticalAlignMiddle": "垂直居中",
"verticalAlignBottom": "底端对齐" "verticalAlignBottom": "底端对齐",
"border": "表格边框",
"borderAll": "所有框线",
"borderEmpty": "无框线",
"borderExternal": "外侧框线"
} }
}, },
"datePicker": { "datePicker": {

@ -43,6 +43,7 @@ export const EDITOR_ELEMENT_ZIP_ATTR: Array<keyof IElement> = [
'rowMargin', 'rowMargin',
'dashArray', 'dashArray',
'trList', 'trList',
'borderType',
'width', 'width',
'height', 'height',
'url', 'url',

@ -0,0 +1,5 @@
export enum TableBorder {
ALL = 'all',
EMPTY = 'empty',
EXTERNAL = 'external'
}

@ -34,6 +34,7 @@ import { defaultCursorOption } from './dataset/constant/Cursor'
import { IPageNumber } from './interface/PageNumber' import { IPageNumber } from './interface/PageNumber'
import { defaultPageNumberOption } from './dataset/constant/PageNumber' import { defaultPageNumberOption } from './dataset/constant/PageNumber'
import { VerticalAlign } from './dataset/enum/VerticalAlign' import { VerticalAlign } from './dataset/enum/VerticalAlign'
import { TableBorder } from './dataset/enum/table/Table'
export default class Editor { export default class Editor {
@ -175,7 +176,8 @@ export {
Command, Command,
KeyMap, KeyMap,
BlockType, BlockType,
PaperDirection PaperDirection,
TableBorder
} }
// 对外类型 // 对外类型

@ -1,6 +1,7 @@
import { ControlComponent, ImageDisplay } from '../dataset/enum/Control' import { ControlComponent, ImageDisplay } from '../dataset/enum/Control'
import { ElementType } from '../dataset/enum/Element' import { ElementType } from '../dataset/enum/Element'
import { RowFlex } from '../dataset/enum/Row' import { RowFlex } from '../dataset/enum/Row'
import { TableBorder } from '../dataset/enum/table/Table'
import { IBlock } from './Block' import { IBlock } from './Block'
import { ICheckbox } from './Checkbox' import { ICheckbox } from './Checkbox'
import { IControl } from './Control' import { IControl } from './Control'
@ -32,6 +33,7 @@ export interface IElementStyle {
export interface ITableAttr { export interface ITableAttr {
colgroup?: IColgroup[]; colgroup?: IColgroup[];
trList?: ITr[]; trList?: ITr[];
borderType?: TableBorder;
} }
export interface ITableElement { export interface ITableElement {
@ -40,14 +42,14 @@ export interface ITableElement {
tableId?: string; tableId?: string;
} }
export type ITable = ITableAttr & ITableElement
export interface IHyperlinkElement { export interface IHyperlinkElement {
valueList?: IElement[]; valueList?: IElement[];
url?: string; url?: string;
hyperlinkId?: string; hyperlinkId?: string;
} }
export type ITable = ITableAttr & ITableElement
export interface ISuperscriptSubscript { export interface ISuperscriptSubscript {
actualSize?: number; actualSize?: number;
} }

Loading…
Cancel
Save