@cdc/chart 4.24.11 → 4.24.12-2

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 (65) hide show
  1. package/dist/cdcchart.js +32134 -32039
  2. package/examples/feature/sankey/sankey-example-data.json +126 -13
  3. package/examples/feature/tests-date-exclusions/date-exclusions-config.json +372 -12
  4. package/examples/private/DEV-8850-2.json +493 -0
  5. package/examples/private/DEV-9822.json +574 -0
  6. package/examples/private/DEV-9840.json +553 -0
  7. package/examples/private/DEV-9850-3.json +461 -0
  8. package/examples/private/chart.json +1084 -0
  9. package/examples/private/ci_formatted.json +202 -0
  10. package/examples/private/ci_issue.json +3016 -0
  11. package/examples/private/completed.json +634 -0
  12. package/examples/private/dem-data-long.csv +20 -0
  13. package/examples/private/dem-data-long.json +36 -0
  14. package/examples/private/demographic_data.csv +157 -0
  15. package/examples/private/demographic_data.json +2654 -0
  16. package/examples/private/demographic_dynamic.json +443 -0
  17. package/examples/private/demographic_standard.json +560 -0
  18. package/examples/private/ehdi.json +29939 -0
  19. package/examples/private/test.json +448 -20047
  20. package/index.html +9 -6
  21. package/package.json +2 -2
  22. package/src/CdcChart.tsx +62 -82
  23. package/src/_stories/Chart.Anchors.stories.tsx +31 -0
  24. package/src/_stories/Chart.DynamicSeries.stories.tsx +8 -1
  25. package/src/_stories/Chart.stories.tsx +32 -0
  26. package/src/_stories/ChartAxisLabels.stories.tsx +4 -1
  27. package/{examples/feature/area/area-chart-date-city-temperature.json → src/_stories/_mock/area_chart_stacked.json} +125 -27
  28. package/src/_stories/_mock/line_chart_dynamic_ci.json +493 -0
  29. package/src/_stories/_mock/line_chart_non_dynamic_ci.json +522 -0
  30. package/src/_stories/_mock/short_dates.json +288 -0
  31. package/src/components/AreaChart/components/AreaChart.Stacked.jsx +15 -3
  32. package/src/components/Axis/Categorical.Axis.tsx +2 -2
  33. package/src/components/BarChart/components/BarChart.Horizontal.tsx +46 -37
  34. package/src/components/BarChart/components/BarChart.Vertical.tsx +28 -40
  35. package/src/components/BarChart/helpers/getBarData.ts +28 -0
  36. package/src/components/BarChart/helpers/tests/getBarData.test.ts +74 -0
  37. package/src/components/BoxPlot/BoxPlot.tsx +12 -70
  38. package/src/components/BoxPlot/helpers/index.ts +54 -0
  39. package/src/components/BrushChart.tsx +23 -26
  40. package/src/components/EditorPanel/EditorPanel.tsx +55 -79
  41. package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +1 -0
  42. package/src/components/EditorPanel/useEditorPermissions.ts +5 -1
  43. package/src/components/Legend/Legend.Component.tsx +2 -2
  44. package/src/{hooks/useLegendClasses.ts → components/Legend/helpers/getLegendClasses.ts} +5 -5
  45. package/src/components/Legend/helpers/index.ts +2 -1
  46. package/src/components/Legend/tests/getLegendClasses.test.ts +115 -0
  47. package/src/components/LineChart/components/LineChart.Circle.tsx +1 -1
  48. package/src/components/LineChart/helpers.ts +1 -0
  49. package/src/components/LineChart/index.tsx +47 -1
  50. package/src/components/LinearChart.tsx +180 -172
  51. package/src/components/PieChart/PieChart.tsx +7 -1
  52. package/src/components/Sankey/components/ColumnList.tsx +19 -0
  53. package/src/components/Sankey/components/Sankey.tsx +479 -0
  54. package/src/components/Sankey/helpers/getSankeyTooltip.tsx +33 -0
  55. package/src/components/Sankey/index.tsx +1 -510
  56. package/src/components/Sankey/sankey.scss +16 -16
  57. package/src/components/Sankey/types/index.ts +1 -1
  58. package/src/data/initial-state.js +4 -3
  59. package/src/helpers/countNumOfTicks.ts +57 -0
  60. package/src/helpers/getQuartiles.ts +15 -18
  61. package/src/hooks/useMinMax.ts +18 -4
  62. package/src/hooks/useScales.ts +38 -4
  63. package/src/hooks/useTooltip.tsx +5 -1
  64. package/src/scss/DataTable.scss +5 -0
  65. package/src/scss/main.scss +6 -2
@@ -1,511 +1,2 @@
1
- import { useContext, useState, useRef, useEffect } from 'react'
2
-
3
- // External Libraries
4
- import { PlacesType, Tooltip as ReactTooltip } from 'react-tooltip'
5
- import { SankeyGraph, sankey, sankeyLinkHorizontal, sankeyLeft } from 'd3-sankey'
6
- import { Group } from '@visx/group'
7
- import { Text } from '@visx/text'
8
- import ReactDOMServer from 'react-dom/server'
9
-
10
- // Cdc
11
- import './sankey.scss'
12
- import 'react-tooltip/dist/react-tooltip.css'
13
- import ConfigContext from '@cdc/chart/src/ConfigContext'
14
- import { ChartContext } from '../../types/ChartContext'
15
- import type { SankeyNode, SankeyProps } from './types'
16
- import { SankeyChartConfig, AllChartsConfig } from '../../types/ChartConfig'
17
- import useSankeyAlert from './useSankeyAlert'
18
-
19
- const Sankey = ({ width, height, runtime }: SankeyProps) => {
20
- const { config, handleChartTabbing, legendId } = useContext<ChartContext>(ConfigContext)
21
- const { sankey: sankeyConfig } = config
22
-
23
- const isSankeyChartConfig = (config: AllChartsConfig | SankeyChartConfig): config is SankeyChartConfig => {
24
- return config.visualizationType === 'Sankey'
25
- }
26
-
27
- const [largestGroupWidth, setLargestGroupWidth] = useState(0)
28
- const groupRefs = useRef([])
29
-
30
- //Tooltip
31
- const [tooltipID, setTooltipID] = useState<string>('')
32
- const { showAlert, alert } = useSankeyAlert()
33
-
34
- const handleNodeClick = (nodeId: string) => {
35
- // Store the previous tooltipID
36
- const previousTooltipID = tooltipID
37
-
38
- // If the previous tooltipID exists, clear it
39
- if (previousTooltipID) {
40
- setTooltipID('')
41
- }
42
-
43
- // Update the tooltipID with the new nodeId if it's different from the previous one
44
- if (previousTooltipID !== nodeId) {
45
- setTooltipID(nodeId)
46
- }
47
- }
48
-
49
- // Uses Visx Groups innerRef to get all Group elements that are mapped.
50
- // Sets the largest group width in state and subtracts that group the svg width to calculate overall width.
51
- useEffect(() => {
52
- let largest = 0
53
- groupRefs?.current?.map(g => {
54
- const groupWidth = g?.getBoundingClientRect().width
55
- if (groupWidth > largest) {
56
- largest = groupWidth
57
- }
58
- })
59
- setLargestGroupWidth(largest)
60
- }, [groupRefs, sankeyConfig, window.innerWidth])
61
-
62
- if (!isSankeyChartConfig(config)) return
63
- const data = config?.data[0]
64
-
65
- //Retrieve all the unique values for the Nodes
66
- const uniqueNodes = Array.from(new Set(data?.links?.flatMap(link => [link.source, link.target])))
67
-
68
- // Convert JSON data to the format required
69
- const sankeyData: SankeyGraph<SankeyNode, { source: number; target: number }> = {
70
- nodes: uniqueNodes.map(nodeId => ({ id: nodeId })),
71
- links: data?.links?.map(link => ({
72
- source: uniqueNodes.findIndex(node => node === link.source),
73
- target: uniqueNodes.findIndex(node => node === link.target),
74
- value: link.value
75
- }))
76
- }
77
-
78
- let textPositionHorizontal = 5
79
- const BUFFER = 50
80
-
81
- // Set the sankey diagram properties console.log('largestGroupWidth', largestGroupWidth)
82
-
83
- const sankeyGenerator = sankey<SankeyNode, { source: number; target: number }>()
84
- .nodeWidth(sankeyConfig.nodeSize.nodeWidth)
85
- .nodePadding(sankeyConfig.nodePadding)
86
- .iterations(sankeyConfig.iterations)
87
- .nodeAlign(sankeyLeft)
88
- .extent([
89
- [sankeyConfig.margin.margin_x, Number(sankeyConfig.margin.margin_y)],
90
- [width - textPositionHorizontal - largestGroupWidth, config.heights.vertical - BUFFER]
91
- ])
92
-
93
- const { nodes, links } = sankeyGenerator(sankeyData)
94
-
95
- const nodeStyle = (id: string) => {
96
- let textPositionHorizontal = 30
97
- let textPositionVertical = 0
98
- let classStyle = 'node-value--storynode'
99
- let storyNodes = true
100
-
101
- // TODO: need a dynamic way to apply classes here instead of checking static values.
102
-
103
- if (data?.storyNodeText?.every(node => node.StoryNode !== id)) {
104
- storyNodes = false
105
- textPositionVertical = 10
106
- textPositionHorizontal = 8
107
- classStyle = 'node-value'
108
- }
109
-
110
- return { textPositionHorizontal, textPositionVertical, classStyle, storyNodes }
111
- }
112
-
113
- const activeConnection = (id: String) => {
114
- if (!sankeyData?.nodes) return { sourceNodes: [], activeLinks: [] }
115
-
116
- const currentNode = sankeyData.nodes.find(node => node.id === id)
117
-
118
- const sourceNodes = []
119
- const activeLinks = []
120
-
121
- if (currentNode) {
122
- links.forEach(link => {
123
- const targetObj: any = link.target
124
- const sourceObj: any = link.source
125
- if (targetObj.id === id) {
126
- sourceNodes.push(sourceObj.id)
127
- }
128
- })
129
-
130
- sourceNodes.forEach(id => {
131
- links.forEach(link => {
132
- const targetObj: any = link.target
133
- const sourceObj: any = link.source
134
- if (targetObj.id === tooltipID && sourceObj.id === id) {
135
- activeLinks.push(link)
136
- }
137
- })
138
- })
139
- }
140
-
141
- return { sourceNodes, activeLinks }
142
- }
143
-
144
- const tooltipVal = `${(data?.tooltips?.find(item => item.node === tooltipID) || {}).value}`
145
- const tooltipSummary = `${(data?.tooltips?.find(item => item.node === tooltipID) || {}).summary}`
146
- const tooltipColumn1Label = (data?.tooltips?.find(item => item.node === tooltipID) || {}).column1Label
147
- const tooltipColumn2Label = (data?.tooltips?.find(item => item.node === tooltipID) || {}).column2Label
148
- const tooltipColumn1 = (data?.tooltips?.find(item => item.node === tooltipID) || {}).column1
149
- const tooltipColumn2 = (data?.tooltips?.find(item => item.node === tooltipID) || {}).column2
150
-
151
- const ColumnList = ({ columnData }) => {
152
- return (
153
- <ul>
154
- {columnData?.map((entry, index) => (
155
- <li key={index}>
156
- {entry.label}: {entry.value} ({entry.additional_info}%)
157
- </li>
158
- ))}
159
- </ul>
160
- )
161
- }
162
-
163
- const tooltipColumn1Data = ReactDOMServer.renderToString(<ColumnList columnData={tooltipColumn1} />)
164
- const tooltipColumn2Data = ReactDOMServer.renderToString(<ColumnList columnData={tooltipColumn2} />)
165
-
166
- const sankeyToolTip = `<div class="sankey-chart__tooltip">
167
- <span class="sankey-chart__tooltip--tooltip-header">${tooltipID}</span>
168
- <span class="sankey-chart__tooltip--tooltip-header">${tooltipVal}</span>
169
- <div class="divider"></div>
170
- <span><strong>Summary: </strong>${tooltipSummary}</span>
171
- <div class="divider"></div>
172
- <div class="sankey-chart__tooltip--info-section">
173
- <div>
174
- <span><strong>${tooltipColumn1Label}<strong></span>
175
- ${tooltipColumn1Data}
176
- </div>
177
- <div>
178
- <span><strong>${tooltipColumn2Label}<strong></span>
179
- ${tooltipColumn2Data}
180
- </div>
181
- </div>
182
- </div>`
183
-
184
- // Draw the nodes
185
- const allNodes = sankeyData.nodes.map((node, i) => {
186
- let { textPositionHorizontal, textPositionVertical, classStyle, storyNodes } = nodeStyle(node.id)
187
- let { sourceNodes } = activeConnection(tooltipID)
188
-
189
- let opacityValue = sankeyConfig.opacity.nodeOpacityDefault
190
- let nodeColor = sankeyConfig.nodeColor.default
191
-
192
- if (tooltipID !== node.id && tooltipID !== '' && !sourceNodes.includes(node.id)) {
193
- nodeColor = sankeyConfig.nodeColor.inactive
194
- opacityValue = sankeyConfig.opacity.nodeOpacityInactive
195
- }
196
-
197
- return (
198
- <Group className='' key={i}>
199
- <rect
200
- height={node.y1! - node.y0! + 2} // increasing node size to account for smaller nodes
201
- width={sankeyGenerator.nodeWidth()}
202
- x={node.x0}
203
- y={node.y0! - 1} //adjusting here the node starts so it looks more center with the link
204
- fill={nodeColor}
205
- fillOpacity={opacityValue}
206
- rx={sankeyConfig.rxValue}
207
- // todo: move enable tooltips to sankey
208
- data-tooltip-html={data.tooltips && config.enableTooltips && tooltipID !== '' ? sankeyToolTip : null}
209
- data-tooltip-id={`cdc-open-viz-tooltip-${runtime.uniqueId}-sankey`}
210
- onClick={() => handleNodeClick(node.id)}
211
- style={{ pointerEvents: 'visible', cursor: 'pointer' }}
212
- />
213
- {storyNodes ? (
214
- <>
215
- <Text
216
- /* Text Position Horizontal
217
- x0 is the left edge of the node
218
- # - positions text # units to the right of the left edge of the node */
219
- x={node.x0! + textPositionHorizontal}
220
- textAnchor={sankeyData.nodes.length - 1 === i ? 'end' : 'start'}
221
- verticalAnchor='end'
222
- /*Text Position Vertical
223
- y1 and y0 are the top and bottom edges of the node
224
- y1+y0 = total height
225
- dividing by 2 gives you the midpoint of the node
226
- minus 30 raises the vertical position to be higher
227
- */
228
- y={(node.y1! + node.y0!) / 2 - 30}
229
- /* Using x and y in combination with dominant baseline allows for a more
230
- precise positioning of the text within the svg
231
- dominant baseline allows for different vertical alignments
232
- text-before-edge aligns the text's bottom edge with the bottom edge of the container
233
- */
234
- fill={sankeyConfig.nodeFontColor}
235
- fontWeight='bold' // font weight
236
- className='node-text'
237
- style={{ pointerEvents: 'auto', cursor: 'pointer' }} // Enable pointer events
238
- onClick={() => handleNodeClick(node.id)}
239
- data-tooltip-html={data.tooltips && config.enableTooltips && tooltipID !== '' ? sankeyToolTip : null}
240
- data-tooltip-id={`cdc-open-viz-tooltip-${runtime.uniqueId}-sankey`}
241
- >
242
- {(data?.storyNodeText?.find(storyNode => storyNode.StoryNode === node.id) || {}).segmentTextBefore}
243
- </Text>
244
- <Text
245
- verticalAnchor='end'
246
- className={classStyle}
247
- x={node.x0! + textPositionHorizontal}
248
- y={(node.y1! + node.y0! + 25) / 2}
249
- fill={sankeyConfig.storyNodeFontColor || sankeyConfig.nodeFontColor}
250
- fontWeight='bold'
251
- textAnchor='start'
252
- style={{ pointerEvents: 'auto', cursor: 'pointer' }} // Enable pointer events
253
- onClick={() => handleNodeClick(node.id)}
254
- data-tooltip-html={data.tooltips && config.enableTooltips && tooltipID !== '' ? sankeyToolTip : null}
255
- data-tooltip-id={`cdc-open-viz-tooltip-${runtime.uniqueId}-sankey`}
256
- >
257
- {typeof node.value === 'number' ? node.value.toLocaleString() : node.value}
258
- </Text>
259
- <Text
260
- x={node.x0! + textPositionHorizontal}
261
- // plus 50 will move the vertical position down
262
- y={(node.y1! + node.y0!) / 2 + 50}
263
- fill={sankeyConfig.nodeFontColor}
264
- fontWeight='bold'
265
- textAnchor={sankeyData.nodes.length === i ? 'end' : 'start'}
266
- className='node-text'
267
- verticalAnchor='end'
268
- style={{ pointerEvents: 'auto', cursor: 'pointer' }} // Enable pointer events
269
- onClick={() => handleNodeClick(node.id)}
270
- data-tooltip-html={data.tooltips && config.enableTooltips && tooltipID !== '' ? sankeyToolTip : null}
271
- data-tooltip-id={`cdc-open-viz-tooltip-${runtime.uniqueId}-sankey`}
272
- >
273
- {(data?.storyNodeText?.find(storyNode => storyNode.StoryNode === node.id) || {}).segmentTextAfter}
274
- </Text>
275
- </>
276
- ) : (
277
- <>
278
- <Text
279
- style={{ pointerEvents: 'auto', cursor: 'pointer' }} // Enable pointer events
280
- onClick={() => handleNodeClick(node.id)}
281
- data-tooltip-html={data.tooltips && config.enableTooltips && tooltipID !== '' ? sankeyToolTip : null}
282
- data-tooltip-id={`cdc-open-viz-tooltip-${runtime.uniqueId}-sankey`}
283
- x={node.x0! + textPositionHorizontal}
284
- y={(node.y1! + node.y0!) / 2 + textPositionVertical}
285
- dominantBaseline='text-before-edge'
286
- fill={sankeyConfig.nodeFontColor}
287
- fontWeight='bold'
288
- textAnchor='start'
289
- >
290
- {node.id}
291
- </Text>
292
- <text
293
- x={node.x0! + textPositionHorizontal}
294
- /* adding 30 allows the node value to be on the next line underneath the node id */
295
- y={(node.y1! + node.y0!) / 2 + 30}
296
- dominantBaseline='text-before-edge'
297
- fill={sankeyConfig.nodeFontColor}
298
- //fontSize={16}
299
- fontWeight='bold'
300
- textAnchor='start'
301
- style={{ pointerEvents: 'auto', cursor: 'pointer' }} // Enable pointer events
302
- onClick={() => handleNodeClick(node.id)}
303
- data-tooltip-html={data.tooltips && config.enableTooltips && tooltipID !== '' ? sankeyToolTip : null}
304
- data-tooltip-id={`cdc-open-viz-tooltip-${runtime.uniqueId}-sankey`}
305
- >
306
- <tspan className={classStyle}>
307
- {sankeyConfig.nodeValueStyle.textBefore +
308
- (typeof node.value === 'number' ? node.value.toLocaleString() : node.value) +
309
- sankeyConfig.nodeValueStyle.textAfter}
310
- </tspan>
311
- </text>
312
- </>
313
- )}
314
- </Group>
315
- )
316
- })
317
-
318
- // Draw the links
319
- const allLinks = links.map((link, i) => {
320
- const linkGenerator = sankeyLinkHorizontal()
321
- const path = linkGenerator(link)
322
- let opacityValue = sankeyConfig.opacity.LinkOpacityDefault
323
- let strokeColor = sankeyConfig.linkColor.default
324
-
325
- let { activeLinks } = activeConnection(tooltipID)
326
-
327
- if (!activeLinks.includes(link) && tooltipID !== '') {
328
- strokeColor = sankeyConfig.linkColor.inactive
329
- opacityValue = sankeyConfig.opacity.LinkOpacityInactive
330
- }
331
-
332
- return (
333
- <path
334
- key={i}
335
- d={path!}
336
- stroke={strokeColor}
337
- fill='none'
338
- strokeOpacity={opacityValue}
339
- strokeWidth={link.width! + 2}
340
- style={{ pointerEvents: 'auto', cursor: 'pointer' }} // Enable pointer events
341
- onClick={() => handleNodeClick(link.target.id || null)}
342
- data-tooltip-html={data.tooltips && config.enableTooltips && tooltipID !== '' ? sankeyToolTip : null}
343
- data-tooltip-id={`cdc-open-viz-tooltip-${runtime.uniqueId}-sankey`}
344
- />
345
- )
346
- })
347
-
348
- // max depth - calculates how many nodes deep the chart goes.
349
- const maxDepth: number = sankeyData.nodes.reduce((maxDepth, node) => {
350
- return Math.max(maxDepth, node.depth)
351
- }, -1)
352
-
353
- // finalNodesAtMaxDepth - get only the right most nodes on the chart.
354
- const finalNodesAtMaxDepth = sankeyData.nodes.filter(node => node.depth === maxDepth)
355
-
356
- const finalNodes = finalNodesAtMaxDepth.map((node, i) => {
357
- let { textPositionHorizontal, textPositionVertical, classStyle, storyNodes } = nodeStyle(node.id)
358
- let { sourceNodes } = activeConnection(tooltipID)
359
-
360
- let opacityValue = sankeyConfig.opacity.nodeOpacityDefault
361
- let nodeColor = sankeyConfig.nodeColor.default
362
-
363
- if (tooltipID !== node.id && tooltipID !== '' && !sourceNodes.includes(node.id)) {
364
- nodeColor = sankeyConfig.nodeColor.inactive
365
- opacityValue = sankeyConfig.opacity.nodeOpacityInactive
366
- }
367
-
368
- return (
369
- <Group className='' key={i} innerRef={el => (groupRefs.current[i] = el)}>
370
- <rect
371
- height={node.y1! - node.y0! + 2} // increasing node size to account for smaller nodes
372
- width={sankeyGenerator.nodeWidth()}
373
- x={node.x0}
374
- y={node.y0! - 1} //adjusting here the node starts so it looks more center with the link
375
- fill={nodeColor}
376
- fillOpacity={opacityValue}
377
- rx={sankeyConfig.rxValue}
378
- // todo: move enable tooltips to sankey
379
- data-tooltip-html={data.tooltips && config.enableTooltips && tooltipID !== '' ? sankeyToolTip : null}
380
- data-tooltip-id={`tooltip`}
381
- onClick={() => handleNodeClick(node.id)}
382
- style={{ pointerEvents: 'visible', cursor: 'pointer' }}
383
- />
384
- {storyNodes ? (
385
- <>
386
- <Text
387
- /* Text Position Horizontal
388
- x0 is the left edge of the node
389
- # - positions text # units to the right of the left edge of the node */
390
- x={node.x0! + textPositionHorizontal}
391
- textAnchor={sankeyData.nodes.length - 1 === i ? 'end' : 'start'}
392
- verticalAnchor='end'
393
- /*Text Position Vertical
394
- y1 and y0 are the top and bottom edges of the node
395
- y1+y0 = total height
396
- dividing by 2 gives you the midpoint of the node
397
- minus 30 raises the vertical position to be higher
398
- */
399
- y={(node.y1! + node.y0!) / 2 - 30}
400
- /* Using x and y in combination with dominant baseline allows for a more
401
- precise positioning of the text within the svg
402
- dominant baseline allows for different vertical alignments
403
- text-before-edge aligns the text's bottom edge with the bottom edge of the container
404
- */
405
- fill={sankeyConfig.nodeFontColor}
406
- fontWeight='bold' // font weight
407
- style={{ pointerEvents: 'none' }}
408
- className='node-text'
409
- >
410
- {(data?.storyNodeText?.find(storyNode => storyNode.StoryNode === node.id) || {}).segmentTextBefore}
411
- </Text>
412
- <Text
413
- verticalAnchor='end'
414
- className={classStyle}
415
- x={node.x0! + textPositionHorizontal}
416
- y={(node.y1! + node.y0! + 25) / 2}
417
- fill={sankeyConfig.storyNodeFontColor || sankeyConfig.nodeFontColor}
418
- fontWeight='bold'
419
- textAnchor='start'
420
- style={{ pointerEvents: 'none' }}
421
- >
422
- {typeof node.value === 'number' ? node.value.toLocaleString() : node.value}
423
- </Text>
424
- <Text
425
- x={node.x0! + textPositionHorizontal}
426
- // plus 50 will move the vertical position down
427
- y={(node.y1! + node.y0!) / 2 + 50}
428
- fill={sankeyConfig.nodeFontColor}
429
- fontWeight='bold'
430
- textAnchor={sankeyData.nodes.length === i ? 'end' : 'start'}
431
- style={{ pointerEvents: 'none' }}
432
- className='node-text'
433
- verticalAnchor='end'
434
- >
435
- {(data?.storyNodeText?.find(storyNode => storyNode.StoryNode === node.id) || {}).segmentTextAfter}
436
- </Text>
437
- </>
438
- ) : (
439
- <>
440
- <text
441
- x={node.x0! + textPositionHorizontal}
442
- y={(node.y1! + node.y0!) / 2 + textPositionVertical}
443
- dominantBaseline='text-before-edge'
444
- fill={sankeyConfig.nodeFontColor}
445
- fontWeight='bold'
446
- textAnchor='start'
447
- style={{ pointerEvents: 'none' }}
448
- >
449
- <tspan id={node.id} className='node-id'>
450
- {node.id}
451
- </tspan>
452
- </text>
453
- <text
454
- x={node.x0! + textPositionHorizontal}
455
- /* adding 30 allows the node value to be on the next line underneath the node id */
456
- y={(node.y1! + node.y0!) / 2 + 30}
457
- dominantBaseline='text-before-edge'
458
- fill={sankeyConfig.nodeFontColor}
459
- //fontSize={16}
460
- fontWeight='bold'
461
- textAnchor='start'
462
- style={{ pointerEvents: 'none' }}
463
- >
464
- <tspan onClick={() => handleNodeClick(node.id)} className={classStyle}>
465
- {sankeyConfig.nodeValueStyle.textBefore +
466
- (typeof node.value === 'number' ? node.value.toLocaleString() : node.value) +
467
- sankeyConfig.nodeValueStyle.textAfter}
468
- </tspan>
469
- </text>
470
- </>
471
- )}
472
- </Group>
473
- )
474
- })
475
-
476
- return !showAlert ? (
477
- <>
478
- <div className='sankey-chart'>
479
- <svg
480
- className='sankey-chart__diagram'
481
- width={width}
482
- height={Number(config.heights.vertical)}
483
- style={{ overflow: 'visible' }}
484
- >
485
- <Group className='links'>{allLinks}</Group>
486
- <Group className='nodes'>{allNodes}</Group>
487
- <Group className='finalNodes' style={{ display: 'none' }}>
488
- {finalNodes}
489
- </Group>
490
- </svg>
491
-
492
- {/* ReactTooltip needs to remain even if tooltips are disabled -- it handles when a user clicks off of the node and resets
493
- the sankey diagram. When tooltips are disabled this will nothing */}
494
- <ReactTooltip
495
- id={`cdc-open-viz-tooltip-${runtime.uniqueId}-sankey`}
496
- afterHide={() => setTooltipID('')}
497
- events={['click']}
498
- place={'bottom'}
499
- style={{
500
- backgroundColor: `rgba(238, 238, 238, 1)`,
501
- color: 'black',
502
- boxShadow: `0 3px 10px rgb(0 0 0 / 0.2)`
503
- }}
504
- />
505
- </div>
506
- </>
507
- ) : (
508
- alert
509
- )
510
- }
1
+ import Sankey from './components/Sankey'
511
2
  export default Sankey
@@ -7,7 +7,7 @@
7
7
 
8
8
  .cdc-open-viz-module .sankey-chart {
9
9
  --font-size-small: 12px;
10
- --font-size-medium: 14px;
10
+ --font-size-medium: 16px;
11
11
  --font-size-large: 18px;
12
12
  --font-size-xl: 24px;
13
13
 
@@ -107,21 +107,21 @@
107
107
  }
108
108
  }
109
109
 
110
- //small
111
- @media only screen and (max-width: 799px) {
112
- .node-text {
113
- font-size: var(--font-size-small);
114
- }
115
- .node-value--storynode {
116
- font-size: var(--storynode-font-size--small);
117
- }
118
- .node-id {
119
- font-size: var(--font-size-small);
120
- }
121
- .node-value {
122
- font-size: var(--font-size-small);
123
- }
124
- }
110
+ // //small
111
+ // @media only screen and (max-width: 799px) {
112
+ // .node-text {
113
+ // font-size: var(--font-size-small);
114
+ // }
115
+ // .node-value--storynode {
116
+ // font-size: var(--storynode-font-size--small);
117
+ // }
118
+ // .node-id {
119
+ // font-size: var(--font-size-small);
120
+ // }
121
+ // .node-value {
122
+ // font-size: var(--font-size-small);
123
+ // }
124
+ // }
125
125
 
126
126
  //x-small
127
127
  @media only screen and (max-width: 600px) {
@@ -1,4 +1,4 @@
1
- export type Link = { source: string; target: string; value: number }
1
+ export type Link = { source: string; target: string; value: number; id: string }
2
2
 
3
3
  export type Data = {
4
4
  links: Link[]
@@ -49,7 +49,7 @@ export default {
49
49
  labelColor: '#333',
50
50
  tickLabelColor: '#333',
51
51
  tickColor: '#333',
52
- rightHideAxis: true,
52
+ rightHideAxis: false,
53
53
  rightAxisSize: 0,
54
54
  rightLabel: '',
55
55
  rightLabelOffsetSize: 0,
@@ -171,10 +171,11 @@ export default {
171
171
  hideBorder: {
172
172
  side: false,
173
173
  topBottom: true
174
- }
174
+ },
175
+ position: 'right'
175
176
  },
176
177
  brush: {
177
- height: 25,
178
+ height: 45,
178
179
  active: false
179
180
  },
180
181
  exclusions: {
@@ -0,0 +1,57 @@
1
+ export const countNumOfTicks = ({ axis, max, runtime, currentViewport, isHorizontal, data, config, min }) => {
2
+ let { numTicks } = runtime[axis]
3
+ if (runtime[axis].viewportNumTicks && runtime[axis].viewportNumTicks[currentViewport]) {
4
+ numTicks = runtime[axis].viewportNumTicks[currentViewport]
5
+ }
6
+ let tickCount = undefined
7
+
8
+ if (axis === 'yAxis') {
9
+ tickCount =
10
+ isHorizontal && !numTicks
11
+ ? data.length
12
+ : isHorizontal && numTicks
13
+ ? numTicks
14
+ : !isHorizontal && !numTicks
15
+ ? undefined
16
+ : !isHorizontal && numTicks && numTicks
17
+ // to fix edge case of small numbers with decimals
18
+ if (tickCount === undefined && !config.dataFormat.roundTo) {
19
+ // then it is set to Auto
20
+ if (Number(max) <= 3) {
21
+ tickCount = 2
22
+ } else {
23
+ tickCount = 4 // same default as standalone components
24
+ }
25
+ }
26
+ if (Number(tickCount) > Number(max) && !isHorizontal) {
27
+ // cap it and round it so its an integer
28
+ tickCount = Number(min) < 0 ? Math.round(max) * 2 : Math.round(max)
29
+ }
30
+ }
31
+
32
+ if (axis === 'xAxis') {
33
+ tickCount =
34
+ isHorizontal && !numTicks
35
+ ? undefined
36
+ : isHorizontal && numTicks
37
+ ? numTicks
38
+ : !isHorizontal && !numTicks
39
+ ? undefined
40
+ : !isHorizontal && numTicks && numTicks
41
+ if (isHorizontal && tickCount === undefined && !config.dataFormat.roundTo) {
42
+ // then it is set to Auto
43
+ // - check for small numbers situation
44
+ if (max <= 3) {
45
+ tickCount = 2
46
+ } else {
47
+ tickCount = 4 // same default as standalone components
48
+ }
49
+ }
50
+
51
+ if (config.visualizationType === 'Forest Plot') {
52
+ tickCount = config.yAxis.numTicks !== '' ? config.yAxis.numTicks : 4
53
+ }
54
+ }
55
+
56
+ return tickCount
57
+ }