@kanaries/graphic-walker 0.2.14 → 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.
- package/dist/App.d.ts +5 -2
- package/dist/assets/explainer.worker-8428eb12.js.map +1 -1
- package/dist/assets/transform.worker-5d54ff09.js.map +1 -0
- package/dist/assets/viewQuery.worker-ffefc111.js.map +1 -0
- package/dist/components/callout.d.ts +2 -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/components/toolbar/components.d.ts +4 -1
- package/dist/components/toolbar/index.d.ts +2 -0
- package/dist/components/toolbar/toolbar-item.d.ts +3 -0
- package/dist/components/tooltip.d.ts +2 -0
- package/dist/dataSource/dataSelection/config.d.ts +1 -0
- package/dist/dataSource/dataSelection/utils.d.ts +2 -0
- package/dist/datasets/tmp/test.json +1 -0
- package/dist/fields/components.d.ts +0 -1
- package/dist/fields/filterField/filterEditDialog.d.ts +1 -1
- package/dist/graphic-walker.es.js +23930 -23320
- package/dist/graphic-walker.es.js.map +1 -1
- package/dist/graphic-walker.umd.js +143 -273
- package/dist/graphic-walker.umd.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/interfaces.d.ts +23 -1
- package/dist/lib/execExp.d.ts +8 -0
- package/dist/lib/interfaces.d.ts +22 -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 +5 -0
- package/dist/models/visSpecHistory.d.ts +2 -0
- package/dist/renderer/index.d.ts +6 -3
- package/dist/renderer/specRenderer.d.ts +13 -0
- package/dist/services.d.ts +4 -1
- package/dist/store/commonStore.d.ts +6 -0
- package/dist/store/index.d.ts +3 -2
- package/dist/store/visualSpecStore.d.ts +11 -4
- package/dist/utils/dataPrep.d.ts +2 -0
- package/dist/utils/index.d.ts +3 -5
- package/dist/utils/media.d.ts +2 -1
- package/dist/utils/save.d.ts +1 -2
- package/dist/vis/react-vega.d.ts +4 -23
- package/dist/vis/spec/aggregate.d.ts +4 -0
- package/dist/vis/spec/encode.d.ts +19 -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/view.d.ts +67 -0
- package/dist/vis/theme.d.ts +36 -20
- package/dist/visualSettings/index.d.ts +2 -1
- package/dist/workers/transform.d.ts +2 -0
- package/package.json +4 -3
- package/src/App.tsx +23 -15
- package/src/components/callout.tsx +9 -7
- package/src/components/clickMenu.tsx +1 -7
- 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/modal.tsx +1 -15
- package/src/components/sizeSetting.tsx +2 -2
- package/src/components/tabs/defaultTab.tsx +4 -2
- package/src/components/tabs/editableTab.tsx +75 -40
- package/src/components/toolbar/components.tsx +8 -23
- package/src/components/toolbar/index.tsx +11 -4
- package/src/components/toolbar/toolbar-button.tsx +2 -1
- package/src/components/toolbar/toolbar-item.tsx +17 -12
- package/src/components/toolbar/toolbar-select-button.tsx +9 -13
- package/src/components/toolbar/toolbar-toggle-button.tsx +2 -1
- package/src/components/tooltip.tsx +10 -6
- package/src/dataSource/dataSelection/config.ts +11 -0
- package/src/dataSource/dataSelection/csvData.tsx +72 -40
- package/src/dataSource/dataSelection/gwFile.tsx +2 -2
- package/src/dataSource/dataSelection/utils.ts +28 -0
- package/src/dataSource/index.tsx +2 -3
- package/src/dataSource/utils.ts +8 -3
- package/src/fields/components.tsx +13 -50
- package/src/fields/datasetFields/index.tsx +3 -4
- package/src/fields/datasetFields/meaFields.tsx +12 -4
- package/src/fields/encodeFields/singleEncodeEditor.tsx +1 -1
- package/src/fields/filterField/filterEditDialog.tsx +63 -99
- package/src/fields/filterField/slider.tsx +1 -1
- package/src/index.css +4 -4
- package/src/index.tsx +22 -22
- package/src/insightBoard/mainBoard.tsx +9 -2
- package/src/interfaces.ts +30 -3
- package/src/lib/execExp.ts +147 -0
- package/src/lib/interfaces.ts +39 -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 +23 -0
- package/src/locales/en-US.json +8 -3
- package/src/locales/i18n.ts +7 -1
- package/src/locales/ja-JP.json +197 -0
- package/src/locales/zh-CN.json +8 -3
- package/src/main.tsx +1 -1
- package/src/models/visSpecHistory.ts +14 -0
- package/src/renderer/index.tsx +58 -101
- package/src/renderer/specRenderer.tsx +119 -0
- package/src/segments/segmentNav.tsx +3 -16
- package/src/segments/visNav.tsx +17 -6
- package/src/services.ts +37 -1
- package/src/store/commonStore.ts +14 -9
- package/src/store/index.tsx +11 -4
- package/src/store/visualSpecStore.ts +89 -50
- package/src/utils/dataPrep.ts +24 -0
- package/src/utils/index.ts +16 -17
- package/src/utils/media.ts +16 -11
- package/src/utils/normalization.ts +3 -1
- package/src/utils/save.ts +1 -2
- package/src/vis/react-vega.tsx +11 -332
- package/src/vis/spec/aggregate.ts +13 -0
- package/src/vis/spec/encode.ts +69 -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/view.ts +138 -0
- package/src/vis/theme.ts +35 -25
- package/src/visualSettings/index.tsx +22 -33
- 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/components/container.d.ts +0 -2
- package/dist/dataSource/pannel.d.ts +0 -5
- package/src/components/container.tsx +0 -25
- package/src/dataSource/pannel.tsx +0 -71
|
@@ -3,38 +3,13 @@ import styled from "styled-components";
|
|
|
3
3
|
import { useTranslation } from 'react-i18next';
|
|
4
4
|
import { COLORS } from "../config";
|
|
5
5
|
|
|
6
|
-
export const AestheticSegment = styled.div`
|
|
7
|
-
border: 1px solid #e5e7eb;
|
|
8
|
-
// dark mode
|
|
9
|
-
@media (prefers-color-scheme: dark) {
|
|
10
|
-
border: 1px solid #2d3748;
|
|
11
|
-
}
|
|
12
|
-
font-size: 12px;
|
|
13
|
-
margin: 0.2em;
|
|
14
|
-
|
|
15
|
-
.aes-header{
|
|
16
|
-
border-bottom: 1px solid #e5e7eb;
|
|
17
|
-
@media (prefers-color-scheme: dark) {
|
|
18
|
-
border-bottom: 1px solid #2d3748;
|
|
19
|
-
}
|
|
20
|
-
padding: 0.6em;
|
|
21
|
-
h4 {
|
|
22
|
-
font-weight: 400;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
.aes-container{
|
|
26
|
-
/* overflow-x: auto; */
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
`
|
|
30
|
-
|
|
31
6
|
export const FieldListContainer: React.FC<{ name: string }> = (props) => {
|
|
32
7
|
const { t } = useTranslation('translation', { keyPrefix: 'constant.draggable_key' });
|
|
33
8
|
|
|
34
9
|
return (
|
|
35
|
-
<FieldListSegment>
|
|
36
|
-
<div className="fl-header">
|
|
37
|
-
<h4>{t(props.name)}</h4>
|
|
10
|
+
<FieldListSegment className="m-0.5 border border-gray-200 dark:border-gray-700">
|
|
11
|
+
<div className="fl-header border-r border-gray-200 dark:border-gray-800 cursor-default select-none">
|
|
12
|
+
<h4 className="font-normal">{t(props.name)}</h4>
|
|
38
13
|
</div>
|
|
39
14
|
<div className="fl-container">{props.children}</div>
|
|
40
15
|
</FieldListSegment>
|
|
@@ -45,12 +20,12 @@ export const AestheticFieldContainer: React.FC<{ name: string }> = props => {
|
|
|
45
20
|
const { t } = useTranslation('translation', { keyPrefix: 'constant.draggable_key' });
|
|
46
21
|
|
|
47
22
|
return (
|
|
48
|
-
<
|
|
49
|
-
<div className="
|
|
50
|
-
<h4>{t(props.name)}</h4>
|
|
23
|
+
<div className="m-0.5 text-xs border border-gray-200 dark:border-gray-700">
|
|
24
|
+
<div className="border-b border-gray-200 dark:border-gray-800 p-2 cursor-default select-none">
|
|
25
|
+
<h4 className="font-normal">{t(props.name)}</h4>
|
|
51
26
|
</div>
|
|
52
|
-
<div
|
|
53
|
-
</
|
|
27
|
+
<div>{props.children}</div>
|
|
28
|
+
</div>
|
|
54
29
|
);
|
|
55
30
|
}
|
|
56
31
|
|
|
@@ -58,12 +33,12 @@ export const FilterFieldContainer: React.FC = props => {
|
|
|
58
33
|
const { t } = useTranslation('translation', { keyPrefix: 'constant.draggable_key' });
|
|
59
34
|
|
|
60
35
|
return (
|
|
61
|
-
<
|
|
62
|
-
<div className="
|
|
63
|
-
<h4>{t('filters')}</h4>
|
|
36
|
+
<div className="m-0.5 text-xs border border-gray-200 dark:border-gray-700">
|
|
37
|
+
<div className="border-b border-gray-200 dark:border-gray-800 p-2 cursor-default select-none">
|
|
38
|
+
<h4 className="font-normal">{t('filters')}</h4>
|
|
64
39
|
</div>
|
|
65
|
-
<div
|
|
66
|
-
</
|
|
40
|
+
<div>{props.children}</div>
|
|
41
|
+
</div>
|
|
67
42
|
);
|
|
68
43
|
}
|
|
69
44
|
|
|
@@ -91,19 +66,11 @@ export const FilterFieldsContainer = styled.div({
|
|
|
91
66
|
|
|
92
67
|
export const FieldListSegment = styled.div`
|
|
93
68
|
display: flex;
|
|
94
|
-
border: 1px solid #e5e7eb;
|
|
95
|
-
@media (prefers-color-scheme: dark) {
|
|
96
|
-
border: 1px solid #2d3748;
|
|
97
|
-
}
|
|
98
69
|
margin: 0.2em;
|
|
99
70
|
font-size: 12px;
|
|
100
71
|
div.fl-header {
|
|
101
72
|
/* flex-basis: 100px; */
|
|
102
73
|
width: 100px;
|
|
103
|
-
border-right: 1px solid #e5e7eb;
|
|
104
|
-
@media (prefers-color-scheme: dark) {
|
|
105
|
-
border-right: 1px solid #2d3748;
|
|
106
|
-
}
|
|
107
74
|
flex-shrink: 0;
|
|
108
75
|
h4 {
|
|
109
76
|
margin: 0.6em;
|
|
@@ -112,10 +79,6 @@ export const FieldListSegment = styled.div`
|
|
|
112
79
|
}
|
|
113
80
|
div.fl-container {
|
|
114
81
|
flex-grow: 10;
|
|
115
|
-
/* display: flex;
|
|
116
|
-
flex-wrap: wrap; */
|
|
117
|
-
/* overflow-x: auto;
|
|
118
|
-
overflow-y: hidden; */
|
|
119
82
|
}
|
|
120
83
|
`;
|
|
121
84
|
|
|
@@ -2,11 +2,10 @@ import React from "react";
|
|
|
2
2
|
import { Droppable } from "@kanaries/react-beautiful-dnd";
|
|
3
3
|
import { useTranslation } from "react-i18next";
|
|
4
4
|
import styled from 'styled-components';
|
|
5
|
-
import { NestContainer } from "../../components/container";
|
|
6
5
|
import DimFields from "./dimFields";
|
|
7
6
|
import MeaFields from "./meaFields";
|
|
8
7
|
|
|
9
|
-
const DSContainer = styled
|
|
8
|
+
const DSContainer = styled.div`
|
|
10
9
|
@media (min-width: 768px) {
|
|
11
10
|
height: 680px;
|
|
12
11
|
}
|
|
@@ -16,14 +15,14 @@ const DatasetFields: React.FC = (props) => {
|
|
|
16
15
|
const { t } = useTranslation("translation", { keyPrefix: "main.tabpanel.DatasetFields" });
|
|
17
16
|
|
|
18
17
|
return (
|
|
19
|
-
<DSContainer className="border-gray-200 dark:border-gray-700 flex md:flex-col" style={{ paddingBlock: 0, paddingInline: '0.6em' }}>
|
|
18
|
+
<DSContainer className="p-1 m-0.5 border border-gray-200 dark:border-gray-700 flex md:flex-col" style={{ paddingBlock: 0, paddingInline: '0.6em' }}>
|
|
20
19
|
<h4 className="text-xs mb-2 flex-grow-0 cursor-default select-none mt-2">{t("field_list")}</h4>
|
|
21
20
|
<div className="pd-1 overflow-y-auto" style={{ maxHeight: "380px", minHeight: '100px' }}>
|
|
22
21
|
<Droppable droppableId="dimensions" direction="vertical">
|
|
23
22
|
{(provided, snapshot) => <DimFields provided={provided} />}
|
|
24
23
|
</Droppable>
|
|
25
24
|
</div>
|
|
26
|
-
<div className="border-t dark:border-gray-
|
|
25
|
+
<div className="border-t dark:border-gray-700 flex-grow pd-1 overflow-y-auto">
|
|
27
26
|
<Droppable droppableId="measures" direction="vertical">
|
|
28
27
|
{(provided, snapshot) => <MeaFields provided={provided} />}
|
|
29
28
|
</Droppable>
|
|
@@ -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 (
|
|
@@ -48,7 +48,7 @@ const SingleEncodeEditor: React.FC<SingleEncodeEditorProps> = (props) => {
|
|
|
48
48
|
>
|
|
49
49
|
<TrashIcon className="w-4" />
|
|
50
50
|
</div>
|
|
51
|
-
<div className="flex-1 flex items-center border border-gray-200 dark:border-gray-700 border-l-0 px-2 space-x-2">
|
|
51
|
+
<div className="flex-1 flex items-center border border-gray-200 dark:border-gray-700 border-l-0 px-2 space-x-2 truncate">
|
|
52
52
|
<span className="flex-1 truncate">
|
|
53
53
|
{channelItem.name}
|
|
54
54
|
</span>
|
|
@@ -1,64 +1,29 @@
|
|
|
1
|
-
import { CheckCircleIcon } from
|
|
2
|
-
import { observer } from
|
|
3
|
-
import React from
|
|
4
|
-
import { useTranslation } from
|
|
5
|
-
|
|
6
|
-
import Modal from
|
|
7
|
-
import type { IFilterField, IFilterRule } from
|
|
8
|
-
import { useGlobalStore } from
|
|
9
|
-
import Tabs, { RuleFormProps } from
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
onChange,
|
|
15
|
-
}) => {
|
|
16
|
-
return (
|
|
17
|
-
<Tabs
|
|
18
|
-
field={field}
|
|
19
|
-
onChange={onChange}
|
|
20
|
-
tabs={['range', 'one of']}
|
|
21
|
-
/>
|
|
22
|
-
);
|
|
1
|
+
import { CheckCircleIcon } from "@heroicons/react/24/outline";
|
|
2
|
+
import { observer } from "mobx-react-lite";
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { useTranslation } from "react-i18next";
|
|
5
|
+
|
|
6
|
+
import Modal from "../../components/modal";
|
|
7
|
+
import type { IFilterField, IFilterRule } from "../../interfaces";
|
|
8
|
+
import { useGlobalStore } from "../../store";
|
|
9
|
+
import Tabs, { RuleFormProps } from "./tabs";
|
|
10
|
+
import DefaultButton from "../../components/button/default";
|
|
11
|
+
import PrimaryButton from "../../components/button/primary";
|
|
12
|
+
|
|
13
|
+
const QuantitativeRuleForm: React.FC<RuleFormProps> = ({ field, onChange }) => {
|
|
14
|
+
return <Tabs field={field} onChange={onChange} tabs={["range", "one of"]} />;
|
|
23
15
|
};
|
|
24
16
|
|
|
25
|
-
const NominalRuleForm: React.FC<RuleFormProps> = ({
|
|
26
|
-
field
|
|
27
|
-
onChange,
|
|
28
|
-
}) => {
|
|
29
|
-
return (
|
|
30
|
-
<Tabs
|
|
31
|
-
field={field}
|
|
32
|
-
onChange={onChange}
|
|
33
|
-
tabs={['one of']}
|
|
34
|
-
/>
|
|
35
|
-
);
|
|
17
|
+
const NominalRuleForm: React.FC<RuleFormProps> = ({ field, onChange }) => {
|
|
18
|
+
return <Tabs field={field} onChange={onChange} tabs={["one of"]} />;
|
|
36
19
|
};
|
|
37
20
|
|
|
38
|
-
const OrdinalRuleForm: React.FC<RuleFormProps> = ({
|
|
39
|
-
field,
|
|
40
|
-
onChange,
|
|
41
|
-
}) => {
|
|
42
|
-
return (
|
|
43
|
-
<Tabs
|
|
44
|
-
field={field}
|
|
45
|
-
onChange={onChange}
|
|
46
|
-
tabs={['range', 'one of']}
|
|
47
|
-
/>
|
|
48
|
-
);
|
|
21
|
+
const OrdinalRuleForm: React.FC<RuleFormProps> = ({ field, onChange }) => {
|
|
22
|
+
return <Tabs field={field} onChange={onChange} tabs={["range", "one of"]} />;
|
|
49
23
|
};
|
|
50
24
|
|
|
51
|
-
const TemporalRuleForm: React.FC<RuleFormProps> = ({
|
|
52
|
-
field,
|
|
53
|
-
onChange,
|
|
54
|
-
}) => {
|
|
55
|
-
return (
|
|
56
|
-
<Tabs
|
|
57
|
-
field={field}
|
|
58
|
-
onChange={onChange}
|
|
59
|
-
tabs={['one of', 'temporal range']}
|
|
60
|
-
/>
|
|
61
|
-
);
|
|
25
|
+
const TemporalRuleForm: React.FC<RuleFormProps> = ({ field, onChange }) => {
|
|
26
|
+
return <Tabs field={field} onChange={onChange} tabs={["one of", "temporal range"]} />;
|
|
62
27
|
};
|
|
63
28
|
|
|
64
29
|
const EmptyForm: React.FC<RuleFormProps> = () => <React.Fragment />;
|
|
@@ -67,7 +32,7 @@ const FilterEditDialog: React.FC = observer(() => {
|
|
|
67
32
|
const { vizStore } = useGlobalStore();
|
|
68
33
|
const { editingFilterIdx, draggableFieldState } = vizStore;
|
|
69
34
|
|
|
70
|
-
const { t } = useTranslation(
|
|
35
|
+
const { t } = useTranslation("translation", { keyPrefix: "filters" });
|
|
71
36
|
|
|
72
37
|
const field = React.useMemo(() => {
|
|
73
38
|
return editingFilterIdx !== null ? draggableFieldState.filters[editingFilterIdx] : null;
|
|
@@ -83,14 +48,20 @@ const FilterEditDialog: React.FC = observer(() => {
|
|
|
83
48
|
}
|
|
84
49
|
}, [field]);
|
|
85
50
|
|
|
86
|
-
const handleChange = React.useCallback(
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
51
|
+
const handleChange = React.useCallback(
|
|
52
|
+
(r: IFilterRule) => {
|
|
53
|
+
if (editingFilterIdx !== null) {
|
|
54
|
+
setUncontrolledField(
|
|
55
|
+
(uf) =>
|
|
56
|
+
({
|
|
57
|
+
...uf,
|
|
58
|
+
rule: r,
|
|
59
|
+
} as IFilterField)
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
[editingFilterIdx]
|
|
64
|
+
);
|
|
94
65
|
|
|
95
66
|
const handleSubmit = React.useCallback(() => {
|
|
96
67
|
if (editingFilterIdx !== null) {
|
|
@@ -100,45 +71,38 @@ const FilterEditDialog: React.FC = observer(() => {
|
|
|
100
71
|
vizStore.closeFilterEditing();
|
|
101
72
|
}, [editingFilterIdx, uncontrolledField]);
|
|
102
73
|
|
|
103
|
-
const Form = field
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
74
|
+
const Form = field
|
|
75
|
+
? ({
|
|
76
|
+
quantitative: QuantitativeRuleForm,
|
|
77
|
+
nominal: NominalRuleForm,
|
|
78
|
+
ordinal: OrdinalRuleForm,
|
|
79
|
+
temporal: TemporalRuleForm,
|
|
80
|
+
}[field.semanticType] as React.FC<RuleFormProps>)
|
|
81
|
+
: EmptyForm;
|
|
82
|
+
|
|
110
83
|
return uncontrolledField ? (
|
|
111
|
-
<Modal
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
{t(
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
height="3em"
|
|
131
|
-
role="button"
|
|
132
|
-
tabIndex={0}
|
|
133
|
-
aria-label="ok"
|
|
134
|
-
className="cursor-pointer hover:bg-green-50 p-1"
|
|
135
|
-
onClick={handleSubmit}
|
|
136
|
-
strokeWidth="1.5"
|
|
137
|
-
/>
|
|
84
|
+
<Modal show={Boolean(uncontrolledField)} title={t("editing")} onClose={() => vizStore.closeFilterEditing()}>
|
|
85
|
+
<div className="p-4">
|
|
86
|
+
<h2 className="text-base font-semibold py-2 outline-none">{t("form.name")}</h2>
|
|
87
|
+
<span className="inline-flex items-center rounded-full bg-indigo-100 px-3 py-0.5 text-sm font-medium text-indigo-800">
|
|
88
|
+
{uncontrolledField.name}
|
|
89
|
+
</span>
|
|
90
|
+
<h3 className="text-base font-semibold py-2 outline-none">{t("form.rule")}</h3>
|
|
91
|
+
<Form field={uncontrolledField} onChange={handleChange} />
|
|
92
|
+
<div className="mt-4">
|
|
93
|
+
<PrimaryButton
|
|
94
|
+
onClick={handleSubmit}
|
|
95
|
+
text={t("btn.confirm")}
|
|
96
|
+
/>
|
|
97
|
+
<DefaultButton
|
|
98
|
+
className="ml-2"
|
|
99
|
+
onClick={() => vizStore.closeFilterEditing()}
|
|
100
|
+
text={t("btn.cancel")}
|
|
101
|
+
/>
|
|
102
|
+
</div>
|
|
138
103
|
</div>
|
|
139
104
|
</Modal>
|
|
140
105
|
) : null;
|
|
141
106
|
});
|
|
142
107
|
|
|
143
|
-
|
|
144
108
|
export default FilterEditDialog;
|
|
@@ -118,7 +118,6 @@ const Slider: React.FC<SliderProps> = React.memo(function Slider ({
|
|
|
118
118
|
};
|
|
119
119
|
|
|
120
120
|
const dragHandler = fromEvent(document.body, 'mousemove').pipe(
|
|
121
|
-
throttleTime(100),
|
|
122
121
|
map(ev => {
|
|
123
122
|
if (!trackRef.current || !dragging) {
|
|
124
123
|
return null;
|
|
@@ -142,6 +141,7 @@ const Slider: React.FC<SliderProps> = React.memo(function Slider ({
|
|
|
142
141
|
|
|
143
142
|
return pos;
|
|
144
143
|
}),
|
|
144
|
+
throttleTime(100),
|
|
145
145
|
filter(pos => {
|
|
146
146
|
return pos !== null && pos !== range[dragging === 'left' ? 0 : 1];
|
|
147
147
|
}),
|
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
|
});
|
|
@@ -9,6 +9,8 @@ import { baseVis, IReasonType } from "./std2vegaSpec";
|
|
|
9
9
|
import RadioGroupButtons from "./radioGroupButtons";
|
|
10
10
|
import { formatFieldName, mergeMeasures } from "./utils";
|
|
11
11
|
import { useTranslation } from "react-i18next";
|
|
12
|
+
import { useCurrentMediaTheme } from "../utils/media";
|
|
13
|
+
import { builtInThemes } from "../vis/theme";
|
|
12
14
|
|
|
13
15
|
const collection = Insight.IntentionWorkerCollection.init();
|
|
14
16
|
|
|
@@ -41,6 +43,8 @@ const InsightMainBoard: React.FC<InsightMainBoardProps> = (props) => {
|
|
|
41
43
|
const [valueExp, setValueExp] = useState<IMeasureWithStat[]>([]);
|
|
42
44
|
const { t } = useTranslation();
|
|
43
45
|
const container = useRef<HTMLDivElement>(null);
|
|
46
|
+
const mediaTheme = useCurrentMediaTheme();
|
|
47
|
+
const themeConfig = builtInThemes['g2'][mediaTheme];
|
|
44
48
|
|
|
45
49
|
const dimsWithTypes = useMemo(() => {
|
|
46
50
|
const dimensions = fields
|
|
@@ -111,10 +115,13 @@ const InsightMainBoard: React.FC<InsightMainBoardProps> = (props) => {
|
|
|
111
115
|
true
|
|
112
116
|
);
|
|
113
117
|
if (container.current) {
|
|
114
|
-
embed(container.current, _vegaSpec
|
|
118
|
+
embed(container.current, _vegaSpec, {
|
|
119
|
+
actions: false,
|
|
120
|
+
config: themeConfig
|
|
121
|
+
});
|
|
115
122
|
}
|
|
116
123
|
}
|
|
117
|
-
}, [visIndex, recSpaces, visSpaces, fields, dataSource]);
|
|
124
|
+
}, [visIndex, recSpaces, visSpaces, fields, dataSource, themeConfig]);
|
|
118
125
|
|
|
119
126
|
const FilterDesc = useMemo<React.ReactElement[]>(() => {
|
|
120
127
|
if (filters) {
|
package/src/interfaces.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { StatFuncName } from "visual-insights/build/esm/statistics";
|
|
2
2
|
import { AggFC } from 'cube-core/built/types';
|
|
3
|
-
import { IAnalyticType,
|
|
3
|
+
import { IAnalyticType, ISemanticType } from 'visual-insights';
|
|
4
4
|
|
|
5
5
|
export type DeepReadonly<T extends Record<keyof any, any>> = {
|
|
6
6
|
readonly [K in keyof T]: T[K] extends Record<keyof any, any> ? DeepReadonly<T[K]> : T[K];
|
|
@@ -36,6 +36,28 @@ export interface IUncertainMutField {
|
|
|
36
36
|
analyticType: IAnalyticType | '?';
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
|
|
40
|
+
export type IExpParamter = {
|
|
41
|
+
type: 'field';
|
|
42
|
+
value: string;
|
|
43
|
+
} | {
|
|
44
|
+
type: 'value';
|
|
45
|
+
value: any;
|
|
46
|
+
} | {
|
|
47
|
+
type: 'expression';
|
|
48
|
+
value: IExpression;
|
|
49
|
+
} | {
|
|
50
|
+
type: 'constant';
|
|
51
|
+
value: any;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
export interface IExpression {
|
|
56
|
+
op: 'bin' | 'log2' | 'log10' | 'one' | 'binCount';
|
|
57
|
+
params: IExpParamter[];
|
|
58
|
+
as: string;
|
|
59
|
+
}
|
|
60
|
+
|
|
39
61
|
export interface IField {
|
|
40
62
|
/**
|
|
41
63
|
* fid: key in data record
|
|
@@ -52,6 +74,8 @@ export interface IField {
|
|
|
52
74
|
semanticType: ISemanticType;
|
|
53
75
|
analyticType: IAnalyticType;
|
|
54
76
|
cmp?: (a: any, b: any) => number;
|
|
77
|
+
computed?: boolean;
|
|
78
|
+
expressoion?: IExpression;
|
|
55
79
|
}
|
|
56
80
|
|
|
57
81
|
export interface IViewField extends IField {
|
|
@@ -176,7 +200,7 @@ export interface IVisualConfig {
|
|
|
176
200
|
|
|
177
201
|
export interface IVisSpec {
|
|
178
202
|
readonly visId: string;
|
|
179
|
-
readonly name?:
|
|
203
|
+
readonly name?: string;
|
|
180
204
|
readonly encodings: DeepReadonly<DraggableFieldState>;
|
|
181
205
|
readonly config: DeepReadonly<IVisualConfig>;
|
|
182
206
|
}
|
|
@@ -184,4 +208,7 @@ export interface IVisSpec {
|
|
|
184
208
|
export enum ISegmentKey {
|
|
185
209
|
vis = 'vis',
|
|
186
210
|
data = 'data'
|
|
187
|
-
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export type IThemeKey = 'vega' | 'g2';
|
|
214
|
+
export type IDarkMode = 'media' | 'light' | 'dark';
|