fix row remove
This commit is contained in:
parent
295440a347
commit
a06ce1137a
|
@ -24,7 +24,7 @@
|
||||||
v-for="row in rows"
|
v-for="row in rows"
|
||||||
:key="row.index"
|
:key="row.index"
|
||||||
:row="row"
|
:row="row"
|
||||||
:cells="cells[row.index]"
|
:cells="cells[row.index].cells"
|
||||||
:gridSetting="gridSetting"
|
:gridSetting="gridSetting"
|
||||||
:bus="bus"
|
:bus="bus"
|
||||||
@operation:beginEdit="onCellEditBegin"
|
@operation:beginEdit="onCellEditBegin"
|
||||||
|
@ -37,7 +37,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, getCurrentInstance, onMounted, reactive, ref, toRefs, watch } from 'vue';
|
import { computed, onMounted, ref, toRefs, watch } from 'vue';
|
||||||
import { DataSource, GridEventEmitter, GridSetting, GridState, Size } from '@/components/grid/grid.js';
|
import { DataSource, GridEventEmitter, GridSetting, GridState, Size } from '@/components/grid/grid.js';
|
||||||
import MkDataRow from '@/components/grid/MkDataRow.vue';
|
import MkDataRow from '@/components/grid/MkDataRow.vue';
|
||||||
import MkHeaderRow from '@/components/grid/MkHeaderRow.vue';
|
import MkHeaderRow from '@/components/grid/MkHeaderRow.vue';
|
||||||
|
@ -50,6 +50,11 @@ import { GridCurrentState, GridEvent } from '@/components/grid/grid-event.js';
|
||||||
import { ColumnSetting, createColumn, GridColumn } from '@/components/grid/column.js';
|
import { ColumnSetting, createColumn, GridColumn } from '@/components/grid/column.js';
|
||||||
import { createRow, GridRow } from '@/components/grid/row.js';
|
import { createRow, GridRow } from '@/components/grid/row.js';
|
||||||
|
|
||||||
|
type RowHolder = {
|
||||||
|
cells: GridCell[],
|
||||||
|
origin: DataSource,
|
||||||
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
gridSetting?: GridSetting,
|
gridSetting?: GridSetting,
|
||||||
columnSettings: ColumnSetting[],
|
columnSettings: ColumnSetting[],
|
||||||
|
@ -100,7 +105,7 @@ const rows = ref<GridRow[]>([]);
|
||||||
/**
|
/**
|
||||||
* グリッドのセル定義。propsで受け取った{@link data}をもとに、{@link refreshData}で再計算される。
|
* グリッドのセル定義。propsで受け取った{@link data}をもとに、{@link refreshData}で再計算される。
|
||||||
*/
|
*/
|
||||||
const cells = ref<GridCell[][]>([]);
|
const cells = ref<RowHolder[]>([]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mousemoveイベントが発生した際に、イベントから取得したセルアドレスを保持するための変数。
|
* mousemoveイベントが発生した際に、イベントから取得したセルアドレスを保持するための変数。
|
||||||
|
@ -126,13 +131,13 @@ const firstSelectionRowIdx = ref<number>(CELL_ADDRESS_NONE.row);
|
||||||
* 選択状態のセルを取得するための計算プロパティ。選択状態とは{@link GridCell.selected}がtrueのセルのこと。
|
* 選択状態のセルを取得するための計算プロパティ。選択状態とは{@link GridCell.selected}がtrueのセルのこと。
|
||||||
*/
|
*/
|
||||||
const selectedCell = computed(() => {
|
const selectedCell = computed(() => {
|
||||||
const selected = cells.value.flat().filter(it => it.selected);
|
const selected = cells.value.flatMap(it => it.cells).filter(it => it.selected);
|
||||||
return selected.length > 0 ? selected[0] : undefined;
|
return selected.length > 0 ? selected[0] : undefined;
|
||||||
});
|
});
|
||||||
/**
|
/**
|
||||||
* 範囲選択状態のセルを取得するための計算プロパティ。範囲選択状態とは{@link GridCell.ranged}がtrueのセルのこと。
|
* 範囲選択状態のセルを取得するための計算プロパティ。範囲選択状態とは{@link GridCell.ranged}がtrueのセルのこと。
|
||||||
*/
|
*/
|
||||||
const rangedCells = computed(() => cells.value.flat().filter(it => it.ranged));
|
const rangedCells = computed(() => cells.value.flatMap(it => it.cells).filter(it => it.ranged));
|
||||||
/**
|
/**
|
||||||
* 範囲選択状態のセルの範囲を取得するための計算プロパティ。左上のセル番地と右下のセル番地を計算する。
|
* 範囲選択状態のセルの範囲を取得するための計算プロパティ。左上のセル番地と右下のセル番地を計算する。
|
||||||
*/
|
*/
|
||||||
|
@ -441,7 +446,7 @@ function onLeftMouseDown(ev: MouseEvent) {
|
||||||
} else if (isColumnHeaderCellAddress(cellAddress)) {
|
} else if (isColumnHeaderCellAddress(cellAddress)) {
|
||||||
unSelectionRangeAll();
|
unSelectionRangeAll();
|
||||||
|
|
||||||
const colCells = cells.value.map(row => row[cellAddress.col]);
|
const colCells = cells.value.map(row => row.cells[cellAddress.col]);
|
||||||
selectionRange(...colCells.map(cell => cell.address));
|
selectionRange(...colCells.map(cell => cell.address));
|
||||||
|
|
||||||
registerMouseUp();
|
registerMouseUp();
|
||||||
|
@ -453,7 +458,7 @@ function onLeftMouseDown(ev: MouseEvent) {
|
||||||
} else if (isRowNumberCellAddress(cellAddress)) {
|
} else if (isRowNumberCellAddress(cellAddress)) {
|
||||||
unSelectionRangeAll();
|
unSelectionRangeAll();
|
||||||
|
|
||||||
const rowCells = cells.value[cellAddress.row];
|
const rowCells = cells.value[cellAddress.row].cells;
|
||||||
selectionRange(...rowCells.map(cell => cell.address));
|
selectionRange(...rowCells.map(cell => cell.address));
|
||||||
|
|
||||||
expandRowRange(cellAddress.row, cellAddress.row);
|
expandRowRange(cellAddress.row, cellAddress.row);
|
||||||
|
@ -560,7 +565,7 @@ function onMouseMove(ev: MouseEvent) {
|
||||||
};
|
};
|
||||||
|
|
||||||
const rightBottom = {
|
const rightBottom = {
|
||||||
col: Math.min(...cells.value.map(it => it.length - 1)),
|
col: Math.min(...cells.value.map(it => it.cells.length - 1)),
|
||||||
row: Math.max(targetCellAddress.row, firstSelectionRowIdx.value),
|
row: Math.max(targetCellAddress.row, firstSelectionRowIdx.value),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -619,7 +624,7 @@ function onContextMenu(ev: MouseEvent) {
|
||||||
function onCellEditBegin(sender: GridCell) {
|
function onCellEditBegin(sender: GridCell) {
|
||||||
state.value = 'cellEditing';
|
state.value = 'cellEditing';
|
||||||
editingCellAddress.value = sender.address;
|
editingCellAddress.value = sender.address;
|
||||||
for (const cell of cells.value.flat()) {
|
for (const cell of cells.value.flatMap(it => it.cells)) {
|
||||||
if (cell.address.col !== sender.address.col || cell.address.row !== sender.address.row) {
|
if (cell.address.col !== sender.address.col || cell.address.row !== sender.address.row) {
|
||||||
// 編集状態となったセル以外は全部選択解除
|
// 編集状態となったセル以外は全部選択解除
|
||||||
cell.selected = false;
|
cell.selected = false;
|
||||||
|
@ -637,7 +642,7 @@ function onChangeCellValue(sender: GridCell, newValue: CellValue) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function onChangeCellContentSize(sender: GridCell, contentSize: Size) {
|
function onChangeCellContentSize(sender: GridCell, contentSize: Size) {
|
||||||
cells.value[sender.address.row][sender.address.col].contentSize = contentSize;
|
cells.value[sender.address.row].cells[sender.address.col].contentSize = contentSize;
|
||||||
if (sender.column.setting.width === 'auto') {
|
if (sender.column.setting.width === 'auto') {
|
||||||
calcLargestCellWidth(sender.column);
|
calcLargestCellWidth(sender.column);
|
||||||
}
|
}
|
||||||
|
@ -707,7 +712,7 @@ function calcLargestCellWidth(column: GridColumn) {
|
||||||
|
|
||||||
const largestCellWidth = (_cells.length > 0)
|
const largestCellWidth = (_cells.length > 0)
|
||||||
? _cells
|
? _cells
|
||||||
.map(row => row[column.index])
|
.map(row => row.cells[column.index])
|
||||||
.reduce(
|
.reduce(
|
||||||
(acc, value) => Math.max(acc, value.contentSize.width),
|
(acc, value) => Math.max(acc, value.contentSize.width),
|
||||||
0,
|
0,
|
||||||
|
@ -749,7 +754,7 @@ function emitGridEvent(ev: GridEvent) {
|
||||||
*/
|
*/
|
||||||
function emitCellValue(sender: GridCell | CellAddress, newValue: CellValue) {
|
function emitCellValue(sender: GridCell | CellAddress, newValue: CellValue) {
|
||||||
const cellAddress = 'address' in sender ? sender.address : sender;
|
const cellAddress = 'address' in sender ? sender.address : sender;
|
||||||
const cell = cells.value[cellAddress.row][cellAddress.col];
|
const cell = cells.value[cellAddress.row].cells[cellAddress.col];
|
||||||
|
|
||||||
const violation = cellValidation(cell, newValue);
|
const violation = cellValidation(cell, newValue);
|
||||||
cell.violation = violation;
|
cell.violation = violation;
|
||||||
|
@ -794,8 +799,8 @@ function selectionCell(target: CellAddress) {
|
||||||
unSelectionRangeAll();
|
unSelectionRangeAll();
|
||||||
|
|
||||||
const _cells = cells.value;
|
const _cells = cells.value;
|
||||||
_cells[target.row][target.col].selected = true;
|
_cells[target.row].cells[target.col].selected = true;
|
||||||
_cells[target.row][target.col].ranged = true;
|
_cells[target.row].cells[target.col].ranged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -804,7 +809,7 @@ function selectionCell(target: CellAddress) {
|
||||||
function selectionRange(...targets: CellAddress[]) {
|
function selectionRange(...targets: CellAddress[]) {
|
||||||
const _cells = cells.value;
|
const _cells = cells.value;
|
||||||
for (const target of targets) {
|
for (const target of targets) {
|
||||||
_cells[target.row][target.col].ranged = true;
|
_cells[target.row].cells[target.col].ranged = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -849,7 +854,7 @@ function unSelectionOutOfRange(leftTop: CellAddress, rightBottom: CellAddress) {
|
||||||
function expandCellRange(leftTop: CellAddress, rightBottom: CellAddress) {
|
function expandCellRange(leftTop: CellAddress, rightBottom: CellAddress) {
|
||||||
const targetRows = cells.value.slice(leftTop.row, rightBottom.row + 1);
|
const targetRows = cells.value.slice(leftTop.row, rightBottom.row + 1);
|
||||||
for (const row of targetRows) {
|
for (const row of targetRows) {
|
||||||
for (const cell of row.slice(leftTop.col, rightBottom.col + 1)) {
|
for (const cell of row.cells.slice(leftTop.col, rightBottom.col + 1)) {
|
||||||
cell.ranged = true;
|
cell.ranged = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -911,20 +916,23 @@ function refreshData() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const _data: DataSource[] = data.value;
|
const _data: DataSource[] = data.value;
|
||||||
const _rows: GridRow[] = _data.map((it, index) => createRow(index, it));
|
const _rows: GridRow[] = _data.map((it, index) => createRow(index));
|
||||||
const _cols: GridColumn[] = columnSettings.value.map(createColumn);
|
const _cols: GridColumn[] = columnSettings.value.map(createColumn);
|
||||||
|
|
||||||
// 行・列の定義から、元データの配列より値を取得してセルを作成する。
|
// 行・列の定義から、元データの配列より値を取得してセルを作成する。
|
||||||
// 行・列の定義はそれぞれインデックスを持っており、そのインデックスは元データの配列番地に対応している。
|
// 行・列の定義はそれぞれインデックスを持っており、そのインデックスは元データの配列番地に対応している。
|
||||||
const _cells = _rows.map((row, rowIndex) =>
|
const _cells: RowHolder[] = _rows.map((row, rowIndex) => (
|
||||||
_cols.map(col =>
|
{
|
||||||
createCell(
|
cells: _cols.map(col =>
|
||||||
col,
|
createCell(
|
||||||
row,
|
col,
|
||||||
(col.setting.bindTo in _data[rowIndex]) ? _data[rowIndex][col.setting.bindTo] : undefined,
|
row,
|
||||||
|
(col.setting.bindTo in _data[rowIndex]) ? _data[rowIndex][col.setting.bindTo] : undefined,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
origin: _data[rowIndex],
|
||||||
);
|
}
|
||||||
|
));
|
||||||
|
|
||||||
rows.value = _rows;
|
rows.value = _rows;
|
||||||
columns.value = _cols;
|
columns.value = _cols;
|
||||||
|
@ -942,25 +950,61 @@ function refreshData() {
|
||||||
* そこで、新しい値とセルが持つ値を突き合わせ、変更があった場合のみセルの値を更新することで、セルを使いまわしつつ値を最新化する。
|
* そこで、新しい値とセルが持つ値を突き合わせ、変更があった場合のみセルの値を更新することで、セルを使いまわしつつ値を最新化する。
|
||||||
*/
|
*/
|
||||||
function patchData(newItems: DataSource[]) {
|
function patchData(newItems: DataSource[]) {
|
||||||
const oldRows = cells.value;
|
const gridRows = cells.value;
|
||||||
if (oldRows.length !== newItems.length) {
|
if (gridRows.length > newItems.length) {
|
||||||
// どこの行が増減したのかを割り出すコストと増減した行以降のインデックスを再付与するコストが重いので
|
// 行数が減った場合
|
||||||
// 行数が変わっていた場合は作り直したほうが楽
|
const diff = gridRows
|
||||||
refreshData();
|
.map((it, idx) => ({ origin: it.origin, idx }))
|
||||||
return;
|
.filter(it => !newItems.includes(it.origin));
|
||||||
}
|
for (const { idx } of diff) {
|
||||||
|
rows.value.splice(idx, 1);
|
||||||
|
gridRows.splice(idx, 1);
|
||||||
|
}
|
||||||
|
|
||||||
const _cols = columns.value;
|
// 行数が減ったので再度採番
|
||||||
for (let rowIdx = 0; rowIdx < oldRows.length; rowIdx++) {
|
for (let rowIdx = 0; rowIdx < rows.value.length; rowIdx++) {
|
||||||
const oldCells = oldRows[rowIdx];
|
rows.value[rowIdx].index = rowIdx;
|
||||||
const newItem = newItems[rowIdx];
|
for (const cell of gridRows[rowIdx].cells) {
|
||||||
for (let colIdx = 0; colIdx < oldCells.length; colIdx++) {
|
cell.address.row = rowIdx;
|
||||||
const _col = _cols[colIdx];
|
}
|
||||||
|
}
|
||||||
|
} else if (gridRows.length < newItems.length) {
|
||||||
|
// 行数が増えた場合
|
||||||
|
const oldOrigins = gridRows.map(it => it.origin);
|
||||||
|
const diff = newItems
|
||||||
|
.map((it, idx) => ({ origin: it, idx }))
|
||||||
|
.filter(it => oldOrigins.indexOf(it.origin) === -1);
|
||||||
|
|
||||||
const oldCell = oldCells[colIdx];
|
const _cols = columns.value;
|
||||||
const newValue = newItem[_col.setting.bindTo];
|
for (const { origin, idx } of diff) {
|
||||||
if (oldCell.value !== newValue) {
|
const newRow = createRow(idx);
|
||||||
oldCell.value = newValue;
|
const newCells = _cols.map(col => createCell(col, newRow, origin[col.setting.bindTo]));
|
||||||
|
|
||||||
|
rows.value.splice(idx, 0, newRow);
|
||||||
|
gridRows.splice(idx, 0, { cells: newCells, origin });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 行数が増えたので再度採番
|
||||||
|
for (let rowIdx = 0; rowIdx < rows.value.length; rowIdx++) {
|
||||||
|
rows.value[rowIdx].index = rowIdx;
|
||||||
|
for (const cell of gridRows[rowIdx].cells) {
|
||||||
|
cell.address.row = rowIdx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 行数が変わらない場合
|
||||||
|
const _cols = columns.value;
|
||||||
|
for (let rowIdx = 0; rowIdx < gridRows.length; rowIdx++) {
|
||||||
|
const oldCells = gridRows[rowIdx].cells;
|
||||||
|
const newItem = newItems[rowIdx];
|
||||||
|
for (let colIdx = 0; colIdx < oldCells.length; colIdx++) {
|
||||||
|
const _col = _cols[colIdx];
|
||||||
|
|
||||||
|
const oldCell = oldCells[colIdx];
|
||||||
|
const newValue = newItem[_col.setting.bindTo];
|
||||||
|
if (oldCell.value !== newValue) {
|
||||||
|
oldCell.value = newValue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,11 @@
|
||||||
import { DataSource } from '@/components/grid/grid.js';
|
|
||||||
|
|
||||||
export type GridRow = {
|
export type GridRow = {
|
||||||
index: number;
|
index: number;
|
||||||
ranged: boolean;
|
ranged: boolean;
|
||||||
origin: DataSource;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createRow(index: number, origin: DataSource): GridRow {
|
export function createRow(index: number): GridRow {
|
||||||
return {
|
return {
|
||||||
index,
|
index,
|
||||||
ranged: false,
|
ranged: false,
|
||||||
origin: origin,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue