@kanaries/graphic-walker 0.2.15 → 0.2.16

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.
Files changed (97) hide show
  1. package/dist/App.d.ts +2 -0
  2. package/dist/assets/explainer.worker-8428eb12.js.map +1 -1
  3. package/dist/assets/transform.worker-5d54ff09.js.map +1 -0
  4. package/dist/assets/viewQuery.worker-ffefc111.js.map +1 -0
  5. package/dist/components/codeExport/index.d.ts +3 -0
  6. package/dist/components/loadingLayer.d.ts +2 -0
  7. package/dist/components/tabs/defaultTab.d.ts +1 -0
  8. package/dist/components/tabs/editableTab.d.ts +1 -2
  9. package/dist/dataSource/dataSelection/config.d.ts +1 -0
  10. package/dist/dataSource/dataSelection/utils.d.ts +2 -0
  11. package/dist/datasets/tmp/test.json +1 -0
  12. package/dist/graphic-walker.es.js +23081 -22577
  13. package/dist/graphic-walker.es.js.map +1 -1
  14. package/dist/graphic-walker.umd.js +130 -130
  15. package/dist/graphic-walker.umd.js.map +1 -1
  16. package/dist/index.d.ts +3 -3
  17. package/dist/interfaces.d.ts +21 -1
  18. package/dist/lib/execExp.d.ts +8 -0
  19. package/dist/lib/interfaces.d.ts +22 -0
  20. package/dist/lib/op/aggregate.d.ts +3 -0
  21. package/dist/lib/op/bin.d.ts +3 -0
  22. package/dist/lib/op/fold.d.ts +3 -0
  23. package/dist/lib/op/stat.d.ts +8 -0
  24. package/dist/lib/viewQuery.d.ts +5 -0
  25. package/dist/models/visSpecHistory.d.ts +2 -0
  26. package/dist/renderer/index.d.ts +8 -7
  27. package/dist/renderer/specRenderer.d.ts +13 -0
  28. package/dist/services.d.ts +4 -1
  29. package/dist/store/commonStore.d.ts +6 -0
  30. package/dist/store/index.d.ts +3 -2
  31. package/dist/store/visualSpecStore.d.ts +11 -4
  32. package/dist/utils/dataPrep.d.ts +2 -0
  33. package/dist/utils/index.d.ts +3 -5
  34. package/dist/utils/save.d.ts +1 -2
  35. package/dist/vis/react-vega.d.ts +1 -22
  36. package/dist/vis/spec/aggregate.d.ts +4 -0
  37. package/dist/vis/spec/encode.d.ts +19 -0
  38. package/dist/vis/spec/field.d.ts +2 -0
  39. package/dist/vis/spec/mark.d.ts +7 -0
  40. package/dist/vis/spec/stack.d.ts +4 -0
  41. package/dist/vis/spec/view.d.ts +67 -0
  42. package/dist/workers/transform.d.ts +2 -0
  43. package/package.json +4 -3
  44. package/src/App.tsx +5 -2
  45. package/src/components/codeExport/index.tsx +114 -0
  46. package/src/components/dataTable/index.tsx +10 -10
  47. package/src/components/loadingLayer.tsx +7 -0
  48. package/src/components/tabs/defaultTab.tsx +4 -2
  49. package/src/components/tabs/editableTab.tsx +74 -39
  50. package/src/dataSource/dataSelection/config.ts +11 -0
  51. package/src/dataSource/dataSelection/csvData.tsx +71 -39
  52. package/src/dataSource/dataSelection/gwFile.tsx +2 -2
  53. package/src/dataSource/dataSelection/utils.ts +28 -0
  54. package/src/dataSource/utils.ts +8 -3
  55. package/src/fields/datasetFields/meaFields.tsx +12 -4
  56. package/src/index.css +4 -4
  57. package/src/index.tsx +22 -22
  58. package/src/interfaces.ts +26 -2
  59. package/src/lib/execExp.ts +147 -0
  60. package/src/lib/interfaces.ts +39 -0
  61. package/src/lib/op/aggregate.ts +49 -0
  62. package/src/lib/op/bin.ts +25 -0
  63. package/src/lib/op/fold.ts +17 -0
  64. package/src/lib/op/stat.ts +46 -0
  65. package/src/lib/viewQuery.ts +23 -0
  66. package/src/locales/en-US.json +4 -2
  67. package/src/locales/i18n.ts +0 -1
  68. package/src/locales/ja-JP.json +4 -2
  69. package/src/locales/zh-CN.json +4 -2
  70. package/src/main.tsx +1 -1
  71. package/src/models/visSpecHistory.ts +14 -0
  72. package/src/renderer/index.tsx +58 -126
  73. package/src/renderer/specRenderer.tsx +119 -0
  74. package/src/segments/segmentNav.tsx +3 -16
  75. package/src/segments/visNav.tsx +17 -6
  76. package/src/services.ts +37 -1
  77. package/src/store/commonStore.ts +14 -9
  78. package/src/store/index.tsx +11 -4
  79. package/src/store/visualSpecStore.ts +89 -50
  80. package/src/utils/dataPrep.ts +24 -0
  81. package/src/utils/index.ts +16 -17
  82. package/src/utils/normalization.ts +3 -1
  83. package/src/utils/save.ts +1 -2
  84. package/src/vis/react-vega.tsx +4 -340
  85. package/src/vis/spec/aggregate.ts +13 -0
  86. package/src/vis/spec/encode.ts +69 -0
  87. package/src/vis/spec/field.ts +10 -0
  88. package/src/vis/spec/mark.ts +30 -0
  89. package/src/vis/spec/stack.ts +11 -0
  90. package/src/vis/spec/view.ts +138 -0
  91. package/src/vis/theme.ts +12 -0
  92. package/src/visualSettings/index.tsx +10 -1
  93. package/src/workers/transform.ts +12 -0
  94. package/src/workers/transform.worker.js +13 -0
  95. package/src/workers/viewQuery.worker.js +16 -0
  96. package/dist/dataSource/pannel.d.ts +0 -5
  97. package/src/dataSource/pannel.tsx +0 -71
@@ -0,0 +1,147 @@
1
+ import { IExpParamter, IExpression, IField, IRow } from "../interfaces";
2
+
3
+ interface IDataFrame {
4
+ [key: string]: any[];
5
+ }
6
+
7
+ export function execExpression (exp: IExpression, dataFrame: IDataFrame, columns: IField[]): IDataFrame {
8
+ const { op, params } = exp;
9
+ const subFrame: IDataFrame = { ...dataFrame };
10
+ const len = dataFrame[Object.keys(dataFrame)[0]].length;
11
+ for (let param of params) {
12
+ switch (param.type) {
13
+ case 'field':
14
+ subFrame[param.value] = dataFrame[param.value];
15
+ break;
16
+ case 'constant':
17
+ subFrame[param.value] = new Array(len).fill(param.value);
18
+ break;
19
+ case 'expression':
20
+ let f = execExpression(param.value, dataFrame, columns);
21
+ Object.keys(f).forEach(key => {
22
+ subFrame[key] = f[key];
23
+ })
24
+ break;
25
+ case 'value':
26
+ default:
27
+ break;
28
+ }
29
+ }
30
+ switch (op) {
31
+ case 'one':
32
+ return one(exp.as, params, subFrame);
33
+ case 'bin':
34
+ return bin(exp.as, params, subFrame);
35
+ case 'log2':
36
+ return log2(exp.as, params, subFrame);
37
+ case 'log10':
38
+ return log10(exp.as, params, subFrame);
39
+ case 'binCount':
40
+ return binCount(exp.as, params, subFrame);
41
+ default:
42
+ return subFrame;
43
+ }
44
+ }
45
+
46
+ function bin(resKey: string, params: IExpParamter[], data: IDataFrame, binSize: number | undefined = 10): IDataFrame {
47
+ const { value: fieldKey } = params[0];
48
+ const fieldValues = data[fieldKey] as number[];
49
+ let _min = Infinity;
50
+ let _max = -Infinity;
51
+ for (let i = 0; i < fieldValues.length; i++) {
52
+ let val = fieldValues[i];
53
+ if (val > _max) _max = val;
54
+ if (val < _min) _min = val;
55
+ }
56
+ const step = (_max - _min) / binSize;
57
+ const beaStep = Math.max(-Math.round(Math.log10(_max - _min)) + 2, 0)
58
+ const newValues = fieldValues.map((v: number) => {
59
+ let bIndex = Math.floor((v - _min) / step);
60
+ if (bIndex === binSize) bIndex = binSize - 1;
61
+ return Number(((bIndex * step + _min)).toFixed(beaStep))
62
+ });
63
+ return {
64
+ ...data,
65
+ [resKey]: newValues,
66
+ }
67
+ }
68
+
69
+ function binCount(resKey: string, params: IExpParamter[], data: IDataFrame, binSize: number | undefined = 10): IDataFrame {
70
+ const { value: fieldKey } = params[0];
71
+ const fieldValues = data[fieldKey] as number[];
72
+
73
+ const valueWithIndices: {val: number; index: number; orderIndex: number }[] = fieldValues.map((v, i) => ({
74
+ val: v,
75
+ index: i
76
+ })).sort((a, b) => a.val - b.val)
77
+ .map((item, i) => ({
78
+ val: item.val,
79
+ index: item.index,
80
+ orderIndex: i
81
+ }))
82
+
83
+ const groupSize = valueWithIndices.length / binSize;
84
+
85
+ const newValues = valueWithIndices.map(item => {
86
+ let bIndex = Math.floor(item.orderIndex / groupSize);
87
+ if (bIndex === binSize) bIndex = binSize - 1;
88
+ return bIndex + 1
89
+ })
90
+ return {
91
+ ...data,
92
+ [resKey]: newValues,
93
+ }
94
+ }
95
+
96
+ function log2(resKey: string, params: IExpParamter[], data: IDataFrame): IDataFrame {
97
+ const { value } = params[0];
98
+ const field = data[value];
99
+ const newField = field.map((v: number) => Math.log2(v));
100
+ return {
101
+ ...data,
102
+ [resKey]: newField,
103
+ }
104
+ }
105
+
106
+ function log10(resKey: string, params: IExpParamter[], data: IDataFrame): IDataFrame {
107
+ const { value: fieldKey } = params[0];
108
+ const fieldValues = data[fieldKey];
109
+ const newField = fieldValues.map((v: number) => Math.log10(v));
110
+ return {
111
+ ...data,
112
+ [resKey]: newField,
113
+ }
114
+ }
115
+
116
+ function one(resKey: string, params: IExpParamter[], data: IDataFrame): IDataFrame {
117
+ // const { value: fieldKey } = params[0];
118
+ if (Object.keys(data).length === 0) return data;
119
+ const len = data[Object.keys(data)[0]].length;
120
+ const newField = new Array(len).fill(1);
121
+ return {
122
+ ...data,
123
+ [resKey]: newField,
124
+ }
125
+ }
126
+
127
+ export function dataset2DataFrame(dataset: IRow[], columns: IField[]): IDataFrame {
128
+ const dataFrame: IDataFrame = {};
129
+ columns.forEach((col) => {
130
+ dataFrame[col.fid] = dataset.map((row) => row[col.fid]);
131
+ });
132
+ return dataFrame;
133
+ }
134
+
135
+ export function dataframe2Dataset(dataFrame: IDataFrame, columns: IField[]): IRow[] {
136
+ if (columns.length === 0) return [];
137
+ const dataset: IRow[] = [];
138
+ const len = dataFrame[Object.keys(dataFrame)[0]].length;
139
+ for (let i = 0; i < len; i++) {
140
+ const row: IRow = {};
141
+ columns.forEach((col) => {
142
+ row[col.fid] = dataFrame[col.fid][i];
143
+ });
144
+ dataset.push(row);
145
+ }
146
+ return dataset;
147
+ }
@@ -0,0 +1,39 @@
1
+ export interface IAggQuery {
2
+ op: 'aggregate';
3
+ groupBy: string[];
4
+ agg: {
5
+ [field: string]:
6
+ | 'sum'
7
+ | 'count'
8
+ | 'max'
9
+ | 'min'
10
+ | 'mean'
11
+ | 'median'
12
+ | 'variance'
13
+ | 'stdev';
14
+ };
15
+ }
16
+
17
+ // interface IFilterQuery {
18
+ // op: 'filter';
19
+ // filter: string;
20
+ // }
21
+
22
+ export interface IFoldQuery {
23
+ op: 'fold';
24
+ foldBy: string[];
25
+ newFoldKeyCol: string;
26
+ newFoldValueCol: string;
27
+ }
28
+
29
+ export interface IBinQuery {
30
+ op: 'bin';
31
+ binBy: string;
32
+ newBinCol: string;
33
+ binSize: number;
34
+ }
35
+
36
+
37
+ export interface IRawQuery {
38
+ op: 'raw';
39
+ }
@@ -0,0 +1,49 @@
1
+ import { IRow } from "visual-insights";
2
+ import { IAggQuery } from "../interfaces";
3
+ import { sum, mean, median, stdev, variance, max, min, count } from "./stat";
4
+
5
+ const aggregatorMap = {
6
+ sum,
7
+ mean,
8
+ median,
9
+ stdev,
10
+ variance,
11
+ max,
12
+ min,
13
+ count,
14
+ };
15
+
16
+ const KEY_JOINER = '___';
17
+
18
+ export function aggregate (data: IRow[], query: IAggQuery): IRow[] {
19
+ const { groupBy, agg } = query;
20
+ const ans: Map<string, IRow> = new Map();
21
+ const groups: Map<string, IRow[]> = new Map();
22
+ for (let row of data) {
23
+ const gk = groupBy.map((k) => row[k]).join(KEY_JOINER);
24
+
25
+ if (!groups.has(gk)) {
26
+ groups.set(gk, []);
27
+ }
28
+ groups.get(gk)?.push(row);
29
+ }
30
+ for (let [gk, subGroup] of groups) {
31
+ if (subGroup.length === 0) {
32
+ continue;
33
+ }
34
+ let aggRow: IRow = {};
35
+ for (let k of groupBy) {
36
+ aggRow[k] = subGroup[0][k];
37
+ }
38
+ for (let meaKey in agg) {
39
+ if (aggRow[meaKey] === undefined) {
40
+ aggRow[meaKey] = 0;
41
+ }
42
+ const values: number[] = subGroup.map((r) => r[meaKey]) ?? [];
43
+ const aggregator = aggregatorMap[agg[meaKey]] ?? sum;
44
+ aggRow[meaKey] = aggregator(values);
45
+ }
46
+ ans.set(gk, aggRow);
47
+ }
48
+ return Array.from(ans.values());
49
+ }
@@ -0,0 +1,25 @@
1
+ import { IRow } from "visual-insights";
2
+ import { IBinQuery } from "../interfaces";
3
+
4
+ export function bin (dataSource: IRow[], query: IBinQuery): IRow[] {
5
+ const { binBy, newBinCol, binSize } = query;
6
+ let _min = Infinity;
7
+ let _max = -Infinity;
8
+ for (let i = 0; i < dataSource.length; i++) {
9
+ let val = dataSource[i][binBy];
10
+ if (val > _max) _max = val;
11
+ if (val < _min) _min = val;
12
+ }
13
+ const step = (_max - _min) / binSize;
14
+ // const beaStep = Math.max(-Math.round(Math.log10(_max - _min)) + 2, 0)
15
+ return dataSource.map((r) => {
16
+ let bIndex = Math.floor((r[binBy] - _min) / step);
17
+ if (bIndex === binSize) bIndex = binSize - 1;
18
+ return {
19
+ ...r,
20
+ [newBinCol]: [bIndex * step + _min, (bIndex + 1) * step + _min],
21
+
22
+ // [binFid]: Number(((bIndex * step + _min)).toFixed(beaStep)),
23
+ };
24
+ });
25
+ }
@@ -0,0 +1,17 @@
1
+ import { IRow } from "visual-insights";
2
+ import { IFoldQuery } from "../interfaces";
3
+
4
+ export function fold (data: IRow[], query: IFoldQuery): IRow[] {
5
+ const { foldBy, newFoldKeyCol, newFoldValueCol } = query;
6
+ const ans: IRow[] = [];
7
+ for (let row of data) {
8
+ for (let k of foldBy) {
9
+ const newRow = { ...row };
10
+ newRow[newFoldKeyCol] = k;
11
+ newRow[newFoldValueCol] = row[k];
12
+ delete newRow[k];
13
+ ans.push(newRow);
14
+ }
15
+ }
16
+ return ans;
17
+ }
@@ -0,0 +1,46 @@
1
+ export function mean(nums: number[]): number {
2
+ return nums.reduce((a, b) => a + b, 0) / nums.length;
3
+ }
4
+
5
+ export function sum(nums: number[]): number {
6
+ return nums.reduce((a, b) => a + b, 0);
7
+ }
8
+
9
+ export function median(nums: number[]): number {
10
+ const sorted = nums.sort((a, b) => a - b);
11
+ const mid = Math.floor(sorted.length / 2);
12
+ return sorted.length % 2 === 0 ? (sorted[mid] + sorted[mid - 1]) / 2 : sorted[mid];
13
+ }
14
+
15
+ export function variance(nums: number[]): number {
16
+ const m = mean(nums);
17
+ return mean(nums.map((x) => (x - m) ** 2));
18
+ }
19
+
20
+ export function stdev(nums: number[]): number {
21
+ return Math.sqrt(variance(nums));
22
+ }
23
+
24
+ export function max(nums: number[]): number {
25
+ let ans = -Infinity;
26
+ for (let n of nums) {
27
+ if (n > ans) {
28
+ ans = n;
29
+ }
30
+ }
31
+ return ans;
32
+ }
33
+
34
+ export function min(nums: number[]): number {
35
+ let ans = Infinity;
36
+ for (let n of nums) {
37
+ if (n < ans) {
38
+ ans = n;
39
+ }
40
+ }
41
+ return ans;
42
+ }
43
+
44
+ export function count(nums: number[]): number {
45
+ return nums.length;
46
+ }
@@ -0,0 +1,23 @@
1
+ import { IRow } from "visual-insights";
2
+ import { IMutField } from "../interfaces";
3
+ import { aggregate } from "./op/aggregate";
4
+ import { fold } from "./op/fold";
5
+ import { IAggQuery, IBinQuery, IFoldQuery, IRawQuery } from "./interfaces";
6
+ import { bin } from "./op/bin";
7
+
8
+ export type IViewQuery = IAggQuery | IFoldQuery | IBinQuery | IRawQuery;
9
+
10
+ export function queryView (rawData: IRow[], metas: IMutField[], query: IViewQuery) {
11
+ switch (query.op) {
12
+ case 'aggregate':
13
+ return aggregate(rawData, query);
14
+ case 'fold':
15
+ return fold(rawData, query);
16
+ case 'bin':
17
+ return bin(rawData, query);
18
+ case 'raw':
19
+ default:
20
+ return rawData;
21
+ }
22
+
23
+ }
@@ -117,7 +117,8 @@
117
117
  "main": {
118
118
  "tablist": {
119
119
  "new": "+ New",
120
- "autoTitle": "Chart {{idx}}"
120
+ "auto_title": "Chart {{idx}}",
121
+ "chart_name": "Chart Name"
121
122
  },
122
123
  "tabpanel": {
123
124
  "menubar": {
@@ -190,6 +191,7 @@
190
191
  "prev": "Previous",
191
192
  "next": "Next",
192
193
  "drop_field": "Drop Field Here",
193
- "confirm": "Confirm"
194
+ "confirm": "Confirm",
195
+ "cancel": "Cancel"
194
196
  }
195
197
  }
@@ -6,7 +6,6 @@ import localeEnUs from './en-US.json';
6
6
  import localeJaJp from './ja-JP.json';
7
7
  import localeZhCn from './zh-CN.json';
8
8
 
9
-
10
9
  const locales: Resource & { 'en-US': any } = {
11
10
  'en': {
12
11
  translation: localeEnUs,
@@ -117,7 +117,8 @@
117
117
  "main": {
118
118
  "tablist": {
119
119
  "new": "+ 新規作成",
120
- "autoTitle": "グラフ {{idx}}"
120
+ "auto_title": "グラフ {{idx}}",
121
+ "chart_name": "グラフ名"
121
122
  },
122
123
  "tabpanel": {
123
124
  "menubar": {
@@ -190,6 +191,7 @@
190
191
  "prev": "前へ",
191
192
  "next": "次へ",
192
193
  "drop_field": "ここにフィールドをドロップ",
193
- "confirm": "確認"
194
+ "confirm": "確認",
195
+ "cancel": "キャンセル"
194
196
  }
195
197
  }
@@ -117,7 +117,8 @@
117
117
  "main": {
118
118
  "tablist": {
119
119
  "new": "+ 新建",
120
- "autoTitle": "图表 {{idx}}"
120
+ "auto_title": "图表 {{idx}}",
121
+ "chart_name": "图表名称"
121
122
  },
122
123
  "tabpanel": {
123
124
  "menubar": {
@@ -190,6 +191,7 @@
190
191
  "prev": "向前",
191
192
  "next": "向后",
192
193
  "drop_field": "拖拽字段至此",
193
- "confirm": "确认"
194
+ "confirm": "确认",
195
+ "cencel": "取消"
194
196
  }
195
197
  }
package/src/main.tsx CHANGED
@@ -1,4 +1,4 @@
1
- import React from "react";
1
+ import React, { useEffect } from "react";
2
2
  import ReactDOM from "react-dom";
3
3
  import { GraphicWalker } from "./index";
4
4
 
@@ -27,6 +27,14 @@ export class VisSpecWithHistory {
27
27
 
28
28
  private batchFlag = false;
29
29
 
30
+ public updateLatest(snapshot: Partial<Readonly<VisSpecWithHistory['snapshots'][0]>>) {
31
+ this.snapshots[this.cursor] = {
32
+ ...this.snapshots[this.cursor],
33
+ ...snapshot,
34
+ }
35
+ }
36
+
37
+
30
38
  private commit(snapshot: Partial<Readonly<VisSpecWithHistory['snapshots'][0]>>): void {
31
39
  if (this.batchFlag) {
32
40
  // batch this commit
@@ -120,6 +128,12 @@ export class VisSpecWithHistory {
120
128
  });
121
129
  }
122
130
 
131
+ public clone () {
132
+ const nextVSWH = new VisSpecWithHistory(this.frame);
133
+ nextVSWH.cursor = this.cursor;
134
+ return nextVSWH;
135
+ }
136
+
123
137
  public exportGW (): IVisSpec {
124
138
  return {
125
139
  ...this.frame
@@ -1,138 +1,70 @@
1
- import { runInAction, toJS } from "mobx";
2
- import { observer } from "mobx-react-lite";
3
- import { Resizable } from "re-resizable";
4
- import React, { useState, useCallback, useEffect, useRef, forwardRef } from "react";
5
- import { applyFilter } from "../services";
6
- import { useGlobalStore } from "../store";
7
- import ReactVega, { IReactVegaHandler } from "../vis/react-vega";
8
- import { IDarkMode, IThemeKey } from "../interfaces";
1
+ import { observer } from 'mobx-react-lite';
2
+ import React, { useState, useEffect, forwardRef } from 'react';
3
+ import { applyFilter, applyViewQuery, transformDataService } from '../services';
4
+ import { DeepReadonly, DraggableFieldState, IDarkMode, IRow, IThemeKey, IVisualConfig } from '../interfaces';
5
+ import SpecRenderer from './specRenderer';
6
+ import { toJS } from 'mobx';
7
+ import { useGlobalStore } from '../store';
8
+ import { IReactVegaHandler } from '../vis/react-vega';
9
+ import { unstable_batchedUpdates } from 'react-dom';
10
+ import { initEncoding, initVisualConfig } from '../store/visualSpecStore';
9
11
 
10
- const ReactiveRenderer = forwardRef<IReactVegaHandler, { themeKey?: IThemeKey; dark?: IDarkMode }>(function ReactiveRenderer(
11
- { themeKey, dark },
12
- ref
13
- ) {
12
+ interface RendererProps {
13
+ themeKey?: IThemeKey;
14
+ dark?: IDarkMode;
15
+ }
16
+ const Renderer = forwardRef<IReactVegaHandler, RendererProps>(function (props, ref) {
17
+ const { themeKey, dark } = props;
18
+ const [waiting, setWaiting] = useState<boolean>(false);
14
19
  const { vizStore, commonStore } = useGlobalStore();
15
- const { draggableFieldState, visualConfig } = vizStore;
16
- const { geoms, interactiveScale, defaultAggregated, stack, showActions, size, exploration } = visualConfig;
20
+ const { allFields, viewFilters, viewDimensions, viewMeasures } = vizStore;
17
21
  const { currentDataset } = commonStore;
18
- const { filters } = draggableFieldState;
19
-
20
- const rows = toJS(draggableFieldState.rows);
21
- const columns = toJS(draggableFieldState.columns);
22
- const color = toJS(draggableFieldState.color);
23
- const opacity = toJS(draggableFieldState.opacity);
24
- const shape = toJS(draggableFieldState.shape);
25
- const theta = toJS(draggableFieldState.theta);
26
- const radius = toJS(draggableFieldState.radius);
27
- const sizeChannel = toJS(draggableFieldState.size);
28
-
29
- const rowLeftFacetFields = rows.slice(0, -1).filter((f) => f.analyticType === "dimension");
30
- const colLeftFacetFields = columns.slice(0, -1).filter((f) => f.analyticType === "dimension");
31
-
32
- const hasFacet = rowLeftFacetFields.length > 0 || colLeftFacetFields.length > 0;
33
-
34
- const shouldTriggerMenu = exploration.mode === "none";
35
-
36
- const handleGeomClick = useCallback(
37
- (values: any, e: any) => {
38
- if (shouldTriggerMenu) {
39
- e.stopPropagation();
40
- runInAction(() => {
41
- commonStore.showEmbededMenu([e.pageX, e.pageY]);
42
- commonStore.setFilters(values);
43
- });
44
- }
45
- },
46
- [shouldTriggerMenu]
47
- );
48
-
49
- // apply filters
50
22
  const { dataSource } = currentDataset;
23
+ const [viewConfig, setViewConfig] = useState<IVisualConfig>(initVisualConfig);
24
+ const [encodings, setEncodings] = useState<DeepReadonly<DraggableFieldState>>(initEncoding);
51
25
 
52
- const [data, setData] = useState(dataSource);
53
- const pendingPromiseRef = useRef<Promise<typeof data> | null>(null);
26
+ const [viewData, setViewData] = useState<IRow[]>([]);
54
27
 
55
28
  useEffect(() => {
56
- setData(dataSource);
57
- }, [dataSource]);
58
-
59
- useEffect(() => {
60
- const p = filters.length === 0 ? Promise.resolve(dataSource) : applyFilter(dataSource, filters);
61
- pendingPromiseRef.current = p;
62
-
63
- p.then((d) => {
64
- if (p !== pendingPromiseRef.current) {
65
- // This promise is out-of-date
66
- return;
67
- }
68
-
69
- setData(d);
70
- }).catch((err) => {
71
- console.error(err);
72
- });
29
+ setWaiting(true);
30
+ applyFilter(dataSource, viewFilters)
31
+ .then((data) => transformDataService(data, allFields))
32
+ .then((d) => {
33
+ // setViewData(d);
34
+ const dims = viewDimensions;
35
+ const meas = viewMeasures;
36
+ const config = toJS(vizStore.visualConfig);
37
+ return applyViewQuery(d, dims.concat(meas), {
38
+ op: config.defaultAggregated ? 'aggregate' : 'raw',
39
+ groupBy: dims.map((f) => f.fid),
40
+ agg: Object.fromEntries(meas.map((f) => [f.fid, f.aggName as any])),
41
+ });
42
+ })
43
+ .then((data) => {
44
+ unstable_batchedUpdates(() => {
45
+ setViewData(data);
46
+ setWaiting(false);
47
+ setEncodings(toJS(vizStore.draggableFieldState));
48
+ setViewConfig(toJS(vizStore.visualConfig));
49
+ });
50
+ })
51
+ .catch((err) => {
52
+ console.error(err);
53
+ setWaiting(false);
54
+ });
55
+ }, [dataSource, viewFilters, allFields, viewDimensions, viewMeasures]);
73
56
 
74
- return () => {
75
- pendingPromiseRef.current = null;
76
- };
77
- }, [dataSource, filters]);
78
- const enableResize = size.mode === "fixed" && !hasFacet;
79
57
  return (
80
- <Resizable
81
- className={enableResize ? "border-blue-400 border-2 overflow-hidden" : ""}
82
- style={{ padding: "12px" }}
83
- onResizeStop={(e, direction, ref, d) => {
84
- vizStore.setChartLayout({
85
- mode: "fixed",
86
- width: size.width + d.width,
87
- height: size.height + d.height,
88
- });
89
- }}
90
- enable={
91
- enableResize
92
- ? undefined
93
- : {
94
- top: false,
95
- right: false,
96
- bottom: false,
97
- left: false,
98
- topRight: false,
99
- bottomRight: false,
100
- bottomLeft: false,
101
- topLeft: false,
102
- }
103
- }
104
- size={{
105
- width: size.width + "px",
106
- height: size.height + "px",
107
- }}
108
- >
109
- <ReactVega
110
- layoutMode={size.mode}
111
- interactiveScale={interactiveScale}
112
- geomType={geoms[0]}
113
- defaultAggregate={defaultAggregated}
114
- stack={stack}
115
- dataSource={data}
116
- rows={rows}
117
- columns={columns}
118
- color={color[0]}
119
- theta={theta[0]}
120
- radius={radius[0]}
121
- shape={shape[0]}
122
- opacity={opacity[0]}
123
- size={sizeChannel[0]}
124
- showActions={showActions}
125
- width={size.width - 12 * 4}
126
- height={size.height - 12 * 4}
127
- ref={ref}
128
- brushEncoding={exploration.mode === "brush" ? exploration.brushDirection : "none"}
129
- selectEncoding={exploration.mode === "point" ? "default" : "none"}
130
- onGeomClick={handleGeomClick}
131
- themeKey={themeKey}
132
- dark={dark}
133
- />
134
- </Resizable>
58
+ <SpecRenderer
59
+ loading={waiting}
60
+ data={viewData}
61
+ ref={ref}
62
+ themeKey={themeKey}
63
+ dark={dark}
64
+ draggableFieldState={encodings}
65
+ visualConfig={viewConfig}
66
+ />
135
67
  );
136
68
  });
137
69
 
138
- export default observer(ReactiveRenderer);
70
+ export default observer(Renderer);