Skip to content

Commit ed00a2e

Browse files
authored
website(graph-layers): Add five examples using graph-viewer category filtering (visgl#365)
1 parent 6239302 commit ed00a2e

12 files changed

Lines changed: 133 additions & 33 deletions

File tree

examples/graph-layers/graph-viewer/app.tsx

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,10 @@ import {
3535
} from '@deck.gl-community/graph-layers';
3636

3737
import {ControlPanel} from './control-panel';
38-
import type {LayoutType, ExampleDefinition} from './layout-options';
38+
import type {LayoutType, ExampleDefinition, GraphExampleType} from './layout-options';
3939
import {CollapseControls} from './collapse-controls';
4040
import {StylesheetEditor} from './stylesheet-editor';
41-
import {DEFAULT_EXAMPLE, EXAMPLES} from './examples';
41+
import {EXAMPLES, filterExamplesByType} from './examples';
4242
import {useGraphViewport} from './use-graph-viewport';
4343

4444
const INITIAL_VIEW_STATE = {
@@ -50,7 +50,6 @@ const INITIAL_VIEW_STATE = {
5050

5151
// the default cursor in the view
5252
const DEFAULT_CURSOR = 'default';
53-
const DEFAULT_LAYOUT = DEFAULT_EXAMPLE?.layouts[0] ?? 'd3-force-layout';
5453
const DEFAULT_STYLESHEET_MESSAGE = '// No style defined for this example';
5554

5655
type LayoutFactory = (options?: Record<string, unknown>) => GraphLayout;
@@ -107,9 +106,26 @@ export const useLoading = (engine) => {
107106
return [{isLoading}, loadingDispatch];
108107
};
109108

110-
export function App(props) {
111-
const [selectedExample, setSelectedExample] = useState<ExampleDefinition | undefined>(DEFAULT_EXAMPLE);
112-
const [selectedLayout, setSelectedLayout] = useState<LayoutType>(DEFAULT_LAYOUT);
109+
type AppProps = {
110+
graphType?: GraphExampleType;
111+
};
112+
113+
export function App({graphType = 'graph'}: AppProps) {
114+
const exampleType = graphType;
115+
const examplesForType = useMemo(
116+
() => filterExamplesByType(EXAMPLES, exampleType),
117+
[exampleType]
118+
);
119+
const defaultExample = useMemo(
120+
() => (examplesForType.length ? examplesForType[0] : EXAMPLES[0]),
121+
[examplesForType]
122+
);
123+
const defaultLayout = defaultExample?.layouts[0] ?? 'd3-force-layout';
124+
125+
const [selectedExample, setSelectedExample] = useState<ExampleDefinition | undefined>(
126+
() => defaultExample
127+
);
128+
const [selectedLayout, setSelectedLayout] = useState<LayoutType>(() => defaultLayout);
113129
const [collapseEnabled, setCollapseEnabled] = useState(true);
114130
const [layoutOverrides, setLayoutOverrides] = useState<
115131
Partial<Record<LayoutType, Record<string, unknown>>>
@@ -118,6 +134,12 @@ export function App(props) {
118134
{chainIds: string[]; collapsedIds: string[]}
119135
| null>(null);
120136

137+
useEffect(() => {
138+
setSelectedExample(defaultExample);
139+
setSelectedLayout(defaultLayout);
140+
setLayoutOverrides({});
141+
}, [defaultExample, defaultLayout]);
142+
121143
const graphData = useMemo(() => selectedExample?.data(), [selectedExample]);
122144
const layoutOptions = useMemo(() => {
123145
if (!selectedExample || !selectedLayout) {
@@ -453,7 +475,8 @@ export function App(props) {
453475
>
454476
<ControlPanel
455477
examples={EXAMPLES}
456-
defaultExample={DEFAULT_EXAMPLE}
478+
defaultExample={selectedExample ?? defaultExample}
479+
graphType={exampleType}
457480
onExampleChange={handleExampleChange}
458481
layoutOptions={layoutOptions}
459482
onLayoutOptionsApply={handleApplyLayoutOptions}

examples/graph-layers/graph-viewer/control-panel.tsx

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@
44

55
import React, {useCallback, useEffect, useMemo, useState} from 'react';
66
import type {ReactNode} from 'react';
7-
import type {ExampleDefinition, LayoutType} from './layout-options';
7+
import type {ExampleDefinition, GraphExampleType, LayoutType} from './layout-options';
88
import {LAYOUT_LABELS} from './layout-options';
9+
import {filterExamplesByType} from './examples';
910
import {LayoutOptionsPanel} from './layout-options-panel';
1011

1112
type ControlPanelProps = {
1213
examples: ExampleDefinition[];
1314
defaultExample?: ExampleDefinition;
15+
graphType?: GraphExampleType;
1416
onExampleChange: (example: ExampleDefinition, layout: LayoutType) => void;
1517
children?: ReactNode;
1618
layoutOptions?: Record<string, unknown>;
@@ -20,27 +22,33 @@ type ControlPanelProps = {
2022
export function ControlPanel({
2123
examples,
2224
defaultExample,
25+
graphType,
2326
onExampleChange,
2427
layoutOptions,
2528
onLayoutOptionsApply,
2629
children
2730
}: ControlPanelProps) {
31+
const filteredExamples = useMemo(
32+
() => filterExamplesByType(examples, graphType),
33+
[examples, graphType]
34+
);
35+
2836
const resolveExampleIndex = useCallback(
2937
(example?: ExampleDefinition) => {
3038
if (!example) {
3139
return 0;
3240
}
3341

34-
const index = examples.findIndex((candidate) => candidate === example);
42+
const index = filteredExamples.findIndex((candidate) => candidate === example);
3543
return index === -1 ? 0 : index;
3644
},
37-
[examples]
45+
[filteredExamples]
3846
);
3947

4048
const [selectedExampleIndex, setSelectedExampleIndex] = useState(() =>
4149
resolveExampleIndex(defaultExample)
4250
);
43-
const selectedExample = examples[selectedExampleIndex];
51+
const selectedExample = filteredExamples[selectedExampleIndex];
4452
const availableLayouts = selectedExample?.layouts ?? [];
4553
const [selectedLayout, setSelectedLayout] = useState<LayoutType | undefined>(
4654
availableLayouts[0]
@@ -107,7 +115,7 @@ export function ControlPanel({
107115
);
108116
}, [selectedExample]);
109117

110-
if (!examples.length) {
118+
if (!filteredExamples.length) {
111119
return null;
112120
}
113121

@@ -151,7 +159,7 @@ export function ControlPanel({
151159
color: '#0f172a'
152160
}}
153161
>
154-
{examples.map((example, index) => (
162+
{filteredExamples.map((example, index) => (
155163
<option key={example.name} value={index}>
156164
{example.name}
157165
</option>

examples/graph-layers/graph-viewer/examples.ts

Lines changed: 54 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@
33
// Copyright (c) vis.gl contributors
44

55
import {SAMPLE_GRAPH_DATASETS} from '../../../modules/graph-layers/test/data/graphs/sample-datasets';
6-
import type {ExampleDefinition, ExampleStyles, LayoutType} from './layout-options';
6+
import type {
7+
ExampleDefinition,
8+
ExampleStyles,
9+
GraphExampleType,
10+
LayoutType
11+
} from './layout-options';
712
import witsRaw from '../../../modules/graph-layers/test/data/examples/wits.json';
813
import sampleMultiGraph from './sample-multi-graph.json';
914

@@ -624,7 +629,8 @@ const ML_PIPELINE_EXAMPLE: ExampleDefinition = {
624629
data: dagPipelineDataset,
625630
layouts: ['d3-dag-layout'],
626631
layoutDescriptions: LAYOUT_DESCRIPTIONS,
627-
style: DAG_PIPELINE_STYLE
632+
style: DAG_PIPELINE_STYLE,
633+
type: 'dag'
628634
};
629635

630636
const BROKEN_STYLESHEET_GRAPH: ExampleGraphData = {
@@ -684,7 +690,8 @@ const BROKEN_STYLESHEET_EXAMPLE: ExampleDefinition = {
684690
data: () => cloneGraphData(BROKEN_STYLESHEET_GRAPH),
685691
layouts: ['d3-force-layout'],
686692
layoutDescriptions: LAYOUT_DESCRIPTIONS,
687-
style: BROKEN_STYLESHEET
693+
style: BROKEN_STYLESHEET,
694+
type: 'graph'
688695
};
689696

690697
export const EXAMPLES: ExampleDefinition[] = [
@@ -694,71 +701,80 @@ export const EXAMPLES: ExampleDefinition[] = [
694701
data: SAMPLE_GRAPH_DATASETS['Les Miserable'],
695702
layouts: ['d3-force-layout', 'gpu-force-layout', 'simple-layout'],
696703
layoutDescriptions: LAYOUT_DESCRIPTIONS,
697-
style: LES_MISERABLES_STYLE
704+
style: LES_MISERABLES_STYLE,
705+
type: 'graph'
698706
},
699707
{
700708
name: 'Random (20, 40)',
701709
description: 'Randomly connected graph with 20 nodes and 40 edges.',
702710
data: SAMPLE_GRAPH_DATASETS['Random (20, 40)'],
703711
layouts: ['d3-force-layout', 'gpu-force-layout', 'simple-layout'],
704712
layoutDescriptions: LAYOUT_DESCRIPTIONS,
705-
style: RANDOM_20_40_STYLE
713+
style: RANDOM_20_40_STYLE,
714+
type: 'graph'
706715
},
707716
{
708717
name: 'Random (100, 200)',
709718
description: 'Random graph with 100 nodes and 200 edges.',
710719
data: SAMPLE_GRAPH_DATASETS['Random (100, 200)'],
711720
layouts: ['d3-force-layout', 'gpu-force-layout', 'simple-layout'],
712721
layoutDescriptions: LAYOUT_DESCRIPTIONS,
713-
style: RANDOM_100_200_STYLE
722+
style: RANDOM_100_200_STYLE,
723+
type: 'graph'
714724
},
715725
{
716726
name: 'Random (1000, 2000)',
717727
description: 'Random graph with 1,000 nodes and 2,000 edges.',
718728
data: SAMPLE_GRAPH_DATASETS['Random (1000, 2000)'],
719729
layouts: ['gpu-force-layout', 'd3-force-layout', 'simple-layout'],
720730
layoutDescriptions: LAYOUT_DESCRIPTIONS,
721-
style: RANDOM_1000_2000_STYLE
731+
style: RANDOM_1000_2000_STYLE,
732+
type: 'graph'
722733
},
723734
{
724735
name: 'Random (5000, 3000)',
725736
description: 'Sparse random graph with 5,000 nodes and 3,000 edges.',
726737
data: SAMPLE_GRAPH_DATASETS['Random (5000, 3000)'],
727738
layouts: ['gpu-force-layout', 'd3-force-layout', 'simple-layout'],
728739
layoutDescriptions: LAYOUT_DESCRIPTIONS,
729-
style: RANDOM_5000_3000_STYLE
740+
style: RANDOM_5000_3000_STYLE,
741+
type: 'graph'
730742
},
731743
{
732744
name: 'Ladder (10)',
733745
description: 'Two parallel chains of 10 nodes connected like a ladder.',
734746
data: SAMPLE_GRAPH_DATASETS['Ladder (10)'],
735747
layouts: ['d3-force-layout', 'gpu-force-layout', 'simple-layout'],
736748
layoutDescriptions: LAYOUT_DESCRIPTIONS,
737-
style: LADDER_10_STYLE
749+
style: LADDER_10_STYLE,
750+
type: 'graph'
738751
},
739752
{
740753
name: 'BalancedBinTree (5)',
741754
description: 'Balanced binary tree with branching factor 2 and depth 5.',
742755
data: SAMPLE_GRAPH_DATASETS['BalancedBinTree (5)'],
743756
layouts: ['d3-force-layout', 'gpu-force-layout', 'simple-layout'],
744757
layoutDescriptions: LAYOUT_DESCRIPTIONS,
745-
style: BALANCED_BIN_TREE_5_STYLE
758+
style: BALANCED_BIN_TREE_5_STYLE,
759+
type: 'graph'
746760
},
747761
{
748762
name: 'BalancedBinTree (8)',
749763
description: 'Balanced binary tree with branching factor 2 and depth 8.',
750764
data: SAMPLE_GRAPH_DATASETS['BalancedBinTree (8)'],
751765
layouts: ['d3-force-layout', 'gpu-force-layout', 'simple-layout'],
752766
layoutDescriptions: LAYOUT_DESCRIPTIONS,
753-
style: BALANCED_BIN_TREE_8_STYLE
767+
style: BALANCED_BIN_TREE_8_STYLE,
768+
type: 'graph'
754769
},
755770
{
756771
name: 'Grid (10, 10)',
757772
description: '10x10 lattice grid graph.',
758773
data: SAMPLE_GRAPH_DATASETS['Grid (10, 10)'],
759774
layouts: ['d3-force-layout', 'gpu-force-layout', 'simple-layout'],
760775
layoutDescriptions: LAYOUT_DESCRIPTIONS,
761-
style: GRID_10_10_STYLE
776+
style: GRID_10_10_STYLE,
777+
type: 'graph'
762778
},
763779
{
764780
name: 'WattsStrogatz (100, 10, 0.06)',
@@ -767,7 +783,8 @@ export const EXAMPLES: ExampleDefinition[] = [
767783
data: SAMPLE_GRAPH_DATASETS['WattsStrogatz (100, 10, 0.06)'],
768784
layouts: ['d3-force-layout', 'gpu-force-layout', 'simple-layout'],
769785
layoutDescriptions: LAYOUT_DESCRIPTIONS,
770-
style: WATTS_STROGATZ_STYLE
786+
style: WATTS_STROGATZ_STYLE,
787+
type: 'graph'
771788
},
772789
{
773790
name: 'University hierarchy (radial)',
@@ -777,6 +794,7 @@ export const EXAMPLES: ExampleDefinition[] = [
777794
layouts: ['radial-layout'],
778795
layoutDescriptions: LAYOUT_DESCRIPTIONS,
779796
style: KNOWLEDGE_GRAPH_STYLE,
797+
type: 'radial',
780798
getLayoutOptions: (layout, _data) =>
781799
layout === 'radial-layout'
782800
? {
@@ -793,6 +811,7 @@ export const EXAMPLES: ExampleDefinition[] = [
793811
layouts: ['radial-layout'],
794812
layoutDescriptions: LAYOUT_DESCRIPTIONS,
795813
style: WITS_REGION_STYLE,
814+
type: 'radial',
796815
getLayoutOptions: (layout, _data) =>
797816
layout === 'radial-layout'
798817
? {
@@ -809,6 +828,7 @@ export const EXAMPLES: ExampleDefinition[] = [
809828
layouts: ['hive-plot-layout'],
810829
layoutDescriptions: LAYOUT_DESCRIPTIONS,
811830
style: KNOWLEDGE_GRAPH_STYLE,
831+
type: 'hive',
812832
getLayoutOptions: (layout, _data) =>
813833
layout === 'hive-plot-layout'
814834
? {
@@ -826,6 +846,7 @@ export const EXAMPLES: ExampleDefinition[] = [
826846
layouts: ['hive-plot-layout'],
827847
layoutDescriptions: LAYOUT_DESCRIPTIONS,
828848
style: WITS_REGION_STYLE,
849+
type: 'hive',
829850
getLayoutOptions: (layout, _data) =>
830851
layout === 'hive-plot-layout'
831852
? {
@@ -843,6 +864,7 @@ export const EXAMPLES: ExampleDefinition[] = [
843864
layouts: ['force-multi-graph-layout'],
844865
layoutDescriptions: LAYOUT_DESCRIPTIONS,
845866
style: MULTI_GRAPH_STYLE,
867+
type: 'multi-graph',
846868
getLayoutOptions: (layout, _data) =>
847869
layout === 'force-multi-graph-layout'
848870
? {
@@ -860,6 +882,7 @@ export const EXAMPLES: ExampleDefinition[] = [
860882
layouts: ['force-multi-graph-layout'],
861883
layoutDescriptions: LAYOUT_DESCRIPTIONS,
862884
style: WITS_REGION_STYLE,
885+
type: 'multi-graph',
863886
getLayoutOptions: (layout, _data) =>
864887
layout === 'force-multi-graph-layout'
865888
? {
@@ -874,4 +897,21 @@ export const EXAMPLES: ExampleDefinition[] = [
874897
BROKEN_STYLESHEET_EXAMPLE
875898
];
876899

877-
export const DEFAULT_EXAMPLE = ML_PIPELINE_EXAMPLE;
900+
export function filterExamplesByType(
901+
examples: ExampleDefinition[],
902+
type?: GraphExampleType
903+
): ExampleDefinition[] {
904+
if (!type) {
905+
return examples;
906+
}
907+
908+
return examples.filter((example) => example.type === type);
909+
}
910+
911+
export function getExamplesByType(type?: GraphExampleType): ExampleDefinition[] {
912+
return filterExamplesByType(EXAMPLES, type);
913+
}
914+
915+
export function getDefaultExample(type?: GraphExampleType): ExampleDefinition | undefined {
916+
return getExamplesByType(type)[0];
917+
}

examples/graph-layers/graph-viewer/layout-options.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
import type {GraphLayerProps} from '@deck.gl-community/graph-layers';
66
import {D3DagLayout} from '@deck.gl-community/graph-layers';
77

8+
export type GraphExampleType = 'graph' | 'radial' | 'multi-graph' | 'hive' | 'dag';
9+
810
export type LayoutType =
911
| 'd3-force-layout'
1012
| 'gpu-force-layout'
@@ -24,6 +26,7 @@ export type ExampleDefinition = {
2426
layouts: LayoutType[];
2527
layoutDescriptions: Record<LayoutType, string>;
2628
style: ExampleStyles;
29+
type: GraphExampleType;
2730
getLayoutOptions?: (
2831
layout: LayoutType,
2932
data: {nodes: unknown[]; edges: unknown[]}

website/src/components/example/make-example.jsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,12 @@ export default function makeExample(DemoComponent, {isInteractive = true, style}
4343

4444
const defaultData = Array.isArray(DemoComponent.data) ? DemoComponent.data.map(_ => null) : null;
4545

46-
return function () {
46+
return function ExampleWrapper(wrapperProps = {}) {
4747
const [data, setData] = useState(defaultData);
4848
const [params, setParams] = useState(defaultParams);
4949
const [meta, setMeta] = useState({});
5050
const baseUrl = useBaseUrl('/');
51+
const {mapStyle: mapStyleOverride, ...forwardedProps} = wrapperProps;
5152

5253
const useParam = useCallback(newParameters => {
5354
const newParams = Object.keys(newParameters).reduce((acc, name) => {
@@ -109,8 +110,9 @@ export default function makeExample(DemoComponent, {isInteractive = true, style}
109110
return (
110111
<DemoContainer style={style}>
111112
<DemoComponent
113+
{...forwardedProps}
112114
data={data}
113-
mapStyle={mapStyle || MAPBOX_STYLES.BLANK}
115+
mapStyle={mapStyleOverride || mapStyle || MAPBOX_STYLES.BLANK}
114116
params={params}
115117
useParam={useParam}
116118
onStateChange={updateMeta}

0 commit comments

Comments
 (0)