feat: move between table cells using up and down keys #465
This commit is contained in:
@@ -741,7 +741,7 @@ export class Draw {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getRowCount(): number {
|
public getRowCount(): number {
|
||||||
return this.rowList.length
|
return this.getRowList().length
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getDataURL(payload: IGetImageOption = {}): Promise<string[]> {
|
public async getDataURL(payload: IGetImageOption = {}): Promise<string[]> {
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ export function left(evt: KeyboardEvent, host: CanvasEvent) {
|
|||||||
if (startIndex === 0) {
|
if (startIndex === 0) {
|
||||||
const originalElementList = draw.getOriginalElementList()
|
const originalElementList = draw.getOriginalElementList()
|
||||||
const trList = originalElementList[positionContext.index!].trList!
|
const trList = originalElementList[positionContext.index!].trList!
|
||||||
for (let r = 0; r < trList.length; r++) {
|
outer: for (let r = 0; r < trList.length; r++) {
|
||||||
const tr = trList[r]
|
const tr = trList[r]
|
||||||
if (tr.id !== element.trId) continue
|
if (tr.id !== element.trId) continue
|
||||||
const tdList = tr.tdList
|
const tdList = tr.tdList
|
||||||
@@ -112,15 +112,15 @@ export function left(evt: KeyboardEvent, host: CanvasEvent) {
|
|||||||
index: positionContext.index,
|
index: positionContext.index,
|
||||||
trIndex: preTrIndex,
|
trIndex: preTrIndex,
|
||||||
tdIndex: preTdIndex,
|
tdIndex: preTdIndex,
|
||||||
tdId: preTr.id,
|
tdId: preTd.id,
|
||||||
trId: preTd.id,
|
trId: preTr.id,
|
||||||
tableId: element.id
|
tableId: element.id
|
||||||
})
|
})
|
||||||
anchorStartIndex = preTd.value.length - 1
|
anchorStartIndex = preTd.value.length - 1
|
||||||
anchorEndIndex = anchorStartIndex
|
anchorEndIndex = anchorStartIndex
|
||||||
draw.getTableTool().render()
|
draw.getTableTool().render()
|
||||||
}
|
}
|
||||||
break
|
break outer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ export function right(evt: KeyboardEvent, host: CanvasEvent) {
|
|||||||
if (!nextElement) {
|
if (!nextElement) {
|
||||||
const originalElementList = draw.getOriginalElementList()
|
const originalElementList = draw.getOriginalElementList()
|
||||||
const trList = originalElementList[positionContext.index!].trList!
|
const trList = originalElementList[positionContext.index!].trList!
|
||||||
for (let r = 0; r < trList.length; r++) {
|
outer: for (let r = 0; r < trList.length; r++) {
|
||||||
const tr = trList[r]
|
const tr = trList[r]
|
||||||
if (tr.id !== element.trId) continue
|
if (tr.id !== element.trId) continue
|
||||||
const tdList = tr.tdList
|
const tdList = tr.tdList
|
||||||
@@ -113,15 +113,15 @@ export function right(evt: KeyboardEvent, host: CanvasEvent) {
|
|||||||
index: positionContext.index,
|
index: positionContext.index,
|
||||||
trIndex: nextTrIndex,
|
trIndex: nextTrIndex,
|
||||||
tdIndex: nextTdIndex,
|
tdIndex: nextTdIndex,
|
||||||
tdId: preTr.id,
|
tdId: preTd.id,
|
||||||
trId: preTd.id,
|
trId: preTr.id,
|
||||||
tableId: element.id
|
tableId: element.id
|
||||||
})
|
})
|
||||||
anchorStartIndex = 0
|
anchorStartIndex = 0
|
||||||
anchorEndIndex = anchorStartIndex
|
anchorEndIndex = anchorStartIndex
|
||||||
draw.getTableTool().render()
|
draw.getTableTool().render()
|
||||||
}
|
}
|
||||||
break
|
break outer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,44 +1,20 @@
|
|||||||
|
import { ElementType } from '../../../../dataset/enum/Element'
|
||||||
import { KeyMap } from '../../../../dataset/enum/KeyMap'
|
import { KeyMap } from '../../../../dataset/enum/KeyMap'
|
||||||
import { MoveDirection } from '../../../../dataset/enum/Observer'
|
import { MoveDirection } from '../../../../dataset/enum/Observer'
|
||||||
import { IElementPosition } from '../../../../interface/Element'
|
import { IElementPosition } from '../../../../interface/Element'
|
||||||
import { CanvasEvent } from '../../CanvasEvent'
|
import { CanvasEvent } from '../../CanvasEvent'
|
||||||
|
|
||||||
export function updown(evt: KeyboardEvent, host: CanvasEvent) {
|
interface IGetNextPositionIndexPayload {
|
||||||
const draw = host.getDraw()
|
positionList: IElementPosition[]
|
||||||
const isReadonly = draw.isReadonly()
|
index: number
|
||||||
if (isReadonly) return
|
rowNo: number
|
||||||
const position = draw.getPosition()
|
isUp: boolean
|
||||||
const cursorPosition = position.getCursorPosition()
|
cursorX: number
|
||||||
if (!cursorPosition) return
|
}
|
||||||
const rangeManager = draw.getRange()
|
// 根据当前位置索引查找上下行最接近的索引位置
|
||||||
const { startIndex, endIndex } = rangeManager.getRange()
|
function getNextPositionIndex(payload: IGetNextPositionIndexPayload) {
|
||||||
const positionList = position.getPositionList()
|
const { positionList, index, isUp, rowNo, cursorX } = payload
|
||||||
let anchorPosition: IElementPosition = cursorPosition
|
let nextIndex = 0
|
||||||
// 扩大选区时,判断移动光标点
|
|
||||||
if (evt.shiftKey) {
|
|
||||||
if (startIndex === cursorPosition.index) {
|
|
||||||
anchorPosition = positionList[endIndex]
|
|
||||||
} else {
|
|
||||||
anchorPosition = positionList[startIndex]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const {
|
|
||||||
index,
|
|
||||||
rowNo,
|
|
||||||
rowIndex,
|
|
||||||
coordinate: {
|
|
||||||
leftTop: [curLeftX],
|
|
||||||
rightTop: [curRightX]
|
|
||||||
}
|
|
||||||
} = anchorPosition
|
|
||||||
// 向上时在首行、向下时在尾行则忽略
|
|
||||||
const isUp = evt.key === KeyMap.Up
|
|
||||||
if (
|
|
||||||
(isUp && rowIndex === 0) ||
|
|
||||||
(!isUp && rowIndex === draw.getRowCount() - 1)
|
|
||||||
) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// 查找下一行位置列表
|
// 查找下一行位置列表
|
||||||
const probablePosition: IElementPosition[] = []
|
const probablePosition: IElementPosition[] = []
|
||||||
if (isUp) {
|
if (isUp) {
|
||||||
@@ -65,7 +41,6 @@ export function updown(evt: KeyboardEvent, host: CanvasEvent) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 查找下一行位置:第一个存在交叉宽度的元素位置
|
// 查找下一行位置:第一个存在交叉宽度的元素位置
|
||||||
let nextIndex = 0
|
|
||||||
for (let p = 0; p < probablePosition.length; p++) {
|
for (let p = 0; p < probablePosition.length; p++) {
|
||||||
const nextPosition = probablePosition[p]
|
const nextPosition = probablePosition[p]
|
||||||
const {
|
const {
|
||||||
@@ -77,14 +52,173 @@ export function updown(evt: KeyboardEvent, host: CanvasEvent) {
|
|||||||
if (p === probablePosition.length - 1) {
|
if (p === probablePosition.length - 1) {
|
||||||
nextIndex = nextPosition.index
|
nextIndex = nextPosition.index
|
||||||
}
|
}
|
||||||
if (curRightX <= nextLeftX || curLeftX >= nextRightX) continue
|
if (cursorX < nextLeftX || cursorX > nextRightX) continue
|
||||||
nextIndex = nextPosition.index
|
nextIndex = nextPosition.index
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
return nextIndex
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updown(evt: KeyboardEvent, host: CanvasEvent) {
|
||||||
|
const draw = host.getDraw()
|
||||||
|
const isReadonly = draw.isReadonly()
|
||||||
|
if (isReadonly) return
|
||||||
|
const position = draw.getPosition()
|
||||||
|
const cursorPosition = position.getCursorPosition()
|
||||||
|
if (!cursorPosition) return
|
||||||
|
const rangeManager = draw.getRange()
|
||||||
|
const { startIndex, endIndex } = rangeManager.getRange()
|
||||||
|
let positionList = position.getPositionList()
|
||||||
|
const isUp = evt.key === KeyMap.Up
|
||||||
|
// 新的光标开始结束位置
|
||||||
|
let anchorStartIndex = -1
|
||||||
|
let anchorEndIndex = -1
|
||||||
|
// 单元格之间跳转及跳出表格逻辑
|
||||||
|
const positionContext = position.getPositionContext()
|
||||||
|
if (
|
||||||
|
!evt.shiftKey &&
|
||||||
|
positionContext.isTable &&
|
||||||
|
((isUp && cursorPosition.rowIndex === 0) ||
|
||||||
|
(!isUp && cursorPosition.rowIndex === draw.getRowCount() - 1))
|
||||||
|
) {
|
||||||
|
const { index, trIndex, tdIndex, tableId } = positionContext
|
||||||
|
if (isUp) {
|
||||||
|
// 向上移动-第一行则移出到表格外,否则上一行相同列位置
|
||||||
|
if (trIndex === 0) {
|
||||||
|
position.setPositionContext({
|
||||||
|
isTable: false
|
||||||
|
})
|
||||||
|
anchorStartIndex = index! - 1
|
||||||
|
anchorEndIndex = anchorStartIndex
|
||||||
|
draw.getTableTool().dispose()
|
||||||
|
} else {
|
||||||
|
// 查找上一行相同列索引位置信息
|
||||||
|
let preTrIndex = -1
|
||||||
|
let preTdIndex = -1
|
||||||
|
const originalElementList = draw.getOriginalElementList()
|
||||||
|
const trList = originalElementList[index!].trList!
|
||||||
|
// 当前单元格所在列实际索引
|
||||||
|
const curTdColIndex = trList[trIndex!].tdList[tdIndex!].colIndex!
|
||||||
|
outer: for (let r = trIndex! - 1; r >= 0; r--) {
|
||||||
|
const tr = trList[r]
|
||||||
|
const tdList = tr.tdList!
|
||||||
|
for (let d = 0; d < tdList.length; d++) {
|
||||||
|
const td = tdList[d]
|
||||||
|
if (
|
||||||
|
td.colIndex === curTdColIndex ||
|
||||||
|
(td.colIndex! + td.colspan - 1 >= curTdColIndex &&
|
||||||
|
td.colIndex! <= curTdColIndex)
|
||||||
|
) {
|
||||||
|
preTrIndex = r
|
||||||
|
preTdIndex = d
|
||||||
|
break outer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!~preTrIndex || !~preTdIndex) return
|
||||||
|
const preTr = trList[preTrIndex]
|
||||||
|
const preTd = preTr.tdList[preTdIndex]
|
||||||
|
position.setPositionContext({
|
||||||
|
isTable: true,
|
||||||
|
index,
|
||||||
|
trIndex: preTrIndex,
|
||||||
|
tdIndex: preTdIndex,
|
||||||
|
tdId: preTr.id,
|
||||||
|
trId: preTd.id,
|
||||||
|
tableId
|
||||||
|
})
|
||||||
|
anchorStartIndex = preTd.value.length - 1
|
||||||
|
anchorEndIndex = anchorStartIndex
|
||||||
|
draw.getTableTool().render()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 向下移动-最后一行则移出表格外,否则下一行相同列位置
|
||||||
|
const originalElementList = draw.getOriginalElementList()
|
||||||
|
const trList = originalElementList[index!].trList!
|
||||||
|
if (trIndex === trList.length - 1) {
|
||||||
|
position.setPositionContext({
|
||||||
|
isTable: false
|
||||||
|
})
|
||||||
|
anchorStartIndex = index!
|
||||||
|
anchorEndIndex = anchorStartIndex
|
||||||
|
draw.getTableTool().dispose()
|
||||||
|
} else {
|
||||||
|
// 查找下一行相同列索引位置信息
|
||||||
|
let nexTrIndex = -1
|
||||||
|
let nextTdIndex = -1
|
||||||
|
// 当前单元格所在列实际索引
|
||||||
|
const curTdColIndex = trList[trIndex!].tdList[tdIndex!].colIndex!
|
||||||
|
outer: for (let r = trIndex! + 1; r < trList.length; r++) {
|
||||||
|
const tr = trList[r]
|
||||||
|
const tdList = tr.tdList!
|
||||||
|
for (let d = 0; d < tdList.length; d++) {
|
||||||
|
const td = tdList[d]
|
||||||
|
if (
|
||||||
|
td.colIndex === curTdColIndex ||
|
||||||
|
(td.colIndex! + td.colspan - 1 >= curTdColIndex &&
|
||||||
|
td.colIndex! <= curTdColIndex)
|
||||||
|
) {
|
||||||
|
nexTrIndex = r
|
||||||
|
nextTdIndex = d
|
||||||
|
break outer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!~nexTrIndex || !~nextTdIndex) return
|
||||||
|
const nextTr = trList[nexTrIndex]
|
||||||
|
const nextTd = nextTr.tdList[nextTdIndex]
|
||||||
|
position.setPositionContext({
|
||||||
|
isTable: true,
|
||||||
|
index,
|
||||||
|
trIndex: nexTrIndex,
|
||||||
|
tdIndex: nextTdIndex,
|
||||||
|
tdId: nextTr.id,
|
||||||
|
trId: nextTd.id,
|
||||||
|
tableId
|
||||||
|
})
|
||||||
|
anchorStartIndex = nextTd.value.length - 1
|
||||||
|
anchorEndIndex = anchorStartIndex
|
||||||
|
draw.getTableTool().render()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 普通元素及跳进表格逻辑
|
||||||
|
let anchorPosition: IElementPosition = cursorPosition
|
||||||
|
// 扩大选区时,判断移动光标点
|
||||||
|
if (evt.shiftKey) {
|
||||||
|
if (startIndex === cursorPosition.index) {
|
||||||
|
anchorPosition = positionList[endIndex]
|
||||||
|
} else {
|
||||||
|
anchorPosition = positionList[startIndex]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const {
|
||||||
|
index,
|
||||||
|
rowNo,
|
||||||
|
rowIndex,
|
||||||
|
coordinate: {
|
||||||
|
rightTop: [curRightX]
|
||||||
|
}
|
||||||
|
} = anchorPosition
|
||||||
|
// 向上时在首行、向下时在尾行则忽略
|
||||||
|
if (
|
||||||
|
(isUp && rowIndex === 0) ||
|
||||||
|
(!isUp && rowIndex === draw.getRowCount() - 1)
|
||||||
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 查找下一行位置列表
|
||||||
|
const nextIndex = getNextPositionIndex({
|
||||||
|
positionList,
|
||||||
|
index,
|
||||||
|
rowNo,
|
||||||
|
isUp,
|
||||||
|
cursorX: curRightX
|
||||||
|
})
|
||||||
if (!nextIndex) return
|
if (!nextIndex) return
|
||||||
// shift则缩放选区
|
// shift则缩放选区
|
||||||
let anchorStartIndex = nextIndex
|
anchorStartIndex = nextIndex
|
||||||
let anchorEndIndex = nextIndex
|
anchorEndIndex = nextIndex
|
||||||
if (evt.shiftKey) {
|
if (evt.shiftKey) {
|
||||||
if (startIndex !== endIndex) {
|
if (startIndex !== endIndex) {
|
||||||
if (startIndex === cursorPosition.index) {
|
if (startIndex === cursorPosition.index) {
|
||||||
@@ -100,6 +234,91 @@ export function updown(evt: KeyboardEvent, host: CanvasEvent) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 如果下一行是表格则进入单元格内
|
||||||
|
const elementList = draw.getElementList()
|
||||||
|
const nextElement = elementList[nextIndex]
|
||||||
|
if (nextElement.type === ElementType.TABLE) {
|
||||||
|
const { scale } = draw.getOptions()
|
||||||
|
const margins = draw.getMargins()
|
||||||
|
const trList = nextElement.trList!
|
||||||
|
// 查找进入的单元格及元素位置
|
||||||
|
let trIndex = -1
|
||||||
|
let tdIndex = -1
|
||||||
|
let tdPositionIndex = -1
|
||||||
|
if (isUp) {
|
||||||
|
outer: for (let r = trList.length - 1; r >= 0; r--) {
|
||||||
|
const tr = trList[r]
|
||||||
|
const tdList = tr.tdList!
|
||||||
|
for (let d = 0; d < tdList.length; d++) {
|
||||||
|
const td = tdList[d]
|
||||||
|
const tdX = td.x! * scale + margins[3]
|
||||||
|
const tdWidth = td.width! * scale
|
||||||
|
if (curRightX >= tdX && curRightX <= tdX + tdWidth) {
|
||||||
|
const tdPositionList = td.positionList!
|
||||||
|
const lastPosition = tdPositionList[tdPositionList.length - 1]
|
||||||
|
const nextPositionIndex =
|
||||||
|
getNextPositionIndex({
|
||||||
|
positionList: tdPositionList,
|
||||||
|
index: lastPosition.index + 1, // 虚拟起始位置+1(从左往右找)
|
||||||
|
rowNo: lastPosition.rowNo - 1, // 虚拟起始行号-1(从下往上找)
|
||||||
|
isUp,
|
||||||
|
cursorX: curRightX
|
||||||
|
}) || lastPosition.index
|
||||||
|
trIndex = r
|
||||||
|
tdIndex = d
|
||||||
|
tdPositionIndex = nextPositionIndex
|
||||||
|
break outer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
outer: for (let r = 0; r < trList.length; r++) {
|
||||||
|
const tr = trList[r]
|
||||||
|
const tdList = tr.tdList!
|
||||||
|
for (let d = 0; d < tdList.length; d++) {
|
||||||
|
const td = tdList[d]
|
||||||
|
const tdX = td.x! * scale + margins[3]
|
||||||
|
const tdWidth = td.width! * scale
|
||||||
|
if (curRightX >= tdX && curRightX <= tdX + tdWidth) {
|
||||||
|
const tdPositionList = td.positionList!
|
||||||
|
const nextPositionIndex =
|
||||||
|
getNextPositionIndex({
|
||||||
|
positionList: tdPositionList,
|
||||||
|
index: -1, // 虚拟起始位置-1(从右往左找)
|
||||||
|
rowNo: -1, // 虚拟起始行号-1(从上往下找)
|
||||||
|
isUp,
|
||||||
|
cursorX: curRightX
|
||||||
|
}) || 0
|
||||||
|
trIndex = r
|
||||||
|
tdIndex = d
|
||||||
|
tdPositionIndex = nextPositionIndex
|
||||||
|
break outer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 设置上下文
|
||||||
|
if (~trIndex && ~tdIndex && ~tdPositionIndex) {
|
||||||
|
const nextTr = trList[trIndex]
|
||||||
|
const nextTd = nextTr.tdList[tdIndex]
|
||||||
|
position.setPositionContext({
|
||||||
|
isTable: true,
|
||||||
|
index: nextIndex,
|
||||||
|
trIndex: trIndex,
|
||||||
|
tdIndex: tdIndex,
|
||||||
|
tdId: nextTd.id,
|
||||||
|
trId: nextTr.id,
|
||||||
|
tableId: nextElement.id
|
||||||
|
})
|
||||||
|
anchorStartIndex = tdPositionIndex
|
||||||
|
anchorEndIndex = anchorStartIndex
|
||||||
|
positionList = position.getPositionList()
|
||||||
|
draw.getTableTool().render()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 执行跳转
|
||||||
|
if (!~anchorStartIndex || !~anchorEndIndex) return
|
||||||
if (anchorStartIndex > anchorEndIndex) {
|
if (anchorStartIndex > anchorEndIndex) {
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
[anchorStartIndex, anchorEndIndex] = [anchorEndIndex, anchorStartIndex]
|
[anchorStartIndex, anchorEndIndex] = [anchorEndIndex, anchorStartIndex]
|
||||||
|
|||||||
Reference in New Issue
Block a user