Skip to content

Commit e4a520e

Browse files
committed
fix: prevent crash on PivotTable row move
1 parent 93f8e73 commit e4a520e

File tree

3 files changed

+323
-3
lines changed

3 files changed

+323
-3
lines changed

packages/vtable/examples/menu.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,10 @@ export const menus = [
250250
path: 'pivot',
251251
name: 'pivot-tree-hide'
252252
},
253+
{
254+
path: 'pivot',
255+
name: 'pivot-moveRow'
256+
},
253257
{
254258
path: 'pivot',
255259
name: 'pivot-rowSeriesNumber'
Lines changed: 308 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,308 @@
1+
import * as VTable from '../../src';
2+
import { bindDebugTool } from '../../src/scenegraph/debug-tool';
3+
const PivotTable = VTable.PivotTable;
4+
const CONTAINER_ID = 'vTable';
5+
6+
export function createTable() {
7+
fetch('https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/North_American_Superstore_Pivot2_data.json')
8+
.then(res => res.json())
9+
.then(data => {
10+
VTable.register.icon('book', {
11+
type: 'svg', //指定svg格式图标,其他还支持path,image,font
12+
svg: `<svg t="1669210190896" class="icon" viewBox="0 0 1427 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4793" width="200" height="200"><path d="M1351.064977 123.555737h-107.862689V92.969424l-36.660345-14.396103C1199.192582 75.698424 1024.753324 7.932987 872.167608 7.932987c-71.440118 0-128.592212 14.720339-170.786193 43.880012-42.193982-29.159673-99.302844-43.880012-170.764578-43.880012-152.585716 0-327.024974 67.765437-334.374335 70.640334l-36.638729 14.396103v30.586313H54.291745A43.318002 43.318002 0 0 0 10.973743 166.873739v797.81643c0 23.928657 19.389345 43.318002 43.318002 43.318001h1296.773232a43.318002 43.318002 0 0 0 43.318002-43.318001V166.873739a43.318002 43.318002 0 0 0-43.318002-43.318002z m-165.620024 8.776003v633.169114c-89.446053-30.629545-327.003358-100.03778-455.184871-25.203987V102.566825c36.141566-26.998096 87.025087-36.898118 141.907526-36.898118 143.420629 0 313.277345 66.663033 313.277345 66.663033zM1120.035635 804.971249H739.295474c74.293399-70.467408 258.243596-36.595497 380.740161 0zM530.616837 65.668707c54.860823 0 105.765959 9.921638 141.88591 36.898118v637.730042c-128.181512-74.790562-365.695585-5.425558-455.163254 25.203987V132.33174s169.856715-66.663033 313.277344-66.663033z m132.850518 739.302542H282.662347c122.453333-36.638729 306.489993-70.575487 380.805008 0z m644.27962 116.400918H97.609746V210.170125h61.994027v652.536844H1243.202288V210.170125h64.544687v711.202042z" p-id="4794"></path></svg>`,
13+
width: 20,
14+
height: 20,
15+
name: 'book',
16+
positionType: VTable.TYPES.IconPosition.inlineEnd,
17+
marginLeft: 2,
18+
marginRight: 0,
19+
visibleTime: 'always',
20+
hover: {
21+
width: 22,
22+
height: 22,
23+
bgColor: 'rgba(22,44,66,0.2)'
24+
},
25+
tooltip: {
26+
title: '书籍',
27+
placement: VTable.TYPES.Placement.left
28+
}
29+
});
30+
31+
const option: VTable.PivotTableConstructorOptions = {
32+
container: document.getElementById(CONTAINER_ID),
33+
records: data,
34+
rowTree: [
35+
{
36+
dimensionKey: 'Category',
37+
value: 'Furniture',
38+
hierarchyState: 'expand',
39+
children: [
40+
{
41+
dimensionKey: 'Sub-Category',
42+
value: 'Bookcases',
43+
hierarchyState: 'collapse'
44+
},
45+
{
46+
dimensionKey: 'Sub-Category',
47+
value: 'Chairs',
48+
hierarchyState: 'collapse'
49+
},
50+
{
51+
dimensionKey: 'Sub-Category',
52+
value: 'Furnishings'
53+
},
54+
{
55+
dimensionKey: 'Sub-Category',
56+
value: 'Tables'
57+
}
58+
]
59+
},
60+
{
61+
dimensionKey: 'Category',
62+
value: 'Office Supplies',
63+
children: [
64+
{
65+
dimensionKey: 'Sub-Category',
66+
value: 'Appliances'
67+
},
68+
{
69+
dimensionKey: 'Sub-Category',
70+
value: 'Art'
71+
},
72+
{
73+
dimensionKey: 'Sub-Category',
74+
value: 'Binders'
75+
},
76+
{
77+
dimensionKey: 'Sub-Category',
78+
value: 'Envelopes'
79+
},
80+
{
81+
dimensionKey: 'Sub-Category',
82+
value: 'Fasteners'
83+
},
84+
{
85+
dimensionKey: 'Sub-Category',
86+
value: 'Labels'
87+
},
88+
{
89+
dimensionKey: 'Sub-Category',
90+
value: 'Paper'
91+
},
92+
{
93+
dimensionKey: 'Sub-Category',
94+
value: 'Storage'
95+
},
96+
{
97+
dimensionKey: 'Sub-Category',
98+
value: 'Supplies'
99+
}
100+
]
101+
},
102+
{
103+
dimensionKey: 'Category',
104+
value: 'Technology',
105+
children: [
106+
{
107+
dimensionKey: 'Sub-Category',
108+
value: 'Accessories'
109+
},
110+
{
111+
dimensionKey: 'Sub-Category',
112+
value: 'Copiers'
113+
},
114+
{
115+
dimensionKey: 'Sub-Category',
116+
value: 'Machines'
117+
},
118+
{
119+
dimensionKey: 'Sub-Category',
120+
value: 'Phones'
121+
}
122+
]
123+
}
124+
],
125+
columnTree: [
126+
{
127+
dimensionKey: 'Region',
128+
value: 'West',
129+
children: [
130+
{
131+
value: 'Sales',
132+
indicatorKey: 'Sales'
133+
},
134+
{
135+
value: 'Profit',
136+
indicatorKey: 'Profit'
137+
}
138+
]
139+
},
140+
{
141+
dimensionKey: 'Region',
142+
value: 'South',
143+
children: [
144+
{
145+
value: 'Sales',
146+
indicatorKey: 'Sales'
147+
},
148+
{
149+
value: 'Profit',
150+
indicatorKey: 'Profit'
151+
}
152+
]
153+
},
154+
{
155+
dimensionKey: 'Region',
156+
value: 'Central',
157+
children: [
158+
{
159+
value: 'Sales',
160+
indicatorKey: 'Sales'
161+
},
162+
{
163+
value: 'Profit',
164+
indicatorKey: 'Profit'
165+
}
166+
]
167+
},
168+
{
169+
dimensionKey: 'Region',
170+
value: 'East',
171+
children: [
172+
{
173+
value: 'Sales',
174+
indicatorKey: 'Sales'
175+
},
176+
{
177+
value: 'Profit',
178+
indicatorKey: 'Profit'
179+
}
180+
]
181+
}
182+
],
183+
rows: [
184+
{
185+
dimensionKey: 'Category',
186+
title: 'Catogery', // Changed from dimensionTitle to title
187+
width: 'auto'
188+
},
189+
{
190+
dimensionKey: 'Sub-Category',
191+
title: 'Sub-Catogery', // Changed from dimensionTitle to title
192+
width: 'auto'
193+
}
194+
],
195+
columns: [
196+
{
197+
dimensionKey: 'Region',
198+
title: 'Region', // Changed from dimensionTitle to title
199+
headerStyle: {
200+
textStick: true
201+
},
202+
width: 'auto'
203+
}
204+
],
205+
indicators: [
206+
{
207+
indicatorKey: 'Sales',
208+
title: 'Sales', // Changed from caption to title
209+
width: 'auto',
210+
showSort: false,
211+
headerStyle: {
212+
fontWeight: 'normal'
213+
},
214+
format: value => {
215+
if (value != null) {
216+
return '$' + Number(value).toFixed(2);
217+
}
218+
return '';
219+
},
220+
style: {
221+
padding: [16, 28, 16, 28],
222+
color(args) {
223+
if (args.dataValue >= 0) {
224+
return 'black';
225+
}
226+
return 'red';
227+
}
228+
}
229+
},
230+
{
231+
indicatorKey: 'Profit',
232+
title: 'Profit', // Changed from caption to title
233+
width: 'auto',
234+
showSort: false,
235+
headerStyle: {
236+
fontWeight: 'normal'
237+
},
238+
format: value => {
239+
if (value != null) {
240+
return '$' + Number(value).toFixed(2);
241+
}
242+
return '';
243+
},
244+
style: {
245+
padding: [16, 28, 16, 28],
246+
color(args) {
247+
if (args.dataValue >= 0) {
248+
return 'black';
249+
}
250+
return 'red';
251+
}
252+
}
253+
}
254+
],
255+
corner: {
256+
titleOnDimension: 'row',
257+
headerStyle: {
258+
textStick: true
259+
}
260+
},
261+
rowHierarchyType: 'tree',
262+
widthMode: 'standard',
263+
rowHierarchyIndent: 20,
264+
rowExpandLevel: 1,
265+
dragOrder: {
266+
dragHeaderMode: 'all',
267+
validateDragOrderOnEnd(source, target) {
268+
if (source.row === 3) {
269+
return false;
270+
}
271+
return true;
272+
}
273+
},
274+
rowSeriesNumber: {
275+
enable: true,
276+
title: '行号',
277+
dragOrder: true, // dragOrder for rowSeriesNumber might need specific handling or might not be directly supported in PivotTable in the same way as ListTable.
278+
width: 'auto',
279+
icon: 'book',
280+
headerStyle: {
281+
color: 'black',
282+
bgColor: 'pink'
283+
},
284+
style: {
285+
color: 'red'
286+
}
287+
},
288+
theme: VTable.themes.BRIGHT // Added a default theme
289+
};
290+
291+
const instance = new PivotTable(option);
292+
window.tableInstance = instance;
293+
bindDebugTool(instance.scenegraph.stage, { customGrapicKeys: ['col', 'row'] });
294+
295+
// You might want to add event listeners or other logic here if needed
296+
})
297+
.catch(error => console.error('Error fetching or processing data:', error));
298+
}
299+
300+
// To run this example, you would typically call createTable()
301+
// For example, in your main.ts or an HTML file:
302+
// document.addEventListener('DOMContentLoaded', createTable);
303+
// Or if you have a button to trigger it:
304+
// const button = document.createElement('button');
305+
// button.innerText = 'Create Pivot Table';
306+
// button.onclick = createTable;
307+
// document.body.appendChild(button);
308+
// Ensure you have a div with id="vTable" in your HTML: <div id="vTable"></div>

packages/vtable/src/state/cell-move/index.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -205,14 +205,22 @@ export function endMoveCol(state: StateManager): boolean {
205205
}
206206
}
207207
if (
208-
!(state.table as ListTable).transpose &&
208+
state.table.isListTable() &&
209209
(state.table.internalProps.layoutMap as SimpleHeaderLayoutMap).isSeriesNumberInBody(
210210
state.columnMove.colSource,
211211
state.columnMove.rowSource
212212
)
213213
) {
214-
const sourceRecordPath = (state.table as ListTable).getRecordIndexByCell(0, moveContext.sourceIndex);
215-
const targetRecordPath = (state.table as ListTable).getRecordIndexByCell(0, moveContext.targetIndex);
214+
let sourceRecordPath;
215+
let targetRecordPath;
216+
217+
if (!(state.table as ListTable).transpose) {
218+
sourceRecordPath = (state.table as ListTable).getRecordIndexByCell(0, moveContext.sourceIndex);
219+
targetRecordPath = (state.table as ListTable).getRecordIndexByCell(0, moveContext.targetIndex);
220+
} else {
221+
sourceRecordPath = (state.table as ListTable).getRecordIndexByCell(moveContext.sourceIndex, 0);
222+
targetRecordPath = (state.table as ListTable).getRecordIndexByCell(moveContext.targetIndex, 0);
223+
}
216224

217225
state.table.changeRecordOrder(moveContext.sourceIndex, moveContext.targetIndex);
218226

0 commit comments

Comments
 (0)