@kanaries/graphic-walker 0.2.4 → 0.2.6

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 (76) hide show
  1. package/dist/App.d.ts +1 -0
  2. package/dist/graphic-walker.es.js +1 -1
  3. package/dist/graphic-walker.es.js.map +1 -1
  4. package/dist/graphic-walker.umd.js +1 -1
  5. package/dist/graphic-walker.umd.js.map +1 -1
  6. package/package.json +3 -2
  7. package/src/App.tsx +141 -0
  8. package/src/assets/kanaries.ico +0 -0
  9. package/src/components/clickMenu.tsx +29 -0
  10. package/src/components/container.tsx +16 -0
  11. package/src/components/dataTypeIcon.tsx +20 -0
  12. package/src/components/liteForm.tsx +16 -0
  13. package/src/components/modal.tsx +85 -0
  14. package/src/components/sizeSetting.tsx +95 -0
  15. package/src/components/tabs/pureTab.tsx +70 -0
  16. package/src/config.ts +57 -0
  17. package/src/constants.ts +1 -0
  18. package/src/dataSource/config.ts +62 -0
  19. package/src/dataSource/dataSelection/csvData.tsx +77 -0
  20. package/src/dataSource/dataSelection/gwFile.tsx +38 -0
  21. package/src/dataSource/dataSelection/index.tsx +57 -0
  22. package/src/dataSource/dataSelection/publicData.tsx +57 -0
  23. package/src/dataSource/index.tsx +78 -0
  24. package/src/dataSource/pannel.tsx +71 -0
  25. package/src/dataSource/table.tsx +125 -0
  26. package/src/dataSource/utils.ts +47 -0
  27. package/src/fields/aestheticFields.tsx +23 -0
  28. package/src/fields/components.tsx +159 -0
  29. package/src/fields/datasetFields/dimFields.tsx +45 -0
  30. package/src/fields/datasetFields/fieldPill.tsx +10 -0
  31. package/src/fields/datasetFields/index.tsx +28 -0
  32. package/src/fields/datasetFields/meaFields.tsx +58 -0
  33. package/src/fields/fieldsContext.tsx +59 -0
  34. package/src/fields/filterField/filterEditDialog.tsx +143 -0
  35. package/src/fields/filterField/filterPill.tsx +113 -0
  36. package/src/fields/filterField/index.tsx +61 -0
  37. package/src/fields/filterField/slider.tsx +236 -0
  38. package/src/fields/filterField/tabs.tsx +421 -0
  39. package/src/fields/obComponents/obFContainer.tsx +40 -0
  40. package/src/fields/obComponents/obPill.tsx +48 -0
  41. package/src/fields/posFields/index.tsx +33 -0
  42. package/src/fields/select.tsx +31 -0
  43. package/src/fields/utils.ts +31 -0
  44. package/src/index.css +13 -0
  45. package/src/index.tsx +12 -0
  46. package/src/insightBoard/index.tsx +30 -0
  47. package/src/insightBoard/mainBoard.tsx +203 -0
  48. package/src/insightBoard/radioGroupButtons.tsx +50 -0
  49. package/src/insightBoard/selectionSpec.ts +113 -0
  50. package/src/insightBoard/std2vegaSpec.ts +184 -0
  51. package/src/insightBoard/utils.ts +32 -0
  52. package/src/insights.ts +408 -0
  53. package/src/interfaces.ts +154 -0
  54. package/src/locales/en-US.json +140 -0
  55. package/src/locales/i18n.ts +50 -0
  56. package/src/locales/zh-CN.json +140 -0
  57. package/src/main.tsx +10 -0
  58. package/src/models/visSpecHistory.ts +129 -0
  59. package/src/renderer/index.tsx +104 -0
  60. package/src/segments/visNav.tsx +48 -0
  61. package/src/services.ts +139 -0
  62. package/src/store/commonStore.ts +158 -0
  63. package/src/store/index.tsx +53 -0
  64. package/src/store/visualSpecStore.ts +586 -0
  65. package/src/utils/autoMark.ts +34 -0
  66. package/src/utils/index.ts +251 -0
  67. package/src/utils/normalization.ts +158 -0
  68. package/src/utils/save.ts +46 -0
  69. package/src/vis/future-react-vega.tsx +193 -0
  70. package/src/vis/gen-vega.tsx +52 -0
  71. package/src/vis/react-vega.tsx +398 -0
  72. package/src/visualSettings/index.tsx +252 -0
  73. package/src/visualSettings/menubar.tsx +109 -0
  74. package/src/vite-env.d.ts +1 -0
  75. package/src/workers/explainer.worker.js +78 -0
  76. package/src/workers/filter.worker.js +70 -0
@@ -0,0 +1,154 @@
1
+ import { StatFuncName } from "visual-insights/build/esm/statistics";
2
+ import { AggFC } from 'cube-core/built/types';
3
+ import { IAnalyticType, IMutField as VIMutField, ISemanticType } from 'visual-insights';
4
+
5
+ export type DeepReadonly<T extends Record<keyof any, any>> = {
6
+ readonly [K in keyof T]: T[K] extends Record<keyof any, any> ? DeepReadonly<T[K]> : T[K];
7
+ };
8
+
9
+ export interface IRow {
10
+ [key: string]: any;
11
+ }
12
+ /**
13
+ * @deprecated
14
+ */
15
+ export type SemanticType = 'quantitative' | 'nominal' | 'ordinal' | 'temporal';
16
+
17
+ export interface Filters {
18
+ [key: string]: any[];
19
+ }
20
+
21
+ export interface IMutField {
22
+ fid: string;
23
+ key?: string;
24
+ name?: string;
25
+ disable?: boolean;
26
+ semanticType: ISemanticType;
27
+ analyticType: IAnalyticType;
28
+ };
29
+
30
+ export interface IField {
31
+ /**
32
+ * fid: key in data record
33
+ */
34
+ fid: string;
35
+ /**
36
+ * display name for field
37
+ */
38
+ name: string;
39
+ /**
40
+ * aggregator's name
41
+ */
42
+ aggName?: string;
43
+ semanticType: ISemanticType;
44
+ analyticType: IAnalyticType;
45
+ cmp?: (a: any, b: any) => number;
46
+ }
47
+
48
+ export interface IViewField extends IField {
49
+ dragId: string;
50
+ sort?: 'none' | 'ascending' | 'descending';
51
+ }
52
+
53
+ export interface Measure extends IField {
54
+ aggregator?: AggFC;
55
+ minWidth?: number;
56
+ formatter?: (value: number | undefined) => number | string;
57
+ [key: string]: any;
58
+ }
59
+
60
+ export interface DataSet {
61
+ id: string;
62
+ name: string;
63
+ rawFields: IMutField[];
64
+ dataSource: IRow[];
65
+ }
66
+
67
+ export interface IFieldNeighbor {
68
+ key: string;
69
+ cc: number;
70
+ }
71
+
72
+ export interface IMeasure {
73
+ key: string;
74
+ op: StatFuncName
75
+ }
76
+
77
+ export interface IDataSet {
78
+ id: string;
79
+ name: string;
80
+ rawFields: IMutField[];
81
+ dsId: string;
82
+ }
83
+ /**
84
+ * use as props to create a new dataset(IDataSet).
85
+ */
86
+ export interface IDataSetInfo {
87
+ name: string;
88
+ rawFields: IMutField[];
89
+ dataSource: IRow[]
90
+ }
91
+
92
+ export interface IDataSource {
93
+ id: string;
94
+ data: IRow[]
95
+ }
96
+
97
+ export interface IFilterField extends IViewField {
98
+ rule: IFilterRule | null;
99
+ }
100
+
101
+ export interface DraggableFieldState {
102
+ fields: IViewField[];
103
+ dimensions: IViewField[];
104
+ measures: IViewField[];
105
+ rows: IViewField[];
106
+ columns: IViewField[];
107
+ color: IViewField[];
108
+ opacity: IViewField[];
109
+ size: IViewField[];
110
+ shape: IViewField[];
111
+ theta: IViewField[];
112
+ radius: IViewField[];
113
+ filters: IFilterField[];
114
+ }
115
+
116
+ export interface IDraggableStateKey {
117
+ id: keyof DraggableFieldState;
118
+ mode: number
119
+ }
120
+
121
+ export type IFilterRule = {
122
+ type: 'range';
123
+ value: readonly [number, number];
124
+ } | {
125
+ type: 'temporal range';
126
+ value: readonly [number, number];
127
+ } | {
128
+ type: 'one of';
129
+ value: Set<string | number>;
130
+ };
131
+
132
+
133
+ export type IStackMode = 'none' | 'stack' | 'normalize';
134
+
135
+ export interface IVisualConfig {
136
+ defaultAggregated: boolean;
137
+ geoms: string[];
138
+ stack: 'none' | 'stack' | 'normalize';
139
+ showActions: boolean;
140
+ interactiveScale: boolean;
141
+ sorted: 'none' | 'ascending' | 'descending';
142
+ size: {
143
+ mode: 'auto' | 'fixed';
144
+ width: number;
145
+ height: number;
146
+ }
147
+ }
148
+
149
+ export interface IVisSpec {
150
+ readonly visId: string;
151
+ readonly name?: [string, Record<string, any>?];
152
+ readonly encodings: DeepReadonly<DraggableFieldState>;
153
+ readonly config: DeepReadonly<IVisualConfig>;
154
+ }
@@ -0,0 +1,140 @@
1
+ {
2
+ "constant": {
3
+ "row_count": "Row count",
4
+ "analytic_type": {
5
+ "dimension": "dimension",
6
+ "measure": "measure"
7
+ },
8
+ "mark_type": {
9
+ "__enum__": "Mark Type",
10
+ "auto": "Auto",
11
+ "bar": "Bar",
12
+ "line": "Line",
13
+ "area": "Area",
14
+ "trail": "Trail",
15
+ "point": "Scatter",
16
+ "circle": "Circle",
17
+ "tick": "Tick",
18
+ "rect": "Rectangle",
19
+ "arc": "Arc",
20
+ "boxplot": "Box (Box Plot)"
21
+ },
22
+ "stack_mode": {
23
+ "__enum__": "Stack Mode",
24
+ "none": "None",
25
+ "stack": "Stack",
26
+ "normalize": "Normalize"
27
+ },
28
+ "layout_type": {
29
+ "__enum__": "Layout Mode",
30
+ "auto": "Auto",
31
+ "fixed": "Fixed"
32
+ },
33
+ "draggable_key": {
34
+ "fields": "Fields",
35
+ "columns": "Columns",
36
+ "rows": "Rows",
37
+ "color": "Color",
38
+ "opacity": "Opacity",
39
+ "size": "Size",
40
+ "shape": "Shape",
41
+ "theta": "Angle",
42
+ "radius": "Radius",
43
+ "filters": "Filters"
44
+ },
45
+ "aggregator": {
46
+ "sum": "Sum",
47
+ "mean": "Mean",
48
+ "count": "Count"
49
+ },
50
+ "filter_type": {
51
+ "one_of": "One-Of",
52
+ "range": "Range",
53
+ "temporal_range": "Date Range"
54
+ }
55
+ },
56
+ "App": {
57
+ "labels": {
58
+ "data_interpretation": "Interpret Data"
59
+ }
60
+ },
61
+ "DataSource": {
62
+ "labels": {
63
+ "cur_dataset": "Current Dataset"
64
+ },
65
+ "buttons": {
66
+ "create_dataset": "Create Dataset",
67
+ "export_as_file": "Save As File",
68
+ "import_file": "Import Graphic Walker File"
69
+ },
70
+ "dialog": {
71
+ "create_data_source": "New Data Source",
72
+ "data_types": "Choose Import Methods",
73
+ "text_file_data": "Open Local Text File",
74
+ "public_data": "Use Public Dataset",
75
+ "data_source_type": "Data Source Type: [{{sourceType}}]",
76
+ "file": {
77
+ "open": "Open...",
78
+ "submit": "Submit",
79
+ "dataset_name": "Dataset Name"
80
+ },
81
+ "public": {
82
+ "submit": "Submit"
83
+ }
84
+ }
85
+ },
86
+ "main": {
87
+ "tablist": {
88
+ "new": "+ New",
89
+ "autoTitle": "Chart {{idx}}"
90
+ },
91
+ "tabpanel": {
92
+ "menubar": {
93
+ "undo": "Undo",
94
+ "redo": "Redo"
95
+ },
96
+ "settings": {
97
+ "toggle": {
98
+ "aggregation": "Aggregation",
99
+ "stack": "Stack",
100
+ "axes_resize": "Axes Resizing",
101
+ "debug": "debugging"
102
+ },
103
+ "sort": "Sorting Order",
104
+ "button": {
105
+ "ascending": "Sort in Ascending Order",
106
+ "descending": "Sort in Descending Order",
107
+ "transpose": "Transpose"
108
+ },
109
+ "size": "Resize",
110
+ "size_setting": {
111
+ "width": "Width",
112
+ "height": "Height"
113
+ }
114
+ },
115
+ "DatasetFields": {
116
+ "field_list": "Field List"
117
+ }
118
+ }
119
+ },
120
+ "filters": {
121
+ "to_edit": "Edit This Rule",
122
+ "empty_rule": "! (empty rule)",
123
+ "editing": "Edit Rule",
124
+ "form": {
125
+ "name": "Field",
126
+ "rule": "Rule"
127
+ },
128
+ "header": {
129
+ "visibility": "Visible",
130
+ "value": "Label",
131
+ "count": "Count"
132
+ },
133
+ "selected_keys": "{{ count }} items selected",
134
+ "btn": {
135
+ "select_all": "Select All",
136
+ "unselect_all": "Unselect All",
137
+ "reverse": "Reverse Selection"
138
+ }
139
+ }
140
+ }
@@ -0,0 +1,50 @@
1
+ import i18n, { Resource } from 'i18next';
2
+ import { initReactI18next } from 'react-i18next';
3
+ import LanguageDetector from 'i18next-browser-languagedetector';
4
+
5
+ import localeEnUs from './en-US.json';
6
+ import localeZhCn from './zh-CN.json';
7
+
8
+
9
+ const locales: Resource & { 'en-US': any } = {
10
+ 'en': {
11
+ translation: localeEnUs,
12
+ },
13
+ 'en-US': {
14
+ translation: localeEnUs,
15
+ },
16
+ 'zh': {
17
+ translation: localeZhCn,
18
+ },
19
+ 'zh-CN': {
20
+ translation: localeZhCn,
21
+ },
22
+ } as const;
23
+
24
+ i18n.use(initReactI18next).use(LanguageDetector).init({
25
+ fallbackLng: 'en-US',
26
+ interpolation: {
27
+ escapeValue: false, // not needed for react as it escapes by default
28
+ },
29
+ resources: locales,
30
+ });
31
+
32
+ const loadedLangs: string[] = []; // exclude built-in keys to enable rewrite
33
+
34
+ export const mergeLocaleRes = (resources: { [lang: string]: Resource }) => {
35
+ for (const lang in resources) {
36
+ if (Object.prototype.hasOwnProperty.call(resources, lang)) {
37
+ if (loadedLangs.includes(lang)) {
38
+ continue;
39
+ }
40
+
41
+ loadedLangs.push(lang);
42
+ const resource = resources[lang];
43
+ i18n.addResourceBundle(lang, 'translation', resource, false, true);
44
+ }
45
+ }
46
+ };
47
+
48
+ export const setLocaleLanguage = (lang: string) => {
49
+ return i18n.changeLanguage(lang);
50
+ };
@@ -0,0 +1,140 @@
1
+ {
2
+ "constant": {
3
+ "row_count": "行数",
4
+ "analytic_type": {
5
+ "dimension": "维度",
6
+ "measure": "度量"
7
+ },
8
+ "mark_type": {
9
+ "__enum__": "标记类型",
10
+ "auto": "自动",
11
+ "bar": "条形",
12
+ "line": "折线",
13
+ "area": "面积",
14
+ "trail": "痕迹",
15
+ "point": "散点",
16
+ "circle": "圆",
17
+ "tick": "标记",
18
+ "rect": "矩形",
19
+ "arc": "弧形",
20
+ "boxplot": "统计箱"
21
+ },
22
+ "layout_type": {
23
+ "__enum__": "尺寸模式",
24
+ "auto": "自动",
25
+ "fixed": "固定"
26
+ },
27
+ "stack_mode": {
28
+ "__enum__": "堆叠模式",
29
+ "none": "关闭",
30
+ "stack": "堆叠",
31
+ "normalize": "归一化"
32
+ },
33
+ "draggable_key": {
34
+ "fields": "字段",
35
+ "columns": "列",
36
+ "rows": "行",
37
+ "color": "颜色",
38
+ "opacity": "透明度",
39
+ "size": "大小",
40
+ "shape": "形状",
41
+ "theta": "角度",
42
+ "radius": "半径",
43
+ "filters": "筛选器"
44
+ },
45
+ "aggregator": {
46
+ "sum": "求和",
47
+ "mean": "平均值",
48
+ "count": "计数"
49
+ },
50
+ "filter_type": {
51
+ "one_of": "按值筛选",
52
+ "range": "按范围筛选",
53
+ "temporal_range": "按日期范围筛选"
54
+ }
55
+ },
56
+ "App": {
57
+ "labels": {
58
+ "data_interpretation": "数据解读"
59
+ }
60
+ },
61
+ "DataSource": {
62
+ "labels": {
63
+ "cur_dataset": "当前数据集"
64
+ },
65
+ "buttons": {
66
+ "create_dataset": "创建数据集",
67
+ "export_as_file": "保存到文件",
68
+ "import_file": "导入文件"
69
+ },
70
+ "dialog": {
71
+ "create_data_source": "创建数据源",
72
+ "data_types": "选择类型",
73
+ "text_file_data": "从文件中导入",
74
+ "public_data": "公共数据集",
75
+ "data_source_type": "数据源类型:[{{sourceType}}]",
76
+ "file": {
77
+ "open": "打开文件...",
78
+ "submit": "确认",
79
+ "dataset_name": "数据集名称"
80
+ },
81
+ "public": {
82
+ "submit": "确认"
83
+ }
84
+ }
85
+ },
86
+ "main": {
87
+ "tablist": {
88
+ "new": "+ 新建",
89
+ "autoTitle": "图表 {{idx}}"
90
+ },
91
+ "tabpanel": {
92
+ "menubar": {
93
+ "undo": "撤销",
94
+ "redo": "重做"
95
+ },
96
+ "settings": {
97
+ "toggle": {
98
+ "aggregation": "聚合度量",
99
+ "stack": "开启堆叠",
100
+ "axes_resize": "坐标系缩放",
101
+ "debug": "图表调试"
102
+ },
103
+ "sort": "排序",
104
+ "button": {
105
+ "ascending": "升序排序",
106
+ "descending": "降序排序",
107
+ "transpose": "转置"
108
+ },
109
+ "size": "调整尺寸",
110
+ "size_setting": {
111
+ "width": "宽度",
112
+ "height": "高度"
113
+ }
114
+ },
115
+ "DatasetFields": {
116
+ "field_list": "字段列表"
117
+ }
118
+ }
119
+ },
120
+ "filters": {
121
+ "to_edit": "编辑这条规则",
122
+ "empty_rule": "! (空的规则)",
123
+ "editing": "编辑规则",
124
+ "form": {
125
+ "name": "字段",
126
+ "rule": "规则"
127
+ },
128
+ "header": {
129
+ "visibility": "可见",
130
+ "value": "标签",
131
+ "count": "计数"
132
+ },
133
+ "selected_keys": "{{ count }} 个标签已选择",
134
+ "btn": {
135
+ "select_all": "全部选中",
136
+ "unselect_all": "全部取消",
137
+ "reverse": "选择反向"
138
+ }
139
+ }
140
+ }
package/src/main.tsx ADDED
@@ -0,0 +1,10 @@
1
+ import React from 'react'
2
+ import ReactDOM from 'react-dom'
3
+ import { GraphicWalker } from './index'
4
+
5
+ ReactDOM.render(
6
+ <React.StrictMode>
7
+ <GraphicWalker />
8
+ </React.StrictMode>,
9
+ document.getElementById('root')
10
+ )
@@ -0,0 +1,129 @@
1
+ import { toJS } from "mobx";
2
+ import { MAX_HISTORY_SIZE } from "../config";
3
+ import { DeepReadonly, DraggableFieldState, IVisSpec, IVisualConfig } from "../interfaces";
4
+
5
+ export class VisSpecWithHistory {
6
+
7
+ readonly visId: IVisSpec['visId'];
8
+ private snapshots: Pick<IVisSpec, 'name' | 'encodings' | 'config'>[];
9
+ private cursor: number;
10
+
11
+ constructor(data: IVisSpec) {
12
+ this.visId = data.visId;
13
+ this.snapshots = [{
14
+ name: data.name,
15
+ encodings: data.encodings,
16
+ config: data.config,
17
+ }];
18
+ this.cursor = 0;
19
+ }
20
+
21
+ private get frame(): Readonly<IVisSpec> {
22
+ return {
23
+ visId: this.visId,
24
+ ...this.snapshots[this.cursor]!,
25
+ };
26
+ }
27
+
28
+ private batchFlag = false;
29
+
30
+ private commit(snapshot: Partial<Readonly<VisSpecWithHistory['snapshots'][0]>>): void {
31
+ if (this.batchFlag) {
32
+ // batch this commit
33
+ this.snapshots[this.cursor] = toJS({
34
+ ...this.frame,
35
+ ...snapshot,
36
+ });
37
+
38
+ return;
39
+ }
40
+
41
+ this.batchFlag = true;
42
+
43
+ this.snapshots = [
44
+ ...this.snapshots.slice(0, this.cursor + 1),
45
+ toJS({
46
+ ...this.frame,
47
+ ...snapshot,
48
+ }),
49
+ ];
50
+
51
+ if (this.snapshots.length > MAX_HISTORY_SIZE) {
52
+ this.snapshots.splice(0, 1);
53
+ }
54
+
55
+ this.cursor = this.snapshots.length - 1;
56
+
57
+ requestAnimationFrame(() => this.batchFlag = false);
58
+ }
59
+
60
+ public get canUndo() {
61
+ return this.cursor > 0;
62
+ }
63
+
64
+ public undo(): boolean {
65
+ if (this.cursor === 0) {
66
+ return false;
67
+ }
68
+
69
+ this.cursor -= 1;
70
+
71
+ return true;
72
+ }
73
+
74
+ public get canRedo() {
75
+ return this.cursor < this.snapshots.length - 1;
76
+ }
77
+
78
+ public redo(): boolean {
79
+ if (this.cursor === this.snapshots.length - 1) {
80
+ return false;
81
+ }
82
+
83
+ this.cursor += 1;
84
+
85
+ return true;
86
+ }
87
+
88
+ public rebase() {
89
+ this.snapshots = [this.snapshots[this.cursor]];
90
+ this.cursor = 0;
91
+ }
92
+
93
+ get name() {
94
+ return this.frame.name;
95
+ }
96
+
97
+ set name(name: IVisSpec['name']) {
98
+ this.commit({
99
+ name,
100
+ });
101
+ }
102
+
103
+ get encodings(): DeepReadonly<DraggableFieldState> {
104
+ return this.frame.encodings;
105
+ }
106
+
107
+ set encodings(encodings: IVisSpec['encodings']) {
108
+ this.commit({
109
+ encodings,
110
+ });
111
+ }
112
+
113
+ get config(): DeepReadonly<IVisualConfig> {
114
+ return this.frame.config;
115
+ }
116
+
117
+ set config(config: IVisSpec['config']) {
118
+ this.commit({
119
+ config,
120
+ });
121
+ }
122
+
123
+ public exportGW (): IVisSpec {
124
+ return {
125
+ ...this.frame
126
+ }
127
+ }
128
+
129
+ }