@cosmos.gl/graph 2.4.0 → 2.5.0
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/config.d.ts +69 -0
- package/dist/index.d.ts +16 -6
- package/dist/index.js +4328 -4129
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +113 -45
- package/dist/index.min.js.map +1 -1
- package/dist/modules/Lines/index.d.ts +8 -0
- package/dist/modules/Store/index.d.ts +14 -2
- package/dist/modules/core-module.d.ts +1 -0
- package/dist/stories/beginners/link-hovering/data-generator.d.ts +19 -0
- package/dist/stories/beginners/link-hovering/index.d.ts +5 -0
- package/dist/stories/beginners.stories.d.ts +1 -0
- package/dist/variables.d.ts +5 -2
- package/package.json +1 -1
- package/src/config.ts +86 -2
- package/src/index.ts +151 -31
- package/src/modules/Lines/draw-curve-line.frag +12 -1
- package/src/modules/Lines/draw-curve-line.vert +29 -2
- package/src/modules/Lines/hovered-line-index.frag +27 -0
- package/src/modules/Lines/hovered-line-index.vert +8 -0
- package/src/modules/Lines/index.ts +112 -2
- package/src/modules/Store/index.ts +33 -2
- package/src/modules/core-module.ts +1 -0
- package/src/stories/1. welcome.mdx +2 -1
- package/src/stories/2. configuration.mdx +10 -1
- package/src/stories/3. api-reference.mdx +13 -4
- package/src/stories/beginners/basic-set-up/index.ts +20 -10
- package/src/stories/beginners/link-hovering/data-generator.ts +198 -0
- package/src/stories/beginners/link-hovering/index.ts +61 -0
- package/src/stories/beginners/link-hovering/style.css +73 -0
- package/src/stories/beginners/quick-start.ts +2 -1
- package/src/stories/beginners/remove-points/index.ts +28 -30
- package/src/stories/beginners.stories.ts +17 -0
- package/src/stories/clusters/polygon-selection/index.ts +2 -4
- package/src/stories/shapes/image-example/index.ts +7 -8
- package/src/variables.ts +5 -2
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
interface Point {
|
|
2
|
+
id: number;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
interface Link {
|
|
6
|
+
source: number;
|
|
7
|
+
target: number;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface NetworkData {
|
|
11
|
+
pointPositions: Float32Array;
|
|
12
|
+
pointColors: Float32Array;
|
|
13
|
+
pointSizes: Float32Array;
|
|
14
|
+
links: Float32Array;
|
|
15
|
+
linkColors: Float32Array;
|
|
16
|
+
linkWidths: Float32Array;
|
|
17
|
+
points: Point[];
|
|
18
|
+
connections: Link[];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function hslToRgb (hue: number, saturation: number, lightness: number): [number, number, number] {
|
|
22
|
+
const c = (1 - Math.abs(2 * lightness - 1)) * saturation
|
|
23
|
+
const x = c * (1 - Math.abs(((hue / 60) % 2) - 1))
|
|
24
|
+
const m = lightness - c / 2
|
|
25
|
+
|
|
26
|
+
let r, g, b
|
|
27
|
+
if (hue >= 0 && hue < 60) {
|
|
28
|
+
r = c; g = x; b = 0
|
|
29
|
+
} else if (hue >= 60 && hue < 120) {
|
|
30
|
+
r = x; g = c; b = 0
|
|
31
|
+
} else if (hue >= 120 && hue < 180) {
|
|
32
|
+
r = 0; g = c; b = x
|
|
33
|
+
} else if (hue >= 180 && hue < 240) {
|
|
34
|
+
r = 0; g = x; b = c
|
|
35
|
+
} else if (hue >= 240 && hue < 300) {
|
|
36
|
+
r = x; g = 0; b = c
|
|
37
|
+
} else {
|
|
38
|
+
r = c; g = 0; b = x
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return [r + m, g + m, b + m]
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function generatePoints (count: number): Point[] {
|
|
45
|
+
const points: Point[] = []
|
|
46
|
+
for (let i = 0; i < count; i++) {
|
|
47
|
+
points.push({ id: i })
|
|
48
|
+
}
|
|
49
|
+
return points
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function generateConnections (points: Point[]): Link[] {
|
|
53
|
+
const connections: Link[] = []
|
|
54
|
+
const pointCount = points.length
|
|
55
|
+
|
|
56
|
+
// Sequential connections
|
|
57
|
+
for (let i = 0; i < pointCount; i++) {
|
|
58
|
+
const nextId1 = (i + 1) % pointCount
|
|
59
|
+
const nextId2 = (i + 2) % pointCount
|
|
60
|
+
connections.push({ source: i, target: nextId1 })
|
|
61
|
+
if (i % 2 === 0) {
|
|
62
|
+
connections.push({ source: i, target: nextId2 })
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Hub connections
|
|
67
|
+
const hubPoints = [0, 10, 20, 30, 40, 50, 60, 70]
|
|
68
|
+
hubPoints.forEach(hub => {
|
|
69
|
+
for (let i = 1; i <= 5; i++) {
|
|
70
|
+
const targetId = (hub + i * 3) % pointCount
|
|
71
|
+
if (targetId !== hub) {
|
|
72
|
+
connections.push({ source: hub, target: targetId })
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
// Cross connections
|
|
78
|
+
for (let i = 0; i < pointCount / 2; i++) {
|
|
79
|
+
const oppositeId = i + Math.floor(pointCount / 2)
|
|
80
|
+
if (i % 3 === 0) {
|
|
81
|
+
connections.push({ source: i, target: oppositeId })
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Random connections
|
|
86
|
+
for (let i = 0; i < 30; i++) {
|
|
87
|
+
const source = Math.floor(Math.random() * pointCount)
|
|
88
|
+
const target = Math.floor(Math.random() * pointCount)
|
|
89
|
+
if (source !== target) {
|
|
90
|
+
const exists = connections.some(conn =>
|
|
91
|
+
(conn.source === source && conn.target === target) ||
|
|
92
|
+
(conn.source === target && conn.target === source)
|
|
93
|
+
)
|
|
94
|
+
if (!exists) {
|
|
95
|
+
connections.push({ source, target })
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return connections
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function generatePointPositions (points: Point[]): Float32Array {
|
|
104
|
+
const radius = 100
|
|
105
|
+
const positions = new Float32Array(points.length * 2)
|
|
106
|
+
|
|
107
|
+
points.forEach((point, i) => {
|
|
108
|
+
const angle = (i / points.length) * Math.PI * 2
|
|
109
|
+
const pointRadius = radius + (Math.random() - 0.5) * 20
|
|
110
|
+
|
|
111
|
+
positions[i * 2] = Math.cos(angle) * pointRadius
|
|
112
|
+
positions[i * 2 + 1] = Math.sin(angle) * pointRadius
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
return positions
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function generatePointColors (points: Point[]): Float32Array {
|
|
119
|
+
const colors = new Float32Array(points.length * 4)
|
|
120
|
+
|
|
121
|
+
points.forEach((point, i) => {
|
|
122
|
+
const hue = (point.id / points.length) * 360
|
|
123
|
+
const [r, g, b] = hslToRgb(hue, 0.8, 0.6)
|
|
124
|
+
|
|
125
|
+
colors[i * 4] = r
|
|
126
|
+
colors[i * 4 + 1] = g
|
|
127
|
+
colors[i * 4 + 2] = b
|
|
128
|
+
colors[i * 4 + 3] = 1.0
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
return colors
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function generatePointSizes (points: Point[]): Float32Array {
|
|
135
|
+
const sizes = new Float32Array(points.length)
|
|
136
|
+
sizes.fill(10)
|
|
137
|
+
return sizes
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function generateLinkData (connections: Link[], points: Point[]): {
|
|
141
|
+
links: Float32Array;
|
|
142
|
+
linkColors: Float32Array;
|
|
143
|
+
linkWidths: Float32Array;
|
|
144
|
+
} {
|
|
145
|
+
const links = new Float32Array(connections.length * 2)
|
|
146
|
+
const linkColors = new Float32Array(connections.length * 4)
|
|
147
|
+
const linkWidths = new Float32Array(connections.length)
|
|
148
|
+
|
|
149
|
+
connections.forEach((connection, i) => {
|
|
150
|
+
links[i * 2] = connection.source
|
|
151
|
+
links[i * 2 + 1] = connection.target
|
|
152
|
+
|
|
153
|
+
// Color links based on average hue of connected points
|
|
154
|
+
const sourceHue = (connection.source / points.length) * 360
|
|
155
|
+
const targetHue = (connection.target / points.length) * 360
|
|
156
|
+
|
|
157
|
+
let avgHue
|
|
158
|
+
const hueDiff = Math.abs(targetHue - sourceHue)
|
|
159
|
+
if (hueDiff > 180) {
|
|
160
|
+
avgHue = ((sourceHue + targetHue + 360) / 2) % 360
|
|
161
|
+
} else {
|
|
162
|
+
avgHue = (sourceHue + targetHue) / 2
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const [r, g, b] = hslToRgb(avgHue, 0.7, 0.5)
|
|
166
|
+
|
|
167
|
+
linkColors[i * 4] = r
|
|
168
|
+
linkColors[i * 4 + 1] = g
|
|
169
|
+
linkColors[i * 4 + 2] = b
|
|
170
|
+
linkColors[i * 4 + 3] = 0.9
|
|
171
|
+
|
|
172
|
+
linkWidths[i] = 2
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
return { links, linkColors, linkWidths }
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export function generateData (pointCount: number = 500): NetworkData {
|
|
179
|
+
const points = generatePoints(pointCount)
|
|
180
|
+
const connections = generateConnections(points)
|
|
181
|
+
|
|
182
|
+
const pointPositions = generatePointPositions(points)
|
|
183
|
+
const pointColors = generatePointColors(points)
|
|
184
|
+
const pointSizes = generatePointSizes(points)
|
|
185
|
+
|
|
186
|
+
const { links, linkColors, linkWidths } = generateLinkData(connections, points)
|
|
187
|
+
|
|
188
|
+
return {
|
|
189
|
+
pointPositions,
|
|
190
|
+
pointColors,
|
|
191
|
+
pointSizes,
|
|
192
|
+
links,
|
|
193
|
+
linkColors,
|
|
194
|
+
linkWidths,
|
|
195
|
+
points,
|
|
196
|
+
connections,
|
|
197
|
+
}
|
|
198
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Graph, GraphConfigInterface } from '@cosmos.gl/graph'
|
|
2
|
+
import { generateData } from './data-generator'
|
|
3
|
+
import './style.css'
|
|
4
|
+
|
|
5
|
+
export const linkHovering = (): { div: HTMLDivElement; graph: Graph } => {
|
|
6
|
+
const data = generateData()
|
|
7
|
+
const infoPanel = document.createElement('div')
|
|
8
|
+
|
|
9
|
+
// Create div container
|
|
10
|
+
const div = document.createElement('div')
|
|
11
|
+
div.style.height = '100vh'
|
|
12
|
+
div.style.width = '100%'
|
|
13
|
+
div.style.position = 'relative'
|
|
14
|
+
|
|
15
|
+
// Configure graph
|
|
16
|
+
const config: GraphConfigInterface = {
|
|
17
|
+
backgroundColor: '#2d313a',
|
|
18
|
+
scalePointsOnZoom: true,
|
|
19
|
+
linkArrows: false,
|
|
20
|
+
curvedLinks: true,
|
|
21
|
+
enableSimulation: false,
|
|
22
|
+
hoveredLinkWidthIncrease: 4,
|
|
23
|
+
attribution: 'visualized with <a href="https://cosmograph.app/" style="color: var(--cosmosgl-attribution-color);" target="_blank">Cosmograph</a>',
|
|
24
|
+
|
|
25
|
+
onLinkMouseOver: (linkIndex: number) => {
|
|
26
|
+
infoPanel.style.display = 'block'
|
|
27
|
+
infoPanel.textContent = `Link ${linkIndex}`
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
onLinkMouseOut: () => {
|
|
31
|
+
infoPanel.style.display = 'none'
|
|
32
|
+
},
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Create graph instance
|
|
36
|
+
const graph = new Graph(div, config)
|
|
37
|
+
|
|
38
|
+
// Set data
|
|
39
|
+
graph.setPointPositions(data.pointPositions)
|
|
40
|
+
graph.setPointColors(data.pointColors)
|
|
41
|
+
graph.setPointSizes(data.pointSizes)
|
|
42
|
+
graph.setLinks(data.links)
|
|
43
|
+
graph.setLinkColors(data.linkColors)
|
|
44
|
+
graph.setLinkWidths(data.linkWidths)
|
|
45
|
+
|
|
46
|
+
// Render graph
|
|
47
|
+
graph.zoom(0.9)
|
|
48
|
+
graph.render()
|
|
49
|
+
|
|
50
|
+
infoPanel.style.cssText = `
|
|
51
|
+
position: absolute;
|
|
52
|
+
top: 20px;
|
|
53
|
+
left: 20px;
|
|
54
|
+
color: white;
|
|
55
|
+
font-size: 14px;
|
|
56
|
+
display: none;
|
|
57
|
+
`
|
|
58
|
+
div.appendChild(infoPanel)
|
|
59
|
+
|
|
60
|
+
return { div, graph }
|
|
61
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/* Enhanced styling for the link hovering demo */
|
|
2
|
+
|
|
3
|
+
.company-network {
|
|
4
|
+
background: radial-gradient(circle at 50% 50%, #1a1a2e 0%, #0a0a0a 100%);
|
|
5
|
+
position: relative;
|
|
6
|
+
overflow: hidden;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.info-panel {
|
|
10
|
+
backdrop-filter: blur(12px);
|
|
11
|
+
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.info-panel:hover {
|
|
15
|
+
transform: translateY(-2px);
|
|
16
|
+
box-shadow: 0 20px 48px rgba(0, 0, 0, 0.6), 0 8px 24px rgba(0, 0, 0, 0.4);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.relationship-type-indicator {
|
|
20
|
+
display: inline-block;
|
|
21
|
+
width: 12px;
|
|
22
|
+
height: 12px;
|
|
23
|
+
border-radius: 50%;
|
|
24
|
+
margin-right: 8px;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.relationship-type-indicator.management {
|
|
28
|
+
background: linear-gradient(45deg, #FFAD6B, #FF8A65);
|
|
29
|
+
box-shadow: 0 2px 8px rgba(255, 173, 107, 0.4);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.relationship-type-indicator.collaboration {
|
|
33
|
+
background: linear-gradient(45deg, #59C0FF, #42A5F5);
|
|
34
|
+
box-shadow: 0 2px 8px rgba(89, 192, 255, 0.4);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.relationship-type-indicator.mentorship {
|
|
38
|
+
background: linear-gradient(45deg, #6BD17B, #66BB6A);
|
|
39
|
+
box-shadow: 0 2px 8px rgba(107, 209, 123, 0.4);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.relationship-type-indicator.friendship {
|
|
43
|
+
background: linear-gradient(45deg, #FF61AD, #EC407A);
|
|
44
|
+
box-shadow: 0 2px 8px rgba(255, 97, 173, 0.4);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.person-card {
|
|
48
|
+
background: rgba(255, 255, 255, 0.03);
|
|
49
|
+
border-radius: 8px;
|
|
50
|
+
padding: 12px;
|
|
51
|
+
margin: 6px 0;
|
|
52
|
+
border-left: 3px solid transparent;
|
|
53
|
+
border: 1px solid rgba(255, 255, 255, 0.06);
|
|
54
|
+
transition: all 0.2s ease;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.person-card.highlighted {
|
|
58
|
+
border-left-color: #59C0FF;
|
|
59
|
+
background: rgba(89, 192, 255, 0.08);
|
|
60
|
+
box-shadow: 0 4px 16px rgba(89, 192, 255, 0.15);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/* Modern color scheme variables */
|
|
64
|
+
:root {
|
|
65
|
+
--cosmos-orange: #FFAD6B;
|
|
66
|
+
--cosmos-blue: #59C0FF;
|
|
67
|
+
--cosmos-green: #6BD17B;
|
|
68
|
+
--cosmos-pink: #FF61AD;
|
|
69
|
+
--cosmos-gray: #C7CDD1;
|
|
70
|
+
--cosmos-dark-bg: rgba(16, 20, 40, 0.95);
|
|
71
|
+
--cosmos-card-bg: rgba(255, 255, 255, 0.03);
|
|
72
|
+
--cosmos-border: rgba(255, 255, 255, 0.08);
|
|
73
|
+
}
|
|
@@ -18,7 +18,8 @@ export const quickStart = (): { graph: Graph; div: HTMLDivElement} => {
|
|
|
18
18
|
fitViewPadding: 0.3, // centers the graph width padding of ~30% of screen
|
|
19
19
|
rescalePositions: true, // rescale positions
|
|
20
20
|
enableDrag: true, // enable dragging points
|
|
21
|
-
|
|
21
|
+
onPointClick: pointIndex => { console.log('Clicked point index: ', pointIndex) },
|
|
22
|
+
onBackgroundClick: () => { console.log('Clicked background') },
|
|
22
23
|
attribution: 'visualized with <a href="https://cosmograph.app/" style="color: var(--cosmosgl-attribution-color);" target="_blank">Cosmograph</a>',
|
|
23
24
|
/* ... */
|
|
24
25
|
}
|
|
@@ -22,40 +22,38 @@ export const removePoints = (): { graph: Graph; div: HTMLDivElement} => {
|
|
|
22
22
|
|
|
23
23
|
const graph = new Graph(graphDiv, {
|
|
24
24
|
...config,
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
(posIndex % 2 === 0 && posIndex !== i * 2) ||
|
|
25
|
+
onPointClick: (i): void => {
|
|
26
|
+
// Filter out the clicked point from positions array
|
|
27
|
+
const currentPositions = graph.getPointPositions()
|
|
28
|
+
const newPointPositions = currentPositions
|
|
29
|
+
.filter((pos, posIndex) => {
|
|
30
|
+
return (
|
|
31
|
+
(posIndex % 2 === 0 && posIndex !== i * 2) ||
|
|
33
32
|
(posIndex % 2 === 1 && posIndex !== i * 2 + 1)
|
|
34
|
-
)
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
// Convert links array to source-target pairs for easier filtering
|
|
38
|
-
const pairedNumbers = []
|
|
39
|
-
for (let j = 0; j < graphLinks.length; j += 2) {
|
|
40
|
-
const pair = [graphLinks[j], graphLinks[j + 1]]
|
|
41
|
-
pairedNumbers.push(pair)
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Remove links connected to deleted point and adjust indices of remaining links
|
|
45
|
-
graphLinks = (pairedNumbers
|
|
46
|
-
.filter(
|
|
47
|
-
([sourceIndex, targetIndex]) => sourceIndex !== i && targetIndex !== i
|
|
48
33
|
)
|
|
49
|
-
|
|
50
|
-
.map((p) => {
|
|
51
|
-
if (p > i) return p - 1
|
|
52
|
-
else return p
|
|
53
|
-
})
|
|
34
|
+
})
|
|
54
35
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
36
|
+
// Convert links array to source-target pairs for easier filtering
|
|
37
|
+
const pairedNumbers = []
|
|
38
|
+
for (let j = 0; j < graphLinks.length; j += 2) {
|
|
39
|
+
const pair = [graphLinks[j], graphLinks[j + 1]]
|
|
40
|
+
pairedNumbers.push(pair)
|
|
58
41
|
}
|
|
42
|
+
|
|
43
|
+
// Remove links connected to deleted point and adjust indices of remaining links
|
|
44
|
+
graphLinks = (pairedNumbers
|
|
45
|
+
.filter(
|
|
46
|
+
([sourceIndex, targetIndex]) => sourceIndex !== i && targetIndex !== i
|
|
47
|
+
)
|
|
48
|
+
.flat() as number[])
|
|
49
|
+
.map((p) => {
|
|
50
|
+
if (p > i) return p - 1
|
|
51
|
+
else return p
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
graph.setPointPositions(new Float32Array(newPointPositions))
|
|
55
|
+
graph.setLinks(new Float32Array(graphLinks))
|
|
56
|
+
graph.render(isPaused ? 0 : undefined)
|
|
59
57
|
console.log('Clicked node: ', i)
|
|
60
58
|
},
|
|
61
59
|
})
|
|
@@ -6,6 +6,7 @@ import { quickStart } from './beginners/quick-start'
|
|
|
6
6
|
import { basicSetUp } from './beginners/basic-set-up'
|
|
7
7
|
import { pointLabels } from './beginners/point-labels'
|
|
8
8
|
import { removePoints } from './beginners/remove-points'
|
|
9
|
+
import { linkHovering } from './beginners/link-hovering'
|
|
9
10
|
|
|
10
11
|
import quickStartStoryRaw from './beginners/quick-start?raw'
|
|
11
12
|
import basicSetUpStoryRaw from './beginners/basic-set-up/index?raw'
|
|
@@ -19,6 +20,9 @@ import removePointsStoryRaw from './beginners/remove-points/index?raw'
|
|
|
19
20
|
import removePointsStoryCssRaw from './beginners/remove-points/style.css?raw'
|
|
20
21
|
import removePointsStoryConfigRaw from './beginners/remove-points/config.ts?raw'
|
|
21
22
|
import removePointsStoryDataGenRaw from './beginners/remove-points/data-gen.ts?raw'
|
|
23
|
+
import linkHoveringStoryRaw from './beginners/link-hovering/index?raw'
|
|
24
|
+
import linkHoveringStoryDataGenRaw from './beginners/link-hovering/data-generator.ts?raw'
|
|
25
|
+
import linkHoveringStoryCssRaw from './beginners/link-hovering/style.css?raw'
|
|
22
26
|
|
|
23
27
|
// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
|
|
24
28
|
const meta: Meta<CosmosStoryProps> = {
|
|
@@ -96,5 +100,18 @@ export const RemovePoints: Story = {
|
|
|
96
100
|
],
|
|
97
101
|
},
|
|
98
102
|
}
|
|
103
|
+
|
|
104
|
+
export const LinkHovering: Story = {
|
|
105
|
+
...createStory(linkHovering),
|
|
106
|
+
name: 'Link Hovering',
|
|
107
|
+
parameters: {
|
|
108
|
+
sourceCode: [
|
|
109
|
+
{ name: 'Story', code: linkHoveringStoryRaw },
|
|
110
|
+
{ name: 'data-generator.ts', code: linkHoveringStoryDataGenRaw },
|
|
111
|
+
{ name: 'style.css', code: linkHoveringStoryCssRaw },
|
|
112
|
+
],
|
|
113
|
+
},
|
|
114
|
+
}
|
|
115
|
+
|
|
99
116
|
// eslint-disable-next-line import/no-default-export
|
|
100
117
|
export default meta
|
|
@@ -17,10 +17,8 @@ export const polygonSelection = (): {div: HTMLDivElement; graph: Graph; destroy:
|
|
|
17
17
|
pointSize: 8,
|
|
18
18
|
backgroundColor: '#1a1a2e',
|
|
19
19
|
pointGreyoutOpacity: 0.2,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
graph.unselectPoints()
|
|
23
|
-
}
|
|
20
|
+
onBackgroundClick: (): void => {
|
|
21
|
+
graph.unselectPoints()
|
|
24
22
|
},
|
|
25
23
|
})
|
|
26
24
|
|
|
@@ -194,14 +194,13 @@ export const imageExample = async (): Promise<{div: HTMLDivElement; graph: Graph
|
|
|
194
194
|
renderHoveredPointRing: true,
|
|
195
195
|
|
|
196
196
|
// Add click handler for point and background selection
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
}
|
|
197
|
+
onPointClick: (pointIndex: number): void => {
|
|
198
|
+
// Use built-in functionality to select the clicked point and its neighbors
|
|
199
|
+
graph.selectPointByIndex(pointIndex, true)
|
|
200
|
+
},
|
|
201
|
+
onBackgroundClick: (): void => {
|
|
202
|
+
// Clear selection when clicking on background
|
|
203
|
+
graph.unselectPoints()
|
|
205
204
|
},
|
|
206
205
|
})
|
|
207
206
|
|
package/src/variables.ts
CHANGED
|
@@ -14,18 +14,21 @@ export const defaultConfigValues = {
|
|
|
14
14
|
spaceSize: 8192,
|
|
15
15
|
pointSizeScale: 1,
|
|
16
16
|
linkWidthScale: 1,
|
|
17
|
-
|
|
17
|
+
linkArrowsSizeScale: 1,
|
|
18
18
|
renderLinks: true,
|
|
19
19
|
curvedLinks: false,
|
|
20
20
|
curvedLinkSegments: 19,
|
|
21
21
|
curvedLinkWeight: 0.8,
|
|
22
22
|
curvedLinkControlPointDistance: 0.5,
|
|
23
|
-
|
|
23
|
+
linkArrows: false,
|
|
24
24
|
linkVisibilityDistanceRange: [50, 150],
|
|
25
25
|
linkVisibilityMinTransparency: 0.25,
|
|
26
26
|
hoveredPointCursor: 'auto',
|
|
27
|
+
hoveredLinkCursor: 'auto',
|
|
27
28
|
renderHoveredPointRing: false,
|
|
28
29
|
hoveredPointRingColor: 'white',
|
|
30
|
+
hoveredLinkColor: undefined,
|
|
31
|
+
hoveredLinkWidthIncrease: 5,
|
|
29
32
|
focusedPointRingColor: 'white',
|
|
30
33
|
focusedPointIndex: undefined,
|
|
31
34
|
useClassicQuadtree: false,
|