Skip to content

Commit 270d6c7

Browse files
authored
feat(graph-layers): Add graph widgets (partially functional) (#161)
1 parent e630af4 commit 270d6c7

29 files changed

+563
-57
lines changed

.eslintrc.cjs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,15 @@ module.exports = getESLintConfig({
6161
],
6262
'@typescript-eslint/no-empty-function': 0
6363
}
64+
},
65+
{
66+
files: ['modules/**/*widget*.tsx', 'modules/**/widgets/**/*'],
67+
rules: {
68+
// For widgets. Disable React-style JSX linting since they conflict with Preact JSX.
69+
'react/react-in-jsx-scope': 0
70+
}
6471
}
72+
6573
],
6674
rules: {
6775
// custom rules

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

Lines changed: 38 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,32 +15,49 @@ const DEFAULT_NODE_SIZE = 5;
1515

1616
const DEFAULT_DATASET = 'Random (20, 40)';
1717

18+
const LAYOUTS = ['D3ForceLayout', 'GPUForceLayout', 'SimpleLayout'];
19+
1820
export class App extends Component {
1921
state = {
20-
selectedDataset: DEFAULT_DATASET
22+
selectedDataset: DEFAULT_DATASET,
23+
selectedLayout: DEFAULT_DATASET
2124
};
2225

2326
handleChangeGraph = ({target: {value}}) => this.setState({selectedDataset: value});
2427

28+
handleChangeLayout = ({target: {value}}) => this.setState({selectedLayout: value});
29+
2530
render() {
2631
const {selectedDataset} = this.state;
2732
const graphData = SAMPLE_GRAPH_DATASETS[selectedDataset]();
2833
const graph = JSONLoader({json: graphData});
2934

35+
// return (
36+
// <div style={{width: '100%', zIndex: 999}}>
37+
// <div>
38+
// Dataset:
39+
// <select value={this.state.selectedDataset} onChange={this.handleChangeGraph}>
40+
// {Object.keys(SAMPLE_GRAPH_DATASETS).map((data) => (
41+
// <option key={data} value={data}>
42+
// {data}
43+
// </option>
44+
// ))}
45+
// </select>
46+
// </div>
47+
// <div>
48+
// Layout:
49+
// <select value={this.state.selectedLayout} onChange={this.handleChangeLayout}>
50+
// {LAYOUTS.map((data) => (
51+
// <option key={data} value={data}>
52+
// {data}
53+
// </option>
54+
// ))}
55+
// </select>
56+
// </div>
57+
// </div>
58+
3059
return (
3160
<div style={{display: 'flex', flexDirection: 'column', height: '100%'}}>
32-
<div style={{width: '100%', zIndex: 999}}>
33-
<div>
34-
Dataset:
35-
<select value={this.state.selectedDataset} onChange={this.handleChangeGraph}>
36-
{Object.keys(SAMPLE_GRAPH_DATASETS).map((data) => (
37-
<option key={data} value={data}>
38-
{data}
39-
</option>
40-
))}
41-
</select>
42-
</div>
43-
</div>
4461
<div style={{width: '100%', flex: 1}}>
4562
<GraphGL
4663
graph={graph}
@@ -63,11 +80,12 @@ export class App extends Component {
6380
}
6481
}
6582

66-
if (document.body) {
67-
document.body.style.margin = '0';
68-
const container = document.createElement('div');
69-
document.body.appendChild(container);
70-
const root = createRoot(container);
71-
root.render(<App />);
83+
export function renderToDOM() {
84+
if (document.body) {
85+
document.body.style.margin = '0';
86+
const container = document.createElement('div');
87+
document.body.appendChild(container);
88+
const root = createRoot(container);
89+
root.render(<App />);
90+
}
7291
}
73-
Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
<!doctype html>
22
<html lang="en">
3-
<head>
4-
<meta charset="utf-8" />
5-
<title>deck.gl Community Example</title>
6-
<meta name="viewport" content="width=device-width, initial-scale=1" />
7-
</head>
8-
<body></body>
9-
<script type="module" src="./app.tsx"></script>
3+
<head>
4+
<meta charset="utf-8" />
5+
<title>deck.gl Community Example</title>
6+
<meta name="viewport" content="width=device-width, initial-scale=1" />
7+
</head>
8+
<body></body>
9+
<script type="module">
10+
import {renderToDOM} from "./app.tsx";
11+
renderToDOM(document.body);
12+
</script>
1013
</html>

examples/graph-layers/graph-viewer/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
},
1010
"dependencies": {
1111
"@deck.gl-community/graph-layers": "9.0.2",
12+
"@deck.gl-community/react": "9.0.2",
1213
"deck.gl": "^9.0.0"
1314
},
1415
"devDependencies": {

examples/graph-layers/graph-viewer/react-graph-layers/graph-gl.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import DeckGL from '@deck.gl/react';
88
import {OrthographicView} from '@deck.gl/core';
99
import {BaseLayout, Graph, GraphLayer, log, SimpleLayout} from '@deck.gl-community/graph-layers';
1010
import {PositionedViewControl} from '@deck.gl-community/react';
11+
import {ViewControlWidget} from '@deck.gl-community/graph-layers';
12+
import '@deck.gl/widgets/stylesheet.css';
1113

1214
import {extent} from 'd3-array';
1315
import {useGraphEngine} from './use-graph-engine';
@@ -211,17 +213,22 @@ export const GraphGL = ({
211213
]
212214
) as any
213215
}
216+
widgets={[
217+
new ViewControlWidget({})
218+
]}
214219
getTooltip={getTooltip}
215220
onHover={onHover}
216221
/>
217-
<ViewControlComponent
222+
{/* View control component
223+
<ViewControlComponent
218224
fitBounds={fitBounds}
219225
panBy={panBy}
220226
zoomBy={zoomBy}
221227
zoomLevel={viewState.zoom}
222228
maxZoom={maxZoom}
223229
minZoom={minZoom}
224230
/>
231+
*/}
225232
</div>
226233
</>
227234
);
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { defineConfig } from 'vite';
2+
import fs from 'fs';
3+
4+
/** Run against local source */
5+
const getAliases = async (frameworkName, frameworkRootDir) => {
6+
const modules = await fs.promises.readdir(`${frameworkRootDir}/modules`)
7+
const aliases = {}
8+
modules.forEach(module => {
9+
aliases[`${frameworkName}/${module}`] = `${frameworkRootDir}/modules/${module}/src`;
10+
})
11+
// console.log(aliases);
12+
return aliases
13+
}
14+
15+
const alias = await getAliases('@deck.gl-community', `${__dirname}/../../..`);
16+
17+
// https://vitejs.dev/config/
18+
export default defineConfig(async () => ({
19+
resolve: {alias},
20+
server: {open: true}
21+
}))

modules/graph-layers/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@
3333
"dependencies": {
3434
"@deck.gl/core": "^9.0.12",
3535
"@deck.gl/layers": "^9.0.12",
36+
"@deck.gl/widgets": "^9.0.12",
3637
"@luma.gl/core": "^9.0.12",
38+
"@probe.gl/log": "^4.0.4",
3739
"cardinal-spline-js": "^2.3.10",
3840
"color": "^4.2.3",
3941
"core-js": "^3.29.0",
@@ -45,7 +47,7 @@
4547
"global": "^4.4.0",
4648
"lodash.isequal": "^4.5.0",
4749
"lodash.pick": "^4.4.0",
48-
"probe.gl": "^3.6.0",
50+
"preact": "^10.17.0",
4951
"raf": "^3.4.1"
5052
},
5153
"devDependencies": {

modules/graph-layers/src/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,7 @@ export {EdgeLayer} from './layers/edge-layer';
4040

4141
/** @deprecated Use EdgeLayer */
4242
export {EdgeLayer as CompositeEdgeLayer} from './layers/edge-layer';
43+
44+
// Widgets
45+
46+
export {ViewControlWidget} from './widgets/view-control-widget';

modules/graph-layers/src/utils/log.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// SPDX-License-Identifier: MIT
33
// Copyright (c) vis.gl contributors
44

5-
import {Log, COLOR} from 'probe.gl';
5+
import {Log, COLOR} from '@probe.gl/log';
66

77
export const log = new Log({id: 'graph-layers'}).enable();
88

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// deck.gl-community
2+
// SPDX-License-Identifier: MIT
3+
// Copyright (c) vis.gl contributors
4+
5+
import {Component} from 'preact';
6+
7+
export type LongPressButtonProps = {
8+
onClick: () => void;
9+
children: any;
10+
};
11+
12+
export class LongPressButton extends Component<LongPressButtonProps> {
13+
buttonPressTimer: ReturnType<typeof setTimeout> | null = null;
14+
15+
_repeat = () => {
16+
if (this.buttonPressTimer) {
17+
this.props.onClick();
18+
this.buttonPressTimer = setTimeout(this._repeat, 100);
19+
}
20+
};
21+
22+
_handleButtonPress = () => {
23+
this.buttonPressTimer = setTimeout(this._repeat, 100);
24+
};
25+
26+
_handleButtonRelease = () => {
27+
if (this.buttonPressTimer) {
28+
clearTimeout(this.buttonPressTimer);
29+
}
30+
this.buttonPressTimer = null;
31+
};
32+
33+
render() {
34+
return (
35+
<div className="deck-widget-button">
36+
<div
37+
style={{
38+
pointerEvents: 'auto'
39+
}}
40+
onMouseDown={(event) => {
41+
this._handleButtonPress();
42+
document.addEventListener('mouseup', this._handleButtonRelease, {once: true});
43+
}}
44+
>
45+
{this.props.children}
46+
</div>
47+
</div>
48+
);
49+
}
50+
}

0 commit comments

Comments
 (0)