@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,109 @@
1
+ import { observer } from 'mobx-react-lite';
2
+ import React from 'react';
3
+ import styled from 'styled-components'
4
+ import { ArrowUturnLeftIcon, ArrowUturnRightIcon } from '@heroicons/react/24/solid';
5
+ import { useTranslation } from 'react-i18next';
6
+ import { useGlobalStore } from '../store';
7
+
8
+
9
+ export const MenubarContainer = styled.div({
10
+ marginBlock: '0 0.6em',
11
+ marginInline: '0.2em',
12
+ });
13
+
14
+ const Button = styled.button(({ disabled = false }) => ({
15
+ '&:hover': disabled ? {} : {
16
+ backgroundColor: 'rgba(243, 244, 246, 0.7)',
17
+ },
18
+ color: disabled ? 'rgba(156, 163, 175, 0.5)' : 'rgb(55, 65, 81)',
19
+ '& > pre': {
20
+ display: 'inline-block',
21
+ marginInlineStart: '0.2em',
22
+ },
23
+ marginInlineStart: '0.6em',
24
+ '&:first-child': {
25
+ marginInlineStart: '0',
26
+ },
27
+ cursor: disabled ? 'default' : 'pointer',
28
+ }));
29
+
30
+ interface ButtonWithShortcutProps {
31
+ label: string;
32
+ shortcut: string;
33
+ disabled: boolean;
34
+ handler: () => void;
35
+ icon?: JSX.Element;
36
+ }
37
+
38
+ const ButtonWithShortcut: React.FC<ButtonWithShortcutProps> = ({ label, shortcut, disabled, handler, icon }) => {
39
+ const { t } = useTranslation('translation', { keyPrefix: 'main.tabpanel.menubar' });
40
+
41
+ const rule = React.useMemo(() => {
42
+ const keys = shortcut.split('+').map(d => d.trim());
43
+
44
+ return {
45
+ key: keys.filter(
46
+ d => /^[a-z]$/i.test(d)
47
+ )[0],
48
+ ctrlKey: keys.includes('Ctrl'),
49
+ shiftKey: keys.includes('Shift'),
50
+ altKey: keys.includes('Alt'),
51
+ };
52
+ }, [shortcut]);
53
+
54
+ React.useEffect(() => {
55
+ const cb = (ev: KeyboardEvent) => {
56
+ if (
57
+ ev.ctrlKey === rule.ctrlKey
58
+ && ev.shiftKey === rule.shiftKey
59
+ && ev.altKey === rule.altKey
60
+ && ev.key.toLowerCase() === rule.key.toLowerCase()
61
+ ) {
62
+ handler();
63
+ ev.stopPropagation();
64
+ }
65
+ };
66
+
67
+ document.body.addEventListener('keydown', cb);
68
+
69
+ return () => document.body.removeEventListener('keydown', cb);
70
+ }, [rule, handler]);
71
+
72
+ return (
73
+ <Button
74
+ className="text-sm px-3 py-1 border text-gray-400 select-none"
75
+ disabled={disabled}
76
+ onClick={handler}
77
+ aria-label={t(label)}
78
+ title={`${t(label)} (${shortcut})`}
79
+ >
80
+ {icon || t(label)}
81
+ </Button>
82
+ );
83
+ };
84
+
85
+ const Menubar: React.FC = () => {
86
+ const { vizStore } = useGlobalStore();
87
+ const { canUndo, canRedo } = vizStore;
88
+
89
+ return (
90
+ <MenubarContainer>
91
+ <ButtonWithShortcut
92
+ label="undo"
93
+ disabled={!canUndo}
94
+ handler={vizStore.undo.bind(vizStore)}
95
+ shortcut="Ctrl+Z"
96
+ icon={<ArrowUturnLeftIcon width="1.4em" height="1.4em" />}
97
+ />
98
+ <ButtonWithShortcut
99
+ label="redo"
100
+ disabled={!canRedo}
101
+ handler={vizStore.redo.bind(vizStore)}
102
+ shortcut="Ctrl+Shift+Z"
103
+ icon={<ArrowUturnRightIcon width="1.4em" height="1.4em" />}
104
+ />
105
+ </MenubarContainer>
106
+ );
107
+ }
108
+
109
+ export default observer(Menubar);
@@ -0,0 +1 @@
1
+ /// <reference types="vite/client" />
@@ -0,0 +1,78 @@
1
+ /* eslint no-restricted-globals: 0 */
2
+ /* eslint-disable */
3
+ // import { Record, Filters } from '../interfaces';
4
+ import { getPredicatesFromVegaSignals } from '../utils';
5
+ import { DataExplainer } from '../insights';
6
+ const state = {
7
+ de: null
8
+ };
9
+
10
+ function preAnalysis (props) {
11
+ const { fields, dataSource } = props; // as ReqData;
12
+ const de = new DataExplainer(dataSource);
13
+ de.setFields(fields);
14
+ de.preAnalysis();
15
+ state.de = de;
16
+ return true
17
+ }
18
+
19
+ function getFieldsSummary (props) {
20
+ const de = state.de;
21
+ if (de !== null) {
22
+ return de.engine.fields;
23
+ }
24
+ throw new Error('data explainer is not init.')
25
+ }
26
+ function getExplaination(props) {
27
+
28
+ const { filters = {}, currentSpace } = props; // as ReqData;
29
+ const predicates = getPredicatesFromVegaSignals(filters, currentSpace.dimensions, []);
30
+ const de = state.de;
31
+ const ansSpaces = de.explain(predicates, currentSpace.dimensions, currentSpace.measures);
32
+ const visSpaces = de.getVisSpec(ansSpaces);
33
+ const valueExp = de.explainValue(predicates, currentSpace.dimensions, currentSpace.measures);
34
+ const measureStats = [];
35
+ for (let i = 0; i < valueExp.length; i++) {
36
+ if (valueExp[i] !== 0) {
37
+ measureStats.push({
38
+ ...currentSpace.measures[i],
39
+ score: valueExp[i]
40
+ })
41
+ }
42
+ }
43
+ const fields = de.engine.fields;
44
+ return {
45
+ explainations: ansSpaces,
46
+ visSpaces,
47
+ valueExp: measureStats,
48
+ fieldsWithSemanticType: fields.map(f => ({
49
+ key: f.key,
50
+ type: f.semanticType
51
+ }))
52
+ };
53
+ }
54
+
55
+ function main (e) {
56
+ const { type, data } = e.data;
57
+ console.log(type, data)
58
+ let res = false;
59
+ try {
60
+ switch (type) {
61
+ case 'getExplaination':
62
+ res = getExplaination(data);
63
+ break;
64
+ case 'preAnalysis':
65
+ res = preAnalysis(data);
66
+ break;
67
+ default:
68
+ throw new Error(`type ${type} is not supported.`);
69
+ }
70
+ self.postMessage(res);
71
+ } catch (error) {
72
+ // discuss
73
+ console.log(error)
74
+ self.postMessage(false)
75
+ }
76
+ }
77
+
78
+ self.addEventListener('message', main, false);
@@ -0,0 +1,70 @@
1
+ /* eslint no-restricted-globals: 0 */
2
+ /* eslint-disable */
3
+
4
+ /**
5
+ * @param {import('../interfaces').IRow[]} dataSource
6
+ * @param {import('../interfaces').IFilterField[]} filters
7
+ * @return {import('../interfaces').IRow[]}
8
+ */
9
+ const filter = (dataSource, filters) => {
10
+ return dataSource.filter(which => {
11
+ for (const { rule, fid } of filters) {
12
+ if (!rule) {
13
+ continue;
14
+ }
15
+
16
+ switch (rule.type) {
17
+ case 'one of': {
18
+ if (rule.value.has(which[fid])) {
19
+ break;
20
+ } else {
21
+ return false;
22
+ }
23
+ }
24
+ case 'range': {
25
+ if (rule.value[0] <= which[fid] && which[fid] <= rule.value[1]) {
26
+ break;
27
+ } else {
28
+ return false;
29
+ }
30
+ }
31
+ case 'temporal range': {
32
+ try {
33
+ const time = new Date(which[fid]).getTime();
34
+
35
+ if (
36
+ rule.value[0] <= time && time <= rule.value[1]
37
+ ) {
38
+ break;
39
+ } else {
40
+ return false;
41
+ }
42
+ } catch (error) {
43
+ console.error(error);
44
+
45
+ return false;
46
+ }
47
+ }
48
+ default: {
49
+ console.warn('Unresolvable filter rule', rule);
50
+ continue;
51
+ }
52
+ }
53
+ }
54
+
55
+ return true;
56
+ });
57
+ };
58
+
59
+ /**
60
+ * @param {MessageEvent<{ dataSource: import('../interfaces').IRow[]; filters: import('../interfaces').IFilterField[] }>} e
61
+ */
62
+ const main = e => {
63
+ const { dataSource, filters } = e.data;
64
+
65
+ const filtered = filter(dataSource, filters);
66
+
67
+ self.postMessage(filtered);
68
+ };
69
+
70
+ self.addEventListener('message', main, false);