Skip to content

Commit

Permalink
feat&fix: repeat & facet hack
Browse files Browse the repository at this point in the history
  • Loading branch information
ObservedObserver committed Sep 25, 2021
1 parent 2f44a3b commit 36894bc
Show file tree
Hide file tree
Showing 10 changed files with 377 additions and 74 deletions.
3 changes: 1 addition & 2 deletions packages/frontend/src/pages/visualInterface/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import React from 'react';
import React, { useMemo } from 'react';
import { observer } from 'mobx-react-lite';
import { GraphicWalker } from '@kanaries/graphic-walker';
import { useGlobalStore } from '../../store';
import { useMemo } from 'react';
import { IMutField } from '@kanaries/graphic-walker/dist/interfaces';
import '@kanaries/graphic-walker/dist/style.css';

Expand Down
1 change: 1 addition & 0 deletions packages/graphic-walker/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"react-beautiful-dnd": "^13.1.0",
"react-dom": "^17.0.2",
"react-json-view": "^1.21.3",
"rxjs": "^7.3.0",
"styled-components": "^5.3.0",
"tailwindcss": "^2.2.15",
"vega": "^5.20.2",
Expand Down
3 changes: 2 additions & 1 deletion packages/graphic-walker/src/Fields/AestheticFields.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ const AestheticFields: React.FC = props => {
{...provided.droppableProps}
ref={provided.innerRef}
>
{provided.placeholder}
{draggableFieldState[dkey.id].map((f, index) => (
<Draggable key={f.id} draggableId={f.id} index={index}>
<Draggable key={`${dkey.id}-${f.id}`} draggableId={`${dkey.id}-${f.id}`} index={index}>
{(provided, snapshot) => {
return (
<Pill
Expand Down
1 change: 1 addition & 0 deletions packages/graphic-walker/src/Fields/DatasetFields.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ const DatasetFields: React.FC = props => {
{...provided.droppableProps}
ref={provided.innerRef}
>
{provided.placeholder}
{dimensions.map((f, index) => (
<Draggable key={f.id} draggableId={f.id} index={dimOriginIndices[index]}>
{(provided, snapshot) => {
Expand Down
3 changes: 2 additions & 1 deletion packages/graphic-walker/src/Fields/posFields.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ const PosFields: React.FC = props => {
{...provided.droppableProps}
ref={provided.innerRef}
>
{provided.placeholder}
{draggableFieldState[dkey.id].map((f, index) => (
<Draggable key={f.id} draggableId={f.id} index={index}>
<Draggable key={`${dkey.id}-${f.id}`} draggableId={`${dkey.id}-${f.id}`} index={index}>
{(provided, snapshot) => {
return (
<Pill
Expand Down
2 changes: 1 addition & 1 deletion packages/graphic-walker/src/config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export const GEMO_TYPES = [
{
value: 'bar',
label: '区间',
label: '矩形',
},
{
value: 'line',
Expand Down
2 changes: 1 addition & 1 deletion packages/graphic-walker/src/utils/normalization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export function compareDistribution (distribution1: Record[], distribution2: Rec
Math.max(targetRecord[mea], record[mea]) /
Math.min(targetRecord[mea], record[mea])
);
console.log('score', score)
// console.log('score', score)
count++;
}
} else {
Expand Down
193 changes: 193 additions & 0 deletions packages/graphic-walker/src/vis/future-react-vega.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
/**
* TODO: This file will be used when vega-lite facets bug is fixed.
* https://github.com/vega/vega-lite/issues/4680
*/
import React, { useEffect, useRef } from 'react';
import { Field, IViewField, Record } from '../interfaces';
import embed from 'vega-embed';
import { Subject } from 'rxjs'
import * as op from 'rxjs/operators';
import { ScenegraphEvent } from 'vega';
const SELECTION_NAME = 'geom';
interface ReactVegaProps {
rows: Field[];
columns: Field[];
dataSource: Record[];
defaultAggregate?: boolean;
geomType: string;
color?: Field;
opacity?: Field;
size?: Field;
onGeomClick?: (values: any, e: any) => void
}
const NULL_FIELD: Field = {
id: '',
name: '',
aggName: 'sum',
type: 'D'
}
const click$ = new Subject<ScenegraphEvent>();
const selection$ = new Subject<any>();
const geomClick$ = selection$.pipe(
op.withLatestFrom(click$),
op.filter(([values, _]) => {
if (Object.keys(values).length > 0) {
return true
}
return false
})
);
function getFieldType(field: Field): 'quantitative' | 'nominal' | 'ordinal' | 'temporal' {
if (field.type === 'M') return 'quantitative';
return 'nominal';
}

function getSingleView(xField: IViewField, yField: IViewField, color: IViewField, opacity: IViewField, size: IViewField, row: IViewField, col: IViewField, defaultAggregated: boolean, geomType: string) {
return {
mark: geomType,
encoding: {
x: {
field: xField.id,
type: getFieldType(xField),
aggregate:
xField.type === 'M' &&
defaultAggregated &&
(xField.aggName as any),
},
y: {
field: yField.id,
type: getFieldType(yField),
aggregate:
yField.type === 'M' &&
defaultAggregated &&
(yField.aggName as any),
},
row: row !== NULL_FIELD ? {
field: row.id,
type: getFieldType(row),
} : undefined,
column: col !== NULL_FIELD ? {
field: col.id,
type: getFieldType(col),
} : undefined,
color: color !== NULL_FIELD ? {
field: color.id,
type: getFieldType(color)
} : undefined,
opacity: opacity !== NULL_FIELD ? {
field: opacity.id,
type: getFieldType(opacity)
} : undefined,
size: size !== NULL_FIELD ? {
field: size.id,
type: getFieldType(size)
} : undefined
}
};
}
const ReactVega: React.FC<ReactVegaProps> = props => {
const {
dataSource = [],
rows = [],
columns = [],
defaultAggregate = true,
geomType,
color,
opacity,
size,
onGeomClick
} = props;
const container = useRef<HTMLDivElement>(null);
useEffect(() => {
const clickSub = geomClick$.subscribe(([values, e]) => {
if (onGeomClick) {
onGeomClick(values, e);
}
})
return () => {
clickSub.unsubscribe();
}
}, []);
useEffect(() => {
if (container.current) {
const rowDims = rows.filter(f => f.type === 'D');
const colDims = columns.filter(f => f.type === 'D');
const rowMeas = rows.filter(f => f.type === 'M');
const colMeas = columns.filter(f => f.type === 'M');

const yField = rows.length > 0 ? rows[rows.length - 1] : NULL_FIELD;
const xField = columns.length > 0 ? columns[columns.length - 1] : NULL_FIELD;

const rowFacetFields = rowDims.slice(0, -1);
const colFacetFields = colDims.slice(0, -1);
const rowFacetField = rowFacetFields.length > 0 ? rowFacetFields[rowFacetFields.length - 1] : NULL_FIELD;
const colFacetField = colFacetFields.length > 0 ? colFacetFields[colFacetFields.length - 1] : NULL_FIELD;

const rowRepeatFields = rowMeas.length === 0 ? rowDims.slice(-1) : rowMeas;//rowMeas.slice(0, -1);
const colRepeatFields = colMeas.length === 0 ? colDims.slice(-1) : colMeas;//colMeas.slice(0, -1);

const rowRepeatField = rowRepeatFields.length > 0 ? rowRepeatFields[rowRepeatFields.length - 1] : NULL_FIELD;
const colRepeatField = colRepeatFields.length > 0 ? colRepeatFields[colRepeatFields.length - 1] : NULL_FIELD;

const dimensions = [...rows, ...columns, color, opacity, size].filter(f => Boolean(f)).map(f => (f as Field).id)

const spec: any = {
data: {
values: dataSource,
},
selection: {
[SELECTION_NAME]: {
type: 'single',
fields: dimensions
}
}
};
if (false) {
// const singleView = getSingleView(
// xField,
// yField,
// color ? color : NULL_FIELD,
// opacity ? opacity : NULL_FIELD,
// size ? size : NULL_FIELD,
// rowFacetField,
// colFacetField,
// defaultAggregate,
// geomType
// );
// spec.mark = singleView.mark;
// spec.encoding = singleView.encoding;
} else {
spec.concat = [];
console.log('latest', rowRepeatFields, colRepeatFields, rowDims, colDims.slice(-1))
for (let i = 0; i < rowRepeatFields.length; i++) {
for (let j = 0; j < colRepeatFields.length; j++) {
const singleView = getSingleView(
colRepeatFields[j] || NULL_FIELD,
rowRepeatFields[i] || NULL_FIELD,
color ? color : NULL_FIELD,
opacity ? opacity : NULL_FIELD,
size ? size : NULL_FIELD,
rowFacetField,
colFacetField,
defaultAggregate,
geomType
);
spec.concat.push(singleView)
}
}
}
console.log(spec)
embed(container.current, spec, { mode: 'vega-lite', actions: false }).then(res => {
res.view.addEventListener('click', (e) => {
click$.next(e);
})
res.view.addSignalListener(SELECTION_NAME, (name: any, values: any) => {
selection$.next(values);
});
});
}
}, [dataSource, rows, columns, defaultAggregate, geomType, color, opacity, size]);
return <div ref={container}></div>
}

export default ReactVega;
Loading

0 comments on commit 36894bc

Please sign in to comment.