@kanaries/graphic-walker 0.2.7 → 0.2.9
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/assets/explainer.worker.90990e9a.js.map +1 -0
- package/dist/fields/filterField/tabs.d.ts +1 -1
- package/dist/graphic-walker.es.js +18046 -17762
- package/dist/graphic-walker.es.js.map +1 -1
- package/dist/graphic-walker.umd.js +140 -116
- package/dist/graphic-walker.umd.js.map +1 -1
- package/dist/insightBoard/std2vegaSpec.d.ts +1 -1
- package/dist/interfaces.d.ts +14 -5
- package/dist/renderer/index.d.ts +2 -1
- package/dist/store/visualSpecStore.d.ts +2 -1
- package/dist/style.css +1 -1
- package/dist/utils/save.d.ts +3 -1
- package/dist/vis/react-vega.d.ts +30 -1
- package/dist/visualSettings/index.d.ts +5 -1
- package/package.json +2 -1
- package/src/App.tsx +10 -7
- package/src/components/modal.tsx +7 -2
- package/src/fields/datasetFields/index.tsx +10 -3
- package/src/fields/fieldsContext.tsx +5 -0
- package/src/interfaces.ts +19 -1
- package/src/locales/en-US.json +23 -2
- package/src/locales/zh-CN.json +23 -2
- package/src/renderer/index.tsx +19 -12
- package/src/store/visualSpecStore.ts +28 -3
- package/src/utils/save.ts +4 -1
- package/src/vis/react-vega.tsx +357 -23
- package/src/visualSettings/index.tsx +127 -4
- package/dist/assets/explainer.worker.0cf1948d.js.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Specification } from 'visual-insights';
|
|
2
2
|
import { IField, IRow } from '../interfaces';
|
|
3
3
|
import { IPredicate } from '../utils';
|
|
4
|
-
export
|
|
4
|
+
export type IReasonType = 'selection_dim_distribution' | 'selection_mea_distribution' | 'children_major_factor' | 'children_outlier';
|
|
5
5
|
export declare const geomTypeMap: {
|
|
6
6
|
[key: string]: any;
|
|
7
7
|
};
|
package/dist/interfaces.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { StatFuncName } from "visual-insights/build/esm/statistics";
|
|
2
2
|
import { AggFC } from 'cube-core/built/types';
|
|
3
3
|
import { IAnalyticType, ISemanticType } from 'visual-insights';
|
|
4
|
-
export
|
|
4
|
+
export type DeepReadonly<T extends Record<keyof any, any>> = {
|
|
5
5
|
readonly [K in keyof T]: T[K] extends Record<keyof any, any> ? DeepReadonly<T[K]> : T[K];
|
|
6
6
|
};
|
|
7
7
|
export interface IRow {
|
|
@@ -10,7 +10,7 @@ export interface IRow {
|
|
|
10
10
|
/**
|
|
11
11
|
* @deprecated
|
|
12
12
|
*/
|
|
13
|
-
export
|
|
13
|
+
export type SemanticType = 'quantitative' | 'nominal' | 'ordinal' | 'temporal';
|
|
14
14
|
export interface Filters {
|
|
15
15
|
[key: string]: any[];
|
|
16
16
|
}
|
|
@@ -102,7 +102,7 @@ export interface IDraggableStateKey {
|
|
|
102
102
|
id: keyof DraggableFieldState;
|
|
103
103
|
mode: number;
|
|
104
104
|
}
|
|
105
|
-
export
|
|
105
|
+
export type IFilterRule = {
|
|
106
106
|
type: 'range';
|
|
107
107
|
value: readonly [number, number];
|
|
108
108
|
} | {
|
|
@@ -112,11 +112,15 @@ export declare type IFilterRule = {
|
|
|
112
112
|
type: 'one of';
|
|
113
113
|
value: Set<string | number>;
|
|
114
114
|
};
|
|
115
|
-
export declare
|
|
115
|
+
export declare const EXPLORATION_TYPES: readonly ["none", "brush", "point"];
|
|
116
|
+
export declare const BRUSH_DIRECTIONS: readonly ["default", "x", "y"];
|
|
117
|
+
export type IStackMode = 'none' | 'stack' | 'normalize';
|
|
118
|
+
export type IExplorationType = (typeof EXPLORATION_TYPES)[number];
|
|
119
|
+
export type IBrushDirection = (typeof BRUSH_DIRECTIONS)[number];
|
|
116
120
|
export interface IVisualConfig {
|
|
117
121
|
defaultAggregated: boolean;
|
|
118
122
|
geoms: string[];
|
|
119
|
-
stack:
|
|
123
|
+
stack: IStackMode;
|
|
120
124
|
showActions: boolean;
|
|
121
125
|
interactiveScale: boolean;
|
|
122
126
|
sorted: 'none' | 'ascending' | 'descending';
|
|
@@ -125,6 +129,11 @@ export interface IVisualConfig {
|
|
|
125
129
|
width: number;
|
|
126
130
|
height: number;
|
|
127
131
|
};
|
|
132
|
+
exploration: {
|
|
133
|
+
mode: IExplorationType;
|
|
134
|
+
/** works when mode is 'brush' */
|
|
135
|
+
brushDirection: IBrushDirection;
|
|
136
|
+
};
|
|
128
137
|
}
|
|
129
138
|
export interface IVisSpec {
|
|
130
139
|
readonly visId: string;
|
package/dist/renderer/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
|
|
2
|
+
import { IReactVegaHandler } from '../vis/react-vega';
|
|
3
|
+
declare const _default: React.MemoExoticComponent<React.ForwardRefExoticComponent<Pick<React.RefAttributes<IReactVegaHandler>, "key"> & React.RefAttributes<IReactVegaHandler>>>;
|
|
3
4
|
export default _default;
|
|
@@ -2,7 +2,7 @@ import { Specification } from "visual-insights";
|
|
|
2
2
|
import { DataSet, DraggableFieldState, IFilterRule, IViewField, IVisualConfig } from "../interfaces";
|
|
3
3
|
import { VisSpecWithHistory } from "../models/visSpecHistory";
|
|
4
4
|
import { CommonStore } from "./commonStore";
|
|
5
|
-
|
|
5
|
+
type DeepReadonly<T extends Record<keyof any, any>> = {
|
|
6
6
|
readonly [K in keyof T]: T[K] extends Record<keyof any, any> ? DeepReadonly<T[K]> : T[K];
|
|
7
7
|
};
|
|
8
8
|
export declare class VizSpecStore {
|
|
@@ -89,6 +89,7 @@ export declare class VizSpecStore {
|
|
|
89
89
|
width?: number;
|
|
90
90
|
height?: number;
|
|
91
91
|
}): void;
|
|
92
|
+
setExploration(value: Partial<IVisualConfig['exploration']>): void;
|
|
92
93
|
reorderField(stateKey: keyof DraggableFieldState, sourceIndex: number, destinationIndex: number): void;
|
|
93
94
|
moveField(sourceKey: keyof DraggableFieldState, sourceIndex: number, destinationKey: keyof DraggableFieldState, destinationIndex: number): void;
|
|
94
95
|
removeField(sourceKey: keyof DraggableFieldState, sourceIndex: number): void;
|
package/dist/style.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
/*! tailwindcss v2.2.19 | MIT License | https://tailwindcss.com *//*! modern-normalize v1.1.0 | MIT License | https://github.com/sindresorhus/modern-normalize */*,:before,:after{box-sizing:border-box}html{tab-size:4}html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}body{font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji"}hr{height:0;color:inherit}abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,select{text-transform:none}button,[type=button],[type=submit]{-webkit-appearance:button}::-moz-focus-inner{border-style:none;padding:0}legend{padding:0}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}button{background-color:transparent;background-image:none}fieldset{margin:0;padding:0}ol,ul{list-style:none;margin:0;padding:0}html{font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";line-height:1.5}body{font-family:inherit;line-height:inherit}*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:currentColor}hr{border-top-width:1px}img{border-style:solid}textarea{resize:vertical}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}table{border-collapse:collapse}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}button,input,optgroup,select,textarea{padding:0;line-height:inherit;color:inherit}pre,code,kbd,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}*,:before,:after{--tw-border-opacity: 1;border-color:rgba(229,231,235,var(--tw-border-opacity))}.container{width:100%}@media (min-width: 640px){.container{max-width:640px}}@media (min-width: 768px){.container{max-width:768px}}@media (min-width: 1024px){.container{max-width:1024px}}@media (min-width: 1280px){.container{max-width:1280px}}@media (min-width: 1536px){.container{max-width:1536px}}.pointer-events-none{pointer-events:none}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.top-2{top:.5rem}.right-2{right:.5rem}.z-auto{z-index:auto}.col-span-1{grid-column:span 1 / span 1}.col-span-2{grid-column:span 2 / span 2}.col-span-3{grid-column:span 3 / span 3}.col-span-5{grid-column:span 5 / span 5}.col-span-7{grid-column:span 7 / span 7}.float-right{float:right}.m-1{margin:.25rem}.m-2{margin:.5rem}.mx-2{margin-left:.5rem;margin-right:.5rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-4{margin-top:1rem}.mr-0{margin-right:0}.mr-1{margin-right:.25rem}.mr-2{margin-right:.5rem}.mr-0\.5{margin-right:.125rem}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.-mb-px{margin-bottom:-1px}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-2{height:.5rem}.h-4{height:1rem}.h-8{height:2rem}.h-9{height:2.25rem}.h-16{height:4rem}.h-48{height:12rem}.w-3{width:.75rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-16{width:4rem}.w-60{width:15rem}.w-full{width:100%}.min-w-96{min-width:96px}.flex-1{flex:1 1 0%}.flex-shrink-0{flex-shrink:0}.flex-shrink{flex-shrink:1}.flex-grow-0{flex-grow:0}.flex-grow{flex-grow:1}.border-collapse{border-collapse:collapse}.transform{--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;transform:translate(var(--tw-translate-x)) translateY(var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes spin{to{transform:rotate(360deg)}}@keyframes ping{75%,to{transform:scale(2);opacity:0}}@keyframes pulse{50%{opacity:.5}}@keyframes bounce{0%,to{transform:translateY(-25%);animation-timing-function:cubic-bezier(.8,0,1,1)}50%{transform:none;animation-timing-function:cubic-bezier(0,0,.2,1)}}.animate-spin{animation:spin 1s linear infinite}.cursor-default{cursor:default}.cursor-pointer{cursor:pointer}.cursor-not-allowed{cursor:not-allowed}.select-none{-webkit-user-select:none;user-select:none}.resize{resize:both}.appearance-none{-webkit-appearance:none;appearance:none}.grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}.grid-cols-12{grid-template-columns:repeat(12,minmax(0,1fr))}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-stretch{align-items:stretch}.justify-center{justify-content:center}.self-center{align-self:center}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.overflow-y-hidden{overflow-y:hidden}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-nowrap{white-space:nowrap}.rounded-sm{border-radius:.125rem}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.border-2{border-width:2px}.border{border-width:1px}.border-t-2{border-top-width:2px}.border-t{border-top-width:1px}.border-r{border-right-width:1px}.border-b{border-bottom-width:1px}.border-l-2{border-left-width:2px}.border-l{border-left-width:1px}.border-transparent{border-color:transparent}.border-gray-200{--tw-border-opacity: 1;border-color:rgba(229,231,235,var(--tw-border-opacity))}.border-gray-300{--tw-border-opacity: 1;border-color:rgba(209,213,219,var(--tw-border-opacity))}.border-gray-400{--tw-border-opacity: 1;border-color:rgba(156,163,175,var(--tw-border-opacity))}.border-gray-500{--tw-border-opacity: 1;border-color:rgba(107,114,128,var(--tw-border-opacity))}.border-blue-400{--tw-border-opacity: 1;border-color:rgba(96,165,250,var(--tw-border-opacity))}.border-blue-500{--tw-border-opacity: 1;border-color:rgba(59,130,246,var(--tw-border-opacity))}.hover\:border-gray-300:hover{--tw-border-opacity: 1;border-color:rgba(209,213,219,var(--tw-border-opacity))}.hover\:border-gray-600:hover{--tw-border-opacity: 1;border-color:rgba(75,85,99,var(--tw-border-opacity))}.focus\:border-gray-500:focus{--tw-border-opacity: 1;border-color:rgba(107,114,128,var(--tw-border-opacity))}.focus\:border-blue-500:focus{--tw-border-opacity: 1;border-color:rgba(59,130,246,var(--tw-border-opacity))}.bg-transparent{background-color:transparent}.bg-white{--tw-bg-opacity: 1;background-color:rgba(255,255,255,var(--tw-bg-opacity))}.bg-gray-100{--tw-bg-opacity: 1;background-color:rgba(243,244,246,var(--tw-bg-opacity))}.bg-gray-400{--tw-bg-opacity: 1;background-color:rgba(156,163,175,var(--tw-bg-opacity))}.bg-red-500{--tw-bg-opacity: 1;background-color:rgba(239,68,68,var(--tw-bg-opacity))}.bg-yellow-600{--tw-bg-opacity: 1;background-color:rgba(217,119,6,var(--tw-bg-opacity))}.bg-blue-100{--tw-bg-opacity: 1;background-color:rgba(219,234,254,var(--tw-bg-opacity))}.bg-blue-600{--tw-bg-opacity: 1;background-color:rgba(37,99,235,var(--tw-bg-opacity))}.bg-indigo-50{--tw-bg-opacity: 1;background-color:rgba(238,242,255,var(--tw-bg-opacity))}.hover\:bg-gray-50:hover{--tw-bg-opacity: 1;background-color:rgba(249,250,251,var(--tw-bg-opacity))}.hover\:bg-gray-100:hover{--tw-bg-opacity: 1;background-color:rgba(243,244,246,var(--tw-bg-opacity))}.hover\:bg-gray-200:hover{--tw-bg-opacity: 1;background-color:rgba(229,231,235,var(--tw-bg-opacity))}.hover\:bg-red-100:hover{--tw-bg-opacity: 1;background-color:rgba(254,226,226,var(--tw-bg-opacity))}.hover\:bg-yellow-100:hover{--tw-bg-opacity: 1;background-color:rgba(254,243,199,var(--tw-bg-opacity))}.hover\:bg-yellow-500:hover{--tw-bg-opacity: 1;background-color:rgba(245,158,11,var(--tw-bg-opacity))}.hover\:bg-green-50:hover{--tw-bg-opacity: 1;background-color:rgba(236,253,245,var(--tw-bg-opacity))}.hover\:bg-blue-100:hover{--tw-bg-opacity: 1;background-color:rgba(219,234,254,var(--tw-bg-opacity))}.disabled\:bg-gray-300:disabled{--tw-bg-opacity: 1;background-color:rgba(209,213,219,var(--tw-bg-opacity))}.p-1{padding:.25rem}.p-2{padding:.5rem}.p-4{padding:1rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.pt-0{padding-top:0}.pt-1{padding-top:.25rem}.pt-0\.5{padding-top:.125rem}.pr-2{padding-right:.5rem}.pr-6{padding-right:1.5rem}.pb-0{padding-bottom:0}.pb-1{padding-bottom:.25rem}.pb-2{padding-bottom:.5rem}.pb-0\.5{padding-bottom:.125rem}.pl-2{padding-left:.5rem}.pl-6{padding-left:1.5rem}.text-xs{font-size:.75rem;line-height:1rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.font-semibold{font-weight:600}.font-bold{font-weight:700}.ordinal{--tw-ordinal: var(--tw-empty, );--tw-slashed-zero: var(--tw-empty, );--tw-numeric-figure: var(--tw-empty, );--tw-numeric-spacing: var(--tw-empty, );--tw-numeric-fraction: var(--tw-empty, );font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.ordinal{--tw-ordinal: ordinal}.leading-none{line-height:1}.text-black{--tw-text-opacity: 1;color:rgba(0,0,0,var(--tw-text-opacity))}.text-white{--tw-text-opacity: 1;color:rgba(255,255,255,var(--tw-text-opacity))}.text-gray-300{--tw-text-opacity: 1;color:rgba(209,213,219,var(--tw-text-opacity))}.text-gray-400{--tw-text-opacity: 1;color:rgba(156,163,175,var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity: 1;color:rgba(107,114,128,var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity: 1;color:rgba(75,85,99,var(--tw-text-opacity))}.text-gray-700{--tw-text-opacity: 1;color:rgba(55,65,81,var(--tw-text-opacity))}.text-gray-800{--tw-text-opacity: 1;color:rgba(31,41,55,var(--tw-text-opacity))}.text-gray-900{--tw-text-opacity: 1;color:rgba(17,24,39,var(--tw-text-opacity))}.text-red-600{--tw-text-opacity: 1;color:rgba(220,38,38,var(--tw-text-opacity))}.text-yellow-500{--tw-text-opacity: 1;color:rgba(245,158,11,var(--tw-text-opacity))}.text-green-500{--tw-text-opacity: 1;color:rgba(16,185,129,var(--tw-text-opacity))}.text-blue-500{--tw-text-opacity: 1;color:rgba(59,130,246,var(--tw-text-opacity))}.hover\:text-gray-700:hover{--tw-text-opacity: 1;color:rgba(55,65,81,var(--tw-text-opacity))}.hover\:text-purple-600:hover{--tw-text-opacity: 1;color:rgba(124,58,237,var(--tw-text-opacity))}.underline{text-decoration:underline}*,:before,:after{--tw-shadow: 0 0 #0000}.shadow{--tw-shadow: 0 1px 3px 0 rgba(0, 0, 0, .1), 0 1px 2px 0 rgba(0, 0, 0, .06);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgba(0, 0, 0, .1), 0 4px 6px -2px rgba(0, 0, 0, .05);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.outline-none{outline:2px solid transparent;outline-offset:2px}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}*,:before,:after{--tw-ring-inset: var(--tw-empty, );--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgba(59, 130, 246, .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000}.filter{--tw-blur: var(--tw-empty, );--tw-brightness: var(--tw-empty, );--tw-contrast: var(--tw-empty, );--tw-grayscale: var(--tw-empty, );--tw-hue-rotate: var(--tw-empty, );--tw-invert: var(--tw-empty, );--tw-saturate: var(--tw-empty, );--tw-sepia: var(--tw-empty, );--tw-drop-shadow: var(--tw-empty, );filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.blur{--tw-blur: blur(8px)}@media (min-width: 1280px){.xl\:col-span-1{grid-column:span 1 / span 1}.xl\:col-span-4{grid-column:span 4 / span 4}.xl\:grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}code{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}
|
|
1
|
+
/*! tailwindcss v2.2.19 | MIT License | https://tailwindcss.com *//*! modern-normalize v1.1.0 | MIT License | https://github.com/sindresorhus/modern-normalize */*,:before,:after{box-sizing:border-box}html{tab-size:4}html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}body{font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji"}hr{height:0;color:inherit}abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,select{text-transform:none}button,[type=button],[type=submit]{-webkit-appearance:button}::-moz-focus-inner{border-style:none;padding:0}legend{padding:0}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}button{background-color:transparent;background-image:none}fieldset{margin:0;padding:0}ol,ul{list-style:none;margin:0;padding:0}html{font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";line-height:1.5}body{font-family:inherit;line-height:inherit}*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:currentColor}hr{border-top-width:1px}img{border-style:solid}textarea{resize:vertical}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}table{border-collapse:collapse}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}button,input,optgroup,select,textarea{padding:0;line-height:inherit;color:inherit}pre,code,kbd,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}*,:before,:after{--tw-border-opacity: 1;border-color:rgba(229,231,235,var(--tw-border-opacity))}.container{width:100%}@media (min-width: 640px){.container{max-width:640px}}@media (min-width: 768px){.container{max-width:768px}}@media (min-width: 1024px){.container{max-width:1024px}}@media (min-width: 1280px){.container{max-width:1280px}}@media (min-width: 1536px){.container{max-width:1536px}}.pointer-events-none{pointer-events:none}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.top-2{top:.5rem}.right-2{right:.5rem}.z-auto{z-index:auto}.col-span-1{grid-column:span 1 / span 1}.col-span-5{grid-column:span 5 / span 5}.float-right{float:right}.m-1{margin:.25rem}.m-2{margin:.5rem}.mx-2{margin-left:.5rem;margin-right:.5rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-4{margin-top:1rem}.mr-0{margin-right:0}.mr-1{margin-right:.25rem}.mr-2{margin-right:.5rem}.mr-0\.5{margin-right:.125rem}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.-mb-px{margin-bottom:-1px}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-2{height:.5rem}.h-3{height:.75rem}.h-4{height:1rem}.h-8{height:2rem}.h-9{height:2.25rem}.h-16{height:4rem}.h-48{height:12rem}.w-3{width:.75rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-16{width:4rem}.w-60{width:15rem}.w-full{width:100%}.min-w-96{min-width:96px}.flex-1{flex:1 1 0%}.flex-shrink-0{flex-shrink:0}.flex-shrink{flex-shrink:1}.flex-grow-0{flex-grow:0}.flex-grow{flex-grow:1}.border-collapse{border-collapse:collapse}.transform{--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;transform:translate(var(--tw-translate-x)) translateY(var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes spin{to{transform:rotate(360deg)}}@keyframes ping{75%,to{transform:scale(2);opacity:0}}@keyframes pulse{50%{opacity:.5}}@keyframes bounce{0%,to{transform:translateY(-25%);animation-timing-function:cubic-bezier(.8,0,1,1)}50%{transform:none;animation-timing-function:cubic-bezier(0,0,.2,1)}}.animate-spin{animation:spin 1s linear infinite}.cursor-default{cursor:default}.cursor-pointer{cursor:pointer}.cursor-not-allowed{cursor:not-allowed}.select-none{-webkit-user-select:none;user-select:none}.resize{resize:both}.appearance-none{-webkit-appearance:none;appearance:none}.grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-stretch{align-items:stretch}.justify-center{justify-content:center}.self-center{align-self:center}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.overflow-y-hidden{overflow-y:hidden}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-nowrap{white-space:nowrap}.rounded-sm{border-radius:.125rem}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.border-2{border-width:2px}.border{border-width:1px}.border-t-2{border-top-width:2px}.border-t{border-top-width:1px}.border-r{border-right-width:1px}.border-b{border-bottom-width:1px}.border-l-2{border-left-width:2px}.border-l{border-left-width:1px}.border-transparent{border-color:transparent}.border-gray-200{--tw-border-opacity: 1;border-color:rgba(229,231,235,var(--tw-border-opacity))}.border-gray-300{--tw-border-opacity: 1;border-color:rgba(209,213,219,var(--tw-border-opacity))}.border-gray-400{--tw-border-opacity: 1;border-color:rgba(156,163,175,var(--tw-border-opacity))}.border-gray-500{--tw-border-opacity: 1;border-color:rgba(107,114,128,var(--tw-border-opacity))}.border-blue-400{--tw-border-opacity: 1;border-color:rgba(96,165,250,var(--tw-border-opacity))}.border-blue-500{--tw-border-opacity: 1;border-color:rgba(59,130,246,var(--tw-border-opacity))}.hover\:border-gray-300:hover{--tw-border-opacity: 1;border-color:rgba(209,213,219,var(--tw-border-opacity))}.hover\:border-gray-600:hover{--tw-border-opacity: 1;border-color:rgba(75,85,99,var(--tw-border-opacity))}.focus\:border-gray-500:focus{--tw-border-opacity: 1;border-color:rgba(107,114,128,var(--tw-border-opacity))}.focus\:border-blue-500:focus{--tw-border-opacity: 1;border-color:rgba(59,130,246,var(--tw-border-opacity))}.bg-transparent{background-color:transparent}.bg-white{--tw-bg-opacity: 1;background-color:rgba(255,255,255,var(--tw-bg-opacity))}.bg-gray-100{--tw-bg-opacity: 1;background-color:rgba(243,244,246,var(--tw-bg-opacity))}.bg-gray-400{--tw-bg-opacity: 1;background-color:rgba(156,163,175,var(--tw-bg-opacity))}.bg-red-500{--tw-bg-opacity: 1;background-color:rgba(239,68,68,var(--tw-bg-opacity))}.bg-yellow-600{--tw-bg-opacity: 1;background-color:rgba(217,119,6,var(--tw-bg-opacity))}.bg-blue-100{--tw-bg-opacity: 1;background-color:rgba(219,234,254,var(--tw-bg-opacity))}.bg-blue-600{--tw-bg-opacity: 1;background-color:rgba(37,99,235,var(--tw-bg-opacity))}.bg-indigo-50{--tw-bg-opacity: 1;background-color:rgba(238,242,255,var(--tw-bg-opacity))}.hover\:bg-gray-50:hover{--tw-bg-opacity: 1;background-color:rgba(249,250,251,var(--tw-bg-opacity))}.hover\:bg-gray-100:hover{--tw-bg-opacity: 1;background-color:rgba(243,244,246,var(--tw-bg-opacity))}.hover\:bg-gray-200:hover{--tw-bg-opacity: 1;background-color:rgba(229,231,235,var(--tw-bg-opacity))}.hover\:bg-red-100:hover{--tw-bg-opacity: 1;background-color:rgba(254,226,226,var(--tw-bg-opacity))}.hover\:bg-yellow-100:hover{--tw-bg-opacity: 1;background-color:rgba(254,243,199,var(--tw-bg-opacity))}.hover\:bg-yellow-500:hover{--tw-bg-opacity: 1;background-color:rgba(245,158,11,var(--tw-bg-opacity))}.hover\:bg-green-50:hover{--tw-bg-opacity: 1;background-color:rgba(236,253,245,var(--tw-bg-opacity))}.hover\:bg-blue-100:hover{--tw-bg-opacity: 1;background-color:rgba(219,234,254,var(--tw-bg-opacity))}.disabled\:bg-gray-300:disabled{--tw-bg-opacity: 1;background-color:rgba(209,213,219,var(--tw-bg-opacity))}.p-1{padding:.25rem}.p-2{padding:.5rem}.p-4{padding:1rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.pt-0{padding-top:0}.pt-1{padding-top:.25rem}.pt-0\.5{padding-top:.125rem}.pr-2{padding-right:.5rem}.pr-6{padding-right:1.5rem}.pb-0{padding-bottom:0}.pb-1{padding-bottom:.25rem}.pb-2{padding-bottom:.5rem}.pb-0\.5{padding-bottom:.125rem}.pl-2{padding-left:.5rem}.pl-6{padding-left:1.5rem}.text-xs{font-size:.75rem;line-height:1rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.font-semibold{font-weight:600}.font-bold{font-weight:700}.ordinal{--tw-ordinal: var(--tw-empty, );--tw-slashed-zero: var(--tw-empty, );--tw-numeric-figure: var(--tw-empty, );--tw-numeric-spacing: var(--tw-empty, );--tw-numeric-fraction: var(--tw-empty, );font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.ordinal{--tw-ordinal: ordinal}.leading-none{line-height:1}.text-black{--tw-text-opacity: 1;color:rgba(0,0,0,var(--tw-text-opacity))}.text-white{--tw-text-opacity: 1;color:rgba(255,255,255,var(--tw-text-opacity))}.text-gray-300{--tw-text-opacity: 1;color:rgba(209,213,219,var(--tw-text-opacity))}.text-gray-400{--tw-text-opacity: 1;color:rgba(156,163,175,var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity: 1;color:rgba(107,114,128,var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity: 1;color:rgba(75,85,99,var(--tw-text-opacity))}.text-gray-700{--tw-text-opacity: 1;color:rgba(55,65,81,var(--tw-text-opacity))}.text-gray-800{--tw-text-opacity: 1;color:rgba(31,41,55,var(--tw-text-opacity))}.text-gray-900{--tw-text-opacity: 1;color:rgba(17,24,39,var(--tw-text-opacity))}.text-red-600{--tw-text-opacity: 1;color:rgba(220,38,38,var(--tw-text-opacity))}.text-yellow-500{--tw-text-opacity: 1;color:rgba(245,158,11,var(--tw-text-opacity))}.text-green-500{--tw-text-opacity: 1;color:rgba(16,185,129,var(--tw-text-opacity))}.text-blue-500{--tw-text-opacity: 1;color:rgba(59,130,246,var(--tw-text-opacity))}.hover\:text-gray-700:hover{--tw-text-opacity: 1;color:rgba(55,65,81,var(--tw-text-opacity))}.hover\:text-purple-600:hover{--tw-text-opacity: 1;color:rgba(124,58,237,var(--tw-text-opacity))}.underline{text-decoration:underline}*,:before,:after{--tw-shadow: 0 0 #0000}.shadow{--tw-shadow: 0 1px 3px 0 rgba(0, 0, 0, .1), 0 1px 2px 0 rgba(0, 0, 0, .06);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgba(0, 0, 0, .1), 0 4px 6px -2px rgba(0, 0, 0, .05);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.outline-none{outline:2px solid transparent;outline-offset:2px}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}*,:before,:after{--tw-ring-inset: var(--tw-empty, );--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgba(59, 130, 246, .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000}.filter{--tw-blur: var(--tw-empty, );--tw-brightness: var(--tw-empty, );--tw-contrast: var(--tw-empty, );--tw-grayscale: var(--tw-empty, );--tw-hue-rotate: var(--tw-empty, );--tw-invert: var(--tw-empty, );--tw-saturate: var(--tw-empty, );--tw-sepia: var(--tw-empty, );--tw-drop-shadow: var(--tw-empty, );filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.blur{--tw-blur: blur(8px)}@media (min-width: 768px){.md\:col-span-2{grid-column:span 2 / span 2}.md\:col-span-3{grid-column:span 3 / span 3}.md\:col-span-7{grid-column:span 7 / span 7}.md\:grid{display:grid}.md\:grid-cols-12{grid-template-columns:repeat(12,minmax(0,1fr))}.md\:flex-col{flex-direction:column}}@media (min-width: 1280px){.xl\:col-span-1{grid-column:span 1 / span 1}.xl\:col-span-4{grid-column:span 4 / span 4}.xl\:grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}code{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}
|
package/dist/utils/save.d.ts
CHANGED
|
@@ -4,7 +4,9 @@ export declare function dumpsGWPureSpec(list: VisSpecWithHistory[]): IVisSpec[];
|
|
|
4
4
|
export declare function parseGWPureSpec(list: IVisSpec[]): VisSpecWithHistory[];
|
|
5
5
|
interface IStoInfo {
|
|
6
6
|
datasets: IDataSet[];
|
|
7
|
-
specList:
|
|
7
|
+
specList: ({
|
|
8
|
+
[K in keyof IVisSpec]: K extends 'config' ? Partial<IVisSpec[K]> : IVisSpec[K];
|
|
9
|
+
})[];
|
|
8
10
|
dataSources: IDataSource[];
|
|
9
11
|
}
|
|
10
12
|
export declare function stringifyGWContent(info: IStoInfo): string;
|
package/dist/vis/react-vega.d.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { IViewField, IRow, IStackMode } from '../interfaces';
|
|
3
|
+
export interface IReactVegaHandler {
|
|
4
|
+
getSVGData: () => Promise<string[]>;
|
|
5
|
+
getCanvasData: () => Promise<string[]>;
|
|
6
|
+
downloadSVG: (filename?: string) => Promise<string[]>;
|
|
7
|
+
downloadPNG: (filename?: string) => Promise<string[]>;
|
|
8
|
+
}
|
|
3
9
|
interface ReactVegaProps {
|
|
4
10
|
rows: Readonly<IViewField[]>;
|
|
5
11
|
columns: Readonly<IViewField[]>;
|
|
@@ -19,6 +25,29 @@ interface ReactVegaProps {
|
|
|
19
25
|
width: number;
|
|
20
26
|
height: number;
|
|
21
27
|
onGeomClick?: (values: any, e: any) => void;
|
|
28
|
+
selectEncoding: SingleViewProps['selectEncoding'];
|
|
29
|
+
brushEncoding: SingleViewProps['brushEncoding'];
|
|
30
|
+
}
|
|
31
|
+
interface SingleViewProps {
|
|
32
|
+
x: IViewField;
|
|
33
|
+
y: IViewField;
|
|
34
|
+
color: IViewField;
|
|
35
|
+
opacity: IViewField;
|
|
36
|
+
size: IViewField;
|
|
37
|
+
shape: IViewField;
|
|
38
|
+
xOffset: IViewField;
|
|
39
|
+
yOffset: IViewField;
|
|
40
|
+
row: IViewField;
|
|
41
|
+
column: IViewField;
|
|
42
|
+
theta: IViewField;
|
|
43
|
+
radius: IViewField;
|
|
44
|
+
defaultAggregated: boolean;
|
|
45
|
+
stack: IStackMode;
|
|
46
|
+
geomType: string;
|
|
47
|
+
enableCrossFilter: boolean;
|
|
48
|
+
asCrossFilterTrigger: boolean;
|
|
49
|
+
selectEncoding: 'default' | 'none';
|
|
50
|
+
brushEncoding: 'x' | 'y' | 'default' | 'none';
|
|
22
51
|
}
|
|
23
|
-
declare const ReactVega: React.
|
|
52
|
+
declare const ReactVega: React.ForwardRefExoticComponent<ReactVegaProps & React.RefAttributes<IReactVegaHandler>>;
|
|
24
53
|
export default ReactVega;
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { IReactVegaHandler } from '../vis/react-vega';
|
|
2
3
|
export declare const LiteContainer: import("styled-components").StyledComponent<"div", any, {}, never>;
|
|
3
|
-
|
|
4
|
+
interface IVisualSettings {
|
|
5
|
+
rendererHandler?: React.RefObject<IReactVegaHandler>;
|
|
6
|
+
}
|
|
7
|
+
declare const _default: React.FunctionComponent<IVisualSettings>;
|
|
4
8
|
export default _default;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kanaries/graphic-walker",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.9",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"dev:front_end": "vite --host",
|
|
6
6
|
"dev": "npm run dev:front_end",
|
|
@@ -61,6 +61,7 @@
|
|
|
61
61
|
"@types/styled-components": "^5.1.26",
|
|
62
62
|
"@types/uuid": "^8.3.1",
|
|
63
63
|
"@vitejs/plugin-react-refresh": "^1.3.6",
|
|
64
|
+
"styled-components": "^5.3.6",
|
|
64
65
|
"typescript": "^4.3.2",
|
|
65
66
|
"vite": "^3.1.0"
|
|
66
67
|
},
|
package/src/App.tsx
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import React, { useState, useEffect } from 'react';
|
|
1
|
+
import React, { useState, useEffect, useRef } from 'react';
|
|
2
2
|
import { Specification } from 'visual-insights';
|
|
3
3
|
import { observer } from 'mobx-react-lite';
|
|
4
4
|
import { LightBulbIcon } from '@heroicons/react/24/outline'
|
|
5
5
|
import { toJS } from 'mobx';
|
|
6
6
|
import { useTranslation } from 'react-i18next';
|
|
7
7
|
import { IMutField, IRow } from './interfaces';
|
|
8
|
+
import type { IReactVegaHandler } from './vis/react-vega';
|
|
8
9
|
import VisualSettings from './visualSettings';
|
|
9
10
|
import { Container, NestContainer } from './components/container';
|
|
10
11
|
import ClickMenu from './components/clickMenu';
|
|
@@ -88,6 +89,8 @@ const App: React.FC<EditorProps> = props => {
|
|
|
88
89
|
}
|
|
89
90
|
}, [currentDataset, spec]);
|
|
90
91
|
|
|
92
|
+
const rendererRef = useRef<IReactVegaHandler>(null);
|
|
93
|
+
|
|
91
94
|
return (
|
|
92
95
|
<div className="App">
|
|
93
96
|
{ !hideDataSourceConfig && <DataSourceSegment preWorkDone={insightReady} />}
|
|
@@ -97,23 +100,23 @@ const App: React.FC<EditorProps> = props => {
|
|
|
97
100
|
</div>
|
|
98
101
|
<Container style={{ marginTop: '0em', borderTop: 'none' }}>
|
|
99
102
|
<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
|
+
<VisualSettings rendererHandler={rendererRef} />
|
|
104
|
+
<div className="md:grid md:grid-cols-12 xl:grid-cols-6">
|
|
105
|
+
<div className="md:col-span-3 xl:col-span-1">
|
|
103
106
|
<DatasetFields />
|
|
104
107
|
</div>
|
|
105
|
-
<div className="col-span-2 xl:col-span-1">
|
|
108
|
+
<div className="md:col-span-2 xl:col-span-1">
|
|
106
109
|
<FilterField />
|
|
107
110
|
<AestheticFields />
|
|
108
111
|
</div>
|
|
109
|
-
<div className="col-span-7 xl:col-span-4">
|
|
112
|
+
<div className="md:col-span-7 xl:col-span-4">
|
|
110
113
|
<div>
|
|
111
114
|
<PosFields />
|
|
112
115
|
</div>
|
|
113
116
|
<NestContainer style={{ minHeight: '600px', overflow: 'auto' }} onMouseLeave={() => {
|
|
114
117
|
vizEmbededMenu.show && commonStore.closeEmbededMenu();
|
|
115
118
|
}}>
|
|
116
|
-
{datasets.length > 0 && <ReactiveRenderer />}
|
|
119
|
+
{datasets.length > 0 && <ReactiveRenderer ref={rendererRef} />}
|
|
117
120
|
<InsightBoard />
|
|
118
121
|
{vizEmbededMenu.show && (
|
|
119
122
|
<ClickMenu x={vizEmbededMenu.position[0]} y={vizEmbededMenu.position[1]}>
|
package/src/components/modal.tsx
CHANGED
|
@@ -2,7 +2,6 @@ import React, { useRef } from 'react';
|
|
|
2
2
|
import styled from 'styled-components';
|
|
3
3
|
import { XCircleIcon } from '@heroicons/react/24/outline';
|
|
4
4
|
|
|
5
|
-
|
|
6
5
|
const Background = styled.div({
|
|
7
6
|
position: 'fixed',
|
|
8
7
|
left: 0,
|
|
@@ -14,7 +13,13 @@ const Background = styled.div({
|
|
|
14
13
|
});
|
|
15
14
|
|
|
16
15
|
const Container = styled.div`
|
|
17
|
-
width:
|
|
16
|
+
width: 98%;
|
|
17
|
+
@media (min-width: 600px) {
|
|
18
|
+
width: 80%;
|
|
19
|
+
}
|
|
20
|
+
@media (min-width: 1100px) {
|
|
21
|
+
width: 880px;
|
|
22
|
+
}
|
|
18
23
|
max-height: 800px;
|
|
19
24
|
overflow: auto;
|
|
20
25
|
> div.header {
|
|
@@ -1,17 +1,24 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { Droppable } from "react-beautiful-dnd";
|
|
3
3
|
import { useTranslation } from "react-i18next";
|
|
4
|
+
import styled from 'styled-components';
|
|
4
5
|
import { NestContainer } from "../../components/container";
|
|
5
6
|
import DimFields from "./dimFields";
|
|
6
7
|
import MeaFields from "./meaFields";
|
|
7
8
|
|
|
9
|
+
const DSContainer = styled(NestContainer)`
|
|
10
|
+
@media (min-width: 768px) {
|
|
11
|
+
height: 680px;
|
|
12
|
+
}
|
|
13
|
+
`
|
|
14
|
+
|
|
8
15
|
const DatasetFields: React.FC = (props) => {
|
|
9
16
|
const { t } = useTranslation("translation", { keyPrefix: "main.tabpanel.DatasetFields" });
|
|
10
17
|
|
|
11
18
|
return (
|
|
12
|
-
<
|
|
19
|
+
<DSContainer className="flex md:flex-col" style={{ paddingBlock: 0 }}>
|
|
13
20
|
<h4 className="text-xs mb-2 flex-grow-0 cursor-default select-none mt-2">{t("field_list")}</h4>
|
|
14
|
-
<div className="pd-1 overflow-y-auto" style={{ maxHeight: "380px" }}>
|
|
21
|
+
<div className="pd-1 overflow-y-auto" style={{ maxHeight: "380px", minHeight: '100px' }}>
|
|
15
22
|
<Droppable droppableId="dimensions" direction="vertical">
|
|
16
23
|
{(provided, snapshot) => <DimFields provided={provided} />}
|
|
17
24
|
</Droppable>
|
|
@@ -21,7 +28,7 @@ const DatasetFields: React.FC = (props) => {
|
|
|
21
28
|
{(provided, snapshot) => <MeaFields provided={provided} />}
|
|
22
29
|
</Droppable>
|
|
23
30
|
</div>
|
|
24
|
-
</
|
|
31
|
+
</DSContainer>
|
|
25
32
|
);
|
|
26
33
|
};
|
|
27
34
|
|
package/src/interfaces.ts
CHANGED
|
@@ -129,13 +129,26 @@ export type IFilterRule = {
|
|
|
129
129
|
value: Set<string | number>;
|
|
130
130
|
};
|
|
131
131
|
|
|
132
|
+
export const EXPLORATION_TYPES = [
|
|
133
|
+
'none',
|
|
134
|
+
'brush',
|
|
135
|
+
'point',
|
|
136
|
+
] as const;
|
|
137
|
+
|
|
138
|
+
export const BRUSH_DIRECTIONS = [
|
|
139
|
+
'default',
|
|
140
|
+
'x',
|
|
141
|
+
'y',
|
|
142
|
+
] as const;
|
|
132
143
|
|
|
133
144
|
export type IStackMode = 'none' | 'stack' | 'normalize';
|
|
145
|
+
export type IExplorationType = (typeof EXPLORATION_TYPES)[number];
|
|
146
|
+
export type IBrushDirection = (typeof BRUSH_DIRECTIONS)[number];
|
|
134
147
|
|
|
135
148
|
export interface IVisualConfig {
|
|
136
149
|
defaultAggregated: boolean;
|
|
137
150
|
geoms: string[];
|
|
138
|
-
stack:
|
|
151
|
+
stack: IStackMode;
|
|
139
152
|
showActions: boolean;
|
|
140
153
|
interactiveScale: boolean;
|
|
141
154
|
sorted: 'none' | 'ascending' | 'descending';
|
|
@@ -144,6 +157,11 @@ export interface IVisualConfig {
|
|
|
144
157
|
width: number;
|
|
145
158
|
height: number;
|
|
146
159
|
}
|
|
160
|
+
exploration: {
|
|
161
|
+
mode: IExplorationType;
|
|
162
|
+
/** works when mode is 'brush' */
|
|
163
|
+
brushDirection: IBrushDirection;
|
|
164
|
+
};
|
|
147
165
|
}
|
|
148
166
|
|
|
149
167
|
export interface IVisSpec {
|
package/src/locales/en-US.json
CHANGED
|
@@ -30,6 +30,18 @@
|
|
|
30
30
|
"auto": "Auto",
|
|
31
31
|
"fixed": "Fixed"
|
|
32
32
|
},
|
|
33
|
+
"exploration_mode": {
|
|
34
|
+
"__enum__": "Exploration Mode",
|
|
35
|
+
"none": "Off",
|
|
36
|
+
"brush": "Brush",
|
|
37
|
+
"point": "Point"
|
|
38
|
+
},
|
|
39
|
+
"brush_mode": {
|
|
40
|
+
"__enum__": "Brush Direction",
|
|
41
|
+
"default": "Both",
|
|
42
|
+
"x": "X-Only",
|
|
43
|
+
"y": "Y-Only"
|
|
44
|
+
},
|
|
33
45
|
"draggable_key": {
|
|
34
46
|
"fields": "Fields",
|
|
35
47
|
"columns": "Columns",
|
|
@@ -45,7 +57,14 @@
|
|
|
45
57
|
"aggregator": {
|
|
46
58
|
"sum": "Sum",
|
|
47
59
|
"mean": "Mean",
|
|
48
|
-
"count": "Count"
|
|
60
|
+
"count": "Count",
|
|
61
|
+
"median": "Median",
|
|
62
|
+
"min": "Min",
|
|
63
|
+
"max": "Max",
|
|
64
|
+
"q1": "Q1",
|
|
65
|
+
"q3": "Q3",
|
|
66
|
+
"stdev": "Standard Deviation",
|
|
67
|
+
"variance": "Variance"
|
|
49
68
|
},
|
|
50
69
|
"filter_type": {
|
|
51
70
|
"one_of": "One-Of",
|
|
@@ -104,7 +123,9 @@
|
|
|
104
123
|
"button": {
|
|
105
124
|
"ascending": "Sort in Ascending Order",
|
|
106
125
|
"descending": "Sort in Descending Order",
|
|
107
|
-
"transpose": "Transpose"
|
|
126
|
+
"transpose": "Transpose",
|
|
127
|
+
"export_chart": "Export",
|
|
128
|
+
"export_chart_as": "Export as {{type}}"
|
|
108
129
|
},
|
|
109
130
|
"size": "Resize",
|
|
110
131
|
"size_setting": {
|
package/src/locales/zh-CN.json
CHANGED
|
@@ -24,6 +24,18 @@
|
|
|
24
24
|
"auto": "自动",
|
|
25
25
|
"fixed": "固定"
|
|
26
26
|
},
|
|
27
|
+
"exploration_mode": {
|
|
28
|
+
"__enum__": "探索交互",
|
|
29
|
+
"none": "关",
|
|
30
|
+
"brush": "范围",
|
|
31
|
+
"point": "目标"
|
|
32
|
+
},
|
|
33
|
+
"brush_mode": {
|
|
34
|
+
"__enum__": "框选方向",
|
|
35
|
+
"default": "所有",
|
|
36
|
+
"x": "仅 X 轴",
|
|
37
|
+
"y": "仅 Y 轴"
|
|
38
|
+
},
|
|
27
39
|
"stack_mode": {
|
|
28
40
|
"__enum__": "堆叠模式",
|
|
29
41
|
"none": "关闭",
|
|
@@ -45,7 +57,14 @@
|
|
|
45
57
|
"aggregator": {
|
|
46
58
|
"sum": "求和",
|
|
47
59
|
"mean": "平均值",
|
|
48
|
-
"count": "计数"
|
|
60
|
+
"count": "计数",
|
|
61
|
+
"median": "中位数",
|
|
62
|
+
"min": "最小值",
|
|
63
|
+
"max": "最大值",
|
|
64
|
+
"q1": "Q1",
|
|
65
|
+
"q3": "Q3",
|
|
66
|
+
"stdev": "标准差",
|
|
67
|
+
"variance": "方差"
|
|
49
68
|
},
|
|
50
69
|
"filter_type": {
|
|
51
70
|
"one_of": "按值筛选",
|
|
@@ -104,7 +123,9 @@
|
|
|
104
123
|
"button": {
|
|
105
124
|
"ascending": "升序排序",
|
|
106
125
|
"descending": "降序排序",
|
|
107
|
-
"transpose": "转置"
|
|
126
|
+
"transpose": "转置",
|
|
127
|
+
"export_chart": "导出",
|
|
128
|
+
"export_chart_as": "导出 {{type}}"
|
|
108
129
|
},
|
|
109
130
|
"size": "调整尺寸",
|
|
110
131
|
"size_setting": {
|
package/src/renderer/index.tsx
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { runInAction, toJS } from 'mobx';
|
|
2
2
|
import { observer } from 'mobx-react-lite';
|
|
3
3
|
import { Resizable } from 're-resizable';
|
|
4
|
-
import React, { useState, useCallback, useEffect, useRef } from 'react';
|
|
4
|
+
import React, { useState, useCallback, useEffect, useRef, forwardRef } from 'react';
|
|
5
5
|
import { applyFilter } from '../services';
|
|
6
6
|
import { useGlobalStore } from '../store';
|
|
7
|
-
import ReactVega from '../vis/react-vega';
|
|
7
|
+
import ReactVega, { IReactVegaHandler } from '../vis/react-vega';
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
const ReactiveRenderer
|
|
10
|
+
const ReactiveRenderer = forwardRef<IReactVegaHandler, {}>(function ReactiveRenderer (props, ref) {
|
|
11
11
|
const { vizStore, commonStore } = useGlobalStore();
|
|
12
12
|
const { draggableFieldState, visualConfig } = vizStore;
|
|
13
|
-
const { geoms, interactiveScale, defaultAggregated, stack, showActions, size } = visualConfig;
|
|
13
|
+
const { geoms, interactiveScale, defaultAggregated, stack, showActions, size, exploration } = visualConfig;
|
|
14
14
|
const { currentDataset } = commonStore;
|
|
15
15
|
const { filters } = draggableFieldState;
|
|
16
16
|
|
|
@@ -27,13 +27,17 @@ const ReactiveRenderer: React.FC = props => {
|
|
|
27
27
|
const colLeftFacetFields = columns.slice(0, -1).filter(f => f.analyticType === 'dimension');
|
|
28
28
|
|
|
29
29
|
const hasFacet = rowLeftFacetFields.length > 0 || colLeftFacetFields.length > 0;
|
|
30
|
+
|
|
31
|
+
const shouldTriggerMenu = exploration.mode === 'none';
|
|
30
32
|
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
const handleGeomClick = useCallback((values: any, e: any) => {
|
|
34
|
+
if (shouldTriggerMenu) {
|
|
35
|
+
runInAction(() => {
|
|
36
|
+
commonStore.showEmbededMenu([e.pageX, e.pageY])
|
|
37
|
+
commonStore.setFilters(values);
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}, [shouldTriggerMenu]);
|
|
37
41
|
|
|
38
42
|
// apply filters
|
|
39
43
|
const { dataSource } = currentDataset;
|
|
@@ -93,12 +97,15 @@ const ReactiveRenderer: React.FC = props => {
|
|
|
93
97
|
shape={shape[0]}
|
|
94
98
|
opacity={opacity[0]}
|
|
95
99
|
size={sizeChannel[0]}
|
|
96
|
-
onGeomClick={onGeomClick}
|
|
97
100
|
showActions={showActions}
|
|
98
101
|
width={size.width - 12 * 4}
|
|
99
102
|
height={size.height - 12 * 4}
|
|
103
|
+
ref={ref}
|
|
104
|
+
brushEncoding={exploration.mode === 'brush' ? exploration.brushDirection : 'none'}
|
|
105
|
+
selectEncoding={exploration.mode === 'point' ? 'default' : 'none'}
|
|
106
|
+
onGeomClick={handleGeomClick}
|
|
100
107
|
/>
|
|
101
108
|
</Resizable>
|
|
102
|
-
}
|
|
109
|
+
});
|
|
103
110
|
|
|
104
111
|
export default observer(ReactiveRenderer);
|
|
@@ -2,7 +2,7 @@ import { IReactionDisposer, makeAutoObservable, observable, reaction, toJS } fro
|
|
|
2
2
|
import produce from 'immer';
|
|
3
3
|
import { v4 as uuidv4 } from 'uuid';
|
|
4
4
|
import { Specification } from "visual-insights";
|
|
5
|
-
import { DataSet, DraggableFieldState, IFilterRule, IViewField, IVisualConfig } from "../interfaces";
|
|
5
|
+
import { DataSet, DraggableFieldState, IFilterRule, IViewField, IVisSpec, IVisualConfig } from "../interfaces";
|
|
6
6
|
import { CHANNEL_LIMIT, GEMO_TYPES, MetaFieldKeys } from "../config";
|
|
7
7
|
import { makeBinField, makeLogField } from "../utils/normalization";
|
|
8
8
|
import { VisSpecWithHistory } from "../models/visSpecHistory";
|
|
@@ -69,7 +69,11 @@ function initVisualConfig (): IVisualConfig {
|
|
|
69
69
|
mode: 'auto',
|
|
70
70
|
width: 320,
|
|
71
71
|
height: 200
|
|
72
|
-
}
|
|
72
|
+
},
|
|
73
|
+
exploration: {
|
|
74
|
+
mode: 'brush',
|
|
75
|
+
brushDirection: 'default',
|
|
76
|
+
},
|
|
73
77
|
}
|
|
74
78
|
}
|
|
75
79
|
|
|
@@ -77,6 +81,16 @@ type DeepReadonly<T extends Record<keyof any, any>> = {
|
|
|
77
81
|
readonly [K in keyof T]: T[K] extends Record<keyof any, any> ? DeepReadonly<T[K]> : T[K];
|
|
78
82
|
};
|
|
79
83
|
|
|
84
|
+
const forwardVisualConfigs = (backwards: ReturnType<typeof parseGWContent>['specList']): IVisSpec[] => {
|
|
85
|
+
return backwards.map(content => ({
|
|
86
|
+
...content,
|
|
87
|
+
config: {
|
|
88
|
+
...initVisualConfig(),
|
|
89
|
+
...content.config,
|
|
90
|
+
},
|
|
91
|
+
}));
|
|
92
|
+
};
|
|
93
|
+
|
|
80
94
|
|
|
81
95
|
export class VizSpecStore {
|
|
82
96
|
// public fields: IViewField[] = [];
|
|
@@ -363,6 +377,16 @@ export class VizSpecStore {
|
|
|
363
377
|
config.size.height = height;
|
|
364
378
|
});
|
|
365
379
|
}
|
|
380
|
+
public setExploration(value: Partial<IVisualConfig['exploration']>) {
|
|
381
|
+
this.useMutable(({ config }) => {
|
|
382
|
+
if (value.mode) {
|
|
383
|
+
config.exploration.mode = value.mode;
|
|
384
|
+
}
|
|
385
|
+
if (value.brushDirection) {
|
|
386
|
+
config.exploration.brushDirection = value.brushDirection;
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
}
|
|
366
390
|
public reorderField(stateKey: keyof DraggableFieldState, sourceIndex: number, destinationIndex: number) {
|
|
367
391
|
if (MetaFieldKeys.includes(stateKey)) return;
|
|
368
392
|
if (sourceIndex === destinationIndex) return;
|
|
@@ -580,7 +604,8 @@ export class VizSpecStore {
|
|
|
580
604
|
this.commonStore.datasets = content.datasets;
|
|
581
605
|
this.commonStore.dataSources = content.dataSources;
|
|
582
606
|
this.commonStore.dsIndex = Math.max(content.datasets.length - 1, 0);
|
|
583
|
-
|
|
607
|
+
// 补上初始化新版本特性
|
|
608
|
+
this.visList = parseGWPureSpec(forwardVisualConfigs(content.specList));
|
|
584
609
|
this.visIndex = 0;
|
|
585
610
|
}
|
|
586
611
|
}
|
package/src/utils/save.ts
CHANGED
|
@@ -12,7 +12,10 @@ export function parseGWPureSpec (list: IVisSpec[]): VisSpecWithHistory[] {
|
|
|
12
12
|
|
|
13
13
|
interface IStoInfo {
|
|
14
14
|
datasets: IDataSet[];
|
|
15
|
-
specList:
|
|
15
|
+
specList: ({
|
|
16
|
+
/** 由于 gw 内部实现暂时未锁版本,这里获取到的信息可能会与当前实例内容有偏差,需要用初始值合入 */
|
|
17
|
+
[K in keyof IVisSpec]: K extends 'config' ? Partial<IVisSpec[K]> : IVisSpec[K];
|
|
18
|
+
})[];
|
|
16
19
|
dataSources: IDataSource[]
|
|
17
20
|
}
|
|
18
21
|
|