feat: move between table cells using up and down keys #465

pr675
Hufe921 2 years ago
parent a06c13932c
commit 2de1ba7b62

@ -741,7 +741,7 @@ export class Draw {
}
public getRowCount(): number {
return this.rowList.length
return this.getRowList().length
}
public async getDataURL(payload: IGetImageOption = {}): Promise<string[]> {

@ -82,7 +82,7 @@ export function left(evt: KeyboardEvent, host: CanvasEvent) {
if (startIndex === 0) {
const originalElementList = draw.getOriginalElementList()
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]
if (tr.id !== element.trId) continue
const tdList = tr.tdList
@ -112,15 +112,15 @@ export function left(evt: KeyboardEvent, host: CanvasEvent) {
index: positionContext.index,
trIndex: preTrIndex,
tdIndex: preTdIndex,
tdId: preTr.id,
trId: preTd.id,
tdId: preTd.id,
trId: preTr.id,
tableId: element.id
})
anchorStartIndex = preTd.value.length - 1
anchorEndIndex = anchorStartIndex
draw.getTableTool().render()
}
break
break outer
}
}
}

@ -82,7 +82,7 @@ export function right(evt: KeyboardEvent, host: CanvasEvent) {
if (!nextElement) {
const originalElementList = draw.getOriginalElementList()
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]
if (tr.id !== element.trId) continue
const tdList = tr.tdList
@ -113,15 +113,15 @@ export function right(evt: KeyboardEvent, host: CanvasEvent) {
index: positionContext.index,
trIndex: nextTrIndex,
tdIndex: nextTdIndex,
tdId: preTr.id,
trId: preTd.id,
tdId: preTd.id,
trId: preTr.id,
tableId: element.id
})
anchorStartIndex = 0
anchorEndIndex = anchorStartIndex
draw.getTableTool().render()
}
break
break outer
}
}
}

@ -1,44 +1,20 @@
import { ElementType } from '../../../../dataset/enum/Element'
import { KeyMap } from '../../../../dataset/enum/KeyMap'
import { MoveDirection } from '../../../../dataset/enum/Observer'
import { IElementPosition } from '../../../../interface/Element'
import { CanvasEvent } from '../../CanvasEvent'
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()
const positionList = position.getPositionList()
let anchorPosition: IElementPosition = cursorPosition
// 扩大选区时,判断移动光标点
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
}
interface IGetNextPositionIndexPayload {
positionList: IElementPosition[]
index: number
rowNo: number
isUp: boolean
cursorX: number
}
// 根据当前位置索引查找上下行最接近的索引位置
function getNextPositionIndex(payload: IGetNextPositionIndexPayload) {
const { positionList, index, isUp, rowNo, cursorX } = payload
let nextIndex = 0
// 查找下一行位置列表
const probablePosition: IElementPosition[] = []
if (isUp) {
@ -65,7 +41,6 @@ export function updown(evt: KeyboardEvent, host: CanvasEvent) {
}
}
// 查找下一行位置:第一个存在交叉宽度的元素位置
let nextIndex = 0
for (let p = 0; p < probablePosition.length; p++) {
const nextPosition = probablePosition[p]
const {
@ -77,29 +52,273 @@ export function updown(evt: KeyboardEvent, host: CanvasEvent) {
if (p === probablePosition.length - 1) {
nextIndex = nextPosition.index
}
if (curRightX <= nextLeftX || curLeftX >= nextRightX) continue
if (cursorX < nextLeftX || cursorX > nextRightX) continue
nextIndex = nextPosition.index
break
}
if (!nextIndex) return
// shift则缩放选区
let anchorStartIndex = nextIndex
let anchorEndIndex = nextIndex
if (evt.shiftKey) {
if (startIndex !== endIndex) {
if (startIndex === cursorPosition.index) {
anchorStartIndex = startIndex
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 {
anchorEndIndex = endIndex
// 查找上一行相同列索引位置信息
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
// shift则缩放选区
anchorStartIndex = nextIndex
anchorEndIndex = nextIndex
if (evt.shiftKey) {
if (startIndex !== endIndex) {
if (startIndex === cursorPosition.index) {
anchorStartIndex = startIndex
} else {
anchorEndIndex = endIndex
}
} else {
if (isUp) {
anchorEndIndex = endIndex
} else {
anchorStartIndex = startIndex
}
}
}
// 如果下一行是表格则进入单元格内
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) {
anchorEndIndex = endIndex
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 {
anchorStartIndex = startIndex
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) {
// prettier-ignore
[anchorStartIndex, anchorEndIndex] = [anchorEndIndex, anchorStartIndex]

Loading…
Cancel
Save