@kanaries/graphic-walker 0.2.14 → 0.2.15
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 +3 -2
- package/dist/components/callout.d.ts +2 -0
- 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/fields/components.d.ts +0 -1
- package/dist/fields/filterField/filterEditDialog.d.ts +1 -1
- package/dist/graphic-walker.es.js +15103 -14997
- package/dist/graphic-walker.es.js.map +1 -1
- package/dist/graphic-walker.umd.js +134 -264
- package/dist/graphic-walker.umd.js.map +1 -1
- package/dist/interfaces.d.ts +2 -0
- package/dist/renderer/index.d.ts +6 -4
- package/dist/utils/media.d.ts +2 -1
- package/dist/vis/react-vega.d.ts +4 -2
- package/dist/vis/theme.d.ts +36 -20
- package/dist/visualSettings/index.d.ts +2 -1
- package/package.json +1 -1
- package/src/App.tsx +19 -14
- package/src/components/callout.tsx +9 -7
- package/src/components/clickMenu.tsx +1 -7
- package/src/components/modal.tsx +1 -15
- package/src/components/sizeSetting.tsx +2 -2
- package/src/components/tabs/editableTab.tsx +2 -2
- 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/csvData.tsx +1 -1
- package/src/dataSource/index.tsx +2 -3
- package/src/fields/components.tsx +13 -50
- package/src/fields/datasetFields/index.tsx +3 -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/insightBoard/mainBoard.tsx +9 -2
- package/src/interfaces.ts +4 -1
- package/src/locales/en-US.json +5 -2
- package/src/locales/i18n.ts +7 -0
- package/src/locales/ja-JP.json +195 -0
- package/src/locales/zh-CN.json +5 -2
- package/src/renderer/index.tsx +96 -71
- package/src/utils/media.ts +16 -11
- package/src/vis/react-vega.tsx +18 -3
- package/src/vis/theme.ts +23 -25
- package/src/visualSettings/index.tsx +12 -32
- package/dist/components/container.d.ts +0 -2
- package/src/components/container.tsx +0 -25
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
{
|
|
2
|
+
"constant": {
|
|
3
|
+
"row_count": "行数",
|
|
4
|
+
"analytic_type": {
|
|
5
|
+
"dimension": "次元",
|
|
6
|
+
"measure": "尺度"
|
|
7
|
+
},
|
|
8
|
+
"semantic_type": {
|
|
9
|
+
"nominal": "名義尺度",
|
|
10
|
+
"ordinal": "順序尺度",
|
|
11
|
+
"temporal": "時間尺度",
|
|
12
|
+
"quantitative": "数量尺度"
|
|
13
|
+
},
|
|
14
|
+
"mark_type": {
|
|
15
|
+
"__enum__": "マークタイプ",
|
|
16
|
+
"auto": "自動",
|
|
17
|
+
"bar": "バー",
|
|
18
|
+
"line": "ライン",
|
|
19
|
+
"area": "エリア",
|
|
20
|
+
"trail": "トレイル",
|
|
21
|
+
"point": "散布図",
|
|
22
|
+
"circle": "円",
|
|
23
|
+
"tick": "棒線図",
|
|
24
|
+
"rect": "長方形",
|
|
25
|
+
"arc": "アーク",
|
|
26
|
+
"boxplot": "ボックスプロット"
|
|
27
|
+
},
|
|
28
|
+
"stack_mode": {
|
|
29
|
+
"__enum__": "スタックモード",
|
|
30
|
+
"none": "なし",
|
|
31
|
+
"stack": "スタック",
|
|
32
|
+
"normalize": "正規化"
|
|
33
|
+
},
|
|
34
|
+
"layout_type": {
|
|
35
|
+
"__enum__": "レイアウトタイプ",
|
|
36
|
+
"auto": "自動",
|
|
37
|
+
"fixed": "固定"
|
|
38
|
+
},
|
|
39
|
+
"exploration_mode": {
|
|
40
|
+
"__enum__": "探索モード",
|
|
41
|
+
"none": "オフ",
|
|
42
|
+
"brush": "ブラシ",
|
|
43
|
+
"point": "ポイント"
|
|
44
|
+
},
|
|
45
|
+
"brush_mode": {
|
|
46
|
+
"__enum__": "ブラシの方向",
|
|
47
|
+
"default": "両方",
|
|
48
|
+
"x": "X軸のみ",
|
|
49
|
+
"y": "Y軸のみ"
|
|
50
|
+
},
|
|
51
|
+
"draggable_key": {
|
|
52
|
+
"fields": "フィールド",
|
|
53
|
+
"columns": "X軸",
|
|
54
|
+
"rows": "Y軸",
|
|
55
|
+
"color": "色",
|
|
56
|
+
"opacity": "不透明度",
|
|
57
|
+
"size": "大きさ",
|
|
58
|
+
"shape": "形状",
|
|
59
|
+
"theta": "角度",
|
|
60
|
+
"radius": "半径",
|
|
61
|
+
"filters": "フィルター"
|
|
62
|
+
},
|
|
63
|
+
"aggregator": {
|
|
64
|
+
"sum": "合計",
|
|
65
|
+
"mean": "平均",
|
|
66
|
+
"count": "件数",
|
|
67
|
+
"median": "中央値",
|
|
68
|
+
"min": "最小値",
|
|
69
|
+
"max": "最大値",
|
|
70
|
+
"q1": "第一四分位数",
|
|
71
|
+
"q3": "第三四分位数",
|
|
72
|
+
"stdev": "標準偏差",
|
|
73
|
+
"variance": "分散"
|
|
74
|
+
},
|
|
75
|
+
"filter_type": {
|
|
76
|
+
"one_of": "1つ以上",
|
|
77
|
+
"range": "範囲",
|
|
78
|
+
"temporal_range": "日付範囲"
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
"App": {
|
|
82
|
+
"labels": {
|
|
83
|
+
"data_interpretation": "データ解釈"
|
|
84
|
+
},
|
|
85
|
+
"segments": {
|
|
86
|
+
"vis": "可視化",
|
|
87
|
+
"data": "データ"
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
"DataSource": {
|
|
91
|
+
"labels": {
|
|
92
|
+
"cur_dataset": "現在のデータセット"
|
|
93
|
+
},
|
|
94
|
+
"buttons": {
|
|
95
|
+
"create_dataset": "データセットを作成",
|
|
96
|
+
"export_as_file": "ファイルとして保存",
|
|
97
|
+
"import_file": "Graphic Walkerファイルをインポート"
|
|
98
|
+
},
|
|
99
|
+
"dialog": {
|
|
100
|
+
"create_data_source": "新しいデータソース",
|
|
101
|
+
"data_types": "データソースの種類",
|
|
102
|
+
"text_file_data": "ローカルファイル",
|
|
103
|
+
"public_data": "公開データセット",
|
|
104
|
+
"data_source_type": "データソースの種類:{{sourceType}}",
|
|
105
|
+
"file": {
|
|
106
|
+
"open": "開く...",
|
|
107
|
+
"submit": "提出する",
|
|
108
|
+
"dataset_name": "データセット名",
|
|
109
|
+
"choose_file": "データファイルを選択してください",
|
|
110
|
+
"get_start_desc": "データセットの作成を始めましょう。"
|
|
111
|
+
},
|
|
112
|
+
"public": {
|
|
113
|
+
"submit": "提出する"
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
"main": {
|
|
118
|
+
"tablist": {
|
|
119
|
+
"new": "+ 新規作成",
|
|
120
|
+
"autoTitle": "グラフ {{idx}}"
|
|
121
|
+
},
|
|
122
|
+
"tabpanel": {
|
|
123
|
+
"menubar": {
|
|
124
|
+
"undo": "元に戻す",
|
|
125
|
+
"redo": "やり直し"
|
|
126
|
+
},
|
|
127
|
+
"settings": {
|
|
128
|
+
"toggle": {
|
|
129
|
+
"aggregation": "集計",
|
|
130
|
+
"stack": "スタック",
|
|
131
|
+
"axes_resize": "軸のサイズ変更",
|
|
132
|
+
"debug": "デバッグ"
|
|
133
|
+
},
|
|
134
|
+
"sort": "並べ替えの順序",
|
|
135
|
+
"button": {
|
|
136
|
+
"ascending": "昇順に並べ替える",
|
|
137
|
+
"descending": "降順に並べ替える",
|
|
138
|
+
"transpose": "転置",
|
|
139
|
+
"export_chart": "エクスポート",
|
|
140
|
+
"export_chart_as": "{{type}}としてエクスポート"
|
|
141
|
+
},
|
|
142
|
+
"size": "サイズ変更",
|
|
143
|
+
"size_setting": {
|
|
144
|
+
"width": "幅",
|
|
145
|
+
"height": "高さ"
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
"DatasetFields": {
|
|
149
|
+
"field_list": "フィールド一覧"
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
"filters": {
|
|
154
|
+
"to_edit": "このルールを編集",
|
|
155
|
+
"empty_rule": "! (空のルール)",
|
|
156
|
+
"editing": "ルールを編集",
|
|
157
|
+
"form": {
|
|
158
|
+
"name": "フィールド",
|
|
159
|
+
"rule": "ルール"
|
|
160
|
+
},
|
|
161
|
+
"header": {
|
|
162
|
+
"visibility": "表示",
|
|
163
|
+
"value": "ラベル",
|
|
164
|
+
"count": "件数"
|
|
165
|
+
},
|
|
166
|
+
"selected_keys": "{{ count }}件が選択されました",
|
|
167
|
+
"btn": {
|
|
168
|
+
"select_all": "すべて選択",
|
|
169
|
+
"unselect_all": "すべての選択を解除",
|
|
170
|
+
"reverse": "選択を反転する",
|
|
171
|
+
"confirm": "確認",
|
|
172
|
+
"cancel": "キャンセル"
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
"explain": {
|
|
176
|
+
"lg_than": "より大きい",
|
|
177
|
+
"sm_than": "より小さい",
|
|
178
|
+
"expection": "期待値",
|
|
179
|
+
"unrecognized": "未認識",
|
|
180
|
+
"score": "スコア",
|
|
181
|
+
"contains": "を含む",
|
|
182
|
+
"reason": {
|
|
183
|
+
"selection_dim_distribution": "次元のヒント",
|
|
184
|
+
"selection_mea_distribution": "尺度のヒント",
|
|
185
|
+
"children_major_factor": "主要要因",
|
|
186
|
+
"children_outlier": "外れ値"
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
"actions": {
|
|
190
|
+
"prev": "前へ",
|
|
191
|
+
"next": "次へ",
|
|
192
|
+
"drop_field": "ここにフィールドをドロップ",
|
|
193
|
+
"confirm": "確認"
|
|
194
|
+
}
|
|
195
|
+
}
|
package/src/locales/zh-CN.json
CHANGED
|
@@ -167,7 +167,9 @@
|
|
|
167
167
|
"btn": {
|
|
168
168
|
"select_all": "全部选中",
|
|
169
169
|
"unselect_all": "全部取消",
|
|
170
|
-
"reverse": "选择反向"
|
|
170
|
+
"reverse": "选择反向",
|
|
171
|
+
"confirm": "确认",
|
|
172
|
+
"cancel": "取消"
|
|
171
173
|
}
|
|
172
174
|
},
|
|
173
175
|
"explain": {
|
|
@@ -187,6 +189,7 @@
|
|
|
187
189
|
"actions": {
|
|
188
190
|
"prev": "向前",
|
|
189
191
|
"next": "向后",
|
|
190
|
-
"drop_field": "拖拽字段至此"
|
|
192
|
+
"drop_field": "拖拽字段至此",
|
|
193
|
+
"confirm": "确认"
|
|
191
194
|
}
|
|
192
195
|
}
|
package/src/renderer/index.tsx
CHANGED
|
@@ -1,44 +1,50 @@
|
|
|
1
|
-
import { runInAction, toJS } from
|
|
2
|
-
import { observer } from
|
|
3
|
-
import { Resizable } from
|
|
4
|
-
import React, { useState, useCallback, useEffect, useRef, forwardRef } from
|
|
5
|
-
import { applyFilter } from
|
|
6
|
-
import { useGlobalStore } from
|
|
7
|
-
import ReactVega, { IReactVegaHandler } from
|
|
1
|
+
import { runInAction, toJS } from "mobx";
|
|
2
|
+
import { observer } from "mobx-react-lite";
|
|
3
|
+
import { Resizable } from "re-resizable";
|
|
4
|
+
import React, { useState, useCallback, useEffect, useRef, forwardRef } from "react";
|
|
5
|
+
import { applyFilter } from "../services";
|
|
6
|
+
import { useGlobalStore } from "../store";
|
|
7
|
+
import ReactVega, { IReactVegaHandler } from "../vis/react-vega";
|
|
8
|
+
import { IDarkMode, IThemeKey } from "../interfaces";
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
const ReactiveRenderer = forwardRef<IReactVegaHandler, { themeKey?: IThemeKey; dark?: IDarkMode }>(function ReactiveRenderer(
|
|
11
|
+
{ themeKey, dark },
|
|
12
|
+
ref
|
|
13
|
+
) {
|
|
11
14
|
const { vizStore, commonStore } = useGlobalStore();
|
|
12
15
|
const { draggableFieldState, visualConfig } = vizStore;
|
|
13
16
|
const { geoms, interactiveScale, defaultAggregated, stack, showActions, size, exploration } = visualConfig;
|
|
14
17
|
const { currentDataset } = commonStore;
|
|
15
18
|
const { filters } = draggableFieldState;
|
|
16
19
|
|
|
17
|
-
const rows = toJS(draggableFieldState.rows)
|
|
18
|
-
const columns = toJS(draggableFieldState.columns)
|
|
19
|
-
const color = toJS(draggableFieldState.color)
|
|
20
|
-
const opacity = toJS(draggableFieldState.opacity)
|
|
21
|
-
const shape = toJS(draggableFieldState.shape)
|
|
22
|
-
const theta = toJS(draggableFieldState.theta)
|
|
23
|
-
const radius = toJS(draggableFieldState.radius)
|
|
24
|
-
const sizeChannel = toJS(draggableFieldState.size)
|
|
20
|
+
const rows = toJS(draggableFieldState.rows);
|
|
21
|
+
const columns = toJS(draggableFieldState.columns);
|
|
22
|
+
const color = toJS(draggableFieldState.color);
|
|
23
|
+
const opacity = toJS(draggableFieldState.opacity);
|
|
24
|
+
const shape = toJS(draggableFieldState.shape);
|
|
25
|
+
const theta = toJS(draggableFieldState.theta);
|
|
26
|
+
const radius = toJS(draggableFieldState.radius);
|
|
27
|
+
const sizeChannel = toJS(draggableFieldState.size);
|
|
25
28
|
|
|
26
|
-
const rowLeftFacetFields = rows.slice(0, -1).filter(f => f.analyticType ===
|
|
27
|
-
const colLeftFacetFields = columns.slice(0, -1).filter(f => f.analyticType ===
|
|
29
|
+
const rowLeftFacetFields = rows.slice(0, -1).filter((f) => f.analyticType === "dimension");
|
|
30
|
+
const colLeftFacetFields = columns.slice(0, -1).filter((f) => f.analyticType === "dimension");
|
|
28
31
|
|
|
29
32
|
const hasFacet = rowLeftFacetFields.length > 0 || colLeftFacetFields.length > 0;
|
|
30
33
|
|
|
31
|
-
const shouldTriggerMenu = exploration.mode ===
|
|
32
|
-
|
|
33
|
-
const handleGeomClick = useCallback(
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
34
|
+
const shouldTriggerMenu = exploration.mode === "none";
|
|
35
|
+
|
|
36
|
+
const handleGeomClick = useCallback(
|
|
37
|
+
(values: any, e: any) => {
|
|
38
|
+
if (shouldTriggerMenu) {
|
|
39
|
+
e.stopPropagation();
|
|
40
|
+
runInAction(() => {
|
|
41
|
+
commonStore.showEmbededMenu([e.pageX, e.pageY]);
|
|
42
|
+
commonStore.setFilters(values);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
[shouldTriggerMenu]
|
|
47
|
+
);
|
|
42
48
|
|
|
43
49
|
// apply filters
|
|
44
50
|
const { dataSource } = currentDataset;
|
|
@@ -54,14 +60,14 @@ const ReactiveRenderer = forwardRef<IReactVegaHandler, { themeKey?: 'vega' | 'g2
|
|
|
54
60
|
const p = filters.length === 0 ? Promise.resolve(dataSource) : applyFilter(dataSource, filters);
|
|
55
61
|
pendingPromiseRef.current = p;
|
|
56
62
|
|
|
57
|
-
p.then(d => {
|
|
63
|
+
p.then((d) => {
|
|
58
64
|
if (p !== pendingPromiseRef.current) {
|
|
59
65
|
// This promise is out-of-date
|
|
60
66
|
return;
|
|
61
67
|
}
|
|
62
68
|
|
|
63
69
|
setData(d);
|
|
64
|
-
}).catch(err => {
|
|
70
|
+
}).catch((err) => {
|
|
65
71
|
console.error(err);
|
|
66
72
|
});
|
|
67
73
|
|
|
@@ -69,45 +75,64 @@ const ReactiveRenderer = forwardRef<IReactVegaHandler, { themeKey?: 'vega' | 'g2
|
|
|
69
75
|
pendingPromiseRef.current = null;
|
|
70
76
|
};
|
|
71
77
|
}, [dataSource, filters]);
|
|
72
|
-
|
|
73
|
-
return
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
78
|
+
const enableResize = size.mode === "fixed" && !hasFacet;
|
|
79
|
+
return (
|
|
80
|
+
<Resizable
|
|
81
|
+
className={enableResize ? "border-blue-400 border-2 overflow-hidden" : ""}
|
|
82
|
+
style={{ padding: "12px" }}
|
|
83
|
+
onResizeStop={(e, direction, ref, d) => {
|
|
84
|
+
vizStore.setChartLayout({
|
|
85
|
+
mode: "fixed",
|
|
86
|
+
width: size.width + d.width,
|
|
87
|
+
height: size.height + d.height,
|
|
88
|
+
});
|
|
89
|
+
}}
|
|
90
|
+
enable={
|
|
91
|
+
enableResize
|
|
92
|
+
? undefined
|
|
93
|
+
: {
|
|
94
|
+
top: false,
|
|
95
|
+
right: false,
|
|
96
|
+
bottom: false,
|
|
97
|
+
left: false,
|
|
98
|
+
topRight: false,
|
|
99
|
+
bottomRight: false,
|
|
100
|
+
bottomLeft: false,
|
|
101
|
+
topLeft: false,
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
size={{
|
|
105
|
+
width: size.width + "px",
|
|
106
|
+
height: size.height + "px",
|
|
107
|
+
}}
|
|
108
|
+
>
|
|
109
|
+
<ReactVega
|
|
110
|
+
layoutMode={size.mode}
|
|
111
|
+
interactiveScale={interactiveScale}
|
|
112
|
+
geomType={geoms[0]}
|
|
113
|
+
defaultAggregate={defaultAggregated}
|
|
114
|
+
stack={stack}
|
|
115
|
+
dataSource={data}
|
|
116
|
+
rows={rows}
|
|
117
|
+
columns={columns}
|
|
118
|
+
color={color[0]}
|
|
119
|
+
theta={theta[0]}
|
|
120
|
+
radius={radius[0]}
|
|
121
|
+
shape={shape[0]}
|
|
122
|
+
opacity={opacity[0]}
|
|
123
|
+
size={sizeChannel[0]}
|
|
124
|
+
showActions={showActions}
|
|
125
|
+
width={size.width - 12 * 4}
|
|
126
|
+
height={size.height - 12 * 4}
|
|
127
|
+
ref={ref}
|
|
128
|
+
brushEncoding={exploration.mode === "brush" ? exploration.brushDirection : "none"}
|
|
129
|
+
selectEncoding={exploration.mode === "point" ? "default" : "none"}
|
|
130
|
+
onGeomClick={handleGeomClick}
|
|
131
|
+
themeKey={themeKey}
|
|
132
|
+
dark={dark}
|
|
133
|
+
/>
|
|
134
|
+
</Resizable>
|
|
135
|
+
);
|
|
111
136
|
});
|
|
112
137
|
|
|
113
138
|
export default observer(ReactiveRenderer);
|
package/src/utils/media.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useEffect, useState } from "react";
|
|
2
|
+
import { IDarkMode } from "../interfaces";
|
|
2
3
|
|
|
3
4
|
export function currentMediaTheme(): "dark" | "light" {
|
|
4
5
|
if (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches) {
|
|
@@ -8,19 +9,23 @@ export function currentMediaTheme(): "dark" | "light" {
|
|
|
8
9
|
}
|
|
9
10
|
}
|
|
10
11
|
|
|
11
|
-
export function useCurrentMediaTheme(): "dark" | "light" {
|
|
12
|
-
const [theme, setTheme] = useState<"dark" | "light">(currentMediaTheme());
|
|
12
|
+
export function useCurrentMediaTheme(mode: IDarkMode | undefined = 'media'): "dark" | "light" {
|
|
13
|
+
const [theme, setTheme] = useState<"dark" | "light">(mode === 'media' ? currentMediaTheme() : mode);
|
|
13
14
|
|
|
14
15
|
useEffect(() => {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
16
|
+
if (mode === 'media') {
|
|
17
|
+
const mediaQuery = window.matchMedia?.("(prefers-color-scheme: dark)") as MediaQueryList | undefined;
|
|
18
|
+
const listener = (e: MediaQueryListEvent) => {
|
|
19
|
+
setTheme(e.matches ? "dark" : "light");
|
|
20
|
+
};
|
|
21
|
+
mediaQuery?.addEventListener("change", listener);
|
|
22
|
+
return () => {
|
|
23
|
+
mediaQuery?.removeEventListener("change", listener);
|
|
24
|
+
};
|
|
25
|
+
} else {
|
|
26
|
+
setTheme(mode);
|
|
27
|
+
}
|
|
28
|
+
}, [mode]);
|
|
24
29
|
|
|
25
30
|
return theme;
|
|
26
31
|
}
|
package/src/vis/react-vega.tsx
CHANGED
|
@@ -8,7 +8,7 @@ import styled from 'styled-components';
|
|
|
8
8
|
import { autoMark } from '../utils/autoMark';
|
|
9
9
|
import { COUNT_FIELD_ID } from '../constants';
|
|
10
10
|
|
|
11
|
-
import { IViewField, IRow, IStackMode } from '../interfaces';
|
|
11
|
+
import { IViewField, IRow, IStackMode, IDarkMode, IThemeKey } from '../interfaces';
|
|
12
12
|
import { useTranslation } from 'react-i18next';
|
|
13
13
|
import { getVegaTimeFormatRules } from './temporalFormat';
|
|
14
14
|
import { builtInThemes } from './theme';
|
|
@@ -49,7 +49,8 @@ interface ReactVegaProps {
|
|
|
49
49
|
selectEncoding: SingleViewProps['selectEncoding'];
|
|
50
50
|
brushEncoding: SingleViewProps['brushEncoding'];
|
|
51
51
|
/** @default "vega" */
|
|
52
|
-
themeKey?:
|
|
52
|
+
themeKey?: IThemeKey;
|
|
53
|
+
dark?: IDarkMode;
|
|
53
54
|
}
|
|
54
55
|
const NULL_FIELD: IViewField = {
|
|
55
56
|
dragId: '',
|
|
@@ -104,6 +105,7 @@ interface SingleViewProps {
|
|
|
104
105
|
asCrossFilterTrigger: boolean;
|
|
105
106
|
selectEncoding: 'default' | 'none';
|
|
106
107
|
brushEncoding: 'x' | 'y' | 'default' | 'none';
|
|
108
|
+
hideLegend?: boolean;
|
|
107
109
|
}
|
|
108
110
|
|
|
109
111
|
function availableChannels (geomType: string): Set<string> {
|
|
@@ -202,9 +204,16 @@ function getSingleView(props: SingleViewProps) {
|
|
|
202
204
|
brushEncoding,
|
|
203
205
|
enableCrossFilter,
|
|
204
206
|
asCrossFilterTrigger,
|
|
207
|
+
hideLegend = false,
|
|
205
208
|
} = props
|
|
206
209
|
const fields: IViewField[] = [x, y, color, opacity, size, shape, row, column, xOffset, yOffset, theta, radius]
|
|
207
210
|
let markType = geomType;
|
|
211
|
+
let config: any = {};
|
|
212
|
+
if (hideLegend) {
|
|
213
|
+
config.legend = {
|
|
214
|
+
disable: true
|
|
215
|
+
};
|
|
216
|
+
}
|
|
208
217
|
if (geomType === 'auto') {
|
|
209
218
|
const types: ISemanticType[] = [];
|
|
210
219
|
if (x !== NULL_FIELD) types.push(x.semanticType)//types.push(getFieldType(x));
|
|
@@ -219,6 +228,7 @@ function getSingleView(props: SingleViewProps) {
|
|
|
219
228
|
channelStack(encoding, stack);
|
|
220
229
|
if (!enableCrossFilter || brushEncoding === 'none' && selectEncoding === 'none') {
|
|
221
230
|
return {
|
|
231
|
+
config,
|
|
222
232
|
mark: {
|
|
223
233
|
type: markType,
|
|
224
234
|
opacity: 0.96,
|
|
@@ -326,6 +336,7 @@ function getSingleView(props: SingleViewProps) {
|
|
|
326
336
|
|
|
327
337
|
if (brushEncoding !== 'none') {
|
|
328
338
|
return {
|
|
339
|
+
config,
|
|
329
340
|
transform: asCrossFilterTrigger ? [] : [
|
|
330
341
|
{ filter: { param: BRUSH_SIGNAL_NAME } }
|
|
331
342
|
],
|
|
@@ -346,6 +357,7 @@ function getSingleView(props: SingleViewProps) {
|
|
|
346
357
|
}
|
|
347
358
|
|
|
348
359
|
return {
|
|
360
|
+
config,
|
|
349
361
|
transform: asCrossFilterTrigger ? [] : [
|
|
350
362
|
{ filter: { param: POINT_SIGNAL_NAME } }
|
|
351
363
|
],
|
|
@@ -391,12 +403,13 @@ const ReactVega = forwardRef<IReactVegaHandler, ReactVegaProps>(function ReactVe
|
|
|
391
403
|
selectEncoding,
|
|
392
404
|
brushEncoding,
|
|
393
405
|
themeKey = 'vega',
|
|
406
|
+
dark = 'media'
|
|
394
407
|
} = props;
|
|
395
408
|
// const container = useRef<HTMLDivElement>(null);
|
|
396
409
|
// const containers = useRef<(HTMLDivElement | null)[]>([]);
|
|
397
410
|
const [viewPlaceholders, setViewPlaceholders] = useState<React.MutableRefObject<HTMLDivElement>[]>([]);
|
|
398
411
|
const { i18n } = useTranslation();
|
|
399
|
-
const mediaTheme = useCurrentMediaTheme();
|
|
412
|
+
const mediaTheme = useCurrentMediaTheme(dark);
|
|
400
413
|
const themeConfig = builtInThemes[themeKey]?.[mediaTheme];
|
|
401
414
|
useEffect(() => {
|
|
402
415
|
const clickSub = geomClick$.subscribe(([values, e]) => {
|
|
@@ -553,6 +566,7 @@ const ReactVega = forwardRef<IReactVegaHandler, ReactVegaProps>(function ReactVe
|
|
|
553
566
|
for (let i = 0; i < rowRepeatFields.length; i++) {
|
|
554
567
|
for (let j = 0; j < colRepeatFields.length; j++, index++) {
|
|
555
568
|
const sourceId = index;
|
|
569
|
+
const hasLegend = i === 0 && j === colRepeatFields.length - 1;
|
|
556
570
|
const singleView = getSingleView({
|
|
557
571
|
x: colRepeatFields[j] || NULL_FIELD,
|
|
558
572
|
y: rowRepeatFields[i] || NULL_FIELD,
|
|
@@ -573,6 +587,7 @@ const ReactVega = forwardRef<IReactVegaHandler, ReactVegaProps>(function ReactVe
|
|
|
573
587
|
brushEncoding,
|
|
574
588
|
enableCrossFilter: crossFilterTriggerIdx !== -1,
|
|
575
589
|
asCrossFilterTrigger: crossFilterTriggerIdx === sourceId,
|
|
590
|
+
hideLegend: !hasLegend,
|
|
576
591
|
});
|
|
577
592
|
const node = i * colRepeatFields.length + j < viewPlaceholders.length ? viewPlaceholders[i * colRepeatFields.length + j].current : null
|
|
578
593
|
let commonSpec = { ...spec };
|
package/src/vis/theme.ts
CHANGED
|
@@ -1,22 +1,30 @@
|
|
|
1
1
|
const DEFAULT_COLOR = "#5B8FF9";
|
|
2
|
-
|
|
2
|
+
const DARK_COMMON_DESIGN = {
|
|
3
|
+
background: "transparent",
|
|
4
|
+
header: {
|
|
5
|
+
titleColor: "#d1d5db", // change title color to white
|
|
6
|
+
labelColor: "#d1d5db", // change label color to white
|
|
7
|
+
},
|
|
8
|
+
axis: {
|
|
9
|
+
gridColor: "#666",
|
|
10
|
+
domainColor: "#d1d5db", // change axis color to white
|
|
11
|
+
tickColor: "#d1d5db", // change tick color to white
|
|
12
|
+
labelColor: "#d1d5db", // change label color to white
|
|
13
|
+
titleColor: "#d1d5db", // change title 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
|
+
view: {
|
|
20
|
+
stroke: '#666'
|
|
21
|
+
}
|
|
22
|
+
}
|
|
3
23
|
export const VegaTheme = {
|
|
4
24
|
light: {
|
|
5
25
|
background: "transparent",
|
|
6
26
|
},
|
|
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
|
-
},
|
|
27
|
+
dark: DARK_COMMON_DESIGN
|
|
20
28
|
} as const;
|
|
21
29
|
|
|
22
30
|
export const AntVTheme = {
|
|
@@ -65,6 +73,7 @@ export const AntVTheme = {
|
|
|
65
73
|
},
|
|
66
74
|
},
|
|
67
75
|
dark: {
|
|
76
|
+
...DARK_COMMON_DESIGN,
|
|
68
77
|
area: { fill: DEFAULT_COLOR },
|
|
69
78
|
bar: { fill: DEFAULT_COLOR },
|
|
70
79
|
circle: { fill: DEFAULT_COLOR },
|
|
@@ -76,17 +85,6 @@ export const AntVTheme = {
|
|
|
76
85
|
errorbar: { stroke: DEFAULT_COLOR },
|
|
77
86
|
errorband: { fill: DEFAULT_COLOR },
|
|
78
87
|
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
88
|
range: {
|
|
91
89
|
category: [
|
|
92
90
|
"#5B8FF9",
|