@cosmos.gl/graph 2.6.2-rc.0 → 2.7.0-beta.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.
Files changed (186) hide show
  1. package/.eslintrc +147 -0
  2. package/.github/SECURITY.md +13 -0
  3. package/.github/dco.yml +4 -0
  4. package/.github/workflows/github_pages.yml +54 -0
  5. package/.storybook/main.ts +26 -0
  6. package/.storybook/manager-head.html +1 -0
  7. package/.storybook/manager.ts +14 -0
  8. package/.storybook/preview.ts +29 -0
  9. package/.storybook/style.css +3 -0
  10. package/CHARTER.md +69 -0
  11. package/CODE_OF_CONDUCT.md +178 -0
  12. package/CONTRIBUTING.md +22 -0
  13. package/GOVERNANCE.md +21 -0
  14. package/cosmos-2-0-migration-notes.md +98 -0
  15. package/cosmos_awesome.md +96 -0
  16. package/dist/config.d.ts +5 -9
  17. package/dist/graph/utils/error-message.d.ts +1 -1
  18. package/dist/helper.d.ts +39 -2
  19. package/dist/index-FUIgayhu.js +19827 -0
  20. package/dist/index-FUIgayhu.js.map +1 -0
  21. package/dist/index.d.ts +17 -64
  22. package/dist/index.js +14 -14654
  23. package/dist/index.js.map +1 -1
  24. package/dist/index.min.js +1062 -475
  25. package/dist/index.min.js.map +1 -1
  26. package/dist/modules/Clusters/index.d.ts +11 -3
  27. package/dist/modules/ForceCenter/index.d.ts +10 -3
  28. package/dist/modules/ForceGravity/index.d.ts +5 -1
  29. package/dist/modules/ForceLink/index.d.ts +8 -5
  30. package/dist/modules/ForceManyBody/index.d.ts +16 -7
  31. package/dist/modules/ForceMouse/index.d.ts +5 -1
  32. package/dist/modules/GraphData/index.d.ts +0 -1
  33. package/dist/modules/Lines/index.d.ts +11 -5
  34. package/dist/modules/Points/index.d.ts +31 -13
  35. package/dist/modules/Store/index.d.ts +93 -0
  36. package/dist/modules/core-module.d.ts +3 -3
  37. package/dist/stories/beginners/basic-set-up/data-gen.d.ts +4 -0
  38. package/dist/stories/beginners/basic-set-up/index.d.ts +6 -0
  39. package/dist/stories/beginners/link-hovering/data-generator.d.ts +19 -0
  40. package/dist/stories/beginners/link-hovering/index.d.ts +6 -0
  41. package/dist/stories/beginners/point-labels/data.d.ts +13 -0
  42. package/dist/stories/beginners/point-labels/index.d.ts +10 -0
  43. package/dist/stories/beginners/point-labels/labels.d.ts +8 -0
  44. package/dist/stories/beginners/quick-start.d.ts +6 -0
  45. package/dist/stories/beginners/remove-points/config.d.ts +2 -0
  46. package/dist/stories/beginners/remove-points/data-gen.d.ts +4 -0
  47. package/dist/stories/beginners/remove-points/index.d.ts +6 -0
  48. package/dist/stories/beginners.stories.d.ts +10 -0
  49. package/dist/stories/clusters/polygon-selection/index.d.ts +6 -0
  50. package/dist/stories/clusters/polygon-selection/polygon.d.ts +20 -0
  51. package/dist/stories/clusters/radial.d.ts +6 -0
  52. package/dist/stories/clusters/with-labels.d.ts +6 -0
  53. package/dist/stories/clusters/worm.d.ts +6 -0
  54. package/dist/stories/clusters.stories.d.ts +9 -0
  55. package/dist/stories/create-cluster-labels.d.ts +4 -0
  56. package/dist/stories/create-cosmos.d.ts +17 -0
  57. package/dist/stories/create-story.d.ts +16 -0
  58. package/dist/stories/experiments/full-mesh.d.ts +6 -0
  59. package/dist/stories/experiments/mesh-with-holes.d.ts +6 -0
  60. package/dist/stories/experiments.stories.d.ts +7 -0
  61. package/dist/stories/generate-mesh-data.d.ts +12 -0
  62. package/dist/stories/geospatial/moscow-metro-stations/index.d.ts +16 -0
  63. package/dist/stories/geospatial/moscow-metro-stations/moscow-metro-coords.d.ts +1 -0
  64. package/dist/stories/geospatial/moscow-metro-stations/point-colors.d.ts +1 -0
  65. package/dist/stories/geospatial.stories.d.ts +6 -0
  66. package/dist/stories/shapes/all-shapes/index.d.ts +6 -0
  67. package/dist/stories/shapes/image-example/index.d.ts +6 -0
  68. package/dist/stories/shapes.stories.d.ts +7 -0
  69. package/dist/stories/test-luma-migration.d.ts +6 -0
  70. package/dist/stories/test.stories.d.ts +6 -0
  71. package/dist/webgl-device-B9ewDj5L.js +3923 -0
  72. package/dist/webgl-device-B9ewDj5L.js.map +1 -0
  73. package/logo.svg +3 -0
  74. package/package.json +5 -7
  75. package/rollup.config.js +70 -0
  76. package/src/config.ts +728 -0
  77. package/src/declaration.d.ts +12 -0
  78. package/src/graph/utils/error-message.ts +23 -0
  79. package/src/helper.ts +113 -0
  80. package/src/index.ts +1769 -0
  81. package/src/modules/Clusters/calculate-centermass.frag +12 -0
  82. package/src/modules/Clusters/calculate-centermass.vert +38 -0
  83. package/src/modules/Clusters/force-cluster.frag +55 -0
  84. package/src/modules/Clusters/index.ts +578 -0
  85. package/src/modules/Drag/index.ts +33 -0
  86. package/src/modules/FPSMonitor/css.ts +53 -0
  87. package/src/modules/FPSMonitor/index.ts +28 -0
  88. package/src/modules/ForceCenter/calculate-centermass.frag +9 -0
  89. package/src/modules/ForceCenter/calculate-centermass.vert +26 -0
  90. package/src/modules/ForceCenter/force-center.frag +37 -0
  91. package/src/modules/ForceCenter/index.ts +284 -0
  92. package/src/modules/ForceGravity/force-gravity.frag +40 -0
  93. package/src/modules/ForceGravity/index.ts +107 -0
  94. package/src/modules/ForceLink/force-spring.ts +89 -0
  95. package/src/modules/ForceLink/index.ts +293 -0
  96. package/src/modules/ForceManyBody/calculate-level.frag +9 -0
  97. package/src/modules/ForceManyBody/calculate-level.vert +37 -0
  98. package/src/modules/ForceManyBody/force-centermass.frag +61 -0
  99. package/src/modules/ForceManyBody/force-level.frag +138 -0
  100. package/src/modules/ForceManyBody/index.ts +525 -0
  101. package/src/modules/ForceManyBody/quadtree-frag-shader.ts +89 -0
  102. package/src/modules/ForceManyBodyQuadtree/calculate-level.frag +9 -0
  103. package/src/modules/ForceManyBodyQuadtree/calculate-level.vert +25 -0
  104. package/src/modules/ForceManyBodyQuadtree/index.ts +157 -0
  105. package/src/modules/ForceManyBodyQuadtree/quadtree-frag-shader.ts +93 -0
  106. package/src/modules/ForceMouse/force-mouse.frag +35 -0
  107. package/src/modules/ForceMouse/index.ts +102 -0
  108. package/src/modules/GraphData/index.ts +383 -0
  109. package/src/modules/Lines/draw-curve-line.frag +59 -0
  110. package/src/modules/Lines/draw-curve-line.vert +248 -0
  111. package/src/modules/Lines/geometry.ts +18 -0
  112. package/src/modules/Lines/hovered-line-index.frag +43 -0
  113. package/src/modules/Lines/hovered-line-index.vert +13 -0
  114. package/src/modules/Lines/index.ts +661 -0
  115. package/src/modules/Points/atlas-utils.ts +137 -0
  116. package/src/modules/Points/drag-point.frag +34 -0
  117. package/src/modules/Points/draw-highlighted.frag +44 -0
  118. package/src/modules/Points/draw-highlighted.vert +145 -0
  119. package/src/modules/Points/draw-points.frag +259 -0
  120. package/src/modules/Points/draw-points.vert +203 -0
  121. package/src/modules/Points/fill-sampled-points.frag +12 -0
  122. package/src/modules/Points/fill-sampled-points.vert +51 -0
  123. package/src/modules/Points/find-hovered-point.frag +15 -0
  124. package/src/modules/Points/find-hovered-point.vert +90 -0
  125. package/src/modules/Points/find-points-on-area-selection.frag +88 -0
  126. package/src/modules/Points/find-points-on-polygon-selection.frag +89 -0
  127. package/src/modules/Points/index.ts +2292 -0
  128. package/src/modules/Points/track-positions.frag +30 -0
  129. package/src/modules/Points/update-position.frag +39 -0
  130. package/src/modules/Shared/buffer.ts +39 -0
  131. package/src/modules/Shared/clear.frag +10 -0
  132. package/src/modules/Shared/quad.vert +13 -0
  133. package/src/modules/Store/index.ts +283 -0
  134. package/src/modules/Zoom/index.ts +148 -0
  135. package/src/modules/core-module.ts +28 -0
  136. package/src/stories/1. welcome.mdx +75 -0
  137. package/src/stories/2. configuration.mdx +111 -0
  138. package/src/stories/3. api-reference.mdx +591 -0
  139. package/src/stories/beginners/basic-set-up/data-gen.ts +33 -0
  140. package/src/stories/beginners/basic-set-up/index.ts +167 -0
  141. package/src/stories/beginners/basic-set-up/style.css +35 -0
  142. package/src/stories/beginners/link-hovering/data-generator.ts +198 -0
  143. package/src/stories/beginners/link-hovering/index.ts +65 -0
  144. package/src/stories/beginners/link-hovering/style.css +73 -0
  145. package/src/stories/beginners/point-labels/data.ts +73 -0
  146. package/src/stories/beginners/point-labels/index.ts +69 -0
  147. package/src/stories/beginners/point-labels/labels.ts +46 -0
  148. package/src/stories/beginners/point-labels/style.css +16 -0
  149. package/src/stories/beginners/quick-start.ts +54 -0
  150. package/src/stories/beginners/remove-points/config.ts +25 -0
  151. package/src/stories/beginners/remove-points/data-gen.ts +30 -0
  152. package/src/stories/beginners/remove-points/index.ts +96 -0
  153. package/src/stories/beginners/remove-points/style.css +31 -0
  154. package/src/stories/beginners.stories.ts +130 -0
  155. package/src/stories/clusters/polygon-selection/index.ts +52 -0
  156. package/src/stories/clusters/polygon-selection/polygon.ts +143 -0
  157. package/src/stories/clusters/polygon-selection/style.css +8 -0
  158. package/src/stories/clusters/radial.ts +24 -0
  159. package/src/stories/clusters/with-labels.ts +54 -0
  160. package/src/stories/clusters/worm.ts +40 -0
  161. package/src/stories/clusters.stories.ts +77 -0
  162. package/src/stories/create-cluster-labels.ts +50 -0
  163. package/src/stories/create-cosmos.ts +72 -0
  164. package/src/stories/create-story.ts +51 -0
  165. package/src/stories/experiments/full-mesh.ts +13 -0
  166. package/src/stories/experiments/mesh-with-holes.ts +13 -0
  167. package/src/stories/experiments.stories.ts +43 -0
  168. package/src/stories/generate-mesh-data.ts +125 -0
  169. package/src/stories/geospatial/moscow-metro-stations/index.ts +66 -0
  170. package/src/stories/geospatial/moscow-metro-stations/moscow-metro-coords.ts +1 -0
  171. package/src/stories/geospatial/moscow-metro-stations/point-colors.ts +46 -0
  172. package/src/stories/geospatial/moscow-metro-stations/style.css +30 -0
  173. package/src/stories/geospatial.stories.ts +30 -0
  174. package/src/stories/shapes/all-shapes/index.ts +73 -0
  175. package/src/stories/shapes/image-example/icons/box.png +0 -0
  176. package/src/stories/shapes/image-example/icons/lego.png +0 -0
  177. package/src/stories/shapes/image-example/icons/s.png +0 -0
  178. package/src/stories/shapes/image-example/icons/swift.png +0 -0
  179. package/src/stories/shapes/image-example/icons/toolbox.png +0 -0
  180. package/src/stories/shapes/image-example/index.ts +246 -0
  181. package/src/stories/shapes.stories.ts +37 -0
  182. package/src/stories/test-luma-migration.ts +195 -0
  183. package/src/stories/test.stories.ts +25 -0
  184. package/src/variables.ts +68 -0
  185. package/tsconfig.json +41 -0
  186. package/vite.config.ts +52 -0
@@ -0,0 +1,54 @@
1
+ import { Graph } from '@cosmos.gl/graph'
2
+ import { createClusterLabels } from '../create-cluster-labels'
3
+ import { createCosmos } from '../create-cosmos'
4
+ import { generateMeshData } from '../generate-mesh-data'
5
+
6
+ export const withLabels = async (): Promise<{div: HTMLDivElement; graph: Graph; destroy: () => void }> => {
7
+ let nClusters = 2
8
+ const { pointPositions, pointColors, pointClusters } = generateMeshData(100, 100, nClusters, 1.0)
9
+
10
+ const { div, graph, destroy: baseDestroy } = await createCosmos({
11
+ pointPositions,
12
+ pointColors,
13
+ pointClusters,
14
+ simulationGravity: 2,
15
+ simulationCluster: 0.25,
16
+ simulationRepulsion: 10,
17
+ pointSize: 10,
18
+ })
19
+
20
+ const updateClusterLabels = createClusterLabels({ div })
21
+ graph.setZoomLevel(0.3)
22
+
23
+ graph.setConfig({
24
+ onZoom: updateClusterLabels.bind(this, graph),
25
+ onSimulationTick: updateClusterLabels.bind(this, graph),
26
+ })
27
+
28
+ let increasing = true
29
+ const interval = setInterval(() => {
30
+ if (increasing) {
31
+ nClusters += 5
32
+ if (nClusters >= 15) {
33
+ increasing = false
34
+ }
35
+ } else {
36
+ nClusters -= 5
37
+ if (nClusters <= 2) {
38
+ increasing = true
39
+ }
40
+ }
41
+
42
+ const nextData = generateMeshData(100, 100, nClusters, 1.0)
43
+ graph.setPointClusters(nextData.pointClusters)
44
+ graph.setPointColors(nextData.pointColors)
45
+ graph.render(1)
46
+ }, 1500)
47
+
48
+ const destroy = (): void => {
49
+ clearInterval(interval)
50
+ baseDestroy?.()
51
+ }
52
+
53
+ return { div, graph, destroy }
54
+ }
@@ -0,0 +1,40 @@
1
+
2
+ import { Graph } from '@cosmos.gl/graph'
3
+ import { createCosmos } from '../create-cosmos'
4
+ import { generateMeshData } from '../generate-mesh-data'
5
+
6
+ export const worm = async (): Promise<{graph: Graph; div: HTMLDivElement; destroy?: () => void}> => {
7
+ const { pointPositions, pointColors, links, linkColors, pointClusters } = generateMeshData(100, 100, 1000, 1.0)
8
+
9
+ const { div, graph, destroy } = await createCosmos({
10
+ simulationGravity: 0.5,
11
+ simulationRepulsion: 1,
12
+ simulationLinkSpring: 1,
13
+ pointPositions,
14
+ pointColors,
15
+ pointClusters,
16
+ links,
17
+ linkColors,
18
+ onSimulationTick: () => {
19
+ const currentPointColors = graph.getPointColors()
20
+ const newPointColors = new Float32Array(currentPointColors.length)
21
+ for (let i = 0; i < currentPointColors.length / 4; i++) {
22
+ if (i === 0) {
23
+ newPointColors[i * 4] = currentPointColors[currentPointColors.length - 4] as number
24
+ newPointColors[i * 4 + 1] = currentPointColors[currentPointColors.length - 3] as number
25
+ newPointColors[i * 4 + 2] = currentPointColors[currentPointColors.length - 2] as number
26
+ newPointColors[i * 4 + 3] = currentPointColors[currentPointColors.length - 1] as number
27
+ } else {
28
+ newPointColors[i * 4] = currentPointColors[(i - 1) * 4] as number
29
+ newPointColors[i * 4 + 1] = currentPointColors[(i - 1) * 4 + 1] as number
30
+ newPointColors[i * 4 + 2] = currentPointColors[(i - 1) * 4 + 2] as number
31
+ newPointColors[i * 4 + 3] = currentPointColors[(i - 1) * 4 + 3] as number
32
+ }
33
+ }
34
+ graph.setPointColors(newPointColors)
35
+ graph.render()
36
+ },
37
+ })
38
+
39
+ return { div, graph, destroy }
40
+ }
@@ -0,0 +1,77 @@
1
+ import type { Meta } from '@storybook/html'
2
+ import { CosmosStoryProps } from '@/graph/stories/create-cosmos'
3
+ import { createStory, Story } from '@/graph/stories/create-story'
4
+ import { withLabels } from './clusters/with-labels'
5
+ import { worm } from './clusters/worm'
6
+ import { radial } from './clusters/radial'
7
+ import { polygonSelection } from './clusters/polygon-selection'
8
+
9
+ import createCosmosRaw from './create-cosmos?raw'
10
+ import generateMeshDataRaw from './generate-mesh-data?raw'
11
+ import withLabelsStoryRaw from './clusters/with-labels?raw'
12
+ import createClusterLabelsRaw from './create-cluster-labels?raw'
13
+ import wormStory from './clusters/worm?raw'
14
+ import radialStory from './clusters/radial?raw'
15
+ import polygonSelectionStory from './clusters/polygon-selection?raw'
16
+ import polygonSelectionStyleRaw from './clusters/polygon-selection/style.css?raw'
17
+ import polygonSelectionPolygonRaw from './clusters/polygon-selection/polygon.ts?raw'
18
+
19
+ const meta: Meta<CosmosStoryProps> = {
20
+ title: 'Examples/Clusters',
21
+ parameters: {
22
+ controls: {
23
+ disable: true,
24
+ },
25
+ },
26
+ }
27
+
28
+ const sourceCodeAddonParams = [
29
+ { name: 'create-cosmos', code: createCosmosRaw },
30
+ { name: 'generate-mesh-data', code: generateMeshDataRaw },
31
+ ]
32
+
33
+ export const Worm: Story = {
34
+ ...createStory(worm),
35
+ parameters: {
36
+ sourceCode: [
37
+ { name: 'Story', code: wormStory },
38
+ ...sourceCodeAddonParams,
39
+ ],
40
+ },
41
+ }
42
+
43
+ export const Radial: Story = {
44
+ ...createStory(radial),
45
+ parameters: {
46
+ sourceCode: [
47
+ { name: 'Story', code: radialStory },
48
+ ...sourceCodeAddonParams,
49
+ ],
50
+ },
51
+ }
52
+
53
+ export const WithLabels: Story = {
54
+ ...createStory(withLabels),
55
+ parameters: {
56
+ sourceCode: [
57
+ { name: 'Story', code: withLabelsStoryRaw },
58
+ { name: 'create-cluster-labels', code: createClusterLabelsRaw },
59
+ ...sourceCodeAddonParams,
60
+ ],
61
+ },
62
+ }
63
+
64
+ export const PolygonSelection: Story = {
65
+ ...createStory(polygonSelection),
66
+ parameters: {
67
+ sourceCode: [
68
+ { name: 'Story', code: polygonSelectionStory },
69
+ { name: 'polygon.ts', code: polygonSelectionPolygonRaw },
70
+ ...sourceCodeAddonParams,
71
+ { name: 'style.css', code: polygonSelectionStyleRaw },
72
+ ],
73
+ },
74
+ }
75
+
76
+ // eslint-disable-next-line import/no-default-export
77
+ export default meta
@@ -0,0 +1,50 @@
1
+ import { Graph } from '@cosmos.gl/graph'
2
+
3
+ export const createClusterLabels = (props: { div: HTMLDivElement }): (graph: Graph) => void => {
4
+ const clusterLabelDivs: HTMLDivElement[] = []
5
+ return function updateClusterLabels (graph: Graph): void {
6
+ const clusterPositions = graph.getClusterPositions()
7
+ const nClusters = clusterPositions.length / 2
8
+ if (nClusters === 0) return
9
+ if (clusterLabelDivs.length !== nClusters) {
10
+ clusterLabelDivs.forEach((div) => div.remove())
11
+ for (let i = 0; i < nClusters; i++) {
12
+ const clusterLabelDiv = document.createElement('div')
13
+ const contentLabel = document.createElement('p')
14
+ clusterLabelDiv.appendChild(contentLabel)
15
+ clusterLabelDiv.style.position = 'absolute'
16
+ clusterLabelDiv.style.pointerEvents = 'none'
17
+
18
+ contentLabel.style.fontFamily = [
19
+ '"Nunito Sans"',
20
+ '-apple-system',
21
+ '".SFNSText-Regular"',
22
+ '"San Francisco"',
23
+ 'BlinkMacSystemFont',
24
+ '"Segoe UI"',
25
+ '"Helvetica Neue"',
26
+ 'Helvetica',
27
+ 'Arial',
28
+ 'sans-serif',
29
+ ].join(', ')
30
+ contentLabel.style.fontWeight = 'bold'
31
+ contentLabel.style.color = 'white'
32
+ contentLabel.style.transform = 'translate(-50%, -100%)'
33
+ contentLabel.innerText = `Cluster ${i + 1}`
34
+
35
+ props.div.appendChild(clusterLabelDiv)
36
+ clusterLabelDivs[i] = clusterLabelDiv
37
+ }
38
+ }
39
+
40
+ for (let i = 0; i < nClusters; i++) {
41
+ const clusterPosition = clusterPositions.slice(i * 2, i * 2 + 2)
42
+ const x = clusterPosition[0]
43
+ const y = clusterPosition[1]
44
+ const clusterLabelDiv = clusterLabelDivs[i] as HTMLDivElement
45
+ const screenXY = graph.spaceToScreenPosition([x ?? 0, y ?? 0])
46
+ clusterLabelDiv.style.top = `${screenXY[1]}px`
47
+ clusterLabelDiv.style.left = `${screenXY[0]}px`
48
+ }
49
+ }
50
+ }
@@ -0,0 +1,72 @@
1
+ import { Graph, GraphConfigInterface } from '@cosmos.gl/graph'
2
+
3
+ export type CosmosStoryProps = GraphConfigInterface & {
4
+ pointPositions: Float32Array;
5
+ pointColors?: Float32Array;
6
+ pointSizes?: Float32Array;
7
+
8
+ links?: Float32Array;
9
+ linkColors?: Float32Array;
10
+ linkWidths?: Float32Array;
11
+ // linkStrength?: Float32Array;
12
+
13
+ pointClusters?: number[];
14
+ clusterPositions?: number[];
15
+ clusterStrength?: Float32Array;
16
+ }
17
+
18
+ export const createCosmos = (props: CosmosStoryProps): { div: HTMLDivElement; graph: Graph; destroy?: () => void} => {
19
+ const div = document.createElement('div')
20
+ div.style.height = '100vh'
21
+ div.style.width = '100%'
22
+
23
+ const config: GraphConfigInterface = {
24
+ backgroundColor: '#2d313a',
25
+ pointSize: 3,
26
+ pointColor: '#4B5BBF',
27
+ pointGreyoutOpacity: 0.1,
28
+ scalePointsOnZoom: true,
29
+ linkWidth: 0.8,
30
+ linkColor: '#5F74C2',
31
+ linkArrows: false,
32
+ linkGreyoutOpacity: 0,
33
+ curvedLinks: true,
34
+ renderLinks: true,
35
+ renderHoveredPointRing: true,
36
+ fitViewOnInit: false,
37
+ hoveredPointRingColor: '#4B5BBF',
38
+ enableDrag: true,
39
+ simulationLinkDistance: 1,
40
+ simulationLinkSpring: 2,
41
+ simulationRepulsion: 0.5,
42
+ simulationGravity: 0.02,
43
+ simulationFriction: 0.7,
44
+ simulationDecay: 10000000,
45
+ attribution: 'visualized with <a href="https://cosmograph.app/" style="color: var(--cosmosgl-attribution-color);" target="_blank">Cosmograph</a>',
46
+ ...props,
47
+ }
48
+
49
+ const graph = new Graph(div, config)
50
+
51
+ graph.setPointPositions(props.pointPositions)
52
+ if (props.pointColors) graph.setPointColors(props.pointColors)
53
+ if (props.pointSizes) graph.setPointSizes(props.pointSizes)
54
+
55
+ if (props.links) graph.setLinks(props.links)
56
+ if (props.linkColors) graph.setLinkColors(props.linkColors)
57
+ if (props.linkWidths) graph.setLinkWidths(props.linkWidths)
58
+ // if (props.linkStrength) graph.setLinkStrength(props.linkStrength)
59
+
60
+ if (props.pointClusters) graph.setPointClusters(props.pointClusters)
61
+ if (props.clusterPositions) graph.setClusterPositions(props.clusterPositions)
62
+ if (props.clusterStrength) graph.setPointClusterStrength(props.clusterStrength)
63
+
64
+ graph.zoom(0.9)
65
+ graph.render()
66
+
67
+ const destroy = (): void => {
68
+ graph.destroy()
69
+ }
70
+
71
+ return { div, graph, destroy }
72
+ }
@@ -0,0 +1,51 @@
1
+ import { Graph } from '@cosmos.gl/graph'
2
+ import type { StoryObj } from '@storybook/html'
3
+ import { CosmosStoryProps } from '@/graph/stories/create-cosmos'
4
+
5
+ export type Story = StoryObj<CosmosStoryProps & { graph: Graph; destroy?: () => void }>;
6
+
7
+ export const createStory: (storyFunction: () => {
8
+ graph: Graph;
9
+ div: HTMLDivElement;
10
+ destroy?: () => void;
11
+ } | Promise<{
12
+ graph: Graph;
13
+ div: HTMLDivElement;
14
+ destroy?: () => void;
15
+ }>) => Story = (storyFunction) => ({
16
+ async beforeEach (d): Promise<() => void> {
17
+ return (): void => {
18
+ d.args.destroy?.()
19
+ d.args.graph?.destroy()
20
+ }
21
+ },
22
+ render: (args): HTMLDivElement => {
23
+ const result = storyFunction()
24
+
25
+ if (result instanceof Promise) {
26
+ // For async story functions, create a simple div and update it when ready
27
+ const div = document.createElement('div')
28
+ div.style.height = '100vh'
29
+ div.style.width = '100%'
30
+ div.innerHTML = '<div style="display: flex; align-items: center; justify-content: center; height: 100%; color: #666;">Loading story...</div>'
31
+
32
+ result.then((story) => {
33
+ args.graph = story.graph
34
+ args.destroy = story.destroy
35
+ // Replace the content with the actual story div
36
+ div.innerHTML = ''
37
+ div.appendChild(story.div)
38
+ }).catch((error) => {
39
+ console.error('Failed to load story:', error)
40
+ div.innerHTML = '<div style="display: flex; align-items: center; justify-content: center; height: 100%; color: #ff0000;">Failed to load story</div>'
41
+ })
42
+
43
+ return div
44
+ } else {
45
+ // Synchronous story function
46
+ args.graph = result.graph
47
+ args.destroy = result.destroy
48
+ return result.div
49
+ }
50
+ },
51
+ })
@@ -0,0 +1,13 @@
1
+ import { Graph } from '@cosmos.gl/graph'
2
+ import { createCosmos } from '../create-cosmos'
3
+ import { generateMeshData } from '../generate-mesh-data'
4
+
5
+ export const fullMesh = async (): Promise<{ graph: Graph; div: HTMLDivElement; destroy?: () => void}> => {
6
+ const { pointPositions, links, pointColors } = generateMeshData(40, 30, 15, 1.0)
7
+
8
+ return createCosmos({
9
+ pointPositions,
10
+ links,
11
+ pointColors,
12
+ })
13
+ }
@@ -0,0 +1,13 @@
1
+ import { Graph } from '@cosmos.gl/graph'
2
+ import { createCosmos } from '../create-cosmos'
3
+ import { generateMeshData } from '../generate-mesh-data'
4
+
5
+ export const meshWithHoles = async (): Promise<{ graph: Graph; div: HTMLDivElement; destroy?: () => void}> => {
6
+ const { pointPositions, links, pointColors } = generateMeshData(40, 80, 15, 0.8)
7
+
8
+ return createCosmos({
9
+ pointPositions,
10
+ links,
11
+ pointColors,
12
+ })
13
+ }
@@ -0,0 +1,43 @@
1
+ import type { Meta } from '@storybook/html'
2
+
3
+ import { createStory, Story } from '@/graph/stories/create-story'
4
+ import { CosmosStoryProps } from './create-cosmos'
5
+ import { meshWithHoles } from './experiments/mesh-with-holes'
6
+ import { fullMesh } from './experiments/full-mesh'
7
+
8
+ import createCosmosRaw from './create-cosmos?raw'
9
+ import generateMeshDataRaw from './generate-mesh-data?raw'
10
+ import meshWithHolesRaw from './experiments/mesh-with-holes?raw'
11
+ import fullMeshRaw from './experiments/full-mesh?raw'
12
+
13
+ // More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
14
+ const meta: Meta<CosmosStoryProps> = {
15
+ title: 'Examples/Experiments',
16
+ }
17
+
18
+ const sourceCodeAddonParams = [
19
+ { name: 'create-cosmos', code: createCosmosRaw },
20
+ { name: 'generate-mesh-data', code: generateMeshDataRaw },
21
+ ]
22
+
23
+ export const FullMesh: Story = {
24
+ ...createStory(fullMesh),
25
+ parameters: {
26
+ sourceCode: [
27
+ { name: 'Story', code: fullMeshRaw },
28
+ ...sourceCodeAddonParams,
29
+ ],
30
+ },
31
+ }
32
+ export const MeshWithHoles: Story = {
33
+ ...createStory(meshWithHoles),
34
+ parameters: {
35
+ sourceCode: [
36
+ { name: 'Story', code: meshWithHolesRaw },
37
+ ...sourceCodeAddonParams,
38
+ ],
39
+ },
40
+ }
41
+
42
+ // eslint-disable-next-line import/no-default-export
43
+ export default meta
@@ -0,0 +1,125 @@
1
+ import { scaleLinear, scaleSequential } from 'd3-scale'
2
+ import { interpolateWarm } from 'd3-scale-chromatic'
3
+ import { getRgbaColor } from '@cosmos.gl/graph'
4
+
5
+ function getRandom (min: number, max: number): number {
6
+ return Math.random() * (max - min) + min
7
+ }
8
+
9
+ function getPositionOnCircle (radius: number, angle: number, center: number): [number, number] {
10
+ const x = center + radius * Math.cos(angle)
11
+ const y = center + radius * Math.sin(angle)
12
+ return [x, y]
13
+ }
14
+
15
+ export type MeshData = {
16
+ pointPositions: Float32Array;
17
+ pointColors: Float32Array;
18
+ pointSizes: Float32Array;
19
+
20
+ links: Float32Array;
21
+ linkColors: Float32Array;
22
+ linkWidths: Float32Array;
23
+ // linkStrength: Float32Array;
24
+
25
+ pointClusters: number[];
26
+ clusterPositions: number[];
27
+ clusterStrength: Float32Array;
28
+ }
29
+
30
+ export function generateMeshData (
31
+ n: number,
32
+ m: number,
33
+ nClusters: number,
34
+ wholeness: number,
35
+ radialness = [10, 1000]
36
+ ): MeshData {
37
+ const pointColorScale = scaleSequential(interpolateWarm)
38
+ pointColorScale.domain([0, nClusters])
39
+ const radius = scaleLinear(radialness)
40
+ radius.domain([0, nClusters])
41
+
42
+ const pointPositions = new Float32Array(n * m * 2)
43
+ const links: number[] = []
44
+ const pointClusters = new Array(n * m)
45
+ const clusterPositions = new Array(nClusters * 2)
46
+ const clusterStrength = new Float32Array(n * m)
47
+ const pointColors = new Float32Array(n * m * 4)
48
+ const pointSizes = new Float32Array(n * m)
49
+
50
+ // The maximum texture size can vary between devices and WebGL versions
51
+ // The space size should be less than the maximum texture size to ensure better visual quality of the generated mesh.
52
+ const gl = document.createElement('canvas').getContext('webgl')
53
+ const spaceSize = (gl?.getParameter(gl.MAX_TEXTURE_SIZE) ?? 16384) / 2
54
+ gl?.getExtension('WEBGL_lose_context')?.loseContext()
55
+
56
+ for (let clusterIndex = 0; clusterIndex < nClusters; clusterIndex += 1) {
57
+ const [x, y] = getPositionOnCircle(radius(clusterIndex), 15 * Math.PI * (clusterIndex / nClusters), spaceSize / 2)
58
+ clusterPositions[clusterIndex * 2] = x
59
+ clusterPositions[clusterIndex * 2 + 1] = y
60
+ }
61
+
62
+ for (let pointIndex = 0; pointIndex < n * m; pointIndex += 1) {
63
+ const x = spaceSize * getRandom(0.495, 0.505)
64
+ const y = spaceSize * getRandom(0.495, 0.505)
65
+ pointPositions[pointIndex * 2] = x
66
+ pointPositions[pointIndex * 2 + 1] = y
67
+
68
+ pointClusters[pointIndex] = pointIndex % nClusters
69
+ clusterStrength[pointIndex] = (nClusters - (pointIndex % nClusters)) / nClusters
70
+ const pointColor = pointColorScale(pointIndex % nClusters)
71
+ const rgba = getRgbaColor(pointColor)
72
+ pointColors[pointIndex * 4] = rgba[0]
73
+ pointColors[pointIndex * 4 + 1] = rgba[1]
74
+ pointColors[pointIndex * 4 + 2] = rgba[2]
75
+ pointColors[pointIndex * 4 + 3] = rgba[3]
76
+
77
+ pointSizes[pointIndex] = getRandom(1, 5)
78
+
79
+ const nextPointIndex = pointIndex + 1
80
+ const bottomPointIndex = pointIndex + n
81
+ const pointLine = Math.floor(pointIndex / n)
82
+ const nextPointLine = Math.floor(nextPointIndex / n)
83
+ const bottomPointLine = Math.floor(bottomPointIndex / n)
84
+
85
+ if (pointLine === nextPointLine && Math.random() < wholeness) {
86
+ links.push(pointIndex)
87
+ links.push(nextPointIndex)
88
+ }
89
+
90
+ if (bottomPointLine < m && Math.random() < wholeness) {
91
+ links.push(pointIndex)
92
+ links.push(bottomPointIndex)
93
+ }
94
+ }
95
+
96
+ const linkColors = new Float32Array(links.length / 2 * 4)
97
+ const linkWidths = new Float32Array(links.length / 2)
98
+ // const linkStrength = new Float32Array(links.length / 2)
99
+ for (let i = 0; i < links.length / 2; i++) {
100
+ const sourcePointIndex = links[i * 2] as number
101
+ const rgba = getRgbaColor(pointColorScale(sourcePointIndex % nClusters))
102
+ linkColors[i * 4 + 0] = rgba[0]
103
+ linkColors[i * 4 + 1] = rgba[1]
104
+ linkColors[i * 4 + 2] = rgba[2]
105
+ linkColors[i * 4 + 3] = 0.9
106
+
107
+ linkWidths[i] = getRandom(0.4, 0.8)
108
+ // linkStrength[i] = (n * m - sourcePointIndex) / (n * m)
109
+ }
110
+
111
+ return {
112
+ pointPositions,
113
+ pointColors,
114
+ pointSizes,
115
+
116
+ links: new Float32Array(links),
117
+ linkColors,
118
+ linkWidths,
119
+ // linkStrength,
120
+
121
+ pointClusters,
122
+ clusterStrength,
123
+ clusterPositions,
124
+ }
125
+ }
@@ -0,0 +1,66 @@
1
+ import { Graph } from '@cosmos.gl/graph'
2
+ import { moscowMetroCoords } from './moscow-metro-coords'
3
+ import { getPointColors } from './point-colors'
4
+ import './style.css'
5
+
6
+ /**
7
+ * This example demonstrates the importance of rescaling positions by Cosmos.
8
+ * The Moscow Metro station coordinates are are normalized (0-1 range in both dimensions).
9
+ * By default, cosmos.gl rescales these positions to fit the canvas.
10
+ * When disabling rescaling (`rescalePositions: false`):
11
+ * - Points render using raw coordinates
12
+ * - The entire graph occupies a tiny 1x1 area in WebGL's clip space (-1 to 1)
13
+ * - This causes visual artifacts due to WebGL's floating-point precision limitations
14
+ * - Points cluster in the center and may exhibit rendering glitches
15
+ */
16
+ export const moscowMetroStations = (): {graph: Graph; div: HTMLDivElement; destroy?: () => void } => {
17
+ const div = document.createElement('div')
18
+ div.className = 'app'
19
+
20
+ const graphDiv = document.createElement('div')
21
+ graphDiv.className = 'graph'
22
+ div.appendChild(graphDiv)
23
+
24
+ const actionsDiv = document.createElement('div')
25
+ actionsDiv.className = 'actions'
26
+ div.appendChild(actionsDiv)
27
+
28
+ let rescalePositions = true
29
+
30
+ const graph = new Graph(graphDiv, {
31
+ backgroundColor: '#2d313a',
32
+ scalePointsOnZoom: false,
33
+ rescalePositions,
34
+ pointColor: '#FEE08B',
35
+ enableSimulation: false,
36
+ enableDrag: false,
37
+ fitViewOnInit: true,
38
+ attribution: 'visualized with <a href="https://cosmograph.app/" style="color: var(--cosmosgl-attribution-color);" target="_blank">Cosmograph</a>',
39
+ })
40
+
41
+ const pointColors = getPointColors(moscowMetroCoords)
42
+
43
+ graph.setPointPositions(new Float32Array(moscowMetroCoords))
44
+ graph.setPointColors(pointColors)
45
+ graph.render()
46
+
47
+ const disableEnableRescaleButton = document.createElement('div')
48
+ disableEnableRescaleButton.className = 'action'
49
+ disableEnableRescaleButton.textContent = 'Disable Rescale'
50
+ actionsDiv.appendChild(disableEnableRescaleButton)
51
+
52
+ disableEnableRescaleButton.addEventListener('click', () => {
53
+ rescalePositions = !rescalePositions
54
+ disableEnableRescaleButton.textContent = rescalePositions ? 'Disable Rescale' : 'Enable Rescale'
55
+ graph.setConfig({ rescalePositions })
56
+ graph.setPointPositions(new Float32Array(moscowMetroCoords))
57
+ graph.render()
58
+ graph.fitView()
59
+ })
60
+
61
+ const destroy = (): void => {
62
+ graph.destroy()
63
+ }
64
+
65
+ return { div, graph, destroy }
66
+ }
@@ -0,0 +1 @@
1
+ export const moscowMetroCoords = [0.6048172222222222, 0.8100822222222221, 0.6048466666666666, 0.8100211111111111, 0.6047641666666667, 0.8099794444444445, 0.6046672222222222, 0.8099377777777779, 0.6046313888888889, 0.8098894444444444, 0.6046005555555556, 0.8098627777777778, 0.6045797222222222, 0.8098277777777778, 0.6045522222222223, 0.8098094444444445, 0.6045200000000001, 0.8097761111111111, 0.6044905555555555, 0.809765, 0.6044722222222223, 0.8097288888888888, 0.6044547222222222, 0.8096961111111111, 0.6044286111111111, 0.8096422222222223, 0.604385, 0.8095927777777777, 0.6043441666666667, 0.8095738888888888, 0.6043311111111112, 0.8095016666666666, 0.6042591666666667, 0.8094033333333334, 0.6041833333333333, 0.8093172222222222, 0.6041202777777778, 0.8092427777777778, 0.6040902777777778, 0.8091438888888888, 0.6040052777777778, 0.8090722222222223, 0.6039555555555556, 0.809015, 0.603910125, 0.8088964833333334, 0.6039827833333333, 0.8088124555555556, 0.6040537, 0.8087146833333334, 0.6040783888888889, 0.8086688666666666, 0.6041465694444444, 0.8086257777777778, 0.6041172222222222, 0.8104394444444444, 0.6041011111111112, 0.8103655555555556, 0.6041002777777777, 0.8103049999999999, 0.6041297222222222, 0.8102211111111111, 0.604161111111111, 0.8101055555555556, 0.6042091666666667, 0.8100283333333334, 0.6042580555555556, 0.8100016666666666, 0.6043277777777778, 0.8099427777777778, 0.6043986111111112, 0.8098705555555555, 0.6044327777777778, 0.809833888888889, 0.6044624999999999, 0.8098038888888889, 0.6044972222222222, 0.8097655555555556, 0.6045263888888889, 0.809675, 0.6045491666666667, 0.809613888888889, 0.6046044444444445, 0.8094855555555556, 0.6046225, 0.8094166666666667, 0.6046216666666667, 0.809325, 0.6045797222222222, 0.809195, 0.604601111111111, 0.8090877777777779, 0.6046372222222222, 0.8090077777777778, 0.6047080555555555, 0.8089622222222222, 0.6047738888888889, 0.8089488888888888, 0.6048455555555555, 0.8089649999999999, 0.6049055555555556, 0.80907, 0.6037622222222222, 0.8103127777777778, 0.6037838888888889, 0.8102538888888888, 0.6038394444444445, 0.8101966666666667, 0.6038477777777778, 0.81014, 0.6038975, 0.8100211111111111, 0.6039113888888888, 0.8097594444444444, 0.6039355555555556, 0.8096711111111111, 0.6040163888888889, 0.8096150000000001, 0.604085, 0.8096088888888889, 0.6042172222222223, 0.8096455555555555, 0.6043458333333334, 0.80969, 0.6043952777777778, 0.8097077777777778, 0.6044613888888889, 0.8097344444444445, 0.6045044444444444, 0.8097588888888888, 0.6046047222222223, 0.8097644444444444, 0.6046683333333334, 0.80985, 0.6047325, 0.8098983333333334, 0.60478, 0.8099072222222222, 0.6048627777777777, 0.8099366666666666, 0.6049483333333333, 0.8099322222222223, 0.6049980555555556, 0.8099711111111112, 0.6049961111111111, 0.8100522222222222, 0.6040163888888889, 0.8096150000000001, 0.6040752777777778, 0.8096444444444444, 0.6041202777777778, 0.8096644444444444, 0.6041602777777778, 0.8096877777777778, 0.6042083333333333, 0.8097000000000001, 0.6042622222222223, 0.8096661111111112, 0.6043008333333333, 0.8096599999999999, 0.6042608333333334, 0.8097127777777777, 0.6042799999999999, 0.8097233333333334, 0.604348611111111, 0.8096866666666668, 0.6043958333333334, 0.8097155555555556, 0.6044463888888889, 0.8097322222222222, 0.6044680555555555, 0.8097361111111111, 0.6043455555555556, 0.8096922222222221, 0.6043816666666667, 0.809785, 0.6044011111111112, 0.8098688888888889, 0.6044522222222223, 0.8098883333333333, 0.6045327777777778, 0.8098877777777778, 0.6045969444444445, 0.80986, 0.6046097222222222, 0.8097611111111112, 0.6045880555555556, 0.8096766666666667, 0.6045497222222223, 0.8096211111111111, 0.6045119444444444, 0.8096061111111112, 0.6044697222222223, 0.8096094444444445, 0.6044208333333333, 0.8096427777777778, 0.6046147222222221, 0.8104844444444445, 0.6046233333333333, 0.8103855555555555, 0.6045908333333334, 0.8103066666666666, 0.6045508333333334, 0.8102494444444445, 0.6045586111111111, 0.8101172222222223, 0.6045527777777778, 0.8100488888888888, 0.604545, 0.8099644444444445, 0.6045327777777778, 0.8098955555555556, 0.6045330555555556, 0.8098516666666667, 0.6045483333333334, 0.8098116666666666, 0.6045369444444444, 0.8097516666666666, 0.6045205555555555, 0.8096733333333332, 0.6044755555555555, 0.8096144444444445, 0.6044674999999999, 0.8095544444444444, 0.6044058333333333, 0.8094872222222221, 0.6043702777777779, 0.8093761111111112, 0.6043408333333333, 0.8093222222222222, 0.6043177777777777, 0.8092788888888889, 0.6042791666666667, 0.8092061111111112, 0.6042380555555555, 0.8091266666666667, 0.6042188888888889, 0.8090738888888889, 0.6041894444444444, 0.808995, 0.6042591666666667, 0.8089238888888889, 0.6043169444444445, 0.8088944444444445, 0.60399, 0.8103372222222223, 0.6039988888888889, 0.8102805555555557, 0.6039911111111111, 0.8101483333333335, 0.6039866666666667, 0.810101111111111, 0.6040669444444444, 0.8100477777777778, 0.6041486111111111, 0.8099638888888888, 0.60422, 0.809875, 0.6042966666666666, 0.8098544444444444, 0.6043369444444445, 0.8098055555555554, 0.6043875, 0.8097844444444444, 0.6044663888888889, 0.8098055555555554, 0.6045163888888889, 0.8097811111111112, 0.6045369444444444, 0.8097516666666666, 0.6045894444444444, 0.8096677777777779, 0.6046275, 0.8096216666666667, 0.6046858333333334, 0.809585, 0.6048100000000001, 0.8094933333333333, 0.6049044444444445, 0.8094755555555556, 0.6049813888888889, 0.8095388888888888, 0.6050502777777779, 0.8095311111111111, 0.6051458333333333, 0.8094516666666667, 0.6051563888888889, 0.8093638888888889, 0.6051616666666667, 0.8093016666666668, 0.6037075, 0.8090772222222221, 0.6037644444444444, 0.8091088888888889, 0.6038058333333334, 0.8091533333333334, 0.6038636111111111, 0.8091627777777777, 0.6039366666666667, 0.8092194444444445, 0.6040252777777777, 0.8092827777777779, 0.6041202777777778, 0.8093866666666666, 0.6041622222222223, 0.8094305555555555, 0.60421, 0.8094827777777778, 0.6041583333333334, 0.8095811111111112, 0.6042172222222223, 0.8096455555555555, 0.6042552777777778, 0.8097083333333334, 0.6045205555555555, 0.8096733333333332, 0.6045952777777778, 0.8096727777777779, 0.6046733333333333, 0.8097066666666666, 0.6047752777777777, 0.8097355555555555, 0.6048611111111111, 0.8097644444444444, 0.6049627777777777, 0.8097283333333334, 0.6050461111111111, 0.8097316666666666, 0.6051772222222223, 0.809695, 0.6044083333333333, 0.8105444444444444, 0.6044538888888888, 0.8104655555555556, 0.6044575, 0.8103516666666667, 0.6044163888888889, 0.8102627777777778, 0.6043736111111111, 0.8101950000000001, 0.6043791666666667, 0.8100977777777778, 0.6043936111111111, 0.8100383333333332, 0.6044125, 0.8099594444444445, 0.6044475, 0.8098944444444445, 0.6044963888888889, 0.8098377777777779, 0.6044713888888888, 0.8098022222222222, 0.6044644444444445, 0.8097283333333334, 0.6044944444444444, 0.809655, 0.6045127777777778, 0.8096000000000001, 0.6045080555555556, 0.8094927777777777, 0.6045066666666666, 0.80935, 0.6044733333333333, 0.8092911111111112, 0.6044597222222222, 0.8092372222222223, 0.60444, 0.80918, 0.6044630555555556, 0.8091138888888889, 0.6044694444444445, 0.8090133333333334, 0.6044566666666666, 0.8089577777777778, 0.6044455555555556, 0.8088605555555556, 0.604435, 0.8087933333333333, 0.6043802777777778, 0.8087183333333333, 0.604300925, 0.8103611111111112, 0.6043364194444444, 0.8103101833333333, 0.6043729166666667, 0.8102555555555556, 0.6043736111111111, 0.8101950000000001, 0.6044113888888889, 0.8101266666666667, 0.6044522222222223, 0.8100738888888889, 0.6044894444444444, 0.8099744444444444, 0.6044863888888888, 0.8098977777777777, 0.6045, 0.8098266666666667, 0.6045533333333334, 0.8098155555555555, 0.604603611111111, 0.8097583333333335, 0.6046719444444444, 0.8097016666666667, 0.6046313888888889, 0.8096283333333334, 0.6046555555555555, 0.8095477777777779, 0.6046808333333333, 0.8094855555555556, 0.6047972222222222, 0.8094077777777777, 0.6048694444444445, 0.8093938888888889, 0.6048938888888888, 0.8093100000000001, 0.6048625, 0.8092205555555555, 0.6048419444444444, 0.8091666666666667, 0.6048433333333334, 0.8090744444444444, 0.6048436111111111, 0.8090061111111112, 0.6048480555555555, 0.8089577777777778, 0.6046638888888889, 0.8099461111111111, 0.6047305916666667, 0.8098905111111111, 0.6047409638888889, 0.8098040999999999, 0.6047754138888889, 0.8097426111111111, 0.6048057666666666, 0.8096208222222223, 0.6048011111111111, 0.8094833333333333, 0.6047972222222222, 0.8094111111111112, 0.604736111111111, 0.8093583333333334, 0.6046794444444444, 0.8093083333333333, 0.6045797222222222, 0.809195, 0.6044983333333332, 0.809185, 0.6044397222222222, 0.8091833333333333, 0.6043669444444445, 0.8092016666666666, 0.6042775, 0.809215, 0.6042272222222221, 0.8092783333333333, 0.6041805555555555, 0.809321111111111, 0.6041252777777777, 0.80938, 0.6040672222222222, 0.809428888888889, 0.6040325000000001, 0.8095294444444445, 0.6040158333333333, 0.8096133333333333, 0.6040572222222222, 0.8097177777777778, 0.6040855555555555, 0.8097694444444444, 0.6041233333333333, 0.8098544444444444, 0.6042552777777778, 0.8097083333333334, 0.6042388888888889, 0.8097594444444444, 0.6042241666666667, 0.8098711111111112, 0.6042591666666667, 0.8099255555555556, 0.6043252777777778, 0.8099544444444444, 0.6044111111111111, 0.8099644444444445, 0.6043227777777778, 0.8088911111111111, 0.6043802777777778, 0.8087894444444444, 0.6043797222222222, 0.8087166666666668, 0.6043183333333333, 0.8086005555555555, 0.6042861111111111, 0.8085861111111111, 0.6042522222222222, 0.8085655555555555, 0.6042105555555556, 0.8085444444444445, 0.6043858333333334, 0.8101055555555556, 0.6044197222222222, 0.8101211111111111, 0.6044691666666667, 0.8101211111111111, 0.6045191666666667, 0.8101211111111111, 0.6045508333333334, 0.8101333333333334, 0.6045691666666667, 0.8101622222222223, 0.6043594444444444, 0.8102622222222221, 0.6044250000000001, 0.8102644444444445, 0.6045591666666666, 0.8102555555555556, 0.6046258333333333, 0.8102222222222223, 0.604723888888889, 0.8101666666666666, 0.6048247222222222, 0.8100955555555557, 0.60485, 0.8100216666666666, 0.604841111111111, 0.8099366666666666, 0.6048475, 0.8098411111111111, 0.6048508333333333, 0.8097722222222223, 0.6048177777777778, 0.8096727777777779, 0.6048005555555556, 0.8096233333333334, 0.6047669444444443, 0.8095772222222223, 0.6047161111111111, 0.8095461111111111, 0.6047161111111111, 0.8095461111111111, 0.6046197222222222, 0.8094794444444444, 0.6045786111111111, 0.8094350000000001, 0.6044969444444445, 0.8093888888888888, 0.6044583333333333, 0.8093888888888888, 0.604405, 0.8094827777777778, 0.6043419444444444, 0.8095572222222223, 0.6042591666666667, 0.8096711111111111, 0.6042561111111111, 0.8097066666666666, 0.6042377777777778, 0.8097638888888888, 0.6041866666666666, 0.8098733333333333, 0.6041791666666667, 0.8099322222222223, 0.6041633333333334, 0.809995, 0.6041302777777777, 0.8100755555555555, 0.6041558333333333, 0.8101433333333334, 0.6042230555555556, 0.8102205555555555, 0.6043091666666667, 0.8102622222222221, 0.6048057666666666, 0.8096208222222223, 0.6048941666666666, 0.8095833333333333, 0.6049491666666666, 0.8095477777777779, 0.6050528055555555, 0.8094720555555556, 0.6051419444444445, 0.8094627777777779, 0.60522, 0.8095, 0.6052788888888888, 0.8094916666666667, 0.6053511111111111, 0.8094644444444444]