@kanaries/graphic-walker 0.2.11 → 0.2.12
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 +6 -3
- package/dist/assets/explainer.worker-8428eb12.js.map +1 -1
- package/dist/components/button/base.d.ts +6 -0
- package/dist/components/button/default.d.ts +4 -0
- package/dist/components/button/primary.d.ts +4 -0
- package/dist/dataSource/utils.d.ts +1 -1
- package/dist/graphic-walker.es.js +17671 -18577
- package/dist/graphic-walker.es.js.map +1 -1
- package/dist/graphic-walker.umd.js +134 -134
- package/dist/graphic-walker.umd.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/interfaces.d.ts +8 -0
- package/dist/lib/inferMeta.d.ts +20 -0
- package/dist/store/commonStore.d.ts +1 -1
- package/dist/store/index.d.ts +0 -1
- package/dist/store/visualSpecStore.d.ts +5 -5
- package/dist/utils/dataPrep.d.ts +6 -0
- package/dist/utils/index.d.ts +2 -2
- package/dist/utils/normalization.d.ts +1 -1
- package/dist/utils/save.d.ts +3 -3
- package/dist/utils/throttle.d.ts +1 -1
- package/dist/vis/temporalFormat.d.ts +10 -0
- package/package.json +1 -1
- package/src/App.tsx +27 -10
- package/src/components/button/base.ts +7 -0
- package/src/components/button/default.tsx +17 -0
- package/src/components/button/primary.tsx +17 -0
- package/src/dataSource/dataSelection/csvData.tsx +8 -10
- package/src/dataSource/dataSelection/publicData.tsx +4 -4
- package/src/dataSource/index.tsx +10 -12
- package/src/dataSource/table.tsx +33 -20
- package/src/dataSource/utils.ts +30 -35
- package/src/fields/datasetFields/dimFields.tsx +1 -5
- package/src/fields/datasetFields/meaFields.tsx +1 -5
- package/src/fields/obComponents/obFContainer.tsx +1 -5
- package/src/index.tsx +3 -4
- package/src/interfaces.ts +9 -0
- package/src/lib/inferMeta.ts +88 -0
- package/src/locales/en-US.json +6 -0
- package/src/locales/zh-CN.json +6 -0
- package/src/main.tsx +1 -1
- package/src/store/commonStore.ts +8 -3
- package/src/store/index.tsx +0 -2
- package/src/store/visualSpecStore.ts +245 -183
- package/src/utils/autoMark.ts +14 -14
- package/src/utils/dataPrep.ts +44 -0
- package/src/utils/index.ts +140 -128
- package/src/utils/normalization.ts +59 -51
- package/src/utils/save.ts +22 -21
- package/src/utils/throttle.ts +5 -1
- package/src/vis/react-vega.tsx +6 -10
- package/src/vis/temporalFormat.ts +66 -0
- package/dist/pitch/dnd-offset.d.ts +0 -2
- package/src/pitch/dnd-offset.ts +0 -64
package/src/utils/save.ts
CHANGED
|
@@ -1,48 +1,49 @@
|
|
|
1
1
|
import { IDataSet, IDataSource, IVisSpec } from "../interfaces";
|
|
2
2
|
import { VisSpecWithHistory } from "../models/visSpecHistory";
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
return list.map(l => l.exportGW())
|
|
4
|
+
export function dumpsGWPureSpec(list: VisSpecWithHistory[]): IVisSpec[] {
|
|
5
|
+
return list.map((l) => l.exportGW());
|
|
7
6
|
}
|
|
8
7
|
|
|
9
|
-
export function parseGWPureSpec
|
|
10
|
-
return list.map(l => new VisSpecWithHistory(l))
|
|
8
|
+
export function parseGWPureSpec(list: IVisSpec[]): VisSpecWithHistory[] {
|
|
9
|
+
return list.map((l) => new VisSpecWithHistory(l));
|
|
11
10
|
}
|
|
12
11
|
|
|
13
12
|
interface IStoInfo {
|
|
14
13
|
datasets: IDataSet[];
|
|
15
|
-
specList:
|
|
14
|
+
specList: {
|
|
16
15
|
/** 由于 gw 内部实现暂时未锁版本,这里获取到的信息可能会与当前实例内容有偏差,需要用初始值合入 */
|
|
17
|
-
[K in keyof IVisSpec]: K extends
|
|
18
|
-
}
|
|
19
|
-
dataSources: IDataSource[]
|
|
16
|
+
[K in keyof IVisSpec]: K extends "config" ? Partial<IVisSpec[K]> : IVisSpec[K];
|
|
17
|
+
}[];
|
|
18
|
+
dataSources: IDataSource[];
|
|
20
19
|
}
|
|
21
20
|
|
|
22
|
-
export function stringifyGWContent
|
|
23
|
-
return JSON.stringify(info)
|
|
21
|
+
export function stringifyGWContent(info: IStoInfo) {
|
|
22
|
+
return JSON.stringify(info);
|
|
24
23
|
}
|
|
25
24
|
|
|
26
|
-
export function parseGWContent
|
|
27
|
-
return JSON.parse(raw)
|
|
25
|
+
export function parseGWContent(raw: string): IStoInfo {
|
|
26
|
+
return JSON.parse(raw);
|
|
28
27
|
}
|
|
29
28
|
|
|
30
29
|
export function download(data: string, filename: string, type: string) {
|
|
31
|
-
var file = new Blob([data], {type: type});
|
|
30
|
+
var file = new Blob([data], { type: type });
|
|
32
31
|
// @ts-ignore
|
|
33
|
-
if (window.navigator.msSaveOrOpenBlob)
|
|
32
|
+
if (window.navigator.msSaveOrOpenBlob)
|
|
33
|
+
// IE10+
|
|
34
34
|
// @ts-ignore
|
|
35
35
|
window.navigator.msSaveOrOpenBlob(file, filename);
|
|
36
|
-
else {
|
|
36
|
+
else {
|
|
37
|
+
// Others
|
|
37
38
|
var a = document.createElement("a"),
|
|
38
|
-
|
|
39
|
+
url = URL.createObjectURL(file);
|
|
39
40
|
a.href = url;
|
|
40
41
|
a.download = filename;
|
|
41
42
|
document.body.appendChild(a);
|
|
42
43
|
a.click();
|
|
43
|
-
setTimeout(function() {
|
|
44
|
+
setTimeout(function () {
|
|
44
45
|
document.body.removeChild(a);
|
|
45
|
-
window.URL.revokeObjectURL(url);
|
|
46
|
-
}, 0);
|
|
46
|
+
window.URL.revokeObjectURL(url);
|
|
47
|
+
}, 0);
|
|
47
48
|
}
|
|
48
|
-
}
|
|
49
|
+
}
|
package/src/utils/throttle.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
const throttle = (
|
|
1
|
+
const throttle = (
|
|
2
|
+
fn: () => void,
|
|
3
|
+
time: number,
|
|
4
|
+
options?: Partial<{ leading: boolean; trailing: boolean }>
|
|
5
|
+
): (() => void) => {
|
|
2
6
|
const { leading = true, trailing = false } = options ?? {};
|
|
3
7
|
|
|
4
8
|
let dirty = false;
|
package/src/vis/react-vega.tsx
CHANGED
|
@@ -9,6 +9,8 @@ import { autoMark } from '../utils/autoMark';
|
|
|
9
9
|
import { COUNT_FIELD_ID } from '../constants';
|
|
10
10
|
|
|
11
11
|
import { IViewField, IRow, IStackMode } from '../interfaces';
|
|
12
|
+
import { useTranslation } from 'react-i18next';
|
|
13
|
+
import { getVegaTimeFormatRules } from './temporalFormat';
|
|
12
14
|
|
|
13
15
|
const CanvaContainer = styled.div<{rowSize: number; colSize: number;}>`
|
|
14
16
|
display: grid;
|
|
@@ -119,12 +121,9 @@ function channelEncode(props: EncodeProps) {
|
|
|
119
121
|
title: props[c].name,
|
|
120
122
|
type: props[c].semanticType
|
|
121
123
|
}
|
|
122
|
-
if (props[c].semanticType === 'temporal') {
|
|
123
|
-
encoding[c].axis = { format: '%Y-%m' }
|
|
124
|
-
}
|
|
125
124
|
}
|
|
126
125
|
})
|
|
127
|
-
// FIXME:
|
|
126
|
+
// FIXME: temporal fix, only for x and y relative order
|
|
128
127
|
if (encoding.x && encoding.y) {
|
|
129
128
|
if ((props.x.sort && props.x.sort) || (props.y && props.y.sort)) {
|
|
130
129
|
if (props.x.sort !== 'none' && (props.y.sort === 'none' || !Boolean(props.y.sort))) {
|
|
@@ -383,6 +382,7 @@ const ReactVega = forwardRef<IReactVegaHandler, ReactVegaProps>(function ReactVe
|
|
|
383
382
|
// const container = useRef<HTMLDivElement>(null);
|
|
384
383
|
// const containers = useRef<(HTMLDivElement | null)[]>([]);
|
|
385
384
|
const [viewPlaceholders, setViewPlaceholders] = useState<React.MutableRefObject<HTMLDivElement>[]>([]);
|
|
385
|
+
const { i18n } = useTranslation();
|
|
386
386
|
useEffect(() => {
|
|
387
387
|
const clickSub = geomClick$.subscribe(([values, e]) => {
|
|
388
388
|
if (onGeomClick) {
|
|
@@ -502,7 +502,7 @@ const ReactVega = forwardRef<IReactVegaHandler, ReactVegaProps>(function ReactVe
|
|
|
502
502
|
spec.params.push(...singleView.params!);
|
|
503
503
|
}
|
|
504
504
|
if (viewPlaceholders.length > 0 && viewPlaceholders[0].current) {
|
|
505
|
-
embed(viewPlaceholders[0].current, spec, { mode: 'vega-lite', actions: showActions }).then(res => {
|
|
505
|
+
embed(viewPlaceholders[0].current, spec, { mode: 'vega-lite', actions: showActions, timeFormatLocale: getVegaTimeFormatRules(i18n.language) }).then(res => {
|
|
506
506
|
vegaRefs.current = [res.view];
|
|
507
507
|
try {
|
|
508
508
|
res.view.addEventListener('click', (e) => {
|
|
@@ -583,10 +583,8 @@ const ReactVega = forwardRef<IReactVegaHandler, ReactVegaProps>(function ReactVe
|
|
|
583
583
|
ans.params = commonSpec.params;
|
|
584
584
|
}
|
|
585
585
|
if (node) {
|
|
586
|
-
embed(node, ans, { mode: 'vega-lite', actions: showActions }).then(res => {
|
|
586
|
+
embed(node, ans, { mode: 'vega-lite', actions: showActions, timeFormatLocale: getVegaTimeFormatRules(i18n.language) }).then(res => {
|
|
587
587
|
vegaRefs.current.push(res.view);
|
|
588
|
-
// 这种 case 下,我们来考虑联动的 params
|
|
589
|
-
// vega 使用 Data 来维护 params 的状态,只需要打通这些状态就可以实现联动
|
|
590
588
|
const paramStores = (res.vgSpec.data?.map(d => d.name) ?? []).filter(
|
|
591
589
|
name => [BRUSH_SIGNAL_NAME, POINT_SIGNAL_NAME].map(p => `${p}_store`).includes(name)
|
|
592
590
|
).map(name => name.replace(/_store$/, ''));
|
|
@@ -611,12 +609,10 @@ const ReactVega = forwardRef<IReactVegaHandler, ReactVegaProps>(function ReactVe
|
|
|
611
609
|
});
|
|
612
610
|
}
|
|
613
611
|
});
|
|
614
|
-
// 订阅
|
|
615
612
|
subscribe(entry => {
|
|
616
613
|
if (entry.source === sourceId || !entry.data) {
|
|
617
614
|
return;
|
|
618
615
|
}
|
|
619
|
-
// 防止被动更新触发广播
|
|
620
616
|
noBroadcasting = true;
|
|
621
617
|
res.view.setState({
|
|
622
618
|
data: {
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
export function getVegaTimeFormatRules(lang: string) {
|
|
2
|
+
switch (lang) {
|
|
3
|
+
case 'zh-CN':
|
|
4
|
+
return {
|
|
5
|
+
dateTime: '%x %A %X',
|
|
6
|
+
date: '%Y年%-m月%-d日',
|
|
7
|
+
time: '%H:%M:%S',
|
|
8
|
+
periods: ['上午', '下午'],
|
|
9
|
+
days: ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'],
|
|
10
|
+
shortDays: ['周日', '周一', '周二', '周三', '周四', '周五', '周六'],
|
|
11
|
+
months: [
|
|
12
|
+
'一月',
|
|
13
|
+
'二月',
|
|
14
|
+
'三月',
|
|
15
|
+
'四月',
|
|
16
|
+
'五月',
|
|
17
|
+
'六月',
|
|
18
|
+
'七月',
|
|
19
|
+
'八月',
|
|
20
|
+
'九月',
|
|
21
|
+
'十月',
|
|
22
|
+
'十一月',
|
|
23
|
+
'十二月',
|
|
24
|
+
],
|
|
25
|
+
shortMonths: [
|
|
26
|
+
'一月',
|
|
27
|
+
'二月',
|
|
28
|
+
'三月',
|
|
29
|
+
'四月',
|
|
30
|
+
'五月',
|
|
31
|
+
'六月',
|
|
32
|
+
'七月',
|
|
33
|
+
'八月',
|
|
34
|
+
'九月',
|
|
35
|
+
'十月',
|
|
36
|
+
'十一月',
|
|
37
|
+
'十二月',
|
|
38
|
+
],
|
|
39
|
+
};
|
|
40
|
+
case 'en-US':
|
|
41
|
+
default:
|
|
42
|
+
return {
|
|
43
|
+
dateTime: '%x, %X',
|
|
44
|
+
date: '%-m/%-d/%Y',
|
|
45
|
+
time: '%-I:%M:%S %p',
|
|
46
|
+
periods: ['AM', 'PM'],
|
|
47
|
+
days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
|
|
48
|
+
shortDays: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
|
|
49
|
+
months: [
|
|
50
|
+
'January',
|
|
51
|
+
'February',
|
|
52
|
+
'March',
|
|
53
|
+
'April',
|
|
54
|
+
'May',
|
|
55
|
+
'June',
|
|
56
|
+
'July',
|
|
57
|
+
'August',
|
|
58
|
+
'September',
|
|
59
|
+
'October',
|
|
60
|
+
'November',
|
|
61
|
+
'December',
|
|
62
|
+
],
|
|
63
|
+
shortMonths: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
}
|
package/src/pitch/dnd-offset.ts
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { DraggableProvided } from "react-beautiful-dnd";
|
|
2
|
-
|
|
3
|
-
function getElementBoxInfo(ele: HTMLElement) {
|
|
4
|
-
const style = window.getComputedStyle(ele);
|
|
5
|
-
const borderLeft = parseInt(style.borderLeftWidth);
|
|
6
|
-
const paddingLeft = parseInt(style.paddingLeft);
|
|
7
|
-
const marginLeft = parseInt(style.marginLeft);
|
|
8
|
-
const borderTop = parseInt(style.borderTopWidth);
|
|
9
|
-
const paddingTop = parseInt(style.paddingTop);
|
|
10
|
-
const marginTop = parseInt(style.marginTop);
|
|
11
|
-
return {
|
|
12
|
-
borderLeft,
|
|
13
|
-
paddingLeft,
|
|
14
|
-
marginLeft,
|
|
15
|
-
borderTop,
|
|
16
|
-
paddingTop,
|
|
17
|
-
marginTop,
|
|
18
|
-
style
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export function fixDraggableOffset(provided: DraggableProvided, containerDOM: HTMLElement | undefined | null) {
|
|
23
|
-
if (typeof containerDOM === 'undefined' || containerDOM === null) return;
|
|
24
|
-
const containerRect = containerDOM.getBoundingClientRect();
|
|
25
|
-
const offset = { x: containerRect.left, y: containerRect.top };
|
|
26
|
-
let parent: HTMLElement | null = containerDOM.parentElement;
|
|
27
|
-
while (parent !== null) {
|
|
28
|
-
const box = getElementBoxInfo(parent);
|
|
29
|
-
const {
|
|
30
|
-
borderLeft: parentBorderLeft,
|
|
31
|
-
paddingLeft: parentPaddingLeft,
|
|
32
|
-
marginLeft: parentMarginLeft,
|
|
33
|
-
borderTop: parentBorderTop,
|
|
34
|
-
paddingTop: parentPaddingTop,
|
|
35
|
-
marginTop: parentMarginTop,
|
|
36
|
-
style
|
|
37
|
-
} = box;
|
|
38
|
-
offset.x -= ( parentBorderLeft + parentPaddingLeft + parentMarginLeft);
|
|
39
|
-
offset.y -= (parentBorderTop + parentPaddingTop + parentMarginTop);
|
|
40
|
-
if (style.position === 'absolute' || style.position === 'fixed') {
|
|
41
|
-
|
|
42
|
-
break;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
parent = parent.parentElement;
|
|
46
|
-
}
|
|
47
|
-
const root = document.documentElement;
|
|
48
|
-
const scrollTop = (window.pageYOffset || root.scrollTop) - (root.clientTop || 0);
|
|
49
|
-
const scrollLeft = (window.pageXOffset || root.scrollLeft) - (root.clientLeft || 0);
|
|
50
|
-
offset.y += scrollTop;
|
|
51
|
-
offset.x += scrollLeft;
|
|
52
|
-
//@ts-ignore
|
|
53
|
-
const x = (provided.draggableProps.style.left! ?? 0) - offset.x;
|
|
54
|
-
//@ts-ignore
|
|
55
|
-
const y = (provided.draggableProps.style.top! ?? 0) - offset.y
|
|
56
|
-
// TODO: Fix the offset error when there is a layer has padding between fixed layer and provided.draggableProps.style ele.
|
|
57
|
-
// the error seems to be 16px which is the pill's height
|
|
58
|
-
// provided.draggableProps.style.height;// - 2 - 2 - 1 - 1;
|
|
59
|
-
|
|
60
|
-
// @ts-ignore
|
|
61
|
-
provided.draggableProps.style.left = x;
|
|
62
|
-
// @ts-ignore
|
|
63
|
-
provided.draggableProps.style.top = y;
|
|
64
|
-
}
|