@kanaries/graphic-walker 0.2.11 → 0.2.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/App.d.ts +6 -3
- package/dist/assets/explainer.worker-8428eb12.js.map +1 -1
- package/dist/components/button/base.d.ts +6 -0
- package/dist/components/button/default.d.ts +4 -0
- package/dist/components/button/primary.d.ts +4 -0
- package/dist/dataSource/utils.d.ts +1 -1
- package/dist/graphic-walker.es.js +17671 -18577
- package/dist/graphic-walker.es.js.map +1 -1
- package/dist/graphic-walker.umd.js +134 -134
- package/dist/graphic-walker.umd.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/interfaces.d.ts +8 -0
- package/dist/lib/inferMeta.d.ts +20 -0
- package/dist/store/commonStore.d.ts +1 -1
- package/dist/store/index.d.ts +0 -1
- package/dist/store/visualSpecStore.d.ts +5 -5
- package/dist/utils/dataPrep.d.ts +6 -0
- package/dist/utils/index.d.ts +2 -2
- package/dist/utils/normalization.d.ts +1 -1
- package/dist/utils/save.d.ts +3 -3
- package/dist/utils/throttle.d.ts +1 -1
- package/dist/vis/temporalFormat.d.ts +10 -0
- package/package.json +1 -1
- package/src/App.tsx +27 -10
- package/src/components/button/base.ts +7 -0
- package/src/components/button/default.tsx +17 -0
- package/src/components/button/primary.tsx +17 -0
- package/src/dataSource/dataSelection/csvData.tsx +8 -10
- package/src/dataSource/dataSelection/publicData.tsx +4 -4
- package/src/dataSource/index.tsx +10 -12
- package/src/dataSource/table.tsx +33 -20
- package/src/dataSource/utils.ts +30 -35
- package/src/fields/datasetFields/dimFields.tsx +1 -5
- package/src/fields/datasetFields/meaFields.tsx +1 -5
- package/src/fields/obComponents/obFContainer.tsx +1 -5
- package/src/index.tsx +3 -4
- package/src/interfaces.ts +9 -0
- package/src/lib/inferMeta.ts +88 -0
- package/src/locales/en-US.json +6 -0
- package/src/locales/zh-CN.json +6 -0
- package/src/main.tsx +1 -1
- package/src/store/commonStore.ts +8 -3
- package/src/store/index.tsx +0 -2
- package/src/store/visualSpecStore.ts +245 -183
- package/src/utils/autoMark.ts +14 -14
- package/src/utils/dataPrep.ts +44 -0
- package/src/utils/index.ts +140 -128
- package/src/utils/normalization.ts +59 -51
- package/src/utils/save.ts +22 -21
- package/src/utils/throttle.ts +5 -1
- package/src/vis/react-vega.tsx +6 -10
- package/src/vis/temporalFormat.ts +66 -0
- package/dist/pitch/dnd-offset.d.ts +0 -2
- package/src/pitch/dnd-offset.ts +0 -64
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { IReactionDisposer, makeAutoObservable, observable, reaction, toJS } from "mobx";
|
|
2
|
-
import produce from
|
|
3
|
-
import { v4 as uuidv4 } from
|
|
2
|
+
import produce from "immer";
|
|
3
|
+
import { v4 as uuidv4 } from "uuid";
|
|
4
4
|
import { Specification } from "visual-insights";
|
|
5
5
|
import { DataSet, DraggableFieldState, IFilterRule, IViewField, IVisSpec, IVisualConfig } from "../interfaces";
|
|
6
6
|
import { CHANNEL_LIMIT, GEMO_TYPES, MetaFieldKeys } from "../config";
|
|
@@ -9,34 +9,34 @@ import { VisSpecWithHistory } from "../models/visSpecHistory";
|
|
|
9
9
|
import { dumpsGWPureSpec, parseGWContent, parseGWPureSpec, stringifyGWContent } from "../utils/save";
|
|
10
10
|
import { CommonStore } from "./commonStore";
|
|
11
11
|
|
|
12
|
-
function getChannelSizeLimit
|
|
13
|
-
if (typeof CHANNEL_LIMIT[channel] ===
|
|
12
|
+
function getChannelSizeLimit(channel: string): number {
|
|
13
|
+
if (typeof CHANNEL_LIMIT[channel] === "undefined") return Infinity;
|
|
14
14
|
return CHANNEL_LIMIT[channel];
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
function geomAdapter
|
|
17
|
+
function geomAdapter(geom: string) {
|
|
18
18
|
switch (geom) {
|
|
19
|
-
case
|
|
20
|
-
return
|
|
21
|
-
case
|
|
22
|
-
return
|
|
23
|
-
case
|
|
24
|
-
return
|
|
25
|
-
case
|
|
26
|
-
return
|
|
27
|
-
case
|
|
28
|
-
return
|
|
29
|
-
case
|
|
30
|
-
return
|
|
31
|
-
case
|
|
32
|
-
return
|
|
33
|
-
case
|
|
34
|
-
return
|
|
35
|
-
case
|
|
36
|
-
return
|
|
37
|
-
case
|
|
19
|
+
case "interval":
|
|
20
|
+
return "bar";
|
|
21
|
+
case "line":
|
|
22
|
+
return "line";
|
|
23
|
+
case "boxplot":
|
|
24
|
+
return "boxplot";
|
|
25
|
+
case "area":
|
|
26
|
+
return "area";
|
|
27
|
+
case "point":
|
|
28
|
+
return "point";
|
|
29
|
+
case "arc":
|
|
30
|
+
return "arc";
|
|
31
|
+
case "circle":
|
|
32
|
+
return "circle";
|
|
33
|
+
case "heatmap":
|
|
34
|
+
return "circle";
|
|
35
|
+
case "rect":
|
|
36
|
+
return "rect";
|
|
37
|
+
case "tick":
|
|
38
38
|
default:
|
|
39
|
-
return
|
|
39
|
+
return "tick";
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
|
|
@@ -57,32 +57,32 @@ function initEncoding(): DraggableFieldState {
|
|
|
57
57
|
};
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
function initVisualConfig
|
|
60
|
+
function initVisualConfig(): IVisualConfig {
|
|
61
61
|
return {
|
|
62
62
|
defaultAggregated: true,
|
|
63
63
|
geoms: [GEMO_TYPES[0]!],
|
|
64
|
-
stack:
|
|
64
|
+
stack: "stack",
|
|
65
65
|
showActions: false,
|
|
66
66
|
interactiveScale: false,
|
|
67
|
-
sorted:
|
|
67
|
+
sorted: "none",
|
|
68
68
|
size: {
|
|
69
|
-
mode:
|
|
69
|
+
mode: "auto",
|
|
70
70
|
width: 320,
|
|
71
|
-
height: 200
|
|
71
|
+
height: 200,
|
|
72
72
|
},
|
|
73
73
|
exploration: {
|
|
74
|
-
mode:
|
|
75
|
-
brushDirection:
|
|
74
|
+
mode: "none",
|
|
75
|
+
brushDirection: "default",
|
|
76
76
|
},
|
|
77
|
-
}
|
|
77
|
+
};
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
type DeepReadonly<T extends Record<keyof any, any>> = {
|
|
81
81
|
readonly [K in keyof T]: T[K] extends Record<keyof any, any> ? DeepReadonly<T[K]> : T[K];
|
|
82
82
|
};
|
|
83
83
|
|
|
84
|
-
const forwardVisualConfigs = (backwards: ReturnType<typeof parseGWContent>[
|
|
85
|
-
return backwards.map(content => ({
|
|
84
|
+
const forwardVisualConfigs = (backwards: ReturnType<typeof parseGWContent>["specList"]): IVisSpec[] => {
|
|
85
|
+
return backwards.map((content) => ({
|
|
86
86
|
...content,
|
|
87
87
|
config: {
|
|
88
88
|
...initVisualConfig(),
|
|
@@ -91,7 +91,6 @@ const forwardVisualConfigs = (backwards: ReturnType<typeof parseGWContent>['spec
|
|
|
91
91
|
}));
|
|
92
92
|
};
|
|
93
93
|
|
|
94
|
-
|
|
95
94
|
export class VizSpecStore {
|
|
96
95
|
// public fields: IViewField[] = [];
|
|
97
96
|
private commonStore: CommonStore;
|
|
@@ -105,13 +104,13 @@ export class VizSpecStore {
|
|
|
105
104
|
* Assignment or mutable operations applied to ANY members of this segment
|
|
106
105
|
* is strictly FORBIDDEN.
|
|
107
106
|
* Members of it can only be got as READONLY objects.
|
|
108
|
-
*
|
|
107
|
+
*
|
|
109
108
|
* If you're trying to change the value of it and let mobx catch the action to trigger an update,
|
|
110
109
|
* please use `this.useMutable()` to access to a writable reference
|
|
111
110
|
* (an `immer` draft) of `this.visList[this.visIndex]`.
|
|
112
111
|
*/
|
|
113
112
|
public readonly draggableFieldState: DeepReadonly<DraggableFieldState>;
|
|
114
|
-
private reactions: IReactionDisposer[] = []
|
|
113
|
+
private reactions: IReactionDisposer[] = [];
|
|
115
114
|
/**
|
|
116
115
|
* This segment will always refers to the state of the active tab -
|
|
117
116
|
* `this.visList[this.visIndex].config`.
|
|
@@ -122,7 +121,7 @@ export class VizSpecStore {
|
|
|
122
121
|
* Assignment or mutable operations applied to ANY members of this segment
|
|
123
122
|
* is strictly FORBIDDEN.
|
|
124
123
|
* Members of it can only be got as READONLY objects.
|
|
125
|
-
*
|
|
124
|
+
*
|
|
126
125
|
* If you're trying to change the value of it and let mobx catch the action to trigger an update,
|
|
127
126
|
* please use `this.useMutable()` to access to a writable reference
|
|
128
127
|
* (an `immer` draft) of `this.visList[this.visIndex]`.
|
|
@@ -133,34 +132,42 @@ export class VizSpecStore {
|
|
|
133
132
|
public canUndo = false;
|
|
134
133
|
public canRedo = false;
|
|
135
134
|
public editingFilterIdx: number | null = null;
|
|
136
|
-
constructor
|
|
135
|
+
constructor(commonStore: CommonStore) {
|
|
137
136
|
this.commonStore = commonStore;
|
|
138
137
|
this.draggableFieldState = initEncoding();
|
|
139
138
|
this.visualConfig = initVisualConfig();
|
|
140
|
-
this.visList.push(
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
139
|
+
this.visList.push(
|
|
140
|
+
new VisSpecWithHistory({
|
|
141
|
+
name: ["main.tablist.autoTitle", { idx: 1 }],
|
|
142
|
+
visId: uuidv4(),
|
|
143
|
+
config: this.visualConfig,
|
|
144
|
+
encodings: this.draggableFieldState,
|
|
145
|
+
})
|
|
146
|
+
);
|
|
146
147
|
makeAutoObservable(this, {
|
|
147
148
|
visList: observable.shallow,
|
|
148
149
|
// @ts-expect-error private fields are not supported
|
|
149
|
-
reactions: false
|
|
150
|
+
reactions: false,
|
|
150
151
|
});
|
|
151
152
|
this.reactions.push(
|
|
152
|
-
reaction(
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
153
|
+
reaction(
|
|
154
|
+
() => commonStore.currentDataset,
|
|
155
|
+
(dataset) => {
|
|
156
|
+
// this.initState();
|
|
157
|
+
this.initMetaState(dataset);
|
|
158
|
+
}
|
|
159
|
+
),
|
|
160
|
+
reaction(
|
|
161
|
+
() => this.visList[this.visIndex],
|
|
162
|
+
(frame) => {
|
|
163
|
+
// @ts-ignore Allow assignment here to trigger watch
|
|
164
|
+
this.draggableFieldState = frame.encodings;
|
|
165
|
+
// @ts-ignore Allow assignment here to trigger watch
|
|
166
|
+
this.visualConfig = frame.config;
|
|
167
|
+
this.canUndo = frame.canUndo;
|
|
168
|
+
this.canRedo = frame.canRedo;
|
|
169
|
+
}
|
|
170
|
+
)
|
|
164
171
|
);
|
|
165
172
|
}
|
|
166
173
|
private __dangerous_is_inside_useMutable__ = false;
|
|
@@ -169,38 +176,38 @@ export class VizSpecStore {
|
|
|
169
176
|
* because the state will be overwritten by the root `useMutable()` call,
|
|
170
177
|
* update caused by recursive `useMutable()` call will be reverted or lead to unexpected behaviors.
|
|
171
178
|
* Inline your invoking or just use block with IF statement to avoid this in your cases.
|
|
172
|
-
*
|
|
179
|
+
*
|
|
173
180
|
* Allow to change any deep member of `encodings` or `config`
|
|
174
181
|
* in the active tab `this.visList[this.visIndex]`.
|
|
175
|
-
*
|
|
182
|
+
*
|
|
176
183
|
* - `tab.encodings`
|
|
177
|
-
*
|
|
184
|
+
*
|
|
178
185
|
* A mutable reference of `this.draggableFieldState`
|
|
179
|
-
*
|
|
186
|
+
*
|
|
180
187
|
* - `tab.config`
|
|
181
|
-
*
|
|
188
|
+
*
|
|
182
189
|
* A mutable reference of `this.visualConfig`
|
|
183
190
|
*/
|
|
184
|
-
private useMutable(
|
|
185
|
-
cb: (tab: {
|
|
186
|
-
encodings: DraggableFieldState;
|
|
187
|
-
config: IVisualConfig;
|
|
188
|
-
}) => void,
|
|
189
|
-
) {
|
|
191
|
+
private useMutable(cb: (tab: { encodings: DraggableFieldState; config: IVisualConfig }) => void) {
|
|
190
192
|
if (this.__dangerous_is_inside_useMutable__) {
|
|
191
193
|
throw new Error(
|
|
192
|
-
|
|
193
|
-
|
|
194
|
+
"A recursive call of useMutable() is detected, " +
|
|
195
|
+
"this is prevented because update will be overwritten by parent execution context."
|
|
194
196
|
);
|
|
195
197
|
}
|
|
196
198
|
|
|
197
199
|
this.__dangerous_is_inside_useMutable__ = true;
|
|
198
200
|
|
|
199
|
-
const { encodings, config } = produce(
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
201
|
+
const { encodings, config } = produce(
|
|
202
|
+
{
|
|
203
|
+
encodings: this.visList[this.visIndex].encodings,
|
|
204
|
+
config: this.visList[this.visIndex].config,
|
|
205
|
+
},
|
|
206
|
+
(draft) => {
|
|
207
|
+
cb(draft);
|
|
208
|
+
}
|
|
209
|
+
); // notice that cb() may unexpectedly returns a non-nullable value
|
|
210
|
+
|
|
204
211
|
this.visList[this.visIndex].encodings = encodings;
|
|
205
212
|
this.visList[this.visIndex].config = config;
|
|
206
213
|
|
|
@@ -242,96 +249,98 @@ export class VizSpecStore {
|
|
|
242
249
|
/**
|
|
243
250
|
* dimension fields in visualization
|
|
244
251
|
*/
|
|
245
|
-
public get viewDimensions
|
|
252
|
+
public get viewDimensions(): IViewField[] {
|
|
246
253
|
const { draggableFieldState } = this;
|
|
247
254
|
const state = toJS(draggableFieldState);
|
|
248
255
|
const fields: IViewField[] = [];
|
|
249
256
|
(Object.keys(state) as (keyof DraggableFieldState)[])
|
|
250
|
-
.filter(dkey => !MetaFieldKeys.includes(dkey))
|
|
251
|
-
.forEach(dkey => {
|
|
252
|
-
fields.push(...state[dkey].filter(f => f.analyticType ===
|
|
253
|
-
})
|
|
257
|
+
.filter((dkey) => !MetaFieldKeys.includes(dkey))
|
|
258
|
+
.forEach((dkey) => {
|
|
259
|
+
fields.push(...state[dkey].filter((f) => f.analyticType === "dimension"));
|
|
260
|
+
});
|
|
254
261
|
return fields;
|
|
255
262
|
}
|
|
256
263
|
/**
|
|
257
264
|
* dimension fields in visualization
|
|
258
265
|
*/
|
|
259
|
-
public get viewMeasures
|
|
266
|
+
public get viewMeasures(): IViewField[] {
|
|
260
267
|
const { draggableFieldState } = this;
|
|
261
268
|
const state = toJS(draggableFieldState);
|
|
262
269
|
const fields: IViewField[] = [];
|
|
263
270
|
(Object.keys(state) as (keyof DraggableFieldState)[])
|
|
264
|
-
.filter(dkey => !MetaFieldKeys.includes(dkey))
|
|
265
|
-
.forEach(dkey => {
|
|
266
|
-
fields.push(...state[dkey].filter(f => f.analyticType ===
|
|
267
|
-
})
|
|
271
|
+
.filter((dkey) => !MetaFieldKeys.includes(dkey))
|
|
272
|
+
.forEach((dkey) => {
|
|
273
|
+
fields.push(...state[dkey].filter((f) => f.analyticType === "measure"));
|
|
274
|
+
});
|
|
268
275
|
return fields;
|
|
269
276
|
}
|
|
270
|
-
public addVisualization
|
|
271
|
-
this.visList.push(
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
+
public addVisualization() {
|
|
278
|
+
this.visList.push(
|
|
279
|
+
new VisSpecWithHistory({
|
|
280
|
+
name: ["main.tablist.autoTitle", { idx: this.visList.length + 1 }],
|
|
281
|
+
visId: uuidv4(),
|
|
282
|
+
config: initVisualConfig(),
|
|
283
|
+
encodings: initEncoding(),
|
|
284
|
+
})
|
|
285
|
+
);
|
|
277
286
|
this.visIndex = this.visList.length - 1;
|
|
278
287
|
}
|
|
279
|
-
public selectVisualization
|
|
288
|
+
public selectVisualization(visIndex: number) {
|
|
280
289
|
this.visIndex = visIndex;
|
|
281
290
|
}
|
|
282
|
-
public setVisName
|
|
291
|
+
public setVisName(visIndex: number, name: string) {
|
|
283
292
|
this.useMutable(() => {
|
|
284
293
|
this.visList[visIndex].name = [name];
|
|
285
294
|
});
|
|
286
295
|
}
|
|
287
|
-
public initState
|
|
288
|
-
this.useMutable(tab => {
|
|
296
|
+
public initState() {
|
|
297
|
+
this.useMutable((tab) => {
|
|
289
298
|
tab.encodings = initEncoding();
|
|
290
299
|
this.freezeHistory();
|
|
291
300
|
});
|
|
292
301
|
}
|
|
293
|
-
public initMetaState
|
|
302
|
+
public initMetaState(dataset: DataSet) {
|
|
294
303
|
this.useMutable(({ encodings }) => {
|
|
295
304
|
encodings.fields = dataset.rawFields.map((f) => ({
|
|
296
305
|
dragId: uuidv4(),
|
|
297
306
|
fid: f.fid,
|
|
298
307
|
name: f.name || f.fid,
|
|
299
|
-
aggName: f.analyticType ===
|
|
308
|
+
aggName: f.analyticType === "measure" ? "sum" : undefined,
|
|
300
309
|
analyticType: f.analyticType,
|
|
301
|
-
semanticType: f.semanticType
|
|
310
|
+
semanticType: f.semanticType,
|
|
302
311
|
}));
|
|
303
312
|
encodings.dimensions = dataset.rawFields
|
|
304
|
-
.filter(f => f.analyticType ===
|
|
313
|
+
.filter((f) => f.analyticType === "dimension")
|
|
305
314
|
.map((f) => ({
|
|
306
315
|
dragId: uuidv4(),
|
|
307
316
|
fid: f.fid,
|
|
308
317
|
name: f.name || f.fid,
|
|
309
318
|
semanticType: f.semanticType,
|
|
310
319
|
analyticType: f.analyticType,
|
|
311
|
-
|
|
320
|
+
}));
|
|
312
321
|
encodings.measures = dataset.rawFields
|
|
313
|
-
.filter(f => f.analyticType ===
|
|
322
|
+
.filter((f) => f.analyticType === "measure")
|
|
314
323
|
.map((f) => ({
|
|
315
324
|
dragId: uuidv4(),
|
|
316
325
|
fid: f.fid,
|
|
317
326
|
name: f.name || f.fid,
|
|
318
327
|
analyticType: f.analyticType,
|
|
319
328
|
semanticType: f.semanticType,
|
|
320
|
-
aggName:
|
|
321
|
-
|
|
329
|
+
aggName: "sum",
|
|
330
|
+
}));
|
|
322
331
|
});
|
|
323
332
|
|
|
324
333
|
this.freezeHistory();
|
|
325
334
|
// this.draggableFieldState.measures.push({
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
}
|
|
334
|
-
public clearState
|
|
335
|
+
// dragId: uuidv4(),
|
|
336
|
+
// fid: COUNT_FIELD_ID,
|
|
337
|
+
// name: '记录数',
|
|
338
|
+
// analyticType: 'measure',
|
|
339
|
+
// semanticType: 'quantitative',
|
|
340
|
+
// aggName: 'count'
|
|
341
|
+
// })
|
|
342
|
+
}
|
|
343
|
+
public clearState() {
|
|
335
344
|
this.useMutable(({ encodings }) => {
|
|
336
345
|
for (let key in encodings) {
|
|
337
346
|
if (!MetaFieldKeys.includes(key as keyof DraggableFieldState)) {
|
|
@@ -343,41 +352,35 @@ export class VizSpecStore {
|
|
|
343
352
|
public setVisualConfig<K extends keyof IVisualConfig>(configKey: K, value: IVisualConfig[K]) {
|
|
344
353
|
this.useMutable(({ config }) => {
|
|
345
354
|
switch (true) {
|
|
346
|
-
case [
|
|
347
|
-
return (config as unknown as {[k: string]: boolean})[configKey] = Boolean(value);
|
|
355
|
+
case ["defaultAggregated", "defaultStack", "showActions", "interactiveScale"].includes(configKey): {
|
|
356
|
+
return ((config as unknown as { [k: string]: boolean })[configKey] = Boolean(value));
|
|
348
357
|
}
|
|
349
|
-
case configKey ===
|
|
350
|
-
case configKey ===
|
|
351
|
-
case configKey ===
|
|
352
|
-
case configKey ===
|
|
353
|
-
|
|
354
|
-
return config[configKey] = value;
|
|
358
|
+
case configKey === "geoms" && Array.isArray(value):
|
|
359
|
+
case configKey === "size" && typeof value === "object":
|
|
360
|
+
case configKey === "sorted":
|
|
361
|
+
case configKey === "stack": {
|
|
362
|
+
return (config[configKey] = value);
|
|
355
363
|
}
|
|
356
364
|
default: {
|
|
357
|
-
console.error(
|
|
365
|
+
console.error("unknown key" + configKey);
|
|
358
366
|
}
|
|
359
367
|
}
|
|
360
368
|
});
|
|
361
369
|
}
|
|
362
|
-
public transformCoord
|
|
363
|
-
if (coord ===
|
|
364
|
-
|
|
370
|
+
public transformCoord(coord: "cartesian" | "polar") {
|
|
371
|
+
if (coord === "polar") {
|
|
365
372
|
}
|
|
366
373
|
}
|
|
367
|
-
public setChartLayout(props: {mode: IVisualConfig[
|
|
374
|
+
public setChartLayout(props: { mode: IVisualConfig["size"]["mode"]; width?: number; height?: number }) {
|
|
368
375
|
this.useMutable(({ config }) => {
|
|
369
|
-
const {
|
|
370
|
-
mode = config.size.mode,
|
|
371
|
-
width = config.size.width,
|
|
372
|
-
height = config.size.height
|
|
373
|
-
} = props;
|
|
376
|
+
const { mode = config.size.mode, width = config.size.width, height = config.size.height } = props;
|
|
374
377
|
|
|
375
378
|
config.size.mode = mode;
|
|
376
379
|
config.size.width = width;
|
|
377
380
|
config.size.height = height;
|
|
378
381
|
});
|
|
379
382
|
}
|
|
380
|
-
public setExploration(value: Partial<IVisualConfig[
|
|
383
|
+
public setExploration(value: Partial<IVisualConfig["exploration"]>) {
|
|
381
384
|
this.useMutable(({ config }) => {
|
|
382
385
|
if (value.mode) {
|
|
383
386
|
config.exploration.mode = value.mode;
|
|
@@ -397,13 +400,18 @@ export class VizSpecStore {
|
|
|
397
400
|
fields.splice(destinationIndex, 0, field);
|
|
398
401
|
});
|
|
399
402
|
}
|
|
400
|
-
public moveField(
|
|
401
|
-
|
|
403
|
+
public moveField(
|
|
404
|
+
sourceKey: keyof DraggableFieldState,
|
|
405
|
+
sourceIndex: number,
|
|
406
|
+
destinationKey: keyof DraggableFieldState,
|
|
407
|
+
destinationIndex: number
|
|
408
|
+
) {
|
|
409
|
+
if (sourceKey === "filters") {
|
|
402
410
|
return this.removeField(sourceKey, sourceIndex);
|
|
403
|
-
} else if (destinationKey ===
|
|
404
|
-
return this.appendFilter(destinationIndex, this.draggableFieldState[sourceKey][sourceIndex])
|
|
411
|
+
} else if (destinationKey === "filters") {
|
|
412
|
+
return this.appendFilter(destinationIndex, this.draggableFieldState[sourceKey][sourceIndex]);
|
|
405
413
|
}
|
|
406
|
-
|
|
414
|
+
|
|
407
415
|
this.useMutable(({ encodings }) => {
|
|
408
416
|
let movingField: IViewField;
|
|
409
417
|
// 来源是不是metafield,是->clone;不是->直接删掉
|
|
@@ -418,9 +426,9 @@ export class VizSpecStore {
|
|
|
418
426
|
}
|
|
419
427
|
// 目的地是metafields的情况,只有在来源也是metafields时,会执行字段类型转化操作
|
|
420
428
|
if (MetaFieldKeys.includes(destinationKey)) {
|
|
421
|
-
if (!MetaFieldKeys.includes(sourceKey))return;
|
|
429
|
+
if (!MetaFieldKeys.includes(sourceKey)) return;
|
|
422
430
|
encodings[sourceKey].splice(sourceIndex, 1);
|
|
423
|
-
movingField.analyticType = destinationKey ===
|
|
431
|
+
movingField.analyticType = destinationKey === "dimensions" ? "dimension" : "measure";
|
|
424
432
|
}
|
|
425
433
|
const limitSize = getChannelSizeLimit(destinationKey);
|
|
426
434
|
const fixedDestinationIndex = Math.min(destinationIndex, limitSize - 1);
|
|
@@ -429,7 +437,7 @@ export class VizSpecStore {
|
|
|
429
437
|
});
|
|
430
438
|
}
|
|
431
439
|
public removeField(sourceKey: keyof DraggableFieldState, sourceIndex: number) {
|
|
432
|
-
if (MetaFieldKeys.includes(sourceKey))return;
|
|
440
|
+
if (MetaFieldKeys.includes(sourceKey)) return;
|
|
433
441
|
|
|
434
442
|
this.useMutable(({ encodings }) => {
|
|
435
443
|
const fields = encodings[sourceKey];
|
|
@@ -462,25 +470,29 @@ export class VizSpecStore {
|
|
|
462
470
|
const fieldsInCup = encodings.columns;
|
|
463
471
|
|
|
464
472
|
encodings.columns = encodings.rows;
|
|
465
|
-
encodings.rows = fieldsInCup as typeof encodings.rows;
|
|
473
|
+
encodings.rows = fieldsInCup as typeof encodings.rows; // assume this as writable
|
|
466
474
|
});
|
|
467
475
|
}
|
|
468
476
|
public createBinField(stateKey: keyof DraggableFieldState, index: number) {
|
|
469
477
|
this.useMutable(({ encodings }) => {
|
|
470
|
-
const originField = encodings[stateKey][index]
|
|
478
|
+
const originField = encodings[stateKey][index];
|
|
471
479
|
const binField: IViewField = {
|
|
472
480
|
fid: uuidv4(),
|
|
473
481
|
dragId: uuidv4(),
|
|
474
482
|
name: `bin(${originField.name})`,
|
|
475
|
-
semanticType:
|
|
476
|
-
analyticType:
|
|
483
|
+
semanticType: "ordinal",
|
|
484
|
+
analyticType: "dimension",
|
|
477
485
|
};
|
|
478
486
|
encodings.dimensions.push(binField);
|
|
479
|
-
this.commonStore.currentDataset.dataSource = makeBinField(
|
|
487
|
+
this.commonStore.currentDataset.dataSource = makeBinField(
|
|
488
|
+
this.commonStore.currentDataset.dataSource,
|
|
489
|
+
originField.fid,
|
|
490
|
+
binField.fid
|
|
491
|
+
);
|
|
480
492
|
});
|
|
481
493
|
}
|
|
482
494
|
public createLogField(stateKey: keyof DraggableFieldState, index: number) {
|
|
483
|
-
if (stateKey ===
|
|
495
|
+
if (stateKey === "filters") {
|
|
484
496
|
return;
|
|
485
497
|
}
|
|
486
498
|
|
|
@@ -490,14 +502,18 @@ export class VizSpecStore {
|
|
|
490
502
|
fid: uuidv4(),
|
|
491
503
|
dragId: uuidv4(),
|
|
492
504
|
name: `log10(${originField.name})`,
|
|
493
|
-
semanticType:
|
|
494
|
-
analyticType: originField.analyticType
|
|
505
|
+
semanticType: "quantitative",
|
|
506
|
+
analyticType: originField.analyticType,
|
|
495
507
|
};
|
|
496
508
|
encodings[stateKey].push(logField);
|
|
497
|
-
this.commonStore.currentDataset.dataSource = makeLogField(
|
|
509
|
+
this.commonStore.currentDataset.dataSource = makeLogField(
|
|
510
|
+
this.commonStore.currentDataset.dataSource,
|
|
511
|
+
originField.fid,
|
|
512
|
+
logField.fid
|
|
513
|
+
);
|
|
498
514
|
});
|
|
499
515
|
}
|
|
500
|
-
public setFieldAggregator
|
|
516
|
+
public setFieldAggregator(stateKey: keyof DraggableFieldState, index: number, aggName: string) {
|
|
501
517
|
this.useMutable(({ encodings }) => {
|
|
502
518
|
const fields = encodings[stateKey];
|
|
503
519
|
|
|
@@ -506,54 +522,77 @@ export class VizSpecStore {
|
|
|
506
522
|
}
|
|
507
523
|
});
|
|
508
524
|
}
|
|
509
|
-
public get sortCondition
|
|
525
|
+
public get sortCondition() {
|
|
510
526
|
const { rows, columns } = this.draggableFieldState;
|
|
511
527
|
const yField = rows.length > 0 ? rows[rows.length - 1] : null;
|
|
512
528
|
const xField = columns.length > 0 ? columns[columns.length - 1] : null;
|
|
513
|
-
if (
|
|
514
|
-
|
|
529
|
+
if (
|
|
530
|
+
xField !== null &&
|
|
531
|
+
xField.analyticType === "dimension" &&
|
|
532
|
+
yField !== null &&
|
|
533
|
+
yField.analyticType === "measure"
|
|
534
|
+
) {
|
|
535
|
+
return true;
|
|
515
536
|
}
|
|
516
|
-
if (
|
|
517
|
-
|
|
537
|
+
if (
|
|
538
|
+
xField !== null &&
|
|
539
|
+
xField.analyticType === "measure" &&
|
|
540
|
+
yField !== null &&
|
|
541
|
+
yField.analyticType === "dimension"
|
|
542
|
+
) {
|
|
543
|
+
return true;
|
|
518
544
|
}
|
|
519
545
|
return false;
|
|
520
546
|
}
|
|
521
|
-
public setFieldSort
|
|
547
|
+
public setFieldSort(
|
|
548
|
+
stateKey: keyof DraggableFieldState,
|
|
549
|
+
index: number,
|
|
550
|
+
sortType: "none" | "ascending" | "descending"
|
|
551
|
+
) {
|
|
522
552
|
this.useMutable(({ encodings }) => {
|
|
523
553
|
encodings[stateKey][index].sort = sortType;
|
|
524
554
|
});
|
|
525
555
|
}
|
|
526
|
-
public applyDefaultSort(sortType:
|
|
556
|
+
public applyDefaultSort(sortType: "none" | "ascending" | "descending" = "ascending") {
|
|
527
557
|
this.useMutable(({ encodings }) => {
|
|
528
558
|
const { rows, columns } = encodings;
|
|
529
559
|
const yField = rows.length > 0 ? rows[rows.length - 1] : null;
|
|
530
560
|
const xField = columns.length > 0 ? columns[columns.length - 1] : null;
|
|
531
|
-
|
|
532
|
-
if (
|
|
561
|
+
|
|
562
|
+
if (
|
|
563
|
+
xField !== null &&
|
|
564
|
+
xField.analyticType === "dimension" &&
|
|
565
|
+
yField !== null &&
|
|
566
|
+
yField.analyticType === "measure"
|
|
567
|
+
) {
|
|
533
568
|
encodings.columns[columns.length - 1].sort = sortType;
|
|
534
569
|
return;
|
|
535
570
|
}
|
|
536
|
-
if (
|
|
571
|
+
if (
|
|
572
|
+
xField !== null &&
|
|
573
|
+
xField.analyticType === "measure" &&
|
|
574
|
+
yField !== null &&
|
|
575
|
+
yField.analyticType === "dimension"
|
|
576
|
+
) {
|
|
537
577
|
encodings.rows[rows.length - 1].sort = sortType;
|
|
538
578
|
return;
|
|
539
579
|
}
|
|
540
580
|
});
|
|
541
581
|
}
|
|
542
|
-
public appendField
|
|
582
|
+
public appendField(destinationKey: keyof DraggableFieldState, field: IViewField | undefined) {
|
|
543
583
|
if (MetaFieldKeys.includes(destinationKey)) return;
|
|
544
|
-
if (typeof field ===
|
|
545
|
-
if (destinationKey ===
|
|
584
|
+
if (typeof field === "undefined") return;
|
|
585
|
+
if (destinationKey === "filters") {
|
|
546
586
|
return;
|
|
547
587
|
}
|
|
548
|
-
|
|
549
|
-
|
|
588
|
+
|
|
550
589
|
this.useMutable(({ encodings }) => {
|
|
551
590
|
const cloneField = { ...toJS(field) };
|
|
552
591
|
cloneField.dragId = uuidv4();
|
|
553
592
|
encodings[destinationKey].push(cloneField);
|
|
554
593
|
});
|
|
555
594
|
}
|
|
556
|
-
public renderSpec
|
|
595
|
+
public renderSpec(spec: Specification) {
|
|
557
596
|
const tab = this.visList[this.visIndex];
|
|
558
597
|
|
|
559
598
|
if (tab) {
|
|
@@ -562,44 +601,67 @@ export class VizSpecStore {
|
|
|
562
601
|
// const [xField, yField, ] = spec.position;
|
|
563
602
|
this.clearState();
|
|
564
603
|
if ((spec.geomType?.length ?? 0) > 0) {
|
|
565
|
-
this.setVisualConfig(
|
|
604
|
+
this.setVisualConfig(
|
|
605
|
+
"geoms",
|
|
606
|
+
spec.geomType!.map((g) => geomAdapter(g))
|
|
607
|
+
);
|
|
566
608
|
}
|
|
567
609
|
if ((spec.facets?.length ?? 0) > 0) {
|
|
568
610
|
const facets = (spec.facets || []).concat(spec.highFacets || []);
|
|
569
611
|
for (let facet of facets) {
|
|
570
|
-
this.appendField(
|
|
612
|
+
this.appendField(
|
|
613
|
+
"rows",
|
|
614
|
+
fields.find((f) => f.fid === facet)
|
|
615
|
+
);
|
|
571
616
|
}
|
|
572
617
|
}
|
|
573
618
|
if (spec.position) {
|
|
574
619
|
const [cols, rows] = spec.position;
|
|
575
|
-
if (cols)
|
|
576
|
-
|
|
620
|
+
if (cols)
|
|
621
|
+
this.appendField(
|
|
622
|
+
"columns",
|
|
623
|
+
fields.find((f) => f.fid === cols)
|
|
624
|
+
);
|
|
625
|
+
if (rows)
|
|
626
|
+
this.appendField(
|
|
627
|
+
"rows",
|
|
628
|
+
fields.find((f) => f.fid === rows)
|
|
629
|
+
);
|
|
577
630
|
}
|
|
578
631
|
if ((spec.color?.length ?? 0) > 0) {
|
|
579
|
-
this.appendField(
|
|
632
|
+
this.appendField(
|
|
633
|
+
"color",
|
|
634
|
+
fields.find((f) => f.fid === spec.color![0])
|
|
635
|
+
);
|
|
580
636
|
}
|
|
581
637
|
if ((spec.size?.length ?? 0) > 0) {
|
|
582
|
-
this.appendField(
|
|
638
|
+
this.appendField(
|
|
639
|
+
"size",
|
|
640
|
+
fields.find((f) => f.fid === spec.size![0])
|
|
641
|
+
);
|
|
583
642
|
}
|
|
584
643
|
if ((spec.opacity?.length ?? 0) > 0) {
|
|
585
|
-
this.appendField(
|
|
644
|
+
this.appendField(
|
|
645
|
+
"opacity",
|
|
646
|
+
fields.find((f) => f.fid === spec.opacity![0])
|
|
647
|
+
);
|
|
586
648
|
}
|
|
587
649
|
}
|
|
588
650
|
}
|
|
589
|
-
public destroy
|
|
590
|
-
this.reactions.forEach(rec => {
|
|
651
|
+
public destroy() {
|
|
652
|
+
this.reactions.forEach((rec) => {
|
|
591
653
|
rec();
|
|
592
|
-
})
|
|
654
|
+
});
|
|
593
655
|
}
|
|
594
|
-
public exportAsRaw
|
|
656
|
+
public exportAsRaw() {
|
|
595
657
|
const pureVisList = dumpsGWPureSpec(this.visList);
|
|
596
658
|
return stringifyGWContent({
|
|
597
659
|
datasets: toJS(this.commonStore.datasets),
|
|
598
660
|
dataSources: this.commonStore.dataSources,
|
|
599
|
-
specList: pureVisList
|
|
600
|
-
})
|
|
661
|
+
specList: pureVisList,
|
|
662
|
+
});
|
|
601
663
|
}
|
|
602
|
-
public importRaw
|
|
664
|
+
public importRaw(raw: string) {
|
|
603
665
|
const content = parseGWContent(raw);
|
|
604
666
|
this.commonStore.datasets = content.datasets;
|
|
605
667
|
this.commonStore.dataSources = content.dataSources;
|
|
@@ -608,4 +670,4 @@ export class VizSpecStore {
|
|
|
608
670
|
this.visList = parseGWPureSpec(forwardVisualConfigs(content.specList));
|
|
609
671
|
this.visIndex = 0;
|
|
610
672
|
}
|
|
611
|
-
}
|
|
673
|
+
}
|