@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.
- package/dist/App.d.ts +4 -3
- package/dist/assets/transform.worker-5d54ff09.js.map +1 -0
- package/dist/assets/viewQuery.worker-ffefc111.js.map +1 -0
- package/dist/components/codeExport/index.d.ts +3 -0
- package/dist/components/loadingLayer.d.ts +2 -0
- package/dist/components/tabs/defaultTab.d.ts +1 -0
- package/dist/components/tabs/editableTab.d.ts +1 -2
- package/dist/dataSource/dataSelection/config.d.ts +1 -0
- package/dist/dataSource/dataSelection/utils.d.ts +2 -0
- package/dist/dataSource/index.d.ts +0 -1
- package/dist/datasets/tmp/test.json +1 -0
- package/dist/fields/encodeFields/singleEncodeEditor.d.ts +4 -4
- package/dist/graphic-walker.es.js +29228 -33650
- package/dist/graphic-walker.es.js.map +1 -1
- package/dist/graphic-walker.umd.js +218 -256
- package/dist/graphic-walker.umd.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/interfaces.d.ts +52 -17
- package/dist/lib/execExp.d.ts +8 -0
- package/dist/lib/inferMeta.d.ts +2 -9
- package/dist/lib/insights/explainByChildren.d.ts +16 -0
- package/dist/lib/insights/explainBySelection.d.ts +5 -0
- package/dist/lib/insights/explainValue.d.ts +2 -0
- package/dist/lib/insights/utils.d.ts +11 -0
- package/dist/lib/interfaces.d.ts +23 -0
- package/dist/lib/op/aggregate.d.ts +3 -0
- package/dist/lib/op/bin.d.ts +3 -0
- package/dist/lib/op/fold.d.ts +3 -0
- package/dist/lib/op/stat.d.ts +8 -0
- package/dist/lib/viewQuery.d.ts +4 -0
- package/dist/models/visSpecHistory.d.ts +2 -0
- package/dist/renderer/index.d.ts +8 -7
- package/dist/renderer/specRenderer.d.ts +13 -0
- package/dist/services.d.ts +5 -31
- package/dist/store/commonStore.d.ts +6 -0
- package/dist/store/index.d.ts +3 -2
- package/dist/store/visualSpecStore.d.ts +11 -5
- package/dist/utils/autoMark.d.ts +1 -1
- package/dist/utils/dataPrep.d.ts +3 -2
- package/dist/utils/index.d.ts +3 -5
- package/dist/utils/save.d.ts +1 -2
- package/dist/vis/react-vega.d.ts +2 -22
- package/dist/vis/spec/aggregate.d.ts +4 -0
- package/dist/vis/spec/encode.d.ts +20 -0
- package/dist/vis/spec/field.d.ts +2 -0
- package/dist/vis/spec/mark.d.ts +7 -0
- package/dist/vis/spec/stack.d.ts +4 -0
- package/dist/vis/spec/tooltip.d.ts +4 -0
- package/dist/vis/spec/view.d.ts +73 -0
- package/dist/workers/transform.d.ts +2 -0
- package/package.json +5 -6
- package/src/App.tsx +56 -66
- package/src/components/codeExport/index.tsx +114 -0
- package/src/components/dataTable/index.tsx +10 -10
- package/src/components/loadingLayer.tsx +7 -0
- package/src/components/tabs/defaultTab.tsx +4 -2
- package/src/components/tabs/editableTab.tsx +74 -39
- package/src/dataSource/dataSelection/config.ts +11 -0
- package/src/dataSource/dataSelection/csvData.tsx +71 -39
- package/src/dataSource/dataSelection/gwFile.tsx +2 -2
- package/src/dataSource/dataSelection/utils.ts +28 -0
- package/src/dataSource/index.tsx +0 -17
- package/src/dataSource/utils.ts +8 -3
- package/src/fields/aestheticFields.tsx +1 -2
- package/src/fields/datasetFields/meaFields.tsx +12 -4
- package/src/fields/encodeFields/singleEncodeEditor.tsx +11 -12
- package/src/fields/fieldsContext.tsx +1 -0
- package/src/index.css +4 -4
- package/src/index.tsx +22 -22
- package/src/interfaces.ts +85 -49
- package/src/lib/execExp.ts +147 -0
- package/src/lib/inferMeta.ts +26 -29
- package/src/lib/insights/explainByChildren.ts +50 -0
- package/src/lib/insights/explainBySelection.ts +47 -0
- package/src/lib/insights/explainValue.ts +30 -0
- package/src/lib/insights/utils.ts +21 -0
- package/src/lib/interfaces.ts +33 -0
- package/src/lib/op/aggregate.ts +49 -0
- package/src/lib/op/bin.ts +25 -0
- package/src/lib/op/fold.ts +17 -0
- package/src/lib/op/stat.ts +46 -0
- package/src/lib/viewQuery.ts +22 -0
- package/src/locales/en-US.json +6 -3
- package/src/locales/i18n.ts +0 -1
- package/src/locales/ja-JP.json +4 -2
- package/src/locales/zh-CN.json +6 -3
- package/src/main.tsx +1 -1
- package/src/models/visSpecHistory.ts +14 -0
- package/src/renderer/index.tsx +58 -126
- package/src/renderer/specRenderer.tsx +121 -0
- package/src/segments/segmentNav.tsx +3 -16
- package/src/segments/visNav.tsx +17 -6
- package/src/services.ts +101 -67
- package/src/store/commonStore.ts +14 -9
- package/src/store/index.tsx +11 -4
- package/src/store/visualSpecStore.ts +89 -52
- package/src/utils/autoMark.ts +1 -1
- package/src/utils/dataPrep.ts +25 -2
- package/src/utils/index.ts +16 -17
- package/src/utils/normalization.ts +3 -1
- package/src/utils/save.ts +1 -2
- package/src/vis/react-vega.tsx +9 -340
- package/src/vis/spec/aggregate.ts +13 -0
- package/src/vis/spec/encode.ts +70 -0
- package/src/vis/spec/field.ts +10 -0
- package/src/vis/spec/mark.ts +30 -0
- package/src/vis/spec/stack.ts +11 -0
- package/src/vis/spec/tooltip.ts +16 -0
- package/src/vis/spec/view.ts +136 -0
- package/src/vis/theme.ts +12 -0
- package/src/visualSettings/index.tsx +10 -1
- package/src/workers/transform.ts +12 -0
- package/src/workers/transform.worker.js +13 -0
- package/src/workers/viewQuery.worker.js +16 -0
- package/dist/assets/explainer.worker-8428eb12.js.map +0 -1
- package/dist/dataSource/pannel.d.ts +0 -5
- package/dist/insightBoard/index.d.ts +0 -3
- package/dist/insightBoard/mainBoard.d.ts +0 -11
- package/dist/insightBoard/radioGroupButtons.d.ts +0 -12
- package/dist/insightBoard/selectionSpec.d.ts +0 -13
- package/dist/insightBoard/std2vegaSpec.d.ts +0 -12
- package/dist/insightBoard/utils.d.ts +0 -8
- package/dist/insights.d.ts +0 -61
- package/src/dataSource/pannel.tsx +0 -71
- package/src/insightBoard/index.tsx +0 -31
- package/src/insightBoard/mainBoard.tsx +0 -224
- package/src/insightBoard/radioGroupButtons.tsx +0 -57
- package/src/insightBoard/selectionSpec.ts +0 -113
- package/src/insightBoard/std2vegaSpec.ts +0 -184
- package/src/insightBoard/utils.ts +0 -32
- package/src/insights.ts +0 -408
- 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(
|
|
53
|
-
<p className="mt-1 text-sm text-gray-500">{t(
|
|
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
|
|
77
|
-
<
|
|
78
|
-
className="
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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
|
|
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 {
|
|
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
|
+
// }
|
package/src/dataSource/index.tsx
CHANGED
|
@@ -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
|
};
|
package/src/dataSource/utils.ts
CHANGED
|
@@ -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
|
|
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
|
|
2
|
-
import { IDraggableStateKey } from
|
|
3
|
-
import { observer } from
|
|
4
|
-
import { useGlobalStore } from
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import {
|
|
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
|
|
2
|
-
import { StyleSheetManager } from
|
|
3
|
-
import root from
|
|
4
|
-
import { DOM } from
|
|
5
|
-
import { observer } from
|
|
6
|
-
import App, { IGWProps } from
|
|
7
|
-
import { StoreWrapper } from
|
|
8
|
-
import { FieldsContextWrapper } from
|
|
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
|
|
10
|
+
import "./empty_sheet.css";
|
|
11
11
|
import tailwindStyle from "tailwindcss/tailwind.css?inline";
|
|
12
|
-
import style from
|
|
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
|
-
<
|
|
36
|
-
<
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
<
|
|
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
|
-
</
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
</
|
|
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:
|
|
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
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
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
|
|
149
|
-
|
|
150
|
-
|
|
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 =
|
|
156
|
-
export type IBrushDirection =
|
|
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:
|
|
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?:
|
|
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';
|