@kanaries/graphic-walker 0.2.15 → 0.2.17

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 (132) hide show
  1. package/dist/App.d.ts +4 -3
  2. package/dist/assets/transform.worker-5d54ff09.js.map +1 -0
  3. package/dist/assets/viewQuery.worker-ffefc111.js.map +1 -0
  4. package/dist/components/codeExport/index.d.ts +3 -0
  5. package/dist/components/loadingLayer.d.ts +2 -0
  6. package/dist/components/tabs/defaultTab.d.ts +1 -0
  7. package/dist/components/tabs/editableTab.d.ts +1 -2
  8. package/dist/dataSource/dataSelection/config.d.ts +1 -0
  9. package/dist/dataSource/dataSelection/utils.d.ts +2 -0
  10. package/dist/dataSource/index.d.ts +0 -1
  11. package/dist/datasets/tmp/test.json +1 -0
  12. package/dist/fields/encodeFields/singleEncodeEditor.d.ts +4 -4
  13. package/dist/graphic-walker.es.js +29228 -33650
  14. package/dist/graphic-walker.es.js.map +1 -1
  15. package/dist/graphic-walker.umd.js +218 -256
  16. package/dist/graphic-walker.umd.js.map +1 -1
  17. package/dist/index.d.ts +3 -3
  18. package/dist/interfaces.d.ts +52 -17
  19. package/dist/lib/execExp.d.ts +8 -0
  20. package/dist/lib/inferMeta.d.ts +2 -9
  21. package/dist/lib/insights/explainByChildren.d.ts +16 -0
  22. package/dist/lib/insights/explainBySelection.d.ts +5 -0
  23. package/dist/lib/insights/explainValue.d.ts +2 -0
  24. package/dist/lib/insights/utils.d.ts +11 -0
  25. package/dist/lib/interfaces.d.ts +23 -0
  26. package/dist/lib/op/aggregate.d.ts +3 -0
  27. package/dist/lib/op/bin.d.ts +3 -0
  28. package/dist/lib/op/fold.d.ts +3 -0
  29. package/dist/lib/op/stat.d.ts +8 -0
  30. package/dist/lib/viewQuery.d.ts +4 -0
  31. package/dist/models/visSpecHistory.d.ts +2 -0
  32. package/dist/renderer/index.d.ts +8 -7
  33. package/dist/renderer/specRenderer.d.ts +13 -0
  34. package/dist/services.d.ts +5 -31
  35. package/dist/store/commonStore.d.ts +6 -0
  36. package/dist/store/index.d.ts +3 -2
  37. package/dist/store/visualSpecStore.d.ts +11 -5
  38. package/dist/utils/autoMark.d.ts +1 -1
  39. package/dist/utils/dataPrep.d.ts +3 -2
  40. package/dist/utils/index.d.ts +3 -5
  41. package/dist/utils/save.d.ts +1 -2
  42. package/dist/vis/react-vega.d.ts +2 -22
  43. package/dist/vis/spec/aggregate.d.ts +4 -0
  44. package/dist/vis/spec/encode.d.ts +20 -0
  45. package/dist/vis/spec/field.d.ts +2 -0
  46. package/dist/vis/spec/mark.d.ts +7 -0
  47. package/dist/vis/spec/stack.d.ts +4 -0
  48. package/dist/vis/spec/tooltip.d.ts +4 -0
  49. package/dist/vis/spec/view.d.ts +73 -0
  50. package/dist/workers/transform.d.ts +2 -0
  51. package/package.json +5 -6
  52. package/src/App.tsx +56 -66
  53. package/src/components/codeExport/index.tsx +114 -0
  54. package/src/components/dataTable/index.tsx +10 -10
  55. package/src/components/loadingLayer.tsx +7 -0
  56. package/src/components/tabs/defaultTab.tsx +4 -2
  57. package/src/components/tabs/editableTab.tsx +74 -39
  58. package/src/dataSource/dataSelection/config.ts +11 -0
  59. package/src/dataSource/dataSelection/csvData.tsx +71 -39
  60. package/src/dataSource/dataSelection/gwFile.tsx +2 -2
  61. package/src/dataSource/dataSelection/utils.ts +28 -0
  62. package/src/dataSource/index.tsx +0 -17
  63. package/src/dataSource/utils.ts +8 -3
  64. package/src/fields/aestheticFields.tsx +1 -2
  65. package/src/fields/datasetFields/meaFields.tsx +12 -4
  66. package/src/fields/encodeFields/singleEncodeEditor.tsx +11 -12
  67. package/src/fields/fieldsContext.tsx +1 -0
  68. package/src/index.css +4 -4
  69. package/src/index.tsx +22 -22
  70. package/src/interfaces.ts +85 -49
  71. package/src/lib/execExp.ts +147 -0
  72. package/src/lib/inferMeta.ts +26 -29
  73. package/src/lib/insights/explainByChildren.ts +50 -0
  74. package/src/lib/insights/explainBySelection.ts +47 -0
  75. package/src/lib/insights/explainValue.ts +30 -0
  76. package/src/lib/insights/utils.ts +21 -0
  77. package/src/lib/interfaces.ts +33 -0
  78. package/src/lib/op/aggregate.ts +49 -0
  79. package/src/lib/op/bin.ts +25 -0
  80. package/src/lib/op/fold.ts +17 -0
  81. package/src/lib/op/stat.ts +46 -0
  82. package/src/lib/viewQuery.ts +22 -0
  83. package/src/locales/en-US.json +6 -3
  84. package/src/locales/i18n.ts +0 -1
  85. package/src/locales/ja-JP.json +4 -2
  86. package/src/locales/zh-CN.json +6 -3
  87. package/src/main.tsx +1 -1
  88. package/src/models/visSpecHistory.ts +14 -0
  89. package/src/renderer/index.tsx +58 -126
  90. package/src/renderer/specRenderer.tsx +121 -0
  91. package/src/segments/segmentNav.tsx +3 -16
  92. package/src/segments/visNav.tsx +17 -6
  93. package/src/services.ts +101 -67
  94. package/src/store/commonStore.ts +14 -9
  95. package/src/store/index.tsx +11 -4
  96. package/src/store/visualSpecStore.ts +89 -52
  97. package/src/utils/autoMark.ts +1 -1
  98. package/src/utils/dataPrep.ts +25 -2
  99. package/src/utils/index.ts +16 -17
  100. package/src/utils/normalization.ts +3 -1
  101. package/src/utils/save.ts +1 -2
  102. package/src/vis/react-vega.tsx +9 -340
  103. package/src/vis/spec/aggregate.ts +13 -0
  104. package/src/vis/spec/encode.ts +70 -0
  105. package/src/vis/spec/field.ts +10 -0
  106. package/src/vis/spec/mark.ts +30 -0
  107. package/src/vis/spec/stack.ts +11 -0
  108. package/src/vis/spec/tooltip.ts +16 -0
  109. package/src/vis/spec/view.ts +136 -0
  110. package/src/vis/theme.ts +12 -0
  111. package/src/visualSettings/index.tsx +10 -1
  112. package/src/workers/transform.ts +12 -0
  113. package/src/workers/transform.worker.js +13 -0
  114. package/src/workers/viewQuery.worker.js +16 -0
  115. package/dist/assets/explainer.worker-8428eb12.js.map +0 -1
  116. package/dist/dataSource/pannel.d.ts +0 -5
  117. package/dist/insightBoard/index.d.ts +0 -3
  118. package/dist/insightBoard/mainBoard.d.ts +0 -11
  119. package/dist/insightBoard/radioGroupButtons.d.ts +0 -12
  120. package/dist/insightBoard/selectionSpec.d.ts +0 -13
  121. package/dist/insightBoard/std2vegaSpec.d.ts +0 -12
  122. package/dist/insightBoard/utils.d.ts +0 -8
  123. package/dist/insights.d.ts +0 -61
  124. package/src/dataSource/pannel.tsx +0 -71
  125. package/src/insightBoard/index.tsx +0 -31
  126. package/src/insightBoard/mainBoard.tsx +0 -224
  127. package/src/insightBoard/radioGroupButtons.tsx +0 -57
  128. package/src/insightBoard/selectionSpec.ts +0 -113
  129. package/src/insightBoard/std2vegaSpec.ts +0 -184
  130. package/src/insightBoard/utils.ts +0 -32
  131. package/src/insights.ts +0 -408
  132. package/src/workers/explainer.worker.js +0 -76
@@ -9,7 +9,10 @@ import { useTranslation } from "react-i18next";
9
9
  import DefaultButton from "../../components/button/default";
10
10
  import PrimaryButton from "../../components/button/primary";
11
11
  import DropdownSelect from "../../components/dropdownSelect";
12
- import { charsetOptions } from "./config";
12
+ import { SUPPORTED_FILE_TYPES, charsetOptions } from "./config";
13
+ import { classNames } from "../../utils";
14
+ import { RadioGroup } from "@headlessui/react";
15
+ import { jsonReader } from "./utils";
13
16
 
14
17
  const Container = styled.div`
15
18
  overflow-x: auto;
@@ -22,6 +25,7 @@ const CSVData: React.FC<ICSVData> = (props) => {
22
25
  const { commonStore } = useGlobalStore();
23
26
  const { tmpDSName, tmpDataSource, tmpDSRawFields } = commonStore;
24
27
  const [encoding, setEncoding] = useState<string>("utf-8");
28
+ const [fileType, setFileType] = useState<string>("csv");
25
29
 
26
30
  const onSubmitData = useCallback(() => {
27
31
  commonStore.commitTempDS();
@@ -30,6 +34,27 @@ const CSVData: React.FC<ICSVData> = (props) => {
30
34
  const { t } = useTranslation("translation", { keyPrefix: "DataSource.dialog.file" });
31
35
  const fileLoaded = tmpDataSource.length > 0 && tmpDSRawFields.length > 0;
32
36
 
37
+ const fileUpload = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
38
+ const files = e.target.files;
39
+ if (files !== null) {
40
+ const file = files[0];
41
+ if (fileType === 'csv') {
42
+ FileReader.csvReader({
43
+ file,
44
+ config: { type: "reservoirSampling", size: Infinity },
45
+ onLoading: () => {},
46
+ encoding,
47
+ }).then((data) => {
48
+ commonStore.updateTempDS(data as IRow[]);
49
+ });
50
+ } else {
51
+ jsonReader(file).then((data) => {
52
+ commonStore.updateTempDS(data as IRow[]);
53
+ });
54
+ }
55
+ }
56
+ }, [fileType, encoding]);
57
+
33
58
  return (
34
59
  <Container>
35
60
  {!fileLoaded && (
@@ -49,49 +74,56 @@ const CSVData: React.FC<ICSVData> = (props) => {
49
74
  d="M9 13h6m-3-3v6m-9 1V7a2 2 0 012-2h6l2 2h6a2 2 0 012 2v8a2 2 0 01-2 2H5a2 2 0 01-2-2z"
50
75
  />
51
76
  </svg>
52
- <h3 className="mt-2 text-sm font-semibold text-gray-900">{t('choose_file')}</h3>
53
- <p className="mt-1 text-sm text-gray-500">{t('get_start_desc')}</p>
77
+ <h3 className="mt-2 text-sm font-semibold text-gray-900 dark:text-gray-50">{t("choose_file")}</h3>
78
+ <p className="mt-1 text-sm text-gray-500">{t("get_start_desc")}</p>
54
79
  </div>
55
80
  )}
56
- <input
57
- style={{ display: "none" }}
58
- type="file"
59
- ref={fileRef}
60
- onChange={(e) => {
61
- const files = e.target.files;
62
- if (files !== null) {
63
- const file = files[0];
64
- FileReader.csvReader({
65
- file,
66
- config: { type: "reservoirSampling", size: Infinity },
67
- onLoading: () => {},
68
- encoding,
69
- }).then((data) => {
70
- commonStore.updateTempDS(data as IRow[]);
71
- });
72
- }
73
- }}
74
- />
81
+ <input style={{ display: "none" }} type="file" ref={fileRef} onChange={fileUpload} />
75
82
  {!fileLoaded && (
76
- <div className="my-1 flex justify-center">
77
- <DefaultButton
78
- className="mr-2"
79
- onClick={() => {
80
- if (fileRef.current) {
81
- fileRef.current.click();
82
- }
83
- }}
84
- text={t("open")}
85
- />
86
- <div className="inline-block relative">
87
- <DropdownSelect
88
- buttonClassName="w-36"
89
- options={charsetOptions}
90
- selectedKey={encoding}
91
- onSelect={(k) => {
92
- setEncoding(k);
83
+ <div className="my-1">
84
+ <div className="flex justify-center">
85
+ <RadioGroup value={fileType} onChange={setFileType} className="mt-2">
86
+ <RadioGroup.Label className="sr-only"> Choose a memory option </RadioGroup.Label>
87
+ <div className="grid grid-cols-2 gap-3">
88
+ {SUPPORTED_FILE_TYPES.map((option) => (
89
+ <RadioGroup.Option
90
+ key={option.value}
91
+ value={option.value}
92
+ className={({ active, checked }) =>
93
+ classNames(
94
+ checked
95
+ ? "bg-indigo-600 text-white hover:bg-indigo-500"
96
+ : "ring-1 ring-inset ring-gray-300 hover:bg-gray-50 dark:hover:bg-gray-800",
97
+ "flex cursor-pointer items-center justify-center rounded py-1 px-8 text-sm font-semibold uppercase sm:flex-1"
98
+ )
99
+ }
100
+ >
101
+ <RadioGroup.Label as="span">{option.label}</RadioGroup.Label>
102
+ </RadioGroup.Option>
103
+ ))}
104
+ </div>
105
+ </RadioGroup>
106
+ </div>
107
+ <div className="my-1 flex justify-center">
108
+ <DefaultButton
109
+ className="mr-2"
110
+ onClick={() => {
111
+ if (fileRef.current) {
112
+ fileRef.current.click();
113
+ }
93
114
  }}
115
+ text={t("open")}
94
116
  />
117
+ <div className="inline-block relative">
118
+ <DropdownSelect
119
+ buttonClassName="w-36"
120
+ options={charsetOptions}
121
+ selectedKey={encoding}
122
+ onSelect={(k) => {
123
+ setEncoding(k);
124
+ }}
125
+ />
126
+ </div>
95
127
  </div>
96
128
  </div>
97
129
  )}
@@ -1,4 +1,4 @@
1
- import React, { useRef, useCallback } from "react";
1
+ import React from "react";
2
2
  import { useGlobalStore } from "../../store";
3
3
  import { observer } from "mobx-react-lite";
4
4
 
@@ -7,7 +7,7 @@ interface GWFileProps {
7
7
  fileRef: React.RefObject<HTMLInputElement>;
8
8
  }
9
9
  const GWFile: React.FC<GWFileProps> = (props) => {
10
- const { commonStore, vizStore } = useGlobalStore();
10
+ const { vizStore } = useGlobalStore();
11
11
 
12
12
  return (
13
13
  <input
@@ -0,0 +1,28 @@
1
+ import { IDataSetInfo, IRow } from "../../interfaces";
2
+
3
+ export function jsonReader (file: File): Promise<IRow[]> {
4
+ return new Promise((resolve, reject) => {
5
+ const reader = new FileReader();
6
+ reader.onload = () => {
7
+ try {
8
+ const data = JSON.parse(reader.result as string);
9
+ if (!Array.isArray(data)) {
10
+ throw new Error('Invalid JSON file');
11
+ }
12
+ resolve(data);
13
+ } catch (e) {
14
+ reject(e);
15
+ }
16
+ };
17
+ reader.readAsText(file);
18
+ });
19
+ }
20
+
21
+ // export function jsonArray2DatasetInfo (data: IRow[]): IDataSetInfo {
22
+ // const fields = Object.keys(data[0]);
23
+ // return {
24
+ // name: 'New Dataset',
25
+ // rawFields: fields.map(f => ({ name: f, type: 'number' })),
26
+ // dataSource: data
27
+ // }
28
+ // }
@@ -12,11 +12,9 @@ import DropdownSelect from "../components/dropdownSelect";
12
12
  import PrimaryButton from "../components/button/primary";
13
13
 
14
14
  interface DSSegmentProps {
15
- preWorkDone: boolean;
16
15
  }
17
16
 
18
17
  const DataSourceSegment: React.FC<DSSegmentProps> = (props) => {
19
- const { preWorkDone } = props;
20
18
  const { commonStore, vizStore } = useGlobalStore();
21
19
  const gwFileRef = useRef<HTMLInputElement>(null);
22
20
  const { t } = useTranslation();
@@ -26,9 +24,6 @@ const DataSourceSegment: React.FC<DSSegmentProps> = (props) => {
26
24
  return (
27
25
  <div className="flex items-center m-4 p-4 border border-gray-200 dark:border-gray-700">
28
26
  <GwFile fileRef={gwFileRef} />
29
- {!preWorkDone && (
30
- <div className="animate-spin inline-block mr-2 ml-2 w-4 h-4 rounded-full border-t-2 border-l-2 border-blue-500"></div>
31
- )}
32
27
  {/* <label className="text-xs mr-1 whitespace-nowrap self-center h-4">
33
28
  {t("DataSource.labels.cur_dataset")}
34
29
  </label> */}
@@ -76,18 +71,6 @@ const DataSourceSegment: React.FC<DSSegmentProps> = (props) => {
76
71
  >
77
72
  <DataSelection />
78
73
  </Modal>
79
- {/* {showDSPanel && (
80
- <Modal
81
- title={t("DataSource.dialog.create_data_source")}
82
- onClose={() => {
83
- commonStore.setShowDSPanel(false);
84
- }}
85
- >
86
- <DataSelection />
87
- </Modal>
88
- )} */}
89
- {preWorkDone && <CheckCircleIcon className="text-green-500 w-5 inline-block ml-2" />}
90
- {!preWorkDone && <ArrowPathIcon className="text-yellow-500 w-5 inline-block ml-2" />}
91
74
  </div>
92
75
  );
93
76
  };
@@ -2,6 +2,7 @@ import { IRow, IMutField } from "../interfaces";
2
2
  import { inferMeta } from "../lib/inferMeta";
3
3
  import { guardDataKeys } from "../utils/dataPrep";
4
4
 
5
+
5
6
  export function transData(dataSource: IRow[]): {
6
7
  dataSource: IRow[];
7
8
  fields: IMutField[];
@@ -12,7 +13,11 @@ export function transData(dataSource: IRow[]): {
12
13
  fields: [],
13
14
  };
14
15
  }
15
- const keys = Object.keys(dataSource[0]);
16
+ const sampleRecord = dataSource[0];
17
+ // const rawKeys = Object.keys(sampleRecord);
18
+ // let flatColKeys: string[] = flatNestKeys(sampleRecord);
19
+
20
+ const keys = Object.keys(sampleRecord);
16
21
  const metas = inferMeta({
17
22
  dataSource,
18
23
  fields: keys.map((k) => ({
@@ -21,7 +26,7 @@ export function transData(dataSource: IRow[]): {
21
26
  analyticType: "?",
22
27
  semanticType: "?",
23
28
  })),
24
- });
29
+ })
25
30
  const { safeData, safeMetas } = guardDataKeys(dataSource, metas);
26
31
  const finalData: IRow[] = [];
27
32
  for (let record of safeData) {
@@ -30,7 +35,7 @@ export function transData(dataSource: IRow[]): {
30
35
  if (field.semanticType === "quantitative") {
31
36
  newRecord[field.fid] = Number(record[field.fid]);
32
37
  } else {
33
- newRecord[field.fid] = record[field.fid];
38
+ newRecord[field.fid] = record[field.fid];//getValueByKeyPath(record, field.fid);// record[field.fid];
34
39
  }
35
40
  }
36
41
  finalData.push(newRecord);
@@ -2,10 +2,9 @@ import React from 'react';
2
2
  import { Droppable } from "@kanaries/react-beautiful-dnd";
3
3
  import { DRAGGABLE_STATE_KEYS } from './fieldsContext';
4
4
  import { AestheticFieldContainer } from './components'
5
- import OBFieldContainer from './obComponents/obFContainer';
6
5
  import SingleEncodeEditor from './encodeFields/singleEncodeEditor';
7
6
 
8
- const aestheticFields = DRAGGABLE_STATE_KEYS.filter(f => ['color', 'opacity', 'size', 'shape'].includes(f.id));
7
+ const aestheticFields = DRAGGABLE_STATE_KEYS.filter(f => ['color', 'opacity', 'size', 'shape', 'details'].includes(f.id));
9
8
 
10
9
  const AestheticFields: React.FC = props => {
11
10
  return <div>
@@ -20,18 +20,26 @@ const MeaFields: React.FC<Props> = (props) => {
20
20
  value: "bin",
21
21
  label: "Bin",
22
22
  },
23
+ {
24
+ value: 'binCount',
25
+ label: 'Bin Count'
26
+ },
23
27
  {
24
28
  value: "log10",
25
29
  label: "Log10",
26
30
  },
31
+ {
32
+ value: "log2",
33
+ label: "Log2",
34
+ },
27
35
  ];
28
36
  }, []);
29
37
 
30
38
  const fieldActionHandler = useCallback((selectedValue: any, opIndex: number, meaIndex: number) => {
31
- if (selectedValue === "bin") {
32
- vizStore.createBinField("measures", meaIndex);
33
- } else if (selectedValue === "log10") {
34
- vizStore.createLogField("measures", meaIndex);
39
+ if (selectedValue === "bin" || selectedValue === 'binCount') {
40
+ vizStore.createBinField("measures", meaIndex, selectedValue);
41
+ } else if (selectedValue === "log10" || selectedValue === "log2") {
42
+ vizStore.createLogField("measures", meaIndex, selectedValue);
35
43
  }
36
44
  }, []);
37
45
  return (
@@ -1,15 +1,14 @@
1
- import React, { useMemo } from "react";
2
- import { IDraggableStateKey } from "../../interfaces";
3
- import { observer } from "mobx-react-lite";
4
- import { useGlobalStore } from "../../store";
5
- import DropdownSelect from "./singleEncodeDropDown";
6
- import { DroppableProvided } from "react-beautiful-dnd";
7
- import { ChevronUpDownIcon, TrashIcon } from "@heroicons/react/24/outline";
8
- import { useTranslation } from "react-i18next";
9
- import { COUNT_FIELD_ID } from "../../constants";
10
- import DropdownContext from "../../components/dropdownContext";
11
- import { AGGREGATOR_LIST } from "../fieldsContext";
12
- import { Draggable, DroppableStateSnapshot } from "@kanaries/react-beautiful-dnd";
1
+ import React, { useMemo } from 'react';
2
+ import { IDraggableStateKey } from '../../interfaces';
3
+ import { observer } from 'mobx-react-lite';
4
+ import { useGlobalStore } from '../../store';
5
+ import { DroppableProvided } from 'react-beautiful-dnd';
6
+ import { ChevronUpDownIcon, TrashIcon } from '@heroicons/react/24/outline';
7
+ import { useTranslation } from 'react-i18next';
8
+ import { COUNT_FIELD_ID } from '../../constants';
9
+ import DropdownContext from '../../components/dropdownContext';
10
+ import { AGGREGATOR_LIST } from '../fieldsContext';
11
+ import { Draggable, DroppableStateSnapshot } from '@kanaries/react-beautiful-dnd';
13
12
 
14
13
  interface SingleEncodeEditorProps {
15
14
  dkey: IDraggableStateKey;
@@ -50,6 +50,7 @@ export const DRAGGABLE_STATE_KEYS: Readonly<IDraggableStateKey[]> = [
50
50
  { id: 'theta', mode: 1 },
51
51
  { id: 'radius', mode: 1 },
52
52
  { id: 'filters', mode: 1 },
53
+ { id: 'details', mode: 1 }
53
54
  ] as const;
54
55
 
55
56
  export const AGGREGATOR_LIST: Readonly<string[]> = [
package/src/index.css CHANGED
@@ -10,11 +10,11 @@ html{
10
10
  }
11
11
  }
12
12
  body {
13
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
13
+ /* font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
14
14
  'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
15
- sans-serif;
16
- -webkit-font-smoothing: antialiased;
17
- -moz-osx-font-smoothing: grayscale;
15
+ sans-serif; */
16
+ /* -webkit-font-smoothing: antialiased;
17
+ -moz-osx-font-smoothing: grayscale; */
18
18
  margin: 0px;
19
19
  padding: 0px;
20
20
  }
package/src/index.tsx CHANGED
@@ -1,22 +1,22 @@
1
- import React, { createContext, useEffect, useRef, useState } from 'react';
2
- import { StyleSheetManager } from 'styled-components';
3
- import root from 'react-shadow';
4
- import { DOM } from '@kanaries/react-beautiful-dnd';
5
- import { observer } from 'mobx-react-lite';
6
- import App, { IGWProps } from './App';
7
- import { StoreWrapper } from './store/index';
8
- import { FieldsContextWrapper } from './fields/fieldsContext';
1
+ import React, { createContext, useEffect, useRef, useState } from "react";
2
+ import { StyleSheetManager } from "styled-components";
3
+ import root from "react-shadow";
4
+ import { DOM } from "@kanaries/react-beautiful-dnd";
5
+ import { observer } from "mobx-react-lite";
6
+ import App, { IGWProps } from "./App";
7
+ import { StoreWrapper } from "./store/index";
8
+ import { FieldsContextWrapper } from "./fields/fieldsContext";
9
9
 
10
- import './empty_sheet.css';
10
+ import "./empty_sheet.css";
11
11
  import tailwindStyle from "tailwindcss/tailwind.css?inline";
12
- import style from './index.css?inline';
13
-
12
+ import style from "./index.css?inline";
14
13
 
15
14
  export const ShadowDomContext = createContext<{ root: ShadowRoot | null }>({ root: null });
16
15
 
17
- export const GraphicWalker: React.FC<IGWProps> = observer(props => {
16
+ export const GraphicWalker: React.FC<IGWProps> = observer((props) => {
18
17
  const [shadowRoot, setShadowRoot] = useState<ShadowRoot | null>(null);
19
18
  const rootRef = useRef<HTMLDivElement>(null);
19
+ const { storeRef } = props;
20
20
 
21
21
  useEffect(() => {
22
22
  if (rootRef.current) {
@@ -32,20 +32,20 @@ export const GraphicWalker: React.FC<IGWProps> = observer(props => {
32
32
  }, []);
33
33
 
34
34
  return (
35
- <root.div mode="open" ref={rootRef}>
36
- <style>{tailwindStyle}</style>
37
- <style>{style}</style>
38
- {shadowRoot && (
39
- <StyleSheetManager target={shadowRoot}>
40
- <StoreWrapper keepAlive={props.keepAlive}>
35
+ <StoreWrapper keepAlive={props.keepAlive} storeRef={storeRef}>
36
+ <root.div mode="open" ref={rootRef}>
37
+ <style>{tailwindStyle}</style>
38
+ <style>{style}</style>
39
+ {shadowRoot && (
40
+ <StyleSheetManager target={shadowRoot}>
41
41
  <FieldsContextWrapper>
42
42
  <ShadowDomContext.Provider value={{ root: shadowRoot }}>
43
43
  <App {...props} />
44
44
  </ShadowDomContext.Provider>
45
45
  </FieldsContextWrapper>
46
- </StoreWrapper>
47
- </StyleSheetManager>
48
- )}
49
- </root.div>
46
+ </StyleSheetManager>
47
+ )}
48
+ </root.div>
49
+ </StoreWrapper>
50
50
  );
51
51
  });
package/src/interfaces.ts CHANGED
@@ -1,19 +1,28 @@
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
1
  export type DeepReadonly<T extends Record<keyof any, any>> = {
6
2
  readonly [K in keyof T]: T[K] extends Record<keyof any, any> ? DeepReadonly<T[K]> : T[K];
7
3
  };
4
+ export type ISemanticType = 'quantitative' | 'nominal' | 'ordinal' | 'temporal';
5
+ export type IDataType = 'number' | 'integer' | 'boolean' | 'date' | 'string';
6
+ export type IAnalyticType = 'dimension' | 'measure';
8
7
 
9
8
  export interface IRow {
10
9
  [key: string]: any;
11
10
  }
12
- /**
13
- * @deprecated
14
- */
15
- export type SemanticType = 'quantitative' | 'nominal' | 'ordinal' | 'temporal';
16
11
 
12
+ export type IAggregator = 'sum' | 'count' | 'max' | 'min' | 'mean' | 'median' | 'variance' | 'stdev';
13
+ export interface Specification {
14
+ position?: string[];
15
+ color?: string[];
16
+ size?: string[];
17
+ shape?: string[];
18
+ opacity?: string[];
19
+ facets?: string[];
20
+ page?: string[];
21
+ filter?: string[];
22
+ highFacets?: string[];
23
+ geomType?: string[];
24
+ aggregate?: boolean;
25
+ }
17
26
  export interface Filters {
18
27
  [key: string]: any[];
19
28
  }
@@ -25,7 +34,7 @@ export interface IMutField {
25
34
  disable?: boolean;
26
35
  semanticType: ISemanticType;
27
36
  analyticType: IAnalyticType;
28
- };
37
+ }
29
38
 
30
39
  export interface IUncertainMutField {
31
40
  fid: string;
@@ -36,6 +45,30 @@ export interface IUncertainMutField {
36
45
  analyticType: IAnalyticType | '?';
37
46
  }
38
47
 
48
+ export type IExpParamter =
49
+ | {
50
+ type: 'field';
51
+ value: string;
52
+ }
53
+ | {
54
+ type: 'value';
55
+ value: any;
56
+ }
57
+ | {
58
+ type: 'expression';
59
+ value: IExpression;
60
+ }
61
+ | {
62
+ type: 'constant';
63
+ value: any;
64
+ };
65
+
66
+ export interface IExpression {
67
+ op: 'bin' | 'log2' | 'log10' | 'one' | 'binCount';
68
+ params: IExpParamter[];
69
+ as: string;
70
+ }
71
+
39
72
  export interface IField {
40
73
  /**
41
74
  * fid: key in data record
@@ -52,6 +85,8 @@ export interface IField {
52
85
  semanticType: ISemanticType;
53
86
  analyticType: IAnalyticType;
54
87
  cmp?: (a: any, b: any) => number;
88
+ computed?: boolean;
89
+ expressoion?: IExpression;
55
90
  }
56
91
 
57
92
  export interface IViewField extends IField {
@@ -59,13 +94,6 @@ export interface IViewField extends IField {
59
94
  sort?: 'none' | 'ascending' | 'descending';
60
95
  }
61
96
 
62
- export interface Measure extends IField {
63
- aggregator?: AggFC;
64
- minWidth?: number;
65
- formatter?: (value: number | undefined) => number | string;
66
- [key: string]: any;
67
- }
68
-
69
97
  export interface DataSet {
70
98
  id: string;
71
99
  name: string;
@@ -80,7 +108,20 @@ export interface IFieldNeighbor {
80
108
 
81
109
  export interface IMeasure {
82
110
  key: string;
83
- op: StatFuncName
111
+ op: IAggregator;
112
+ }
113
+
114
+ export interface IPredicate {
115
+ key: string;
116
+ type: "discrete" | "continuous";
117
+ range: Set<any> | [number, number];
118
+ }
119
+
120
+ export interface IExplainProps {
121
+ dataSource: IRow[];
122
+ predicates: IPredicate[];
123
+ viewFields: IField[];
124
+ metas: IField[];
84
125
  }
85
126
 
86
127
  export interface IDataSet {
@@ -95,12 +136,12 @@ export interface IDataSet {
95
136
  export interface IDataSetInfo {
96
137
  name: string;
97
138
  rawFields: IMutField[];
98
- dataSource: IRow[]
139
+ dataSource: IRow[];
99
140
  }
100
141
 
101
142
  export interface IDataSource {
102
143
  id: string;
103
- data: IRow[]
144
+ data: IRow[];
104
145
  }
105
146
 
106
147
  export interface IFilterField extends IViewField {
@@ -125,39 +166,34 @@ export interface DraggableFieldState {
125
166
 
126
167
  export interface IDraggableStateKey {
127
168
  id: keyof DraggableFieldState;
128
- mode: number
129
- }
130
-
131
- export type IFilterRule = {
132
- type: 'range';
133
- value: readonly [number, number];
134
- } | {
135
- type: 'temporal range';
136
- value: readonly [number, number];
137
- } | {
138
- type: 'one of';
139
- value: Set<string | number>;
140
- };
169
+ mode: number;
170
+ }
141
171
 
142
- export const EXPLORATION_TYPES = [
143
- 'none',
144
- 'brush',
145
- 'point',
146
- ] as const;
172
+ export type IFilterRule =
173
+ | {
174
+ type: 'range';
175
+ value: readonly [number, number];
176
+ }
177
+ | {
178
+ type: 'temporal range';
179
+ value: readonly [number, number];
180
+ }
181
+ | {
182
+ type: 'one of';
183
+ value: Set<string | number>;
184
+ };
147
185
 
148
- export const BRUSH_DIRECTIONS = [
149
- 'default',
150
- 'x',
151
- 'y',
152
- ] as const;
186
+ export const EXPLORATION_TYPES = ['none', 'brush', 'point'] as const;
187
+
188
+ export const BRUSH_DIRECTIONS = ['default', 'x', 'y'] as const;
153
189
 
154
190
  export type IStackMode = 'none' | 'stack' | 'normalize';
155
- export type IExplorationType = (typeof EXPLORATION_TYPES)[number];
156
- export type IBrushDirection = (typeof BRUSH_DIRECTIONS)[number];
191
+ export type IExplorationType = typeof EXPLORATION_TYPES[number];
192
+ export type IBrushDirection = typeof BRUSH_DIRECTIONS[number];
157
193
 
158
194
  export interface IVisualConfig {
159
195
  defaultAggregated: boolean;
160
- geoms: string[];
196
+ geoms: string[];
161
197
  stack: IStackMode;
162
198
  showActions: boolean;
163
199
  interactiveScale: boolean;
@@ -166,7 +202,7 @@ export interface IVisualConfig {
166
202
  mode: 'auto' | 'fixed';
167
203
  width: number;
168
204
  height: number;
169
- }
205
+ };
170
206
  exploration: {
171
207
  mode: IExplorationType;
172
208
  /** works when mode is 'brush' */
@@ -176,15 +212,15 @@ export interface IVisualConfig {
176
212
 
177
213
  export interface IVisSpec {
178
214
  readonly visId: string;
179
- readonly name?: [string, Record<string, any>?];
215
+ readonly name?: string;
180
216
  readonly encodings: DeepReadonly<DraggableFieldState>;
181
217
  readonly config: DeepReadonly<IVisualConfig>;
182
218
  }
183
219
 
184
220
  export enum ISegmentKey {
185
221
  vis = 'vis',
186
- data = 'data'
222
+ data = 'data',
187
223
  }
188
224
 
189
225
  export type IThemeKey = 'vega' | 'g2';
190
- export type IDarkMode = 'media' | 'light' | 'dark';
226
+ export type IDarkMode = 'media' | 'light' | 'dark';