@kanaries/graphic-walker 0.2.13 → 0.2.14
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 -2
- package/dist/assets/explainer.worker-8428eb12.js.map +1 -1
- package/dist/components/button/base.d.ts +1 -0
- package/dist/components/button/defaultMini.d.ts +4 -0
- package/dist/components/button/primaryMini.d.ts +4 -0
- package/dist/components/dropdownContext/index.d.ts +13 -0
- package/dist/components/dropdownSelect/index.d.ts +17 -0
- package/dist/components/modal.d.ts +1 -0
- package/dist/components/toolbar/toolbar-item.d.ts +1 -0
- package/dist/dataSource/dataSelection/config.d.ts +2 -0
- package/dist/dataSource/index.d.ts +1 -1
- package/dist/fields/datasetFields/dimFields.d.ts +2 -2
- package/dist/fields/datasetFields/meaFields.d.ts +2 -2
- package/dist/fields/encodeFields/singleEncodeDropDown.d.ts +17 -0
- package/dist/fields/encodeFields/singleEncodeEditor.d.ts +11 -0
- package/dist/fields/obComponents/obPill.d.ts +3 -3
- package/dist/graphic-walker.es.js +20874 -19172
- package/dist/graphic-walker.es.js.map +1 -1
- package/dist/graphic-walker.umd.js +245 -170
- package/dist/graphic-walker.umd.js.map +1 -1
- package/dist/insightBoard/index.d.ts +1 -1
- package/dist/interfaces.d.ts +1 -0
- package/dist/renderer/index.d.ts +3 -1
- package/dist/store/visualSpecStore.d.ts +1 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/media.d.ts +2 -0
- package/dist/vis/react-vega.d.ts +2 -0
- package/dist/vis/theme.d.ts +130 -0
- package/package.json +2 -1
- package/src/App.tsx +8 -5
- package/src/components/button/base.ts +1 -0
- package/src/components/button/default.tsx +6 -2
- package/src/components/button/defaultMini.tsx +17 -0
- package/src/components/button/primary.tsx +6 -2
- package/src/components/button/primaryMini.tsx +21 -0
- package/src/components/callout.tsx +4 -1
- package/src/components/clickMenu.tsx +4 -2
- package/src/components/container.tsx +9 -0
- package/src/components/dataTable/index.tsx +42 -52
- package/src/components/dataTable/pagination.tsx +4 -4
- package/src/components/dataTypeIcon.tsx +1 -1
- package/src/components/dropdownContext/index.tsx +64 -0
- package/src/components/dropdownSelect/index.tsx +92 -0
- package/src/components/modal.tsx +26 -14
- package/src/components/tabs/defaultTab.tsx +4 -4
- package/src/components/tabs/editableTab.tsx +5 -5
- package/src/components/toolbar/components.tsx +18 -1
- package/src/components/toolbar/index.tsx +5 -0
- package/src/components/toolbar/toolbar-button.tsx +6 -1
- package/src/components/toolbar/toolbar-item.tsx +4 -0
- package/src/components/toolbar/toolbar-select-button.tsx +21 -4
- package/src/components/toolbar/toolbar-toggle-button.tsx +6 -1
- package/src/components/tooltip.tsx +4 -1
- package/src/dataSource/dataSelection/config.ts +28 -0
- package/src/dataSource/dataSelection/csvData.tsx +77 -32
- package/src/dataSource/dataSelection/gwFile.tsx +0 -8
- package/src/dataSource/dataSelection/index.tsx +1 -2
- package/src/dataSource/dataSelection/publicData.tsx +2 -3
- package/src/dataSource/index.tsx +81 -61
- package/src/fields/aestheticFields.tsx +3 -1
- package/src/fields/components.tsx +21 -2
- package/src/fields/datasetFields/dimFields.tsx +43 -35
- package/src/fields/datasetFields/index.tsx +2 -2
- package/src/fields/datasetFields/meaFields.tsx +73 -47
- package/src/fields/encodeFields/singleEncodeDropDown.tsx +92 -0
- package/src/fields/encodeFields/singleEncodeEditor.tsx +78 -0
- package/src/fields/filterField/filterEditDialog.tsx +2 -1
- package/src/fields/filterField/filterPill.tsx +1 -1
- package/src/fields/filterField/slider.tsx +1 -1
- package/src/fields/filterField/tabs.tsx +11 -21
- package/src/fields/obComponents/obPill.tsx +65 -35
- package/src/index.css +13 -0
- package/src/insightBoard/index.tsx +24 -23
- package/src/insightBoard/radioGroupButtons.tsx +7 -0
- package/src/interfaces.ts +1 -0
- package/src/lib/inferMeta.ts +1 -1
- package/src/locales/en-US.json +7 -4
- package/src/locales/zh-CN.json +5 -2
- package/src/main.tsx +1 -1
- package/src/renderer/index.tsx +2 -1
- package/src/store/visualSpecStore.ts +16 -0
- package/src/utils/index.ts +19 -0
- package/src/utils/media.ts +26 -0
- package/src/utils/normalization.ts +2 -1
- package/src/vis/react-vega.tsx +20 -4
- package/src/vis/theme.ts +126 -0
- package/src/visualSettings/index.tsx +24 -8
package/src/vis/react-vega.tsx
CHANGED
|
@@ -11,6 +11,8 @@ import { COUNT_FIELD_ID } from '../constants';
|
|
|
11
11
|
import { IViewField, IRow, IStackMode } from '../interfaces';
|
|
12
12
|
import { useTranslation } from 'react-i18next';
|
|
13
13
|
import { getVegaTimeFormatRules } from './temporalFormat';
|
|
14
|
+
import { builtInThemes } from './theme';
|
|
15
|
+
import { useCurrentMediaTheme } from '../utils/media';
|
|
14
16
|
|
|
15
17
|
const CanvaContainer = styled.div<{rowSize: number; colSize: number;}>`
|
|
16
18
|
display: grid;
|
|
@@ -46,6 +48,8 @@ interface ReactVegaProps {
|
|
|
46
48
|
onGeomClick?: (values: any, e: any) => void
|
|
47
49
|
selectEncoding: SingleViewProps['selectEncoding'];
|
|
48
50
|
brushEncoding: SingleViewProps['brushEncoding'];
|
|
51
|
+
/** @default "vega" */
|
|
52
|
+
themeKey?: 'vega' | 'g2';
|
|
49
53
|
}
|
|
50
54
|
const NULL_FIELD: IViewField = {
|
|
51
55
|
dragId: '',
|
|
@@ -119,7 +123,15 @@ function channelEncode(props: EncodeProps) {
|
|
|
119
123
|
encoding[c] = {
|
|
120
124
|
field: props[c].fid,
|
|
121
125
|
title: props[c].name,
|
|
122
|
-
type: props[c].semanticType
|
|
126
|
+
type: props[c].semanticType,
|
|
127
|
+
}
|
|
128
|
+
if (props[c].analyticType !== 'measure') {
|
|
129
|
+
// if `aggregate` is set to null,
|
|
130
|
+
// do not aggregate this field
|
|
131
|
+
encoding[c].aggregate = null;
|
|
132
|
+
}
|
|
133
|
+
if (props[c].analyticType === 'measure') {
|
|
134
|
+
encoding[c].type = 'quantitative'
|
|
123
135
|
}
|
|
124
136
|
}
|
|
125
137
|
})
|
|
@@ -143,7 +155,7 @@ function channelEncode(props: EncodeProps) {
|
|
|
143
155
|
}
|
|
144
156
|
function channelAggregate(encoding: {[key: string]: any}, fields: IViewField[]) {
|
|
145
157
|
Object.values(encoding).forEach(c => {
|
|
146
|
-
const targetField = fields.find(f => f.fid === c.field);
|
|
158
|
+
const targetField = fields.find(f => f.fid === c.field && !('aggregate' in c));
|
|
147
159
|
if (targetField && targetField.fid === COUNT_FIELD_ID) {
|
|
148
160
|
c.field = undefined;
|
|
149
161
|
c.aggregate = 'count';
|
|
@@ -378,11 +390,14 @@ const ReactVega = forwardRef<IReactVegaHandler, ReactVegaProps>(function ReactVe
|
|
|
378
390
|
height,
|
|
379
391
|
selectEncoding,
|
|
380
392
|
brushEncoding,
|
|
393
|
+
themeKey = 'vega',
|
|
381
394
|
} = props;
|
|
382
395
|
// const container = useRef<HTMLDivElement>(null);
|
|
383
396
|
// const containers = useRef<(HTMLDivElement | null)[]>([]);
|
|
384
397
|
const [viewPlaceholders, setViewPlaceholders] = useState<React.MutableRefObject<HTMLDivElement>[]>([]);
|
|
385
398
|
const { i18n } = useTranslation();
|
|
399
|
+
const mediaTheme = useCurrentMediaTheme();
|
|
400
|
+
const themeConfig = builtInThemes[themeKey]?.[mediaTheme];
|
|
386
401
|
useEffect(() => {
|
|
387
402
|
const clickSub = geomClick$.subscribe(([values, e]) => {
|
|
388
403
|
if (onGeomClick) {
|
|
@@ -502,7 +517,7 @@ const ReactVega = forwardRef<IReactVegaHandler, ReactVegaProps>(function ReactVe
|
|
|
502
517
|
spec.params.push(...singleView.params!);
|
|
503
518
|
}
|
|
504
519
|
if (viewPlaceholders.length > 0 && viewPlaceholders[0].current) {
|
|
505
|
-
embed(viewPlaceholders[0].current, spec, { mode: 'vega-lite', actions: showActions, timeFormatLocale: getVegaTimeFormatRules(i18n.language) }).then(res => {
|
|
520
|
+
embed(viewPlaceholders[0].current, spec, { mode: 'vega-lite', actions: showActions, timeFormatLocale: getVegaTimeFormatRules(i18n.language), config: themeConfig }).then(res => {
|
|
506
521
|
vegaRefs.current = [res.view];
|
|
507
522
|
try {
|
|
508
523
|
res.view.addEventListener('click', (e) => {
|
|
@@ -583,7 +598,7 @@ const ReactVega = forwardRef<IReactVegaHandler, ReactVegaProps>(function ReactVe
|
|
|
583
598
|
ans.params = commonSpec.params;
|
|
584
599
|
}
|
|
585
600
|
if (node) {
|
|
586
|
-
embed(node, ans, { mode: 'vega-lite', actions: showActions, timeFormatLocale: getVegaTimeFormatRules(i18n.language) }).then(res => {
|
|
601
|
+
embed(node, ans, { mode: 'vega-lite', actions: showActions, timeFormatLocale: getVegaTimeFormatRules(i18n.language), config: themeConfig }).then(res => {
|
|
587
602
|
vegaRefs.current.push(res.view);
|
|
588
603
|
const paramStores = (res.vgSpec.data?.map(d => d.name) ?? []).filter(
|
|
589
604
|
name => [BRUSH_SIGNAL_NAME, POINT_SIGNAL_NAME].map(p => `${p}_store`).includes(name)
|
|
@@ -673,6 +688,7 @@ const ReactVega = forwardRef<IReactVegaHandler, ReactVegaProps>(function ReactVe
|
|
|
673
688
|
selectEncoding,
|
|
674
689
|
brushEncoding,
|
|
675
690
|
crossFilterTriggerIdx,
|
|
691
|
+
themeConfig,
|
|
676
692
|
]);
|
|
677
693
|
|
|
678
694
|
useImperativeHandle(ref, () => ({
|
package/src/vis/theme.ts
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
const DEFAULT_COLOR = "#5B8FF9";
|
|
2
|
+
|
|
3
|
+
export const VegaTheme = {
|
|
4
|
+
light: {
|
|
5
|
+
background: "transparent",
|
|
6
|
+
},
|
|
7
|
+
dark: {
|
|
8
|
+
background: "transparent",
|
|
9
|
+
axis: {
|
|
10
|
+
gridColor: "#666",
|
|
11
|
+
domainColor: "#d1d5db", // change axis color to white
|
|
12
|
+
tickColor: "#d1d5db", // change tick color to white
|
|
13
|
+
labelColor: "#d1d5db", // change label color to white
|
|
14
|
+
},
|
|
15
|
+
legend: {
|
|
16
|
+
labelColor: "#d1d5db", // change legend label color to white
|
|
17
|
+
titleColor: "#d1d5db" // change legend title color to white
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
} as const;
|
|
21
|
+
|
|
22
|
+
export const AntVTheme = {
|
|
23
|
+
light: {
|
|
24
|
+
area: { fill: DEFAULT_COLOR },
|
|
25
|
+
bar: { fill: DEFAULT_COLOR },
|
|
26
|
+
circle: { fill: DEFAULT_COLOR },
|
|
27
|
+
line: { stroke: DEFAULT_COLOR },
|
|
28
|
+
point: { stroke: DEFAULT_COLOR },
|
|
29
|
+
rect: { fill: DEFAULT_COLOR },
|
|
30
|
+
tick: { stroke: DEFAULT_COLOR },
|
|
31
|
+
boxplot: { fill: DEFAULT_COLOR },
|
|
32
|
+
errorbar: { stroke: DEFAULT_COLOR },
|
|
33
|
+
errorband: { fill: DEFAULT_COLOR },
|
|
34
|
+
arc: { fill: DEFAULT_COLOR },
|
|
35
|
+
background: "transparent",
|
|
36
|
+
range: {
|
|
37
|
+
category: [
|
|
38
|
+
"#5B8FF9",
|
|
39
|
+
"#61DDAA",
|
|
40
|
+
"#65789B",
|
|
41
|
+
"#F6BD16",
|
|
42
|
+
"#7262FD",
|
|
43
|
+
"#78D3F8",
|
|
44
|
+
"#9661BC",
|
|
45
|
+
"#F6903D",
|
|
46
|
+
"#008685",
|
|
47
|
+
"#F08BB4",
|
|
48
|
+
],
|
|
49
|
+
diverging: ["#7b3294", "#c2a5cf", "#f7f7f7", "#a6dba0", "#008837"],
|
|
50
|
+
heatmap: ["#000000", "#7b3294", "#c2a5cf", "#f7f7f7", "#a6dba0", "#008837"],
|
|
51
|
+
ramp: [
|
|
52
|
+
"#EBCCFF",
|
|
53
|
+
"#CCB0FF",
|
|
54
|
+
"#AE95FF",
|
|
55
|
+
"#907BFF",
|
|
56
|
+
"#7262FD",
|
|
57
|
+
"#5349E0",
|
|
58
|
+
"#2F32C3",
|
|
59
|
+
"#001BA7",
|
|
60
|
+
"#00068C"
|
|
61
|
+
],
|
|
62
|
+
},
|
|
63
|
+
scale: {
|
|
64
|
+
continuous: { range: ["#f7fbff", "#08306b"] },
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
dark: {
|
|
68
|
+
area: { fill: DEFAULT_COLOR },
|
|
69
|
+
bar: { fill: DEFAULT_COLOR },
|
|
70
|
+
circle: { fill: DEFAULT_COLOR },
|
|
71
|
+
line: { stroke: DEFAULT_COLOR },
|
|
72
|
+
point: { stroke: DEFAULT_COLOR },
|
|
73
|
+
rect: { fill: DEFAULT_COLOR },
|
|
74
|
+
tick: { stroke: DEFAULT_COLOR },
|
|
75
|
+
boxplot: { fill: DEFAULT_COLOR },
|
|
76
|
+
errorbar: { stroke: DEFAULT_COLOR },
|
|
77
|
+
errorband: { fill: DEFAULT_COLOR },
|
|
78
|
+
arc: { fill: DEFAULT_COLOR },
|
|
79
|
+
background: "transparent", // change background color to dark gray
|
|
80
|
+
axis: {
|
|
81
|
+
gridColor: "#666",
|
|
82
|
+
domainColor: "#d1d5db", // change axis color to white
|
|
83
|
+
tickColor: "#d1d5db", // change tick color to white
|
|
84
|
+
labelColor: "#d1d5db", // change label color to white
|
|
85
|
+
},
|
|
86
|
+
legend: {
|
|
87
|
+
labelColor: "#d1d5db", // change legend label color to white
|
|
88
|
+
titleColor: "#d1d5db" // change legend title color to white
|
|
89
|
+
},
|
|
90
|
+
range: {
|
|
91
|
+
category: [
|
|
92
|
+
"#5B8FF9",
|
|
93
|
+
"#61DDAA",
|
|
94
|
+
"#65789B",
|
|
95
|
+
"#F6BD16",
|
|
96
|
+
"#7262FD",
|
|
97
|
+
"#78D3F8",
|
|
98
|
+
"#9661BC",
|
|
99
|
+
"#F6903D",
|
|
100
|
+
"#008685",
|
|
101
|
+
"#F08BB4",
|
|
102
|
+
],
|
|
103
|
+
diverging: ["#7b3294", "#c2a5cf", "#f7f7f7", "#a6dba0", "#008837"],
|
|
104
|
+
heatmap: ["#000000", "#7b3294", "#c2a5cf", "#f7f7f7", "#a6dba0", "#008837"],
|
|
105
|
+
ramp: [
|
|
106
|
+
"#EBCCFF",
|
|
107
|
+
"#CCB0FF",
|
|
108
|
+
"#AE95FF",
|
|
109
|
+
"#907BFF",
|
|
110
|
+
"#7262FD",
|
|
111
|
+
"#5349E0",
|
|
112
|
+
"#2F32C3",
|
|
113
|
+
"#001BA7",
|
|
114
|
+
"#00068C"
|
|
115
|
+
],
|
|
116
|
+
},
|
|
117
|
+
scale: {
|
|
118
|
+
continuous: { range: ["#f7fbff", "#08306b"] },
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
} as const;
|
|
122
|
+
|
|
123
|
+
export const builtInThemes: { [themeKey: string]: { light: any; dark: any; } } = {
|
|
124
|
+
vega: VegaTheme,
|
|
125
|
+
g2: AntVTheme,
|
|
126
|
+
};
|
|
@@ -41,6 +41,10 @@ export const LiteContainer = styled.div`
|
|
|
41
41
|
border: 1px solid #e5e7eb;
|
|
42
42
|
padding: 1em;
|
|
43
43
|
background-color: #fff;
|
|
44
|
+
@media (prefers-color-scheme: dark) {
|
|
45
|
+
background-color: #000;
|
|
46
|
+
border: 1px solid #4b5563;
|
|
47
|
+
}
|
|
44
48
|
.menu-root {
|
|
45
49
|
position: relative;
|
|
46
50
|
& > *:not(.trigger) {
|
|
@@ -74,6 +78,10 @@ const FormContainer = styled.div`
|
|
|
74
78
|
padding: 0.5em;
|
|
75
79
|
display: flex;
|
|
76
80
|
flex-direction: column;
|
|
81
|
+
color: #444;
|
|
82
|
+
@media (prefers-color-scheme: dark) {
|
|
83
|
+
color: #aaa;
|
|
84
|
+
}
|
|
77
85
|
`;
|
|
78
86
|
|
|
79
87
|
interface IVisualSettings {
|
|
@@ -153,6 +161,11 @@ const VisualSettings: React.FC<IVisualSettings> = ({ rendererHandler }) => {
|
|
|
153
161
|
key: 'mark_type',
|
|
154
162
|
label: tGlobal('constant.mark_type.__enum__'),
|
|
155
163
|
icon: StopIcon,
|
|
164
|
+
styles: {
|
|
165
|
+
icon: {
|
|
166
|
+
color: 'rgb(294,115,22)',
|
|
167
|
+
},
|
|
168
|
+
},
|
|
156
169
|
options: GEMO_TYPES.map(g => ({
|
|
157
170
|
key: g,
|
|
158
171
|
label: tGlobal(`constant.mark_type.${g}`),
|
|
@@ -327,14 +340,14 @@ const VisualSettings: React.FC<IVisualSettings> = ({ rendererHandler }) => {
|
|
|
327
340
|
form: (
|
|
328
341
|
<FormContainer>
|
|
329
342
|
<button
|
|
330
|
-
className="text-xs pt-1 pb-1 pl-6 pr-6 bg-white hover:bg-gray-200"
|
|
343
|
+
className="text-xs pt-1 pb-1 pl-6 pr-6 bg-white dark:bg-zinc-900 hover:bg-gray-200 text-gray-800 dark:text-gray-100 dark:hover:bg-gray-700"
|
|
331
344
|
aria-label={t('button.export_chart_as', { type: 'png' })}
|
|
332
345
|
onClick={() => downloadPNG()}
|
|
333
346
|
>
|
|
334
347
|
{t('button.export_chart_as', { type: 'png' })}
|
|
335
348
|
</button>
|
|
336
349
|
<button
|
|
337
|
-
className="text-xs pt-1 pb-1 pl-6 pr-6 bg-white hover:bg-gray-200"
|
|
350
|
+
className="text-xs pt-1 pb-1 pl-6 pr-6 bg-white dark:bg-zinc-900 hover:bg-gray-200 text-gray-800 dark:text-gray-100 dark:hover:bg-gray-700"
|
|
338
351
|
aria-label={t('button.export_chart_as', { type: 'svg' })}
|
|
339
352
|
onClick={() => downloadSVG()}
|
|
340
353
|
>
|
|
@@ -343,7 +356,7 @@ const VisualSettings: React.FC<IVisualSettings> = ({ rendererHandler }) => {
|
|
|
343
356
|
</FormContainer>
|
|
344
357
|
),
|
|
345
358
|
},
|
|
346
|
-
];
|
|
359
|
+
] as ToolbarItemProps[];
|
|
347
360
|
}, [vizStore, canUndo, canRedo, defaultAggregated, markType, stack, interactiveScale, sizeMode, width, height, explorationMode, brushDirection, showActions, downloadPNG, downloadSVG]);
|
|
348
361
|
|
|
349
362
|
return <div style={{ margin: '0.38em 0.28em 0.2em 0.18em' }}>
|
|
@@ -352,15 +365,18 @@ const VisualSettings: React.FC<IVisualSettings> = ({ rendererHandler }) => {
|
|
|
352
365
|
styles={{
|
|
353
366
|
root: {
|
|
354
367
|
'--background-color': '#fff',
|
|
368
|
+
'--dark-background-color': '#000',
|
|
355
369
|
'--color': '#777',
|
|
356
370
|
'--color-hover': '#555',
|
|
357
|
-
'--
|
|
358
|
-
'--
|
|
371
|
+
'--dark-color': '#999',
|
|
372
|
+
'--dark-color-hover': '#bbb',
|
|
373
|
+
'--blue': 'rgb(79,70,229)',
|
|
374
|
+
'--blue-dark': 'rgb(9, 6, 65)',
|
|
359
375
|
},
|
|
360
376
|
container: {
|
|
361
|
-
border: '1px solid #e5e7eb',
|
|
362
|
-
boxSizing: 'content-box',
|
|
363
|
-
borderRadius: '1px',
|
|
377
|
+
// border: '1px solid #e5e7eb',
|
|
378
|
+
// boxSizing: 'content-box',
|
|
379
|
+
// borderRadius: '1px',
|
|
364
380
|
},
|
|
365
381
|
}}
|
|
366
382
|
/>
|