@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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kanaries/graphic-walker",
3
- "version": "0.2.4",
3
+ "version": "0.2.6",
4
4
  "scripts": {
5
5
  "dev:front_end": "vite --host",
6
6
  "dev": "npm run dev:front_end",
@@ -10,7 +10,8 @@
10
10
  "type": "tsc src/lib.ts --declaration --emitDeclarationOnly --jsx react --esModuleInterop --outDir dist"
11
11
  },
12
12
  "files": [
13
- "dist"
13
+ "dist",
14
+ "src"
14
15
  ],
15
16
  "license": "AGPL",
16
17
  "main": "./dist/graphic-walker.umd.js",
package/src/App.tsx ADDED
@@ -0,0 +1,141 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import { Specification } from 'visual-insights';
3
+ import { observer } from 'mobx-react-lite';
4
+ import { LightBulbIcon } from '@heroicons/react/24/outline'
5
+ import { toJS } from 'mobx';
6
+ import { useTranslation } from 'react-i18next';
7
+ import { IMutField, IRow } from './interfaces';
8
+ import VisualSettings from './visualSettings';
9
+ import { Container, NestContainer } from './components/container';
10
+ import ClickMenu from './components/clickMenu';
11
+ import InsightBoard from './insightBoard/index';
12
+ import PosFields from './fields/posFields';
13
+ import AestheticFields from './fields/aestheticFields';
14
+ import DatasetFields from './fields/datasetFields/index';
15
+ import ReactiveRenderer from './renderer/index';
16
+ import DataSourceSegment from './dataSource/index';
17
+ import { useGlobalStore } from './store';
18
+ import { preAnalysis, destroyWorker } from './services'
19
+ import VisNav from './segments/visNav';
20
+ import { mergeLocaleRes, setLocaleLanguage } from './locales/i18n';
21
+ import Menubar from './visualSettings/menubar';
22
+ import FilterField from './fields/filterField';
23
+ import "tailwindcss/tailwind.css"
24
+ import './index.css'
25
+
26
+
27
+ export interface EditorProps {
28
+ dataSource?: IRow[];
29
+ rawFields?: IMutField[];
30
+ spec?: Specification;
31
+ hideDataSourceConfig?: boolean;
32
+ i18nLang?: string;
33
+ i18nResources?: { [lang: string]: Record<string, string | any> };
34
+ keepAlive?: boolean;
35
+ }
36
+
37
+ const App: React.FC<EditorProps> = props => {
38
+ const { dataSource = [], rawFields = [], spec, i18nLang = 'en-US', i18nResources, hideDataSourceConfig } = props;
39
+ const { commonStore, vizStore } = useGlobalStore();
40
+ const [insightReady, setInsightReady] = useState<boolean>(true);
41
+
42
+ const { currentDataset, datasets, vizEmbededMenu } = commonStore;
43
+
44
+ const { t, i18n } = useTranslation();
45
+ const curLang = i18n.language;
46
+
47
+ useEffect(() => {
48
+ if (i18nResources) {
49
+ mergeLocaleRes(i18nResources);
50
+ }
51
+ }, [i18nResources]);
52
+
53
+ useEffect(() => {
54
+ if (i18nLang !== curLang) {
55
+ setLocaleLanguage(i18nLang);
56
+ }
57
+ }, [i18nLang, curLang]);
58
+
59
+ // use as an embeding module, use outside datasource from props.
60
+ useEffect(() => {
61
+ if (dataSource.length > 0) {
62
+ commonStore.addAndUseDS({
63
+ name: 'context dataset',
64
+ dataSource: dataSource,
65
+ rawFields
66
+ })
67
+ }
68
+ }, [dataSource, rawFields])
69
+
70
+ // do preparation analysis work when using a new dataset
71
+ useEffect(() => {
72
+ const ds = currentDataset;
73
+ if (ds && ds.dataSource.length > 0 && ds.rawFields.length > 0) {
74
+ setInsightReady(false)
75
+ preAnalysis({
76
+ dataSource: ds.dataSource,
77
+ fields: toJS(ds.rawFields)
78
+ }).then(() => {
79
+ setInsightReady(true);
80
+
81
+ if (spec) {
82
+ vizStore.renderSpec(spec);
83
+ }
84
+ })
85
+ }
86
+ return () => {
87
+ destroyWorker();
88
+ }
89
+ }, [currentDataset, spec]);
90
+
91
+ return (
92
+ <div className="App">
93
+ { !hideDataSourceConfig && <DataSourceSegment preWorkDone={insightReady} />}
94
+ <div className='px-2 mx-2'>
95
+ <VisNav />
96
+ {/* <PureTabs tabs={[{label: 'a', key: 'a'}, {label: 'b', key: 'b'}]} selectedKey='a' onSelected={() => {}} /> */}
97
+ </div>
98
+ <Container style={{ marginTop: '0em', borderTop: 'none' }}>
99
+ <Menubar />
100
+ <VisualSettings />
101
+ <div className="grid grid-cols-12 xl:grid-cols-6">
102
+ <div className="col-span-3 xl:col-span-1">
103
+ <DatasetFields />
104
+ </div>
105
+ <div className="col-span-2 xl:col-span-1">
106
+ <FilterField />
107
+ <AestheticFields />
108
+ </div>
109
+ <div className="col-span-7 xl:col-span-4">
110
+ <div>
111
+ <PosFields />
112
+ </div>
113
+ <NestContainer style={{ minHeight: '600px', overflow: 'auto' }} onMouseLeave={() => {
114
+ vizEmbededMenu.show && commonStore.closeEmbededMenu();
115
+ }}>
116
+ {datasets.length > 0 && <ReactiveRenderer />}
117
+ <InsightBoard />
118
+ {vizEmbededMenu.show && (
119
+ <ClickMenu x={vizEmbededMenu.position[0]} y={vizEmbededMenu.position[1]}>
120
+ <div className="flex items-center whitespace-nowrap py-1 px-4 hover:bg-gray-100"
121
+ onClick={() => {
122
+ commonStore.closeEmbededMenu();
123
+ commonStore.setShowInsightBoard(true)
124
+ }}
125
+ >
126
+ <span className="flex-1 pr-2">
127
+ {t('App.labels.data_interpretation')}
128
+ </span>
129
+ <LightBulbIcon className="ml-1 w-3 flex-grow-0 flex-shrink-0" />
130
+ </div>
131
+ </ClickMenu>
132
+ )}
133
+ </NestContainer>
134
+ </div>
135
+ </div>
136
+ </Container>
137
+ </div>
138
+ )
139
+ }
140
+
141
+ export default observer(App);
Binary file
@@ -0,0 +1,29 @@
1
+ import React from 'react';
2
+ import styled from 'styled-components';
3
+
4
+ const MenuContainer = styled.div`
5
+ min-width: 100px;
6
+ background-color: #fff;
7
+ border: 1px solid #f0f0f0;
8
+ position: absolute;
9
+ z-index: 99;
10
+ cursor: pointer;
11
+ /* box-shadow: 0px 0px 8px 1px rgba(0, 0, 0, 0.09); */
12
+ /* border-radius: 2px; */
13
+ padding: 4px;
14
+ `;
15
+ interface ClickMenuProps {
16
+ x: number;
17
+ y: number;
18
+ }
19
+
20
+ const ClickMenu: React.FC<ClickMenuProps> = props => {
21
+ const { x, y, children } = props
22
+ return <MenuContainer className="shadow-lg text-sm" style={{ left: x + 'px', top: y + 'px' }}>
23
+ {
24
+ children
25
+ }
26
+ </MenuContainer>
27
+ }
28
+
29
+ export default ClickMenu;
@@ -0,0 +1,16 @@
1
+ import styled from 'styled-components';
2
+
3
+ export const Container = styled.div`
4
+ border: 1px solid #d9d9d9;
5
+ padding: 1em;
6
+ margin: 1em;
7
+ background-color: #fff;
8
+ `;
9
+
10
+ export const NestContainer = styled.div`
11
+ border: 1px solid #d9d9d9;
12
+ padding: 0.4em;
13
+ font-size: 12px;
14
+ margin: 0.2em;
15
+ background-color: #fff;
16
+ `
@@ -0,0 +1,20 @@
1
+ import React from 'react';
2
+ import { IMutField } from "../interfaces";
3
+ import { DocumentTextIcon, HashtagIcon, CalendarIcon } from '@heroicons/react/24/outline';
4
+
5
+ const DataTypeIcon: React.FC<{dataType: IMutField['semanticType']; analyticType: IMutField['analyticType']}> = props => {
6
+ const { dataType, analyticType } = props;
7
+ const color = analyticType === 'dimension' ? 'text-blue-500' : 'text-green-500'
8
+ const iconClassName = `w-3 inline-block mr-0.5 ${color}`
9
+ switch (dataType) {
10
+ case 'quantitative':
11
+ case 'ordinal':
12
+ return <HashtagIcon className={iconClassName} />
13
+ case 'temporal':
14
+ return <CalendarIcon className={iconClassName} />
15
+ default:
16
+ return <DocumentTextIcon className={iconClassName} />
17
+ }
18
+ }
19
+
20
+ export default DataTypeIcon;
@@ -0,0 +1,16 @@
1
+ import styled from 'styled-components';
2
+
3
+ export const LiteForm = styled.div`
4
+ display: flex;
5
+ align-items: center;
6
+ .item{
7
+ margin: 5px 8px;
8
+ display: flex;
9
+ align-items: center;
10
+ >label {
11
+ margin-right: 4px;
12
+ line-height: 20px;
13
+ font-size: 12px;
14
+ }
15
+ }
16
+ `;
@@ -0,0 +1,85 @@
1
+ import React, { useRef } from 'react';
2
+ import styled from 'styled-components';
3
+ import { XCircleIcon } from '@heroicons/react/24/outline';
4
+
5
+
6
+ const Background = styled.div({
7
+ position: 'fixed',
8
+ left: 0,
9
+ top: 0,
10
+ width: '100vw',
11
+ height: '100vh',
12
+ backdropFilter: 'blur(1px)',
13
+ zIndex: 25535,
14
+ });
15
+
16
+ const Container = styled.div`
17
+ width: 880px;
18
+ max-height: 800px;
19
+ overflow: auto;
20
+ > div.header {
21
+ background-color: #f0f0f0;
22
+ display: flex;
23
+ padding: 12px;
24
+ font-size: 14px;
25
+ align-items: center;
26
+ }
27
+ > div.container {
28
+ padding: 1em;
29
+ }
30
+ position: fixed;
31
+ left: 50%;
32
+ top: 50%;
33
+ transform: translate(-50%, -50%);
34
+ background-color: #fff;
35
+ /* box-shadow: 0px 0px 12px 3px rgba(0, 0, 0, 0.19); */
36
+ border-radius: 4px;
37
+ z-index: 999;
38
+ `;
39
+ interface ModalProps {
40
+ onClose?: () => void
41
+ title?: string;
42
+ }
43
+ const Modal: React.FC<ModalProps> = props => {
44
+ const { onClose, title } = props;
45
+ const prevMouseDownTimeRef = useRef(0);
46
+
47
+ return (
48
+ <Background
49
+ // This is a safer replacement of onClick handler.
50
+ // onClick also happens if the click event is begun by pressing mouse button
51
+ // at a different element and then released when the mouse is moved on the target element.
52
+ // This case is required to be prevented, especially disturbing when interacting
53
+ // with a Slider component.
54
+ onMouseDown={() => prevMouseDownTimeRef.current = Date.now()}
55
+ onMouseOut={() => prevMouseDownTimeRef.current = 0}
56
+ onMouseUp={() => {
57
+ if (Date.now() - prevMouseDownTimeRef.current < 1000) {
58
+ onClose?.();
59
+ }
60
+ }}
61
+ >
62
+ <Container
63
+ role="dialog"
64
+ className="shadow-lg"
65
+ onMouseDown={e => e.stopPropagation()}
66
+ >
67
+ <div className="header relative h-9">
68
+ <header className="font-bold">
69
+ {title}
70
+ </header>
71
+ <XCircleIcon
72
+ className="text-red-600 absolute right-2 w-6 cursor-pointer"
73
+ role="button"
74
+ tabIndex={0}
75
+ aria-label="close dialog"
76
+ onClick={onClose}
77
+ />
78
+ </div>
79
+ <div className="container">{props.children}</div>
80
+ </Container>
81
+ </Background>
82
+ );
83
+ }
84
+
85
+ export default Modal;
@@ -0,0 +1,95 @@
1
+ import { ArrowsPointingOutIcon, XMarkIcon } from "@heroicons/react/24/outline";
2
+ import React, { useState, useEffect } from "react";
3
+ import { useTranslation } from 'react-i18next';
4
+
5
+
6
+ interface SizeSettingProps {
7
+ onWidthChange: (val: number) => void;
8
+ onHeightChange: (val: number) => void;
9
+ width: number;
10
+ height: number;
11
+ }
12
+
13
+ const SizeSetting: React.FC<SizeSettingProps> = props => {
14
+ const { onWidthChange, onHeightChange, width, height } = props
15
+ const [show, setShow] = useState<boolean>(false);
16
+ const { t } = useTranslation('translation', { keyPrefix: 'main.tabpanel.settings.size_setting' });
17
+
18
+ useEffect(() => {
19
+ if (show) {
20
+ const closeDialog = () => {
21
+ setShow(false);
22
+ };
23
+
24
+ document.body.addEventListener('click', closeDialog);
25
+
26
+ return () => {
27
+ document.body.removeEventListener('click', closeDialog);
28
+ };
29
+ }
30
+ }, [show]);
31
+
32
+ return <div className="leading-none cursor-pointer">
33
+ <ArrowsPointingOutIcon
34
+ role="button"
35
+ id="button:size_setting"
36
+ aria-describedby="button:size_setting:label"
37
+ tabIndex={0}
38
+ aria-haspopup="dialog"
39
+ onClick={() => {
40
+ setShow(v => !v)
41
+ }}
42
+ className="w-4 h-4 inline-block mr-0.5 text-gray-900"
43
+ />
44
+ {
45
+ show && <div role="dialog" className="absolute z-auto bg-white p-4 border border-gray-200 shadow cursor-default" onClick={e => e.stopPropagation()} style={{ zIndex: 25535 }}>
46
+ <div>
47
+ <XMarkIcon
48
+ className="text-gray-900 absolute right-2 top-2 w-4 cursor-pointer hover:bg-red-100"
49
+ role="button"
50
+ tabIndex={0}
51
+ aria-label="close"
52
+ onClick={(e) => {
53
+ setShow(false);
54
+ e.stopPropagation();
55
+ }}
56
+ />
57
+ </div>
58
+
59
+ <div className="mt-4 w-60">
60
+ <input className="w-full h-2 bg-blue-100 appearance-none"
61
+ style={{ cursor: 'ew-resize' }}
62
+ type="range"
63
+ name="width"
64
+ value={Math.sqrt(width / 1000)}
65
+ min="0" max="1" step="0.01"
66
+ onChange={(e) => {
67
+ onWidthChange(Math.round(Number(e.target.value) ** 2 * 1000))
68
+ }}
69
+ />
70
+ <output className="text-sm ml-1" htmlFor="width">
71
+ {`${t('width')}: ${width}`}
72
+ </output>
73
+ </div>
74
+ <div className=" mt-2">
75
+ <input className="w-full h-2 bg-blue-100 appearance-none"
76
+ style={{ cursor: 'ew-resize' }}
77
+ type="range"
78
+ name="height"
79
+ value={Math.sqrt(height / 1000)}
80
+ min="0" max="1" step="0.01"
81
+ onChange={(e) => {
82
+ onHeightChange(Math.round(Number(e.target.value) ** 2 * 1000))
83
+ }}
84
+ />
85
+ <output className="text-sm ml-1" htmlFor="height">
86
+ {`${t('height')}: ${height}`}
87
+ </output>
88
+ </div>
89
+
90
+ </div>
91
+ }
92
+ </div>
93
+ }
94
+
95
+ export default SizeSetting;
@@ -0,0 +1,70 @@
1
+ import React, { useCallback, useEffect, useState } from "react";
2
+ import { useTranslation } from "react-i18next";
3
+
4
+
5
+ function classNames(...classes: string[]) {
6
+ return classes.filter(Boolean).join(' ')
7
+ }
8
+
9
+ export interface ITabOption {
10
+ label: string;
11
+ key: string;
12
+ options?: Record<string, any>;
13
+ }
14
+ interface PureTabsProps {
15
+ tabs: ITabOption[];
16
+ selectedKey: string;
17
+ onSelected: (selectedKey: string, index: number) => void;
18
+ allowEdit?: boolean;
19
+ onEditLabel?: (label: string, index: number) => void;
20
+ }
21
+ export default function PureTabs(props: PureTabsProps) {
22
+ const { tabs, selectedKey, onSelected, allowEdit, onEditLabel } = props;
23
+ const [editList, setEditList] = useState<boolean[]>([]);
24
+ const { t } = useTranslation();
25
+
26
+ const clearEditStatus = useCallback(() => {
27
+ setEditList(new Array(tabs.length).fill(false))
28
+ }, [tabs.length]);
29
+
30
+ useEffect(() => {
31
+ clearEditStatus
32
+ }, [clearEditStatus]);
33
+
34
+ return (
35
+ <div className="border-b border-gray-200 overflow-x-auto overflow-y-hidden" onMouseLeave={clearEditStatus}>
36
+ <nav className="-mb-px flex h-8 border-gray-300 border-l" role="tablist" aria-label="Tabs">
37
+ {tabs.map((tab, tabIndex) => (
38
+ <span
39
+ role="tab"
40
+ tabIndex={0}
41
+ dangerouslySetInnerHTML={{
42
+ __html: t(tab.label, tab.options)
43
+ }}
44
+ onClick={() => {
45
+ onSelected(tab.key, tabIndex)
46
+ }}
47
+ onDoubleClick={() => {
48
+ setEditList(v => {
49
+ const nv = [...v];
50
+ nv[tabIndex] = true;
51
+ return nv
52
+ })
53
+ }}
54
+ contentEditable={editList[tabIndex]}
55
+ onInput={(e) => {
56
+ onEditLabel && onEditLabel(`${e.currentTarget.textContent}`, tabIndex)
57
+ }}
58
+ key={tab.key}
59
+ className={classNames(
60
+ tab.key === selectedKey
61
+ ? "border-transparent text-black bg-gray-100"
62
+ : "text-gray-500 hover:text-gray-700 hover:border-gray-300",
63
+ "whitespace-nowrap border-gray-300 py-1 px-2 border-t border-r border-b pr-6 text-sm cursor-pointer"
64
+ )}
65
+ />
66
+ ))}
67
+ </nav>
68
+ </div>
69
+ );
70
+ }
package/src/config.ts ADDED
@@ -0,0 +1,57 @@
1
+ import { DraggableFieldState, IStackMode } from "./interfaces";
2
+
3
+ export const GEMO_TYPES: Readonly<string[]> = [
4
+ 'auto',
5
+ 'bar',
6
+ 'line',
7
+ 'area',
8
+ 'trail',
9
+ 'point',
10
+ 'circle',
11
+ 'tick',
12
+ 'rect',
13
+ 'arc',
14
+ 'boxplot',
15
+ ] as const;
16
+
17
+ export const STACK_MODE: Readonly<IStackMode[]> = [
18
+ 'none',
19
+ 'stack',
20
+ 'normalize'
21
+ ]
22
+
23
+ export const CHART_LAYOUT_TYPE: Readonly<string[]> = [
24
+ 'auto',
25
+ 'fixed',
26
+ ] as const;
27
+
28
+ export const COLORS = {
29
+ // tableau style
30
+ // dimension: 'rgb(73, 150, 178)',
31
+ // measure: 'rgb(0, 177, 128)',
32
+ // dimension: 'rgb(86, 170, 208)',
33
+ // measure: 'rgb(232, 149, 72)'
34
+ dimension: 'rgba(0, 0, 0, 0.9)',
35
+ measure: 'rgba(10, 0, 0, 0.6)',
36
+ black: '#141414',
37
+ white: '#fafafa'
38
+ }
39
+
40
+ export const MAX_HISTORY_SIZE = 20;
41
+
42
+ export const CHANNEL_LIMIT = {
43
+ rows: Infinity,
44
+ columns: Infinity,
45
+ color: 1,
46
+ opacity: 1,
47
+ size: 1,
48
+ shape: 1,
49
+ theta: 1,
50
+ radius: 1
51
+ }
52
+
53
+ export const MetaFieldKeys: Array<keyof DraggableFieldState> = [
54
+ 'dimensions',
55
+ 'measures',
56
+ 'fields'
57
+ ]
@@ -0,0 +1 @@
1
+ export const COUNT_FIELD_ID = 'gw_count_fid';
@@ -0,0 +1,62 @@
1
+ export const DemoDataAssets = process.env.NODE_ENV === 'production' ? {
2
+ CARS: "https://chspace.oss-cn-hongkong.aliyuncs.com/api/ds-cars-service.json",
3
+ STUDENTS: "https://chspace.oss-cn-hongkong.aliyuncs.com/api/ds-students-service.json",
4
+ BTC_GOLD: "https://chspace.oss-cn-hongkong.aliyuncs.com/api/ds_btc_gold_service.json",
5
+ BIKE_SHARING: 'https://chspace.oss-cn-hongkong.aliyuncs.com/api/ds-bikesharing-service.json',
6
+ CAR_SALES: 'https://chspace.oss-cn-hongkong.aliyuncs.com/api/ds-carsales-service.json',
7
+ COLLAGE: 'https://chspace.oss-cn-hongkong.aliyuncs.com/api/ds-collage-service.json',
8
+ TITANIC: 'https://chspace.oss-cn-hongkong.aliyuncs.com/api/ds-titanic-service.json',
9
+ KELPER: 'https://chspace.oss-cn-hongkong.aliyuncs.com/api/ds-kelper-service.json',
10
+ } : {
11
+ // CARS: "https://chspace.oss-cn-hongkong.aliyuncs.com/api/ds-cars-service.json",
12
+ CARS: "/datasets/ds-cars-service.json",
13
+ // STUDENTS: "https://chspace.oss-cn-hongkong.aliyuncs.com/datasets/ds-students-service.json",
14
+ STUDENTS: "/datasets/ds-students-service.json",
15
+ BTC_GOLD: "/datasets/ds_btc_gold_service.json",
16
+ BIKE_SHARING: '/datasets/ds-bikesharing-service.json',
17
+ CAR_SALES: '/datasets/ds-carsales-service.json',
18
+ COLLAGE: '/datasets/ds-collage-service.json',
19
+ TITANIC: '/datasets/ds-titanic-service.json',
20
+ KELPER: '/datasets/ds-kelper-service.json',
21
+ } as const;
22
+
23
+ interface IPublicData {
24
+ key: string;
25
+ title: string;
26
+ desc?: string;
27
+ }
28
+
29
+ export const PUBLIC_DATA_LIST: IPublicData[] = [
30
+ {
31
+ key: "CARS",
32
+ title: "Cars",
33
+ },
34
+ {
35
+ key: "STUDENTS",
36
+ title: "Students' Performance"
37
+ },
38
+ {
39
+ key: "BIKE_SHARING",
40
+ title: "Bike Sharing"
41
+ },
42
+ {
43
+ key: "CAR_SALES",
44
+ title: "Car Sales"
45
+ },
46
+ {
47
+ key: "COLLAGE",
48
+ title: "Collage"
49
+ },
50
+ {
51
+ key: "KELPER",
52
+ title: "NASA Kelper"
53
+ },
54
+ {
55
+ key: 'BTC_GOLD',
56
+ title: "2022MCM Problem C: Trading Strategies"
57
+ },
58
+ {
59
+ key: "TITANIC",
60
+ title: "Titanic"
61
+ }
62
+ ]