@galaxy-io/dls 1.2.6 → 1.3.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/README.md +2 -0
- package/dist/avatar/Avatar.d.ts +2 -1
- package/dist/avatar/Avatar.js +103 -14
- package/dist/buttons/Button.d.ts +6 -1
- package/dist/buttons/Button.js +8 -4
- package/dist/charts/BarChart.d.ts +30 -20
- package/dist/charts/BarChart.js +216 -250
- package/dist/charts/ChartAxis.d.ts +47 -22
- package/dist/charts/ChartAxis.js +81 -60
- package/dist/charts/ChartEmptyState.d.ts +17 -0
- package/dist/charts/ChartEmptyState.js +29 -0
- package/dist/charts/ChartFrame.d.ts +82 -0
- package/dist/charts/ChartFrame.js +86 -0
- package/dist/charts/ChartLegend.d.ts +27 -4
- package/dist/charts/ChartLegend.js +46 -23
- package/dist/charts/ChartPrimitives.d.ts +195 -0
- package/dist/charts/ChartPrimitives.js +268 -0
- package/dist/charts/ChartTooltip.d.ts +27 -6
- package/dist/charts/ChartTooltip.js +56 -50
- package/dist/charts/LineChart.d.ts +42 -20
- package/dist/charts/LineChart.js +186 -237
- package/dist/charts/PieChart.d.ts +48 -32
- package/dist/charts/PieChart.js +159 -171
- package/dist/charts/barChartGeometry.d.ts +87 -0
- package/dist/charts/barChartGeometry.js +218 -0
- package/dist/charts/chartFormat.d.ts +19 -0
- package/dist/charts/chartFormat.js +59 -0
- package/dist/charts/chartScales.d.ts +84 -0
- package/dist/charts/chartScales.js +111 -0
- package/dist/charts/chartTheme.d.ts +18 -0
- package/dist/charts/chartTheme.js +26 -0
- package/dist/charts/constants.d.ts +225 -18
- package/dist/charts/constants.js +240 -32
- package/dist/charts/lineChartGeometry.d.ts +54 -0
- package/dist/charts/lineChartGeometry.js +143 -0
- package/dist/charts/pieChartGeometry.d.ts +48 -0
- package/dist/charts/pieChartGeometry.js +89 -0
- package/dist/charts/types.d.ts +522 -54
- package/dist/charts/types.js +136 -0
- package/dist/charts/useChartDimensions.d.ts +40 -0
- package/dist/charts/useChartDimensions.js +53 -0
- package/dist/charts/useChartFormatters.d.ts +19 -0
- package/dist/charts/useChartFormatters.js +20 -0
- package/dist/charts/useChartInteraction.d.ts +71 -0
- package/dist/charts/useChartInteraction.js +130 -0
- package/dist/charts/useChartTooltipPosition.d.ts +53 -0
- package/dist/charts/useChartTooltipPosition.js +39 -0
- package/dist/hooks/useElementClientSize.d.ts +20 -0
- package/dist/hooks/useElementClientSize.js +43 -0
- package/dist/inputs/CheckboxInput.d.ts +7 -2
- package/dist/inputs/CheckboxInput.js +30 -14
- package/dist/inputs/Input.d.ts +5 -2
- package/dist/inputs/Input.js +20 -17
- package/dist/inputs/MultiSelectInput.js +1 -1
- package/dist/inputs/RadioInput.js +7 -2
- package/dist/styles.css +68 -75
- package/dist/table/InfiniteSpreadsheet.d.ts +6 -0
- package/dist/table/InfiniteSpreadsheet.js +235 -0
- package/dist/table/InfiniteTable.d.ts +7 -88
- package/dist/table/InfiniteTable.js +366 -577
- package/dist/{spreadsheet → table}/SpreadsheetCell.d.ts +6 -4
- package/dist/table/SpreadsheetCell.js +71 -0
- package/dist/{spreadsheet → table}/SpreadsheetCellEditor.js +27 -21
- package/dist/table/SpreadsheetHeaderCell.d.ts +23 -0
- package/dist/table/SpreadsheetHeaderCell.js +91 -0
- package/dist/table/SpreadsheetMenuItem.d.ts +14 -0
- package/dist/table/SpreadsheetMenuItem.js +33 -0
- package/dist/table/SpreadsheetPrimitives.d.ts +172 -0
- package/dist/table/SpreadsheetPrimitives.js +105 -0
- package/dist/table/SpreadsheetRow.d.ts +33 -0
- package/dist/table/SpreadsheetRow.js +73 -0
- package/dist/{spreadsheet → table}/SpreadsheetRowActionCell.d.ts +5 -7
- package/dist/table/SpreadsheetRowActionCell.js +51 -0
- package/dist/table/TableExpandCell.d.ts +11 -0
- package/dist/table/TableExpandCell.js +24 -0
- package/dist/table/TableExpandedRow.d.ts +16 -0
- package/dist/table/TableExpandedRow.js +77 -0
- package/dist/table/TableHeaderCellContent.d.ts +30 -0
- package/dist/table/TableHeaderCellContent.js +48 -0
- package/dist/table/TablePrimitives.d.ts +307 -0
- package/dist/table/TablePrimitives.js +298 -0
- package/dist/table/TableSelectCell.d.ts +18 -0
- package/dist/table/TableSelectCell.js +26 -0
- package/dist/table/TableStatusRow.d.ts +18 -0
- package/dist/table/TableStatusRow.js +50 -0
- package/dist/table/VirtualizedInfiniteTable.d.ts +11 -27
- package/dist/table/VirtualizedInfiniteTable.js +182 -317
- package/dist/table/types.d.ts +249 -0
- package/dist/table/types.js +51 -0
- package/dist/table/useInfiniteScrollSentinel.d.ts +24 -0
- package/dist/table/useInfiniteScrollSentinel.js +53 -0
- package/dist/{spreadsheet/hooks → table}/useSpreadsheetEditing.d.ts +1 -1
- package/dist/{spreadsheet/hooks → table}/useSpreadsheetEditing.js +1 -1
- package/dist/table/useTableColumnLayout.d.ts +28 -0
- package/dist/table/useTableColumnLayout.js +63 -0
- package/dist/table/useTableColumnResize.d.ts +38 -0
- package/dist/table/useTableColumnResize.js +155 -0
- package/dist/table/useTableKeyboardNavigation.d.ts +25 -0
- package/dist/table/useTableKeyboardNavigation.js +83 -0
- package/dist/table/useTableRowExpansion.d.ts +24 -0
- package/dist/table/useTableRowExpansion.js +62 -0
- package/dist/table/useTableRowSelection.d.ts +27 -0
- package/dist/table/useTableRowSelection.js +94 -0
- package/dist/table/utils.d.ts +50 -0
- package/dist/table/utils.js +78 -0
- package/dist/text/MarkdownText.js +45 -27
- package/dist/theme/variants/dark.js +1 -1
- package/dist/widget/Widget.d.ts +2 -0
- package/dist/widget/Widget.js +14 -7
- package/package.json +1 -5
- package/dist/assets/components/enrichment/PerplexityIcon.d.ts +0 -3
- package/dist/assets/components/enrichment/PerplexityIcon.js +0 -35
- package/dist/assets/components/enrichment/TavilyIcon.d.ts +0 -3
- package/dist/assets/components/enrichment/TavilyIcon.js +0 -15
- package/dist/assets/components/onboarding/TenantSetupDark.d.ts +0 -3
- package/dist/assets/components/onboarding/TenantSetupDark.js +0 -498
- package/dist/assets/components/onboarding/TenantSetupLight.d.ts +0 -3
- package/dist/assets/components/onboarding/TenantSetupLight.js +0 -482
- package/dist/assets/components/onboarding/UserSetupDark.d.ts +0 -3
- package/dist/assets/components/onboarding/UserSetupDark.js +0 -1086
- package/dist/assets/components/onboarding/UserSetupLight.d.ts +0 -3
- package/dist/assets/components/onboarding/UserSetupLight.js +0 -1024
- package/dist/assets/components/onboarding/WorkspaceSetupBuildDark.d.ts +0 -3
- package/dist/assets/components/onboarding/WorkspaceSetupBuildDark.js +0 -466
- package/dist/assets/components/onboarding/WorkspaceSetupBuildLight.d.ts +0 -3
- package/dist/assets/components/onboarding/WorkspaceSetupBuildLight.js +0 -460
- package/dist/assets/components/onboarding/WorkspaceSetupConnectDark.d.ts +0 -3
- package/dist/assets/components/onboarding/WorkspaceSetupConnectDark.js +0 -336
- package/dist/assets/components/onboarding/WorkspaceSetupConnectLight.d.ts +0 -3
- package/dist/assets/components/onboarding/WorkspaceSetupConnectLight.js +0 -336
- package/dist/assets/components/onboarding/WorkspaceSetupIntegrateDark.d.ts +0 -3
- package/dist/assets/components/onboarding/WorkspaceSetupIntegrateDark.js +0 -153
- package/dist/assets/components/onboarding/WorkspaceSetupIntegrateLight.d.ts +0 -3
- package/dist/assets/components/onboarding/WorkspaceSetupIntegrateLight.js +0 -153
- package/dist/assets/components/projects/MappingMethodAutoIntrospectDark.d.ts +0 -3
- package/dist/assets/components/projects/MappingMethodAutoIntrospectDark.js +0 -117
- package/dist/assets/components/projects/MappingMethodAutoIntrospectLight.d.ts +0 -3
- package/dist/assets/components/projects/MappingMethodAutoIntrospectLight.js +0 -117
- package/dist/assets/components/projects/MappingMethodBlankDark.d.ts +0 -3
- package/dist/assets/components/projects/MappingMethodBlankDark.js +0 -150
- package/dist/assets/components/projects/MappingMethodBlankDarkHovered.d.ts +0 -3
- package/dist/assets/components/projects/MappingMethodBlankDarkHovered.js +0 -150
- package/dist/assets/components/projects/MappingMethodBlankLight.d.ts +0 -3
- package/dist/assets/components/projects/MappingMethodBlankLight.js +0 -150
- package/dist/assets/components/projects/MappingMethodBlankLightHovered.d.ts +0 -3
- package/dist/assets/components/projects/MappingMethodBlankLightHovered.js +0 -150
- package/dist/assets/components/projects/MappingMethodJsonDark.d.ts +0 -3
- package/dist/assets/components/projects/MappingMethodJsonDark.js +0 -90
- package/dist/assets/components/projects/MappingMethodJsonDarkHovered.d.ts +0 -3
- package/dist/assets/components/projects/MappingMethodJsonDarkHovered.js +0 -90
- package/dist/assets/components/projects/MappingMethodJsonLight.d.ts +0 -3
- package/dist/assets/components/projects/MappingMethodJsonLight.js +0 -90
- package/dist/assets/components/projects/MappingMethodJsonLightHovered.d.ts +0 -3
- package/dist/assets/components/projects/MappingMethodJsonLightHovered.js +0 -90
- package/dist/assets/components/projects/ProjectsEmptyStateDark.d.ts +0 -3
- package/dist/assets/components/projects/ProjectsEmptyStateDark.js +0 -454
- package/dist/assets/components/projects/ProjectsEmptyStateLight.d.ts +0 -3
- package/dist/assets/components/projects/ProjectsEmptyStateLight.js +0 -456
- package/dist/assets/components/root/CreateProjectActionCardDark.d.ts +0 -3
- package/dist/assets/components/root/CreateProjectActionCardDark.js +0 -1796
- package/dist/assets/components/root/CreateProjectActionCardDarkHovered.d.ts +0 -3
- package/dist/assets/components/root/CreateProjectActionCardDarkHovered.js +0 -1796
- package/dist/assets/components/root/CreateProjectActionCardLight.d.ts +0 -3
- package/dist/assets/components/root/CreateProjectActionCardLight.js +0 -1786
- package/dist/assets/components/root/CreateProjectActionCardLightHovered.d.ts +0 -3
- package/dist/assets/components/root/CreateProjectActionCardLightHovered.js +0 -1786
- package/dist/assets/components/root/CreateSourceActionCardDark.d.ts +0 -3
- package/dist/assets/components/root/CreateSourceActionCardDark.js +0 -879
- package/dist/assets/components/root/CreateSourceActionCardDarkHovered.d.ts +0 -3
- package/dist/assets/components/root/CreateSourceActionCardDarkHovered.js +0 -879
- package/dist/assets/components/root/CreateSourceActionCardLight.d.ts +0 -3
- package/dist/assets/components/root/CreateSourceActionCardLight.js +0 -889
- package/dist/assets/components/root/CreateSourceActionCardLightHovered.d.ts +0 -3
- package/dist/assets/components/root/CreateSourceActionCardLightHovered.js +0 -889
- package/dist/assets/components/sources/AttioIcon.d.ts +0 -3
- package/dist/assets/components/sources/AttioIcon.js +0 -11
- package/dist/assets/components/sources/BigquerySourceIcon.d.ts +0 -3
- package/dist/assets/components/sources/BigquerySourceIcon.js +0 -39
- package/dist/assets/components/sources/BrowserbaseSourceIcon.d.ts +0 -3
- package/dist/assets/components/sources/BrowserbaseSourceIcon.js +0 -35
- package/dist/assets/components/sources/ClickhouseLogoSourceIconDark.d.ts +0 -3
- package/dist/assets/components/sources/ClickhouseLogoSourceIconDark.js +0 -13
- package/dist/assets/components/sources/ClickhouseLogoSourceIconLight.d.ts +0 -3
- package/dist/assets/components/sources/ClickhouseLogoSourceIconLight.js +0 -13
- package/dist/assets/components/sources/ConfluenceSourceIcon.d.ts +0 -3
- package/dist/assets/components/sources/ConfluenceSourceIcon.js +0 -30
- package/dist/assets/components/sources/GithubSourceIcon.d.ts +0 -3
- package/dist/assets/components/sources/GithubSourceIcon.js +0 -27
- package/dist/assets/components/sources/GoogleDriveIcon.d.ts +0 -3
- package/dist/assets/components/sources/GoogleDriveIcon.js +0 -45
- package/dist/assets/components/sources/HubspotSourceIcon.d.ts +0 -3
- package/dist/assets/components/sources/HubspotSourceIcon.js +0 -14
- package/dist/assets/components/sources/JiraSourceIcon.d.ts +0 -3
- package/dist/assets/components/sources/JiraSourceIcon.js +0 -54
- package/dist/assets/components/sources/LinearSourceIcon.d.ts +0 -3
- package/dist/assets/components/sources/LinearSourceIcon.js +0 -14
- package/dist/assets/components/sources/MysqlLogoSourceIconDark.d.ts +0 -3
- package/dist/assets/components/sources/MysqlLogoSourceIconDark.js +0 -17
- package/dist/assets/components/sources/NetsuiteSourceIcon.d.ts +0 -3
- package/dist/assets/components/sources/NetsuiteSourceIcon.js +0 -32
- package/dist/assets/components/sources/NotionIcon.d.ts +0 -3
- package/dist/assets/components/sources/NotionIcon.js +0 -20
- package/dist/assets/components/sources/PostgresqlIcon.d.ts +0 -3
- package/dist/assets/components/sources/PostgresqlIcon.js +0 -61
- package/dist/assets/components/sources/S3Icon.d.ts +0 -3
- package/dist/assets/components/sources/S3Icon.js +0 -76
- package/dist/assets/components/sources/SalesforceSourceIcon.d.ts +0 -3
- package/dist/assets/components/sources/SalesforceSourceIcon.js +0 -23
- package/dist/assets/components/sources/SlackIcon.d.ts +0 -3
- package/dist/assets/components/sources/SlackIcon.js +0 -32
- package/dist/assets/components/sources/SnowflakeLogoSourceIconDark.d.ts +0 -3
- package/dist/assets/components/sources/SnowflakeLogoSourceIconDark.js +0 -14
- package/dist/assets/components/sources/SnowflakeLogoSourceIconLight.d.ts +0 -3
- package/dist/assets/components/sources/SnowflakeLogoSourceIconLight.js +0 -14
- package/dist/assets/components/sources/WikipediaSourceIcon.d.ts +0 -3
- package/dist/assets/components/sources/WikipediaSourceIcon.js +0 -1490
- package/dist/avatar/AvatarEmpty.d.ts +0 -7
- package/dist/avatar/AvatarEmpty.js +0 -99
- package/dist/avatar/types.d.ts +0 -5
- package/dist/avatar/types.js +0 -9
- package/dist/charts/utils.d.ts +0 -29
- package/dist/charts/utils.js +0 -62
- package/dist/icons/BackIcon.d.ts +0 -3
- package/dist/icons/BackIcon.js +0 -13
- package/dist/icons/CloseIcon.d.ts +0 -3
- package/dist/icons/CloseIcon.js +0 -13
- package/dist/icons/CreateIcon.d.ts +0 -3
- package/dist/icons/CreateIcon.js +0 -13
- package/dist/icons/ForwardIcon.d.ts +0 -3
- package/dist/icons/ForwardIcon.js +0 -13
- package/dist/icons/HelpIcon.d.ts +0 -3
- package/dist/icons/HelpIcon.js +0 -14
- package/dist/icons/ProjectsIcon.d.ts +0 -3
- package/dist/icons/ProjectsIcon.js +0 -12
- package/dist/icons/SearchIcon.d.ts +0 -3
- package/dist/icons/SearchIcon.js +0 -12
- package/dist/icons/SourcesIcon.d.ts +0 -3
- package/dist/icons/SourcesIcon.js +0 -12
- package/dist/icons/TextIcon.d.ts +0 -4
- package/dist/icons/TextIcon.js +0 -22
- package/dist/icons/WebScrapeIcon.d.ts +0 -4
- package/dist/icons/WebScrapeIcon.js +0 -22
- package/dist/icons/WebhookIcon.d.ts +0 -4
- package/dist/icons/WebhookIcon.js +0 -22
- package/dist/icons/sources/AttioLogomark.d.ts +0 -4
- package/dist/icons/sources/AttioLogomark.js +0 -8
- package/dist/icons/sources/BrowserbaseLogomark.d.ts +0 -4
- package/dist/icons/sources/BrowserbaseLogomark.js +0 -8
- package/dist/icons/sources/ClickhouseLogomark.d.ts +0 -4
- package/dist/icons/sources/ClickhouseLogomark.js +0 -16
- package/dist/icons/sources/ConfluenceLogomark.d.ts +0 -4
- package/dist/icons/sources/ConfluenceLogomark.js +0 -8
- package/dist/icons/sources/GithubLogomark.d.ts +0 -4
- package/dist/icons/sources/GithubLogomark.js +0 -8
- package/dist/icons/sources/GoogleBigqueryLogomark.d.ts +0 -4
- package/dist/icons/sources/GoogleBigqueryLogomark.js +0 -8
- package/dist/icons/sources/GoogleDriveLogomark.d.ts +0 -4
- package/dist/icons/sources/GoogleDriveLogomark.js +0 -8
- package/dist/icons/sources/HubspotLogomark.d.ts +0 -4
- package/dist/icons/sources/HubspotLogomark.js +0 -8
- package/dist/icons/sources/JiraLogomark.d.ts +0 -4
- package/dist/icons/sources/JiraLogomark.js +0 -8
- package/dist/icons/sources/LinearLogomark.d.ts +0 -4
- package/dist/icons/sources/LinearLogomark.js +0 -8
- package/dist/icons/sources/MySQLLogomark.d.ts +0 -4
- package/dist/icons/sources/MySQLLogomark.js +0 -8
- package/dist/icons/sources/NetsuiteLogomark.d.ts +0 -4
- package/dist/icons/sources/NetsuiteLogomark.js +0 -8
- package/dist/icons/sources/NotionLogomark.d.ts +0 -4
- package/dist/icons/sources/NotionLogomark.js +0 -8
- package/dist/icons/sources/PostgresLogomark.d.ts +0 -4
- package/dist/icons/sources/PostgresLogomark.js +0 -8
- package/dist/icons/sources/S3Logomark.d.ts +0 -4
- package/dist/icons/sources/S3Logomark.js +0 -8
- package/dist/icons/sources/SalesforceLogomark.d.ts +0 -4
- package/dist/icons/sources/SalesforceLogomark.js +0 -8
- package/dist/icons/sources/SlackLogoIconmark.d.ts +0 -4
- package/dist/icons/sources/SlackLogoIconmark.js +0 -8
- package/dist/icons/sources/SnowflakeLogomark.d.ts +0 -4
- package/dist/icons/sources/SnowflakeLogomark.js +0 -16
- package/dist/icons/sources/WikipediaLogomark.d.ts +0 -4
- package/dist/icons/sources/WikipediaLogomark.js +0 -8
- package/dist/spreadsheet/InfiniteSpreadsheet.d.ts +0 -3
- package/dist/spreadsheet/InfiniteSpreadsheet.js +0 -265
- package/dist/spreadsheet/SpreadsheetAddColumnButton.d.ts +0 -6
- package/dist/spreadsheet/SpreadsheetAddColumnButton.js +0 -32
- package/dist/spreadsheet/SpreadsheetCell.js +0 -115
- package/dist/spreadsheet/SpreadsheetHeaderCell.d.ts +0 -18
- package/dist/spreadsheet/SpreadsheetHeaderCell.js +0 -141
- package/dist/spreadsheet/SpreadsheetRow.d.ts +0 -21
- package/dist/spreadsheet/SpreadsheetRow.js +0 -68
- package/dist/spreadsheet/SpreadsheetRowActionCell.js +0 -78
- package/dist/spreadsheet/hooks/useColumnResize.d.ts +0 -6
- package/dist/spreadsheet/hooks/useColumnResize.js +0 -46
- package/dist/spreadsheet/types.d.ts +0 -92
- package/dist/spreadsheet/types.js +0 -21
- /package/dist/{spreadsheet → table}/SpreadsheetCellEditor.d.ts +0 -0
package/dist/charts/constants.js
CHANGED
|
@@ -1,38 +1,246 @@
|
|
|
1
|
+
import { ChartPalette } from "./types.js";
|
|
1
2
|
//#region src/charts/constants.ts
|
|
2
3
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
theme.color.text.teal,
|
|
11
|
-
theme.color.text.lime,
|
|
12
|
-
theme.color.text.orange,
|
|
13
|
-
theme.color.text.yellow,
|
|
14
|
-
theme.color.text.success,
|
|
15
|
-
theme.color.text.error
|
|
16
|
-
];
|
|
4
|
+
* Layout and motion tokens for the chart components.
|
|
5
|
+
*
|
|
6
|
+
* This module is evaluated by Linaria at build time — its constants are
|
|
7
|
+
* interpolated statically into styled templates — so it must stay free of
|
|
8
|
+
* component imports. Pulling React, framer-motion or Phosphor in here would
|
|
9
|
+
* drag them into build-time evaluation.
|
|
10
|
+
*/
|
|
17
11
|
var DEFAULT_CHART_MARGIN = {
|
|
18
|
-
top:
|
|
12
|
+
top: 12,
|
|
19
13
|
right: 16,
|
|
20
|
-
bottom:
|
|
21
|
-
left:
|
|
14
|
+
bottom: 36,
|
|
15
|
+
left: 52
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Gap between a value-axis tick label and the plot edge.
|
|
19
|
+
*
|
|
20
|
+
* The label box is `margin.left - VALUE_AXIS_TICK_GAP` wide, so the axis
|
|
21
|
+
* geometry follows the margin instead of hardcoding an offset.
|
|
22
|
+
*/
|
|
23
|
+
var VALUE_AXIS_TICK_GAP = 12;
|
|
24
|
+
/** Height of a value-axis tick label box in px. */
|
|
25
|
+
var VALUE_AXIS_LABEL_HEIGHT = 20;
|
|
26
|
+
/** Height of the category-axis label box in px. */
|
|
27
|
+
var CATEGORY_AXIS_LABEL_HEIGHT = 24;
|
|
28
|
+
/** Gap between the plot's bottom edge and the category labels, in px. */
|
|
29
|
+
var CATEGORY_AXIS_LABEL_GAP = 8;
|
|
30
|
+
/** Band reserved for an axis title, in px. Sized for one CAPTION line. */
|
|
31
|
+
var AXIS_TITLE_BAND = 18;
|
|
32
|
+
/**
|
|
33
|
+
* Clear space between an axis title and its tick labels, in px.
|
|
34
|
+
*
|
|
35
|
+
* The category axis gets this for free: its labels sit in a 24px box and its
|
|
36
|
+
* title in an 18px band, and centring a CAPTION line in each leaves roughly this
|
|
37
|
+
* much air between the two. The value axis has no such slack — its title band
|
|
38
|
+
* abuts the label box exactly — so without reserving it here a wide tick number
|
|
39
|
+
* runs straight into the rotated title, and the two axes visibly disagree.
|
|
40
|
+
*/
|
|
41
|
+
var AXIS_TITLE_GAP = 8;
|
|
42
|
+
/** Default approximate tick count on the value axis. */
|
|
43
|
+
var DEFAULT_VALUE_TICK_COUNT = 5;
|
|
44
|
+
/** Corner radius applied to the outer end of a wide bar, in px. */
|
|
45
|
+
var BAR_RADIUS = 4;
|
|
46
|
+
/** Corner radius for bars narrower than {@link NARROW_BAR_WIDTH}, in px. */
|
|
47
|
+
var BAR_RADIUS_NARROW = 2;
|
|
48
|
+
/** Bars below this width use the smaller radius so the curve doesn't dominate. */
|
|
49
|
+
var NARROW_BAR_WIDTH = 40;
|
|
50
|
+
/**
|
|
51
|
+
* Px shaved off a stacked segment's covered edge to separate it from its
|
|
52
|
+
* neighbour.
|
|
53
|
+
*
|
|
54
|
+
* Keep this a whole number. The geometry snaps every stack boundary to a whole
|
|
55
|
+
* pixel first, so an integer gap renders at exactly the same size at every seam;
|
|
56
|
+
* a fractional one would land differently against the device pixel grid from one
|
|
57
|
+
* boundary to the next and read as uneven.
|
|
58
|
+
*
|
|
59
|
+
* Applied to every segment except the one sitting on the baseline, so each seam
|
|
60
|
+
* gets a gap and the bar still meets the axis flush.
|
|
61
|
+
*/
|
|
62
|
+
var STACK_SEGMENT_GAP = 2;
|
|
63
|
+
/** Minimum rendered height for a non-zero bar, in px. */
|
|
64
|
+
var MIN_BAR_LENGTH = 2;
|
|
65
|
+
/**
|
|
66
|
+
* Target gaps in px between groups, and between bars within a group.
|
|
67
|
+
*
|
|
68
|
+
* The within-group gap must stay clearly smaller than the between-group gap —
|
|
69
|
+
* that ratio is the only thing making a group read as a group. When the two are
|
|
70
|
+
* close, the eye has nothing to bind a group's bars together and the chart reads
|
|
71
|
+
* as one long row of unrelated bars.
|
|
72
|
+
*/
|
|
73
|
+
var GROUP_GAP_COMFORTABLE = 24;
|
|
74
|
+
var BAR_GAP_COMFORTABLE = 6;
|
|
75
|
+
var GROUP_GAP_MEDIUM = 16;
|
|
76
|
+
var BAR_GAP_MEDIUM = 4;
|
|
77
|
+
var GROUP_GAP_TIGHT = 12;
|
|
78
|
+
var BAR_GAP_TIGHT = 3;
|
|
79
|
+
/**
|
|
80
|
+
* Fraction of its available slot a bar actually fills.
|
|
81
|
+
*
|
|
82
|
+
* Bars sized to consume every last pixel of their group read as heavy, and the
|
|
83
|
+
* chart becomes a wall of colour rather than a set of measurements. Holding them
|
|
84
|
+
* back leaves air on both sides of each group without touching the gap between
|
|
85
|
+
* neighbouring bars.
|
|
86
|
+
*/
|
|
87
|
+
var BAR_WIDTH_RATIO = .8;
|
|
88
|
+
/**
|
|
89
|
+
* Ceiling on a single bar's thickness, in px.
|
|
90
|
+
*
|
|
91
|
+
* Without it a two- or three-category chart divides the whole plot between a
|
|
92
|
+
* handful of bars and produces slabs — the width stops carrying information the
|
|
93
|
+
* moment it exceeds what the eye needs to compare heights.
|
|
94
|
+
*/
|
|
95
|
+
var MAX_BAR_WIDTH = 44;
|
|
96
|
+
/** Below this many bars the chart always uses comfortable spacing. */
|
|
97
|
+
var MIN_BARS_FOR_TIGHT_SPACING = 13;
|
|
98
|
+
/**
|
|
99
|
+
* Ceiling on a gap, as a share of the space it divides.
|
|
100
|
+
*
|
|
101
|
+
* The gaps above are absolute pixel values chosen from chart-wide density, which
|
|
102
|
+
* says nothing about how much room a *single* category actually got. Forty
|
|
103
|
+
* categories in a 650px plot leave a 16px step, and a 24px gap subtracted from
|
|
104
|
+
* that goes negative — the width lands on its 1px floor and every bar renders as
|
|
105
|
+
* a hairline. Capping the gap proportionally keeps it honest at any density: it
|
|
106
|
+
* stays exactly as specified whenever there is room, and degrades smoothly when
|
|
107
|
+
* there is not.
|
|
108
|
+
*/
|
|
109
|
+
var MAX_GAP_SHARE = .3;
|
|
110
|
+
/** Plot widths above this stay comfortable; below the tight threshold go tight. */
|
|
111
|
+
var WIDTH_FOR_MEDIUM_SPACING = 650;
|
|
112
|
+
var WIDTH_FOR_TIGHT_SPACING = 500;
|
|
113
|
+
/** Grid lines extend this far past both plot edges, in px. */
|
|
114
|
+
var GRID_LINE_BLEED = 12;
|
|
115
|
+
var DEFAULT_LINE_STROKE_WIDTH = 1.5;
|
|
116
|
+
/** Radius of the dot marking a point on a hovered category, in px. */
|
|
117
|
+
var LINE_POINT_RADIUS = 3.5;
|
|
118
|
+
/** Opacity of the area fill under a line. */
|
|
119
|
+
var LINE_AREA_OPACITY = .12;
|
|
120
|
+
/** Gap between slices, in radians. */
|
|
121
|
+
var PIE_PAD_ANGLE = .012;
|
|
122
|
+
/** Slice corner radius in px. */
|
|
123
|
+
var PIE_CORNER_RADIUS = 2;
|
|
124
|
+
/** Inner radius as a fraction of the outer radius, for donut mode. */
|
|
125
|
+
var PIE_DONUT_INNER_RATIO = .62;
|
|
126
|
+
/**
|
|
127
|
+
* Share of the narrowest slice that its two inner pad insets may consume.
|
|
128
|
+
*
|
|
129
|
+
* d3 turns {@link PIE_PAD_ANGLE} into a *constant linear* gap, and holding that
|
|
130
|
+
* width at radius `r` costs an angular inset of `asin(gap / 2r)` — unbounded as
|
|
131
|
+
* `r` approaches zero. When the two insets no longer fit inside a slice's own
|
|
132
|
+
* span, d3 collapses that slice's inner edge rather than sweeping backwards. The
|
|
133
|
+
* collapse is what makes a hole-less pie look wrong: the gap edge stops being
|
|
134
|
+
* radial, so gaps sit at visibly different widths and lean at slight angles, and
|
|
135
|
+
* it bites hardest between the *narrowest* slices, where the span runs out
|
|
136
|
+
* first.
|
|
137
|
+
*
|
|
138
|
+
* So the inner radius is solved for rather than guessed: pick the radius that
|
|
139
|
+
* keeps both insets inside the narrowest slice, with this much of it spent. At
|
|
140
|
+
* 0.7 the measured gap spread is 1.01× (against 1.46× when the inner edge is
|
|
141
|
+
* left to collapse), and the remaining 30% is what absorbs the corner radius.
|
|
142
|
+
*/
|
|
143
|
+
var PIE_MAX_INSET_SHARE = .7;
|
|
144
|
+
/**
|
|
145
|
+
* Ceiling on the auto-derived inner radius, as a share of the outer radius.
|
|
146
|
+
*
|
|
147
|
+
* The radius needed grows without bound as the narrowest slice shrinks, so a
|
|
148
|
+
* single sliver would otherwise turn a pie into a donut. Past this point the
|
|
149
|
+
* hole is doing more visual damage than the uneven gap it fixes, so the gap is
|
|
150
|
+
* allowed to degrade instead — never worse than it renders today.
|
|
151
|
+
*/
|
|
152
|
+
var PIE_MAX_AUTO_INNER_RATIO = .06;
|
|
153
|
+
/** How far outside the arc the tooltip anchors, in px. */
|
|
154
|
+
var PIE_TOOLTIP_ANCHOR_INSET = 8;
|
|
155
|
+
/**
|
|
156
|
+
* Default share below which a slice is folded into an "Other" bucket.
|
|
157
|
+
*
|
|
158
|
+
* Slivers this thin are unreadable and effectively unhoverable, so grouping
|
|
159
|
+
* them communicates more than rendering each faithfully.
|
|
160
|
+
*/
|
|
161
|
+
var PIE_MIN_SLICE_SHARE = .02;
|
|
162
|
+
/** Margin around a pie, which needs no axis gutters. */
|
|
163
|
+
var PIE_CHART_MARGIN = {
|
|
164
|
+
top: 8,
|
|
165
|
+
right: 8,
|
|
166
|
+
bottom: 8,
|
|
167
|
+
left: 8
|
|
22
168
|
};
|
|
23
|
-
/**
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
var
|
|
31
|
-
/**
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
169
|
+
/**
|
|
170
|
+
* Duration in ms for hover, dim and tooltip transitions.
|
|
171
|
+
*
|
|
172
|
+
* Sits inside the 75–150ms band the DLS uses everywhere else. Hover feedback is
|
|
173
|
+
* a response, not an animation — anything long enough to *watch* reads as the
|
|
174
|
+
* chart being slow rather than the chart being smooth.
|
|
175
|
+
*/
|
|
176
|
+
var CHART_TRANSITION_MS = 100;
|
|
177
|
+
/**
|
|
178
|
+
* Delay in ms before marks return to full strength after the pointer leaves.
|
|
179
|
+
*
|
|
180
|
+
* Restoring immediately makes the whole chart flash while the pointer sweeps
|
|
181
|
+
* across categories. Highlighting stays instant (no delay) — only the
|
|
182
|
+
* *un*-highlight waits, so a sweep reads as one continuous gesture.
|
|
183
|
+
*
|
|
184
|
+
* Kept short because it does less work than it looks: while the pointer is
|
|
185
|
+
* anywhere in the plot the chart is still engaged, so `ChartPlotGroup` and
|
|
186
|
+
* `ChartLegendRow` zero this out and category-to-category sweeping is already
|
|
187
|
+
* instant. All this actually covers is the moment the pointer leaves entirely,
|
|
188
|
+
* where a long delay just feels like lag.
|
|
189
|
+
*/
|
|
190
|
+
var CHART_RESTORE_DELAY_MS = 200;
|
|
191
|
+
/**
|
|
192
|
+
* Opacity ramp for the mark states.
|
|
193
|
+
*
|
|
194
|
+
* The grammar is inherited from the reference charts and is the opposite of the
|
|
195
|
+
* obvious one: hovering does not brighten the hovered mark, it *softens*
|
|
196
|
+
* everything else. `MUTED` applies to marks outside the hovered category;
|
|
197
|
+
* `FADED` to marks outside a *pinned* one.
|
|
198
|
+
*
|
|
199
|
+
* The step down from ACTIVE is deliberately steep. These are large filled areas
|
|
200
|
+
* — bars and arcs — and a filled shape still reads as present at an opacity
|
|
201
|
+
* where a hairline would have vanished, so a timid step barely registers as a
|
|
202
|
+
* highlight at all.
|
|
203
|
+
*
|
|
204
|
+
* Keep `FADED` below `MUTED`, or pinning becomes visually indistinguishable
|
|
205
|
+
* from hovering — the pin exists to say "I am holding this one", which only
|
|
206
|
+
* reads if the rest recede further than they do on hover.
|
|
207
|
+
*/
|
|
208
|
+
var CHART_MARK_OPACITY_ACTIVE = 1;
|
|
209
|
+
var CHART_MARK_OPACITY_MUTED = .1;
|
|
210
|
+
var CHART_MARK_OPACITY_FADED = .04;
|
|
211
|
+
/** Distance in px between the tooltip and its anchor. */
|
|
212
|
+
var CHART_TOOLTIP_OFFSET = 10;
|
|
213
|
+
/** Minimum width of the tooltip, in px. */
|
|
214
|
+
var CHART_TOOLTIP_MIN_WIDTH = 168;
|
|
215
|
+
/** Maximum width of the tooltip, in px. */
|
|
216
|
+
var CHART_TOOLTIP_MAX_WIDTH = 320;
|
|
217
|
+
/**
|
|
218
|
+
* Approximate width of one CAPTION-size character.
|
|
219
|
+
*
|
|
220
|
+
* Axis sizing estimates label widths arithmetically rather than measuring the
|
|
221
|
+
* DOM, so it stays correct during build-time evaluation and server rendering.
|
|
222
|
+
*/
|
|
223
|
+
var CAPTION_CHAR_WIDTH_PX = 6.2;
|
|
224
|
+
/** Ceiling for an auto-sized left margin, so a wide formatter can't eat the plot. */
|
|
225
|
+
var MAX_AUTO_MARGIN_LEFT = 96;
|
|
226
|
+
/** Minimum px between category labels before AUTO mode starts skipping them. */
|
|
227
|
+
var MIN_CATEGORY_LABEL_GAP = 8;
|
|
228
|
+
/**
|
|
229
|
+
* Default assignment order for series colors.
|
|
230
|
+
*
|
|
231
|
+
* Purple leads to match the Galaxy brand. Galaxy blue is deliberately absent —
|
|
232
|
+
* it is structural only, reserved for primary actions and selection.
|
|
233
|
+
*/
|
|
234
|
+
var CHART_PALETTE_ORDER = [
|
|
235
|
+
ChartPalette.PURPLE,
|
|
236
|
+
ChartPalette.PINK,
|
|
237
|
+
ChartPalette.BLUE,
|
|
238
|
+
ChartPalette.TEAL,
|
|
239
|
+
ChartPalette.LIME,
|
|
240
|
+
ChartPalette.ORANGE,
|
|
241
|
+
ChartPalette.YELLOW,
|
|
242
|
+
ChartPalette.GREEN,
|
|
243
|
+
ChartPalette.RED
|
|
244
|
+
];
|
|
37
245
|
//#endregion
|
|
38
|
-
export {
|
|
246
|
+
export { AXIS_TITLE_BAND, AXIS_TITLE_GAP, BAR_GAP_COMFORTABLE, BAR_GAP_MEDIUM, BAR_GAP_TIGHT, BAR_RADIUS, BAR_RADIUS_NARROW, BAR_WIDTH_RATIO, CAPTION_CHAR_WIDTH_PX, CATEGORY_AXIS_LABEL_GAP, CATEGORY_AXIS_LABEL_HEIGHT, CHART_MARK_OPACITY_ACTIVE, CHART_MARK_OPACITY_FADED, CHART_MARK_OPACITY_MUTED, CHART_PALETTE_ORDER, CHART_RESTORE_DELAY_MS, CHART_TOOLTIP_MAX_WIDTH, CHART_TOOLTIP_MIN_WIDTH, CHART_TOOLTIP_OFFSET, CHART_TRANSITION_MS, DEFAULT_CHART_MARGIN, DEFAULT_LINE_STROKE_WIDTH, DEFAULT_VALUE_TICK_COUNT, GRID_LINE_BLEED, GROUP_GAP_COMFORTABLE, GROUP_GAP_MEDIUM, GROUP_GAP_TIGHT, LINE_AREA_OPACITY, LINE_POINT_RADIUS, MAX_AUTO_MARGIN_LEFT, MAX_BAR_WIDTH, MAX_GAP_SHARE, MIN_BARS_FOR_TIGHT_SPACING, MIN_BAR_LENGTH, MIN_CATEGORY_LABEL_GAP, NARROW_BAR_WIDTH, PIE_CHART_MARGIN, PIE_CORNER_RADIUS, PIE_DONUT_INNER_RATIO, PIE_MAX_AUTO_INNER_RATIO, PIE_MAX_INSET_SHARE, PIE_MIN_SLICE_SHARE, PIE_PAD_ANGLE, PIE_TOOLTIP_ANCHOR_INSET, STACK_SEGMENT_GAP, VALUE_AXIS_LABEL_HEIGHT, VALUE_AXIS_TICK_GAP, WIDTH_FOR_MEDIUM_SPACING, WIDTH_FOR_TIGHT_SPACING };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { buildCategoryPointScale, buildValueScale } from "./chartScales";
|
|
2
|
+
import { LineChartCurve } from "./types";
|
|
3
|
+
import type { ChartValueDomain, LineChartColumn, LineChartLineDatum, LineChartPath, LineChartPoint } from "./types";
|
|
4
|
+
/**
|
|
5
|
+
* The union of every line's categories, in first-seen order.
|
|
6
|
+
*
|
|
7
|
+
* Lines are allowed to be sparse, so the axis cannot come from any single one
|
|
8
|
+
* of them. An explicit `categories` list wins, and is worth supplying whenever
|
|
9
|
+
* the data is gappy — inferring order from a union of incomplete series is
|
|
10
|
+
* guesswork, and guessing wrong reorders time.
|
|
11
|
+
*/
|
|
12
|
+
export declare function getLineCategories<TMetric extends string>(lines: LineChartLineDatum<TMetric>[], explicit?: string[]): string[];
|
|
13
|
+
/** Signed value domain across every line, ignoring gaps. */
|
|
14
|
+
export declare function getLineValueDomain<TMetric extends string>(lines: LineChartLineDatum<TMetric>[]): [number, number];
|
|
15
|
+
export interface LineChartGeometry<TMetric extends string> {
|
|
16
|
+
paths: LineChartPath<TMetric>[];
|
|
17
|
+
columns: LineChartColumn<TMetric>[];
|
|
18
|
+
/**
|
|
19
|
+
* Points with no defined neighbour on either side.
|
|
20
|
+
*
|
|
21
|
+
* A lone reading has nothing to connect to, so it produces a zero-length path
|
|
22
|
+
* segment and renders as nothing at all — a silent hole in sparse data. These
|
|
23
|
+
* are drawn as explicit dots so the value is visible without hovering.
|
|
24
|
+
*/
|
|
25
|
+
isolatedPoints: LineChartPoint<TMetric>[];
|
|
26
|
+
categories: string[];
|
|
27
|
+
valueScale: ReturnType<typeof buildValueScale>;
|
|
28
|
+
categoryScale: ReturnType<typeof buildCategoryPointScale>;
|
|
29
|
+
baselineY: number;
|
|
30
|
+
/**
|
|
31
|
+
* Distance between category ticks.
|
|
32
|
+
*
|
|
33
|
+
* Exposed because axis labels must be centred on their tick, which is not the
|
|
34
|
+
* same as being centred on the hit band: the first and last bands are clipped
|
|
35
|
+
* to the plot edge, and centring a label inside a half-width band pushes it
|
|
36
|
+
* off its tick.
|
|
37
|
+
*/
|
|
38
|
+
step: number;
|
|
39
|
+
}
|
|
40
|
+
interface BuildLineChartGeometryArgs<TMetric extends string> {
|
|
41
|
+
lines: LineChartLineDatum<TMetric>[];
|
|
42
|
+
categories?: string[];
|
|
43
|
+
plotWidth: number;
|
|
44
|
+
plotHeight: number;
|
|
45
|
+
curve: LineChartCurve;
|
|
46
|
+
valueDomain?: Partial<ChartValueDomain>;
|
|
47
|
+
strokeWidth?: number;
|
|
48
|
+
resolveColor: (args: {
|
|
49
|
+
metric: TMetric;
|
|
50
|
+
lineIndex: number;
|
|
51
|
+
}) => string;
|
|
52
|
+
}
|
|
53
|
+
export declare function buildLineChartGeometry<TMetric extends string>({ lines, categories: explicitCategories, plotWidth, plotHeight, curve, valueDomain, strokeWidth: defaultStrokeWidth, resolveColor, }: BuildLineChartGeometryArgs<TMetric>): LineChartGeometry<TMetric>;
|
|
54
|
+
export {};
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { LineChartCurve } from "./types.js";
|
|
2
|
+
import { DEFAULT_LINE_STROKE_WIDTH } from "./constants.js";
|
|
3
|
+
import { applyDomainOverride, buildCategoryPointScale, buildValueScale, sanitizeValue } from "./chartScales.js";
|
|
4
|
+
import { match } from "ts-pattern";
|
|
5
|
+
import { area, curveLinear, curveMonotoneX, curveStepAfter, line } from "d3-shape";
|
|
6
|
+
//#region src/charts/lineChartGeometry.ts
|
|
7
|
+
function resolveCurve(curve) {
|
|
8
|
+
return match(curve).with(LineChartCurve.LINEAR, () => curveLinear).with(LineChartCurve.SMOOTH, () => curveMonotoneX).with(LineChartCurve.STEP, () => curveStepAfter).exhaustive();
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* The union of every line's categories, in first-seen order.
|
|
12
|
+
*
|
|
13
|
+
* Lines are allowed to be sparse, so the axis cannot come from any single one
|
|
14
|
+
* of them. An explicit `categories` list wins, and is worth supplying whenever
|
|
15
|
+
* the data is gappy — inferring order from a union of incomplete series is
|
|
16
|
+
* guesswork, and guessing wrong reorders time.
|
|
17
|
+
*/
|
|
18
|
+
function getLineCategories(lines, explicit) {
|
|
19
|
+
if (explicit) return explicit;
|
|
20
|
+
const seen = [];
|
|
21
|
+
const index = /* @__PURE__ */ new Set();
|
|
22
|
+
for (const lineDatum of lines) for (const point of lineDatum.points) if (!index.has(point.x)) {
|
|
23
|
+
index.add(point.x);
|
|
24
|
+
seen.push(point.x);
|
|
25
|
+
}
|
|
26
|
+
return seen;
|
|
27
|
+
}
|
|
28
|
+
/** Signed value domain across every line, ignoring gaps. */
|
|
29
|
+
function getLineValueDomain(lines) {
|
|
30
|
+
let min = 0;
|
|
31
|
+
let max = 0;
|
|
32
|
+
let hasValue = false;
|
|
33
|
+
for (const lineDatum of lines) for (const point of lineDatum.points) {
|
|
34
|
+
if (point.y === null || point.y === void 0) continue;
|
|
35
|
+
const value = sanitizeValue(point.y);
|
|
36
|
+
if (!hasValue) {
|
|
37
|
+
min = value;
|
|
38
|
+
max = value;
|
|
39
|
+
hasValue = true;
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (value < min) min = value;
|
|
43
|
+
if (value > max) max = value;
|
|
44
|
+
}
|
|
45
|
+
return [Math.min(0, min), Math.max(0, max)];
|
|
46
|
+
}
|
|
47
|
+
function buildLineChartGeometry({ lines, categories: explicitCategories, plotWidth, plotHeight, curve, valueDomain, strokeWidth: defaultStrokeWidth = DEFAULT_LINE_STROKE_WIDTH, resolveColor }) {
|
|
48
|
+
const categories = getLineCategories(lines, explicitCategories);
|
|
49
|
+
const valueScale = buildValueScale(applyDomainOverride(getLineValueDomain(lines), valueDomain), [plotHeight, 0]);
|
|
50
|
+
const categoryScale = buildCategoryPointScale(categories, [0, plotWidth]);
|
|
51
|
+
const baselineY = valueScale(0);
|
|
52
|
+
const paths = [];
|
|
53
|
+
const columns = [];
|
|
54
|
+
const isolatedPoints = [];
|
|
55
|
+
if (categories.length === 0 || plotWidth <= 0 || plotHeight <= 0) return {
|
|
56
|
+
paths,
|
|
57
|
+
columns,
|
|
58
|
+
isolatedPoints,
|
|
59
|
+
categories,
|
|
60
|
+
valueScale,
|
|
61
|
+
categoryScale,
|
|
62
|
+
baselineY,
|
|
63
|
+
step: 0
|
|
64
|
+
};
|
|
65
|
+
const curveFactory = resolveCurve(curve);
|
|
66
|
+
const categoryIndex = new Map(categories.map((label, index) => [label, index]));
|
|
67
|
+
const xAt = (index) => categoryScale(categories[index]) ?? 0;
|
|
68
|
+
const pointsByCategory = categories.map(() => []);
|
|
69
|
+
lines.forEach((lineDatum, lineIndex) => {
|
|
70
|
+
const color = resolveColor({
|
|
71
|
+
metric: lineDatum.metric,
|
|
72
|
+
lineIndex
|
|
73
|
+
});
|
|
74
|
+
const stroke = lineDatum.strokeWidth ?? defaultStrokeWidth;
|
|
75
|
+
const plotted = categories.map((_, index) => ({
|
|
76
|
+
categoryIndex: index,
|
|
77
|
+
value: null
|
|
78
|
+
}));
|
|
79
|
+
for (const point of lineDatum.points) {
|
|
80
|
+
const index = categoryIndex.get(point.x);
|
|
81
|
+
if (index === void 0) continue;
|
|
82
|
+
plotted[index].value = point.y === null || point.y === void 0 ? null : sanitizeValue(point.y);
|
|
83
|
+
}
|
|
84
|
+
const isDefined = (p) => p.value !== null;
|
|
85
|
+
const strokePath = line().defined(isDefined).x((p) => xAt(p.categoryIndex)).y((p) => valueScale(p.value)).curve(curveFactory)(plotted) ?? "";
|
|
86
|
+
const areaPath = lineDatum.showArea ? area().defined(isDefined).x((p) => xAt(p.categoryIndex)).y0(baselineY).y1((p) => valueScale(p.value)).curve(curveFactory)(plotted) ?? void 0 : void 0;
|
|
87
|
+
paths.push({
|
|
88
|
+
id: lineDatum.metric,
|
|
89
|
+
metric: lineDatum.metric,
|
|
90
|
+
lineIndex,
|
|
91
|
+
path: strokePath,
|
|
92
|
+
areaPath,
|
|
93
|
+
dashArray: lineDatum.dashSize ? `${lineDatum.dashSize} ${lineDatum.dashSize}` : void 0,
|
|
94
|
+
strokeWidth: stroke,
|
|
95
|
+
color
|
|
96
|
+
});
|
|
97
|
+
plotted.forEach((p, index) => {
|
|
98
|
+
if (p.value === null) return;
|
|
99
|
+
const point = {
|
|
100
|
+
id: `${lineDatum.metric}:${p.categoryIndex}`,
|
|
101
|
+
metric: lineDatum.metric,
|
|
102
|
+
categoryIndex: p.categoryIndex,
|
|
103
|
+
value: p.value,
|
|
104
|
+
x: xAt(p.categoryIndex),
|
|
105
|
+
y: valueScale(p.value),
|
|
106
|
+
color
|
|
107
|
+
};
|
|
108
|
+
pointsByCategory[p.categoryIndex].push(point);
|
|
109
|
+
const hasPrev = index > 0 && plotted[index - 1].value !== null;
|
|
110
|
+
const hasNext = index < plotted.length - 1 && plotted[index + 1].value !== null;
|
|
111
|
+
if (!hasPrev && !hasNext) isolatedPoints.push(point);
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
const step = categories.length > 1 ? categoryScale.step() : plotWidth;
|
|
115
|
+
categories.forEach((label, index) => {
|
|
116
|
+
const x = xAt(index);
|
|
117
|
+
const points = pointsByCategory[index];
|
|
118
|
+
const rawBandX = x - step / 2;
|
|
119
|
+
const bandX = Math.max(0, rawBandX);
|
|
120
|
+
const bandWidth = Math.min(plotWidth, rawBandX + step) - bandX;
|
|
121
|
+
columns.push({
|
|
122
|
+
categoryIndex: index,
|
|
123
|
+
label,
|
|
124
|
+
x,
|
|
125
|
+
bandX,
|
|
126
|
+
bandWidth,
|
|
127
|
+
points,
|
|
128
|
+
anchorY: points.length > 0 ? Math.min(...points.map((p) => p.y)) : baselineY
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
return {
|
|
132
|
+
paths,
|
|
133
|
+
columns,
|
|
134
|
+
isolatedPoints,
|
|
135
|
+
categories,
|
|
136
|
+
valueScale,
|
|
137
|
+
categoryScale,
|
|
138
|
+
baselineY,
|
|
139
|
+
step
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
//#endregion
|
|
143
|
+
export { buildLineChartGeometry, getLineCategories, getLineValueDomain };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { ChartPalette, PieChartArc, PieChartSliceDatum } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Pie and donut geometry.
|
|
4
|
+
*
|
|
5
|
+
* Produces a flat array of finished arcs — path, anchor, colour and share all
|
|
6
|
+
* resolved — so the component body is a `.map()`.
|
|
7
|
+
*
|
|
8
|
+
* Pure: no React, no theme access. Colours arrive through a resolver callback.
|
|
9
|
+
*/
|
|
10
|
+
export interface PieChartGeometry<TSlice extends string> {
|
|
11
|
+
arcs: PieChartArc<TSlice>[];
|
|
12
|
+
/** Sum of every sanitised value. Zero means there is nothing to draw. */
|
|
13
|
+
total: number;
|
|
14
|
+
/** Centre of the pie, in plot coordinates. */
|
|
15
|
+
centerX: number;
|
|
16
|
+
centerY: number;
|
|
17
|
+
outerRadius: number;
|
|
18
|
+
innerRadius: number;
|
|
19
|
+
}
|
|
20
|
+
interface BuildPieChartGeometryArgs<TSlice extends string> {
|
|
21
|
+
slices: PieChartSliceDatum<TSlice>[];
|
|
22
|
+
plotWidth: number;
|
|
23
|
+
plotHeight: number;
|
|
24
|
+
/** Hole size as a fraction of the outer radius. `0` is a solid pie. */
|
|
25
|
+
innerRadiusRatio?: number;
|
|
26
|
+
padAngle?: number;
|
|
27
|
+
cornerRadius?: number;
|
|
28
|
+
/**
|
|
29
|
+
* Slices below this share of the total are folded into one bucket.
|
|
30
|
+
*
|
|
31
|
+
* `0` disables folding. A donut with forty slivers communicates nothing, and
|
|
32
|
+
* the slivers are individually unhoverable, so a modest default is kinder
|
|
33
|
+
* than faithfully rendering every one.
|
|
34
|
+
*/
|
|
35
|
+
minSliceShare?: number;
|
|
36
|
+
/** Label for the folded bucket. */
|
|
37
|
+
aggregatedLabel?: string;
|
|
38
|
+
resolveColor: (args: {
|
|
39
|
+
sliceKey: TSlice | null;
|
|
40
|
+
index: number;
|
|
41
|
+
explicit?: ChartPalette;
|
|
42
|
+
}) => string;
|
|
43
|
+
/** Palette override declared by the caller for a given slice. */
|
|
44
|
+
getSliceColor?: (sliceKey: TSlice) => ChartPalette | undefined;
|
|
45
|
+
getSliceLabel: (sliceKey: TSlice) => string;
|
|
46
|
+
}
|
|
47
|
+
export declare function buildPieChartGeometry<TSlice extends string>({ slices, plotWidth, plotHeight, innerRadiusRatio, padAngle, cornerRadius, minSliceShare, aggregatedLabel, resolveColor, getSliceColor, getSliceLabel, }: BuildPieChartGeometryArgs<TSlice>): PieChartGeometry<TSlice>;
|
|
48
|
+
export {};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { AGGREGATED_SLICE_KEY } from "./types.js";
|
|
2
|
+
import { PIE_DONUT_INNER_RATIO, PIE_MAX_AUTO_INNER_RATIO, PIE_MAX_INSET_SHARE, PIE_PAD_ANGLE } from "./constants.js";
|
|
3
|
+
import { sanitizeValue } from "./chartScales.js";
|
|
4
|
+
import { arc, pie } from "d3-shape";
|
|
5
|
+
//#region src/charts/pieChartGeometry.ts
|
|
6
|
+
function buildPieChartGeometry({ slices, plotWidth, plotHeight, innerRadiusRatio = PIE_DONUT_INNER_RATIO, padAngle = PIE_PAD_ANGLE, cornerRadius = 2, minSliceShare = 0, aggregatedLabel = "Other", resolveColor, getSliceColor, getSliceLabel }) {
|
|
7
|
+
const outerRadius = Math.max(0, Math.min(plotWidth, plotHeight) / 2);
|
|
8
|
+
const gapWidth = outerRadius * Math.max(0, padAngle);
|
|
9
|
+
const requestedInnerRadius = outerRadius * Math.min(Math.max(innerRadiusRatio, 0), .95);
|
|
10
|
+
const centerX = plotWidth / 2;
|
|
11
|
+
const centerY = plotHeight / 2;
|
|
12
|
+
const sanitized = slices.map((slice) => ({
|
|
13
|
+
sliceKey: slice.key,
|
|
14
|
+
value: Math.max(0, sanitizeValue(slice.value))
|
|
15
|
+
}));
|
|
16
|
+
const total = sanitized.reduce((sum, slice) => sum + slice.value, 0);
|
|
17
|
+
const empty = {
|
|
18
|
+
arcs: [],
|
|
19
|
+
total,
|
|
20
|
+
centerX,
|
|
21
|
+
centerY,
|
|
22
|
+
outerRadius,
|
|
23
|
+
innerRadius: requestedInnerRadius
|
|
24
|
+
};
|
|
25
|
+
if (total <= 0 || outerRadius <= 0) return empty;
|
|
26
|
+
const kept = [];
|
|
27
|
+
let foldedValue = 0;
|
|
28
|
+
for (const slice of sanitized) {
|
|
29
|
+
const share = slice.value / total;
|
|
30
|
+
if (minSliceShare > 0 && share < minSliceShare) {
|
|
31
|
+
foldedValue += slice.value;
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
kept.push({
|
|
35
|
+
sliceKey: slice.sliceKey,
|
|
36
|
+
label: getSliceLabel(slice.sliceKey),
|
|
37
|
+
value: slice.value,
|
|
38
|
+
explicit: getSliceColor?.(slice.sliceKey),
|
|
39
|
+
isAggregated: false
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
if (foldedValue > 0) kept.push({
|
|
43
|
+
sliceKey: null,
|
|
44
|
+
label: aggregatedLabel,
|
|
45
|
+
value: foldedValue,
|
|
46
|
+
isAggregated: true
|
|
47
|
+
});
|
|
48
|
+
const maxInset = kept.reduce((min, slice) => Math.min(min, slice.value), Infinity) / total * 2 * Math.PI * PIE_MAX_INSET_SHARE / 2;
|
|
49
|
+
const solvedInnerRadius = gapWidth > 0 && maxInset > 0 ? gapWidth / 2 / Math.sin(maxInset) : 0;
|
|
50
|
+
const innerRadius = Math.max(requestedInnerRadius, Math.min(solvedInnerRadius, outerRadius * PIE_MAX_AUTO_INNER_RATIO));
|
|
51
|
+
const layout = pie().sort(null).value((slice) => slice.value).padAngle(padAngle);
|
|
52
|
+
const arcGenerator = arc().innerRadius(innerRadius).outerRadius(outerRadius).cornerRadius(cornerRadius);
|
|
53
|
+
return {
|
|
54
|
+
arcs: layout(kept).map((slot, index) => {
|
|
55
|
+
const slice = slot.data;
|
|
56
|
+
const midAngle = (slot.startAngle + slot.endAngle) / 2;
|
|
57
|
+
const anchorRadius = outerRadius + 8;
|
|
58
|
+
return {
|
|
59
|
+
id: slice.isAggregated ? AGGREGATED_SLICE_KEY : slice.sliceKey,
|
|
60
|
+
sliceKey: slice.sliceKey,
|
|
61
|
+
label: slice.label,
|
|
62
|
+
value: slice.value,
|
|
63
|
+
share: slice.value / total,
|
|
64
|
+
path: arcGenerator({
|
|
65
|
+
startAngle: slot.startAngle,
|
|
66
|
+
endAngle: slot.endAngle,
|
|
67
|
+
padAngle: slot.padAngle
|
|
68
|
+
}) ?? "",
|
|
69
|
+
startAngle: slot.startAngle,
|
|
70
|
+
endAngle: slot.endAngle,
|
|
71
|
+
anchorX: centerX + Math.sin(midAngle) * anchorRadius,
|
|
72
|
+
anchorY: centerY - Math.cos(midAngle) * anchorRadius,
|
|
73
|
+
color: resolveColor({
|
|
74
|
+
sliceKey: slice.sliceKey,
|
|
75
|
+
index,
|
|
76
|
+
explicit: slice.explicit
|
|
77
|
+
}),
|
|
78
|
+
isAggregated: slice.isAggregated
|
|
79
|
+
};
|
|
80
|
+
}),
|
|
81
|
+
total,
|
|
82
|
+
centerX,
|
|
83
|
+
centerY,
|
|
84
|
+
outerRadius,
|
|
85
|
+
innerRadius
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
//#endregion
|
|
89
|
+
export { buildPieChartGeometry };
|