@keyfunc/keybricks-ds 1.0.4 → 2.1.1
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/DEPLOY.md +4 -4
- package/DESIGN.md +154 -53
- package/INTEGRATION.md +174 -35
- package/SKILL.md +6 -4
- package/_adherence.oxlintrc.json +164 -68
- package/_scripts/build-index.mjs +9 -0
- package/_scripts/build-tokens.mjs +5 -2
- package/assets/icons/icon-index.js +1 -1
- package/assets/icons/icon-index.json +1 -1
- package/components/_cards/accordion.card.html +2 -2
- package/components/_cards/action-chip.card.html +8 -3
- package/components/_cards/activity.card.html +2 -2
- package/components/_cards/alert.card.html +2 -2
- package/components/_cards/app-chrome.card.html +4 -4
- package/components/_cards/banner.card.html +1 -1
- package/components/_cards/breadcrumb.card.html +2 -2
- package/components/_cards/button-1-base.card.html +2 -2
- package/components/_cards/button-2-states.card.html +14 -14
- package/components/_cards/button-3-sizes-icons.card.html +1 -1
- package/components/_cards/button-4-group.card.html +5 -5
- package/components/_cards/canvas-zoom-controls.card.html +1 -1
- package/components/_cards/cards-indicators.card.html +2 -2
- package/components/_cards/charts-1-sparkline.card.html +2 -2
- package/components/_cards/charts-10-gauge.card.html +4 -4
- package/components/_cards/charts-11-funnel.card.html +2 -2
- package/components/_cards/charts-12-treemap.card.html +2 -2
- package/components/_cards/charts-14-radar.card.html +1 -1
- package/components/_cards/charts-15-distribution.card.html +1 -1
- package/components/_cards/charts-16-pareto.card.html +2 -2
- package/components/_cards/charts-17-candlestick.card.html +2 -2
- package/components/_cards/charts-18-sankey.card.html +2 -2
- package/components/_cards/charts-19-chord.card.html +2 -2
- package/components/_cards/charts-2-line.card.html +2 -2
- package/components/_cards/charts-20-sunburst.card.html +2 -2
- package/components/_cards/charts-21-worldmap.card.html +2 -2
- package/components/_cards/charts-22-gantt.card.html +2 -2
- package/components/_cards/charts-23-bar3d.card.html +2 -2
- package/components/_cards/charts-24-pie3d.card.html +2 -2
- package/components/_cards/charts-25-surface3d.card.html +2 -2
- package/components/_cards/charts-26-scatter3d.card.html +2 -2
- package/components/_cards/charts-27-ribbon3d.card.html +2 -2
- package/components/_cards/charts-3-bar.card.html +2 -2
- package/components/_cards/charts-4-barlist.card.html +2 -2
- package/components/_cards/charts-5-donut.card.html +3 -3
- package/components/_cards/charts-6-scatter.card.html +2 -2
- package/components/_cards/charts-7-heatmap.card.html +2 -2
- package/components/_cards/charts-8-waterfall.card.html +2 -2
- package/components/_cards/charts-9-bullet.card.html +2 -2
- package/components/_cards/charts-99-fullpage.card.html +5 -5
- package/components/_cards/checkbox.card.html +4 -4
- package/components/_cards/codeblock.card.html +1 -1
- package/components/_cards/combobox.card.html +3 -2
- package/components/_cards/context-menu.card.html +3 -2
- package/components/_cards/date-picker.card.html +5 -2
- package/components/_cards/diffvalue.card.html +2 -2
- package/components/_cards/divider.card.html +3 -3
- package/components/_cards/drawer.card.html +2 -2
- package/components/_cards/dropdown-menu.card.html +6 -6
- package/components/_cards/dropzone.card.html +1 -1
- package/components/_cards/empty-state.card.html +5 -5
- package/components/_cards/filter-bar.card.html +5 -5
- package/components/_cards/icon-button.card.html +2 -2
- package/components/_cards/icons-1-core.card.html +2 -2
- package/components/_cards/icons-2-feather.card.html +3 -3
- package/components/_cards/icons-3-unicons.card.html +3 -3
- package/components/_cards/input.card.html +5 -2
- package/components/_cards/kbd.card.html +2 -2
- package/components/_cards/keyvalue.card.html +2 -2
- package/components/_cards/listrow.card.html +2 -2
- package/components/_cards/loading.card.html +2 -2
- package/components/_cards/log-viewer.card.html +2 -2
- package/components/_cards/modal.card.html +9 -9
- package/components/_cards/multi-select.card.html +3 -2
- package/components/_cards/number-stepper.card.html +3 -2
- package/components/_cards/pagination.card.html +3 -2
- package/components/_cards/people.card.html +3 -3
- package/components/_cards/pipeline-node.card.html +2 -2
- package/components/_cards/pipeline-palette.card.html +4 -4
- package/components/_cards/radio.card.html +2 -2
- package/components/_cards/search.card.html +5 -2
- package/components/_cards/segmented-control.card.html +2 -2
- package/components/_cards/select.card.html +4 -4
- package/components/_cards/slider.card.html +1 -1
- package/components/_cards/smart-table.card.html +1 -1
- package/components/_cards/spreadsheet.card.html +2 -2
- package/components/_cards/stepper.card.html +2 -2
- package/components/_cards/table.card.html +103 -0
- package/components/_cards/tabs.card.html +3 -2
- package/components/_cards/tag.card.html +5 -2
- package/components/_cards/textarea.card.html +2 -2
- package/components/_cards/timeline.card.html +1 -1
- package/components/_cards/toast.card.html +4 -4
- package/components/_cards/toggles.card.html +3 -3
- package/components/_cards/tooltip.card.html +5 -5
- package/components/_cards/tree.card.html +2 -2
- package/components/_shared/src-buttons.js +1 -1
- package/components/_shared/src-charts.js +1 -1
- package/components/_shared/src-data.js +1 -1
- package/components/_shared/src-display.js +1 -1
- package/components/_shared/src-feedback.js +1 -1
- package/components/_shared/src-forms.js +1 -1
- package/components/_shared/src-navigation.js +1 -1
- package/components/_shared/src-pipeline.js +1 -1
- package/components/_shared/src-tabs.js +1 -1
- package/components/_vue/index.mjs +9 -5
- package/components/buttons/ActionChip.d.ts +3 -1
- package/components/buttons/ActionChip.jsx +4 -4
- package/components/buttons/ActionChip.vue +4 -4
- package/components/buttons/Button.d.ts +5 -2
- package/components/buttons/Button.jsx +15 -18
- package/components/buttons/Button.vue +17 -18
- package/components/buttons/ButtonGroup.vue +1 -1
- package/components/buttons/IconButton.d.ts +2 -1
- package/components/buttons/IconButton.jsx +9 -7
- package/components/buttons/IconButton.vue +10 -8
- package/components/buttons/buttons.prompt.md +6 -5
- package/components/charts/Bar3D.jsx +2 -2
- package/components/charts/Bar3D.vue +2 -2
- package/components/charts/BarChart.jsx +4 -4
- package/components/charts/BarChart.vue +4 -4
- package/components/charts/BarList.jsx +1 -1
- package/components/charts/BarList.vue +1 -1
- package/components/charts/BoxPlot.jsx +1 -1
- package/components/charts/BoxPlot.vue +2 -2
- package/components/charts/BulletChart.jsx +1 -1
- package/components/charts/BulletChart.vue +1 -1
- package/components/charts/CandlestickChart.jsx +2 -2
- package/components/charts/CandlestickChart.vue +3 -3
- package/components/charts/ChartKit.jsx +5 -5
- package/components/charts/ChartLegend.vue +16 -0
- package/components/charts/ChartTooltip.vue +16 -0
- package/components/charts/ChordChart.jsx +2 -2
- package/components/charts/ChordChart.vue +2 -2
- package/components/charts/GanttChart.jsx +2 -2
- package/components/charts/GanttChart.vue +2 -2
- package/components/charts/GaugeChart.jsx +2 -2
- package/components/charts/GaugeChart.vue +2 -2
- package/components/charts/HeatmapChart.jsx +2 -2
- package/components/charts/HeatmapChart.vue +2 -2
- package/components/charts/Histogram.jsx +2 -2
- package/components/charts/Histogram.vue +3 -3
- package/components/charts/LineChart.jsx +1 -1
- package/components/charts/LineChart.vue +3 -3
- package/components/charts/ParetoChart.jsx +3 -3
- package/components/charts/ParetoChart.vue +4 -4
- package/components/charts/PlotGrid.vue +18 -0
- package/components/charts/RadarChart.jsx +1 -1
- package/components/charts/RadarChart.vue +1 -1
- package/components/charts/Ribbon3D.jsx +2 -2
- package/components/charts/Ribbon3D.vue +2 -2
- package/components/charts/SankeyChart.jsx +2 -2
- package/components/charts/SankeyChart.vue +2 -2
- package/components/charts/Scatter3D.jsx +1 -1
- package/components/charts/Scatter3D.vue +1 -1
- package/components/charts/ScatterChart.jsx +3 -3
- package/components/charts/ScatterChart.vue +4 -4
- package/components/charts/Sparkline.jsx +1 -1
- package/components/charts/Sparkline.vue +1 -1
- package/components/charts/SunburstChart.jsx +1 -1
- package/components/charts/SunburstChart.vue +1 -1
- package/components/charts/Surface3D.jsx +2 -2
- package/components/charts/Surface3D.vue +2 -2
- package/components/charts/TreemapChart.jsx +2 -2
- package/components/charts/TreemapChart.vue +2 -2
- package/components/charts/WaterfallChart.jsx +2 -2
- package/components/charts/WaterfallChart.vue +3 -3
- package/components/charts/WorldMap.jsx +2 -2
- package/components/charts/WorldMap.vue +2 -2
- package/components/charts/XLabels.vue +11 -0
- package/components/data/CodeBlock.jsx +1 -1
- package/components/data/CodeBlock.vue +1 -1
- package/components/data/DiffValue.jsx +1 -1
- package/components/data/DiffValue.vue +1 -1
- package/components/data/FilterBar.d.ts +2 -0
- package/components/data/FilterBar.jsx +10 -9
- package/components/data/FilterBar.vue +9 -8
- package/components/data/KeyValue.jsx +3 -3
- package/components/data/KeyValue.vue +3 -3
- package/components/data/ListRow.jsx +2 -2
- package/components/data/ListRow.vue +2 -2
- package/components/data/Pagination.d.ts +5 -1
- package/components/data/Pagination.jsx +16 -12
- package/components/data/Pagination.vue +14 -9
- package/components/data/SmartTable.d.ts +4 -1
- package/components/data/SmartTable.jsx +16 -14
- package/components/data/SmartTable.vue +25 -22
- package/components/data/Spreadsheet.d.ts +2 -0
- package/components/data/Spreadsheet.jsx +12 -11
- package/components/data/Spreadsheet.vue +14 -13
- package/components/data/Table.d.ts +47 -0
- package/components/data/Table.jsx +85 -0
- package/components/data/Table.vue +63 -0
- package/components/data/data.prompt.md +3 -3
- package/components/display/Avatar.vue +3 -2
- package/components/display/AvatarGroup.vue +3 -2
- package/components/display/Badge.vue +1 -1
- package/components/display/Divider.vue +3 -3
- package/components/display/Donut.vue +3 -2
- package/components/display/IconTile.vue +2 -1
- package/components/display/Kbd.vue +1 -1
- package/components/display/ProgressBar.jsx +1 -1
- package/components/display/ProgressBar.vue +1 -1
- package/components/display/StatCard.vue +1 -1
- package/components/display/Tag.d.ts +3 -1
- package/components/display/Tag.jsx +4 -4
- package/components/display/Tag.vue +4 -4
- package/components/feedback/Accordion.jsx +2 -2
- package/components/feedback/Accordion.vue +2 -2
- package/components/feedback/ActivityItem.d.ts +3 -1
- package/components/feedback/ActivityItem.jsx +5 -5
- package/components/feedback/ActivityItem.vue +5 -4
- package/components/feedback/Alert.jsx +4 -4
- package/components/feedback/Alert.vue +3 -3
- package/components/feedback/Banner.jsx +5 -5
- package/components/feedback/Banner.vue +5 -5
- package/components/feedback/ContextMenu.d.ts +3 -1
- package/components/feedback/ContextMenu.jsx +5 -5
- package/components/feedback/ContextMenu.vue +5 -5
- package/components/feedback/DotActivity.vue +3 -3
- package/components/feedback/Drawer.d.ts +2 -0
- package/components/feedback/Drawer.jsx +6 -6
- package/components/feedback/Drawer.vue +22 -15
- package/components/feedback/EmptyState.vue +2 -2
- package/components/feedback/LogViewer.vue +1 -1
- package/components/feedback/Modal.d.ts +2 -0
- package/components/feedback/Modal.jsx +12 -11
- package/components/feedback/Modal.vue +10 -8
- package/components/feedback/Skeleton.vue +2 -1
- package/components/feedback/Spinner.vue +2 -1
- package/components/feedback/Stepper.vue +1 -1
- package/components/feedback/Timeline.jsx +1 -1
- package/components/feedback/Timeline.vue +1 -1
- package/components/feedback/Toast.vue +4 -4
- package/components/feedback/ToastStack.vue +11 -0
- package/components/feedback/Tooltip.vue +19 -0
- package/components/feedback/feedback.prompt.md +4 -4
- package/components/forms/Checkbox.d.ts +3 -2
- package/components/forms/Checkbox.jsx +7 -7
- package/components/forms/Checkbox.vue +8 -8
- package/components/forms/Combobox.d.ts +2 -0
- package/components/forms/Combobox.jsx +12 -10
- package/components/forms/Combobox.vue +11 -10
- package/components/forms/DatePicker.d.ts +4 -0
- package/components/forms/DatePicker.jsx +16 -12
- package/components/forms/DatePicker.vue +15 -11
- package/components/forms/Dropzone.jsx +2 -2
- package/components/forms/Dropzone.vue +5 -5
- package/components/forms/Field.d.ts +5 -1
- package/components/forms/Field.jsx +4 -4
- package/components/forms/Field.vue +4 -4
- package/components/forms/Input.d.ts +5 -1
- package/components/forms/Input.jsx +7 -7
- package/components/forms/Input.vue +3 -3
- package/components/forms/MultiSelect.d.ts +2 -0
- package/components/forms/MultiSelect.jsx +13 -11
- package/components/forms/MultiSelect.vue +12 -11
- package/components/forms/NumberStepper.d.ts +3 -1
- package/components/forms/NumberStepper.jsx +7 -7
- package/components/forms/NumberStepper.vue +8 -7
- package/components/forms/Radio.d.ts +5 -3
- package/components/forms/Radio.jsx +13 -15
- package/components/forms/Radio.vue +9 -10
- package/components/forms/RadioGroup.vue +5 -5
- package/components/forms/SearchInput.d.ts +3 -1
- package/components/forms/SearchInput.jsx +6 -6
- package/components/forms/SearchInput.vue +7 -6
- package/components/forms/Select.d.ts +3 -2
- package/components/forms/Select.jsx +6 -7
- package/components/forms/Select.vue +6 -6
- package/components/forms/Slider.jsx +3 -3
- package/components/forms/Slider.vue +3 -3
- package/components/forms/Switch.d.ts +2 -2
- package/components/forms/Switch.jsx +20 -22
- package/components/forms/Switch.vue +15 -14
- package/components/forms/Textarea.vue +4 -4
- package/components/forms/forms.prompt.md +1 -1
- package/components/forms/input-base.js +2 -1
- package/components/index.d.ts +1 -2
- package/components/index.js +3 -4
- package/components/navigation/Breadcrumb.jsx +3 -3
- package/components/navigation/Breadcrumb.vue +4 -4
- package/components/navigation/DocTree.jsx +3 -3
- package/components/navigation/DocTree.vue +3 -3
- package/components/navigation/PageHeading.vue +1 -1
- package/components/navigation/PageToolbar.vue +7 -6
- package/components/navigation/Sidebar.jsx +1 -1
- package/components/navigation/Sidebar.vue +3 -3
- package/components/navigation/ThemeToggle.vue +2 -1
- package/components/navigation/TopBar.d.ts +3 -1
- package/components/navigation/TopBar.jsx +6 -6
- package/components/navigation/Tree.jsx +5 -5
- package/components/navigation/Tree.vue +5 -5
- package/components/pipeline/ConfigPanel.d.ts +2 -0
- package/components/pipeline/ConfigPanel.jsx +9 -9
- package/components/pipeline/ConfigPanel.vue +9 -9
- package/components/pipeline/DataPreview.d.ts +3 -1
- package/components/pipeline/DataPreview.jsx +7 -7
- package/components/pipeline/DataPreview.vue +7 -7
- package/components/pipeline/NodeCard.jsx +3 -3
- package/components/pipeline/NodeCard.vue +3 -3
- package/components/pipeline/PaletteItem.vue +2 -2
- package/components/pipeline/PaletteListItem.vue +1 -1
- package/components/pipeline/PalettePanel.jsx +2 -2
- package/components/pipeline/PalettePanel.vue +1 -1
- package/components/pipeline/Port.vue +15 -0
- package/components/pipeline/PortLabel.vue +15 -0
- package/components/pipeline/ZoomControls.vue +1 -1
- package/components/pipeline/port-skin.js +13 -0
- package/components/px.js +4 -0
- package/components/tabs/PanelTabs.vue +5 -4
- package/components/tabs/PillTabs.vue +5 -4
- package/components/tabs/SegmentedControl.d.ts +2 -2
- package/components/tabs/SegmentedControl.jsx +7 -7
- package/components/tabs/SegmentedControl.vue +7 -7
- package/components/tabs/Tabs.d.ts +5 -3
- package/components/tabs/Tabs.jsx +15 -15
- package/components/tabs/Tabs.vue +5 -5
- package/components/tabs/ViewToggle.d.ts +3 -1
- package/components/tabs/ViewToggle.jsx +5 -5
- package/components/tabs/ViewToggle.vue +5 -5
- package/components/tabs/tabs.prompt.md +1 -1
- package/keybricks.css +4 -0
- package/package.json +6 -3
- package/readme.md +90 -122
- package/readme.zh-CN.md +120 -0
- package/tokens/charts.css +20 -17
- package/tokens/colors.css +2 -2
- package/tokens/dark.css +2 -2
- package/tokens/hover.css +32 -0
- package/tokens/interaction.css +3 -1
- package/tokens/layout.css +29 -7
- package/tokens/tokens.d.ts +36 -0
- package/tokens/tokens.js +143 -89
- package/tokens/tokens.json +240 -106
- package/tokens/typography.css +27 -14
- package/components/_cards/brand-visual.card.html +0 -43
- package/components/_cards/datatable.card.html +0 -48
- package/components/_shared/src-brand.js +0 -1
- package/components/brand/BrandVisual.d.ts +0 -17
- package/components/brand/BrandVisual.jsx +0 -29
- package/components/brand/BrandVisual.vue +0 -34
- package/components/brand/_dir.card.html +0 -13
- package/components/brand/brandMotifs.js +0 -210
- package/components/buttons/_dir.card.html +0 -13
- package/components/charts/ChartKit.vue +0 -47
- package/components/charts/_dir.card.html +0 -7
- package/components/data/DataTable.d.ts +0 -28
- package/components/data/DataTable.jsx +0 -32
- package/components/data/DataTable.vue +0 -25
- package/components/data/_dir.card.html +0 -13
- package/components/display/_dir.card.html +0 -13
- package/components/feedback/_dir.card.html +0 -13
- package/components/forms/_dir.card.html +0 -13
- package/components/icons/_dir.card.html +0 -13
- package/components/navigation/_dir.card.html +0 -13
- package/components/pipeline/_dir.card.html +0 -13
- package/components/tabs/_dir.card.html +0 -13
|
@@ -21,8 +21,8 @@ export function GaugeChart({ value = 0, max = 100, size = 180, thickness = 14, l
|
|
|
21
21
|
{t > 0 ? <path d={arcPath(cx, cy, rO, rI, A0, A0 + t * 180)} fill={color}
|
|
22
22
|
onMouseEnter={interactive ? () => setHover(true) : undefined} onMouseLeave={interactive ? () => setHover(false) : undefined}
|
|
23
23
|
style={{ filter: hover ? "brightness(1.1)" : "none", transition: "filter var(--dur-fast) var(--ease-out)" }} /> : null}
|
|
24
|
-
<text x={cx - rO + thickness / 2} y={cy + 13} textAnchor="middle" style={{ fontFamily: "var(--font-mono)", fontSize:
|
|
25
|
-
<text x={cx + rO - thickness / 2} y={cy + 13} textAnchor="middle" style={{ fontFamily: "var(--font-mono)", fontSize:
|
|
24
|
+
<text x={cx - rO + thickness / 2} y={cy + 13} textAnchor="middle" style={{ fontFamily: "var(--font-mono)", fontSize: "var(--text-2xs)", fill: "var(--chart-label)" }}>0</text>
|
|
25
|
+
<text x={cx + rO - thickness / 2} y={cy + 13} textAnchor="middle" style={{ fontFamily: "var(--font-mono)", fontSize: "var(--text-2xs)", fill: "var(--chart-label)" }}>{fmtNum(max)}</text>
|
|
26
26
|
</svg>
|
|
27
27
|
<div style={{ position: "absolute", left: 0, right: 0, top: cy - size / 7, textAlign: "center", pointerEvents: "none" }}>
|
|
28
28
|
<div style={{ fontFamily: "var(--font-sans)", fontWeight: "var(--weight-light)", fontSize: size / 7, lineHeight: 1, color: "var(--text-heading)" }}>{valueFormat(value)}</div>
|
|
@@ -18,8 +18,8 @@ const g = computed(() => {
|
|
|
18
18
|
<path :d="g.track" fill="var(--chart-track)"/>
|
|
19
19
|
<path v-if="g.fill" :d="g.fill" :fill="g.color" @mouseenter="interactive && (hover=true)" @mouseleave="interactive && (hover=false)"
|
|
20
20
|
:style="{filter:hover?'brightness(1.1)':'none',transition:'filter var(--dur-fast) var(--ease-out)'}"/>
|
|
21
|
-
<text :x="g.cx-g.rO+thickness/2" :y="g.cy+13" text-anchor="middle" style="font-family:var(--font-mono);font-size:
|
|
22
|
-
<text :x="g.cx+g.rO-thickness/2" :y="g.cy+13" text-anchor="middle" style="font-family:var(--font-mono);font-size:
|
|
21
|
+
<text :x="g.cx-g.rO+thickness/2" :y="g.cy+13" text-anchor="middle" style="font-family:var(--font-mono);font-size:var(--text-2xs);fill:var(--chart-label)">0</text>
|
|
22
|
+
<text :x="g.cx+g.rO-thickness/2" :y="g.cy+13" text-anchor="middle" style="font-family:var(--font-mono);font-size:var(--text-2xs);fill:var(--chart-label)">{{ fmtNum(max) }}</text>
|
|
23
23
|
</svg>
|
|
24
24
|
<div :style="{position:'absolute',left:0,right:0,top:(g.cy-size/7)+'px',textAlign:'center',pointerEvents:'none'}">
|
|
25
25
|
<div :style="{fontFamily:'var(--font-sans)',fontWeight:'var(--weight-light)',fontSize:size/7+'px',lineHeight:1,color:'var(--text-heading)'}">{{ valueFormat(value) }}</div>
|
|
@@ -34,7 +34,7 @@ export function HeatmapChart({ xLabels = [], yLabels = [], values = [], width =
|
|
|
34
34
|
<div style={{ ...wrapStyle, width, ...style }}>
|
|
35
35
|
<div style={{ display: "grid", gridTemplateColumns: `${labelW}px repeat(${cols}, 1fr)`, gap: gap + "px", lineHeight: "normal" }}>
|
|
36
36
|
<span />
|
|
37
|
-
{xLabels.map((x) => <span key={x} style={{ fontFamily: "var(--font-sans)", fontSize:
|
|
37
|
+
{xLabels.map((x) => <span key={x} style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-2xs)", color: "var(--chart-label)", textAlign: "center", paddingBottom: 2 }}>{x}</span>)}
|
|
38
38
|
{yLabels.map((y, r) => (
|
|
39
39
|
<React.Fragment key={y}>
|
|
40
40
|
<span style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-xs)", color: "var(--text-secondary)", display: "flex", alignItems: "center", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", paddingRight: 6 }}>{y}</span>
|
|
@@ -46,7 +46,7 @@ export function HeatmapChart({ xLabels = [], yLabels = [], values = [], width =
|
|
|
46
46
|
onMouseEnter={interactive ? () => setHover({ r, c }) : undefined} onMouseLeave={interactive ? () => setHover(null) : undefined}
|
|
47
47
|
style={{ height: cellHeight, borderRadius: 4, background: cellFill(v), display: "flex", alignItems: "center", justifyContent: "center",
|
|
48
48
|
outline: on ? "2px solid var(--focus-border)" : "none", outlineOffset: -1, transition: "var(--t-hover)", cursor: interactive ? "default" : undefined }}>
|
|
49
|
-
{showValues && v != null ? <span style={{ fontFamily: "var(--font-mono)", fontSize:
|
|
49
|
+
{showValues && v != null ? <span style={{ fontFamily: "var(--font-mono)", fontSize: "var(--text-2xs)", color: textOn(v) }}>{valueFormat(v)}</span> : null}
|
|
50
50
|
</span>
|
|
51
51
|
);
|
|
52
52
|
})}
|
|
@@ -24,13 +24,13 @@ function ink(v){
|
|
|
24
24
|
<div :style="{width:width+'px',...style}">
|
|
25
25
|
<div :style="{display:'grid',gridTemplateColumns:'86px repeat('+xLabels.length+', 1fr)',gap:gap+'px'}">
|
|
26
26
|
<span/>
|
|
27
|
-
<span v-for="x in xLabels" :key="x" style="font-family:var(--font-sans);font-size:
|
|
27
|
+
<span v-for="x in xLabels" :key="x" style="font-family:var(--font-sans);font-size:var(--text-2xs);color:var(--chart-label);text-align:center;padding-bottom:2px">{{ x }}</span>
|
|
28
28
|
<template v-for="(y,r) in yLabels" :key="y">
|
|
29
29
|
<span style="font-family:var(--font-sans);font-size:var(--text-xs);color:var(--text-secondary);display:flex;align-items:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;padding-right:6px">{{ y }}</span>
|
|
30
30
|
<span v-for="(x,c) in xLabels" :key="c" :title="y+' · '+x+(values[r]&&values[r][c]!=null?' = '+valueFormat(values[r][c]):'')"
|
|
31
31
|
@mouseenter="interactive && (hover={r,c})" @mouseleave="interactive && (hover=null)"
|
|
32
32
|
:style="{height:cellHeight+'px',borderRadius:'4px',background:fill(values[r]?values[r][c]:null),display:'flex',alignItems:'center',justifyContent:'center',outline:hover&&hover.r===r&&hover.c===c?'2px solid var(--focus-border)':'none',outlineOffset:'-1px',transition:'var(--t-hover)'}">
|
|
33
|
-
<span v-if="showValues && values[r] && values[r][c]!=null" :style="{fontFamily:'var(--font-mono)',fontSize:'
|
|
33
|
+
<span v-if="showValues && values[r] && values[r][c]!=null" :style="{fontFamily:'var(--font-mono)',fontSize:'var(--text-2xs)',color:ink(values[r][c])}">{{ valueFormat(values[r][c]) }}</span>
|
|
34
34
|
</span>
|
|
35
35
|
</template>
|
|
36
36
|
</div>
|
|
@@ -40,10 +40,10 @@ export function Histogram({ values = [], buckets, bins = 12, width = 560, height
|
|
|
40
40
|
))}
|
|
41
41
|
{mean != null ? <g>
|
|
42
42
|
<line x1={sxVal(mean)} x2={sxVal(mean)} y1={pad.t} y2={height - pad.b} stroke="var(--chart-guide)" strokeWidth="1" strokeDasharray="3 3" />
|
|
43
|
-
<text x={Math.min(sxVal(mean) + 4, width - 60)} y={pad.t - 8} style={{ fontFamily: "var(--font-mono)", fontSize:
|
|
43
|
+
<text x={Math.min(sxVal(mean) + 4, width - 60)} y={pad.t - 8} style={{ fontFamily: "var(--font-mono)", fontSize: "var(--text-2xs)", fill: "var(--chart-label)" }}>mean {valueFormat(mean)}</text>
|
|
44
44
|
</g> : null}
|
|
45
45
|
{axes ? [0, Math.floor(bkt.length / 2), bkt.length - 1].map((i) => (
|
|
46
|
-
<text key={i} x={pad.l + slot * i + slot / 2} y={height - pad.b + 16} textAnchor="middle" style={{ fontFamily: "var(--font-mono)", fontSize:
|
|
46
|
+
<text key={i} x={pad.l + slot * i + slot / 2} y={height - pad.b + 16} textAnchor="middle" style={{ fontFamily: "var(--font-mono)", fontSize: "var(--text-2xs)", fill: "var(--chart-label)" }}>{valueFormat(bkt[i].from)}</text>
|
|
47
47
|
)) : null}
|
|
48
48
|
</svg>
|
|
49
49
|
{hover != null && interactive ? (
|
|
@@ -34,16 +34,16 @@ function move(e){
|
|
|
34
34
|
<template v-if="axes">
|
|
35
35
|
<g v-for="t in g.ticks" :key="t">
|
|
36
36
|
<line :x1="g.pad.l" :x2="width-g.pad.r" :y1="g.sy(t)" :y2="g.sy(t)" :stroke="t===0?'var(--chart-axis)':'var(--chart-grid)'" stroke-width="1"/>
|
|
37
|
-
<text :x="g.pad.l-8" :y="g.sy(t)+3" text-anchor="end" style="font-family:var(--font-mono);font-size:
|
|
37
|
+
<text :x="g.pad.l-8" :y="g.sy(t)+3" text-anchor="end" style="font-family:var(--font-mono);font-size:var(--text-2xs);fill:var(--chart-label)">{{ countFormat(t) }}</text>
|
|
38
38
|
</g>
|
|
39
39
|
</template>
|
|
40
40
|
<rect v-for="(b,i) in g.bkt" :key="i" :x="g.pad.l+g.slot*i+0.5" :y="g.sy(b.n)" :width="Math.max(1,g.slot-1.5)" :height="Math.max(1,g.sy(0)-g.sy(b.n))" rx="2"
|
|
41
41
|
:fill="color" :opacity="hover==null?0.9:(hover===i?1:0.4)" style="transition:opacity var(--dur-fast) var(--ease-out)"/>
|
|
42
42
|
<template v-if="g.mean!=null">
|
|
43
43
|
<line :x1="g.meanLine" :x2="g.meanLine" :y1="g.pad.t" :y2="height-g.pad.b" stroke="var(--chart-guide)" stroke-width="1" stroke-dasharray="3 3"/>
|
|
44
|
-
<text :x="g.meanX" :y="g.pad.t-8" style="font-family:var(--font-mono);font-size:
|
|
44
|
+
<text :x="g.meanX" :y="g.pad.t-8" style="font-family:var(--font-mono);font-size:var(--text-2xs);fill:var(--chart-label)">mean {{ valueFormat(g.mean) }}</text>
|
|
45
45
|
</template>
|
|
46
|
-
<text v-if="axes" v-for="i in g.labels" :key="'l'+i" :x="g.pad.l+g.slot*i+g.slot/2" :y="height-g.pad.b+16" text-anchor="middle" style="font-family:var(--font-mono);font-size:
|
|
46
|
+
<text v-if="axes" v-for="i in g.labels" :key="'l'+i" :x="g.pad.l+g.slot*i+g.slot/2" :y="height-g.pad.b+16" text-anchor="middle" style="font-family:var(--font-mono);font-size:var(--text-2xs);fill:var(--chart-label)">{{ valueFormat(g.bkt[i].from) }}</text>
|
|
47
47
|
</svg>
|
|
48
48
|
<div v-if="hover!=null && interactive" :style="{position:'absolute',left:(g.pad.l+g.slot*hover+g.slot/2)+'px',top:(height/2-10)+'px',transform:(g.pad.l+g.slot*hover)>width*0.62?'translate(calc(-100% - 10px),-50%)':'translate(10px,-50%)',pointerEvents:'none',zIndex:5,background:'var(--bg-surface)',border:'1px solid var(--border-card)',borderRadius:'var(--radius-md)',boxShadow:'var(--shadow-menu)',padding:'7px 10px',lineHeight:'normal',whiteSpace:'nowrap'}">
|
|
49
49
|
<div style="font-family:var(--font-sans);font-size:var(--text-2xs);color:var(--text-muted);padding-bottom:3px">{{ valueFormat(g.bkt[hover].from) }} – {{ valueFormat(g.bkt[hover].to) }}</div>
|
|
@@ -58,7 +58,7 @@ export function LineChart({ series = [], xLabels = [], width = 560, height = 240
|
|
|
58
58
|
{axes ? <PlotGrid w={width} h={height} pad={pad} ticks={ticks} sy={sy} xLabels={thinLabels(xLabels)} sxLabel={sx} yFormat={yFormat} /> : null}
|
|
59
59
|
{target != null ? <g>
|
|
60
60
|
<line x1={pad.l} x2={width - pad.r} y1={sy(target)} y2={sy(target)} stroke="var(--chart-guide)" strokeWidth="1" strokeDasharray="3 3" />
|
|
61
|
-
<text x={width - pad.r} y={sy(target) - 4} textAnchor="end" style={{ fontFamily: "var(--font-sans)", fontSize:
|
|
61
|
+
<text x={width - pad.r} y={sy(target) - 4} textAnchor="end" style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-2xs)", fill: "var(--chart-label)" }}>{targetLabel || "Target " + yFormat(target)}</text>
|
|
62
62
|
</g> : null}
|
|
63
63
|
{painted.map((L) => (
|
|
64
64
|
<g key={L.s.name}>
|
|
@@ -52,13 +52,13 @@ function toggle(name){
|
|
|
52
52
|
<template v-if="axes">
|
|
53
53
|
<g v-for="t in g.ticks" :key="t">
|
|
54
54
|
<line :x1="g.pad.l" :x2="width-g.pad.r" :y1="g.sy(t)" :y2="g.sy(t)" :stroke="t===0?'var(--chart-axis)':'var(--chart-grid)'" stroke-width="1"/>
|
|
55
|
-
<text :x="g.pad.l-8" :y="g.sy(t)+3" text-anchor="end" style="font-family:var(--font-mono);font-size:
|
|
55
|
+
<text :x="g.pad.l-8" :y="g.sy(t)+3" text-anchor="end" style="font-family:var(--font-mono);font-size:var(--text-2xs);fill:var(--chart-label)">{{ yFormat(t) }}</text>
|
|
56
56
|
</g>
|
|
57
|
-
<text v-for="(lb,i) in xLabels" :key="'x'+i" :x="g.sx(i)" :y="height-g.pad.b+16" text-anchor="middle" style="font-family:var(--font-sans);font-size:
|
|
57
|
+
<text v-for="(lb,i) in xLabels" :key="'x'+i" :x="g.sx(i)" :y="height-g.pad.b+16" text-anchor="middle" style="font-family:var(--font-sans);font-size:var(--text-2xs);fill:var(--chart-label)">{{ lb }}</text>
|
|
58
58
|
</template>
|
|
59
59
|
<template v-if="target!=null">
|
|
60
60
|
<line :x1="g.pad.l" :x2="width-g.pad.r" :y1="g.sy(target)" :y2="g.sy(target)" stroke="var(--chart-guide)" stroke-width="1" stroke-dasharray="3 3"/>
|
|
61
|
-
<text :x="width-g.pad.r" :y="g.sy(target)-4" text-anchor="end" style="font-family:var(--font-sans);font-size:
|
|
61
|
+
<text :x="width-g.pad.r" :y="g.sy(target)-4" text-anchor="end" style="font-family:var(--font-sans);font-size:var(--text-2xs);fill:var(--chart-label)">{{ targetLabel || 'Target '+yFormat(target) }}</text>
|
|
62
62
|
</template>
|
|
63
63
|
<g v-for="ln in g.lines" :key="ln.s.name">
|
|
64
64
|
<path v-if="area||stacked" :d="ln.fill" :fill="'url(#'+uid+'-'+series.indexOf(ln.s)+')'"/>
|
|
@@ -32,7 +32,7 @@ export function ParetoChart({ items = [], width = 560, height = 260, axes = true
|
|
|
32
32
|
{axes ? <PlotGrid w={width} h={height} pad={pad} ticks={ticks} sy={sy} xLabels={[]} sxLabel={() => 0} yFormat={valueFormat} /> : null}
|
|
33
33
|
{hover != null ? <rect x={pad.l + slot * hover} y={pad.t} width={slot} height={height - pad.t - pad.b} fill="var(--bg-hover)" /> : null}
|
|
34
34
|
<line x1={pad.l} x2={width - pad.r} y1={sc(threshold)} y2={sc(threshold)} stroke="var(--chart-guide)" strokeWidth="1" strokeDasharray="3 3" />
|
|
35
|
-
<text x={width - pad.r - 2} y={sc(threshold) - 4} textAnchor="end" style={{ fontFamily: "var(--font-sans)", fontSize:
|
|
35
|
+
<text x={width - pad.r - 2} y={sc(threshold) - 4} textAnchor="end" style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-2xs)", fill: "var(--chart-label)" }}>{threshold}%</text>
|
|
36
36
|
{rows.map((r, i) => (
|
|
37
37
|
<rect key={r.label} x={cx(i) - bw / 2} y={sy(r.value)} width={bw} height={Math.max(1, sy(0) - sy(r.value))} rx="2"
|
|
38
38
|
fill={i <= vital ? "var(--series-1)" : "var(--chart-track)"} stroke={i > vital ? "var(--border-control)" : "none"}
|
|
@@ -40,8 +40,8 @@ export function ParetoChart({ items = [], width = 560, height = 260, axes = true
|
|
|
40
40
|
))}
|
|
41
41
|
<path d={linePath(rows.map((r, i) => [cx(i), sc(r.cum)]))} fill="none" stroke="var(--chart-total)" strokeWidth="1.5" />
|
|
42
42
|
{rows.map((r, i) => <circle key={i} cx={cx(i)} cy={sc(r.cum)} r={hover === i ? 3.4 : 2.4} fill="var(--chart-total)" />)}
|
|
43
|
-
{axes ? [0, 25, 50, 75, 100].map((t) => <text key={t} x={width - pad.r + 6} y={sc(t) + 3} style={{ fontFamily: "var(--font-mono)", fontSize:
|
|
44
|
-
{rows.map((r, i) => <text key={"l" + i} x={cx(i)} y={height - pad.b + 15} textAnchor="middle" style={{ fontFamily: "var(--font-sans)", fontSize:
|
|
43
|
+
{axes ? [0, 25, 50, 75, 100].map((t) => <text key={t} x={width - pad.r + 6} y={sc(t) + 3} style={{ fontFamily: "var(--font-mono)", fontSize: "var(--text-2xs)", fill: "var(--chart-label)" }}>{t}%</text>) : null}
|
|
44
|
+
{rows.map((r, i) => <text key={"l" + i} x={cx(i)} y={height - pad.b + 15} textAnchor="middle" style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-2xs)", fill: "var(--chart-label)" }}>{r.label}</text>)}
|
|
45
45
|
</svg>
|
|
46
46
|
{hover != null && interactive ? (
|
|
47
47
|
<ChartTooltip x={cx(hover)} y={height / 2 - 10} flip={cx(hover) > width * 0.62} title={rows[hover].label}
|
|
@@ -33,19 +33,19 @@ function move(e){
|
|
|
33
33
|
<template v-if="axes">
|
|
34
34
|
<g v-for="t in g.ticks" :key="t">
|
|
35
35
|
<line :x1="g.pad.l" :x2="width-g.pad.r" :y1="g.sy(t)" :y2="g.sy(t)" :stroke="t===0?'var(--chart-axis)':'var(--chart-grid)'" stroke-width="1"/>
|
|
36
|
-
<text :x="g.pad.l-8" :y="g.sy(t)+3" text-anchor="end" style="font-family:var(--font-mono);font-size:
|
|
36
|
+
<text :x="g.pad.l-8" :y="g.sy(t)+3" text-anchor="end" style="font-family:var(--font-mono);font-size:var(--text-2xs);fill:var(--chart-label)">{{ valueFormat(t) }}</text>
|
|
37
37
|
</g>
|
|
38
38
|
</template>
|
|
39
39
|
<rect v-if="hover!=null" :x="g.pad.l+g.slot*hover" :y="g.pad.t" :width="g.slot" :height="height-g.pad.t-g.pad.b" fill="var(--bg-hover)"/>
|
|
40
40
|
<line :x1="g.pad.l" :x2="width-g.pad.r" :y1="g.sc(threshold)" :y2="g.sc(threshold)" stroke="var(--chart-guide)" stroke-width="1" stroke-dasharray="3 3"/>
|
|
41
|
-
<text :x="width-g.pad.r-2" :y="g.sc(threshold)-4" text-anchor="end" style="font-family:var(--font-sans);font-size:
|
|
41
|
+
<text :x="width-g.pad.r-2" :y="g.sc(threshold)-4" text-anchor="end" style="font-family:var(--font-sans);font-size:var(--text-2xs);fill:var(--chart-label)">{{ threshold }}%</text>
|
|
42
42
|
<rect v-for="(r,i) in g.rows" :key="r.label" :x="g.cx(i)-g.bw/2" :y="g.sy(r.value)" :width="g.bw" :height="Math.max(1,g.sy(0)-g.sy(r.value))" rx="2"
|
|
43
43
|
:fill="i<=g.vital?'var(--series-1)':'var(--chart-track)'" :stroke="i>g.vital?'var(--border-control)':'none'"
|
|
44
44
|
:opacity="hover==null||hover===i?1:0.5" style="transition:opacity var(--dur-fast) var(--ease-out)"/>
|
|
45
45
|
<path :d="g.line" fill="none" stroke="var(--chart-total)" stroke-width="1.5"/>
|
|
46
46
|
<circle v-for="(r,i) in g.rows" :key="'c'+i" :cx="g.cx(i)" :cy="g.sc(r.cum)" :r="hover===i?3.4:2.4" fill="var(--chart-total)"/>
|
|
47
|
-
<text v-if="axes" v-for="t in g.pct" :key="'p'+t" :x="width-g.pad.r+6" :y="g.sc(t)+3" style="font-family:var(--font-mono);font-size:
|
|
48
|
-
<text v-for="(r,i) in g.rows" :key="'l'+i" :x="g.cx(i)" :y="height-g.pad.b+15" text-anchor="middle" style="font-family:var(--font-sans);font-size:
|
|
47
|
+
<text v-if="axes" v-for="t in g.pct" :key="'p'+t" :x="width-g.pad.r+6" :y="g.sc(t)+3" style="font-family:var(--font-mono);font-size:var(--text-2xs);fill:var(--chart-label)">{{ t }}%</text>
|
|
48
|
+
<text v-for="(r,i) in g.rows" :key="'l'+i" :x="g.cx(i)" :y="height-g.pad.b+15" text-anchor="middle" style="font-family:var(--font-sans);font-size:var(--text-2xs);fill:var(--chart-label)">{{ r.label }}</text>
|
|
49
49
|
</svg>
|
|
50
50
|
<div v-if="hover!=null && interactive" :style="{position:'absolute',left:g.cx(hover)+'px',top:(height/2-10)+'px',transform:g.cx(hover)>width*0.62?'translate(calc(-100% - 10px),-50%)':'translate(10px,-50%)',pointerEvents:'none',zIndex:5,background:'var(--bg-surface)',border:'1px solid var(--border-card)',borderRadius:'var(--radius-md)',boxShadow:'var(--shadow-menu)',padding:'7px 10px',lineHeight:'normal',whiteSpace:'nowrap'}">
|
|
51
51
|
<div style="font-family:var(--font-sans);font-size:var(--text-2xs);color:var(--text-muted);padding-bottom:3px">{{ g.rows[hover].label }}</div>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { fmtNum } from './chart-geometry.js'
|
|
3
|
+
// SVG plot furniture: y tick labels + horizontal gridlines (zero line darker), x category labels.
|
|
4
|
+
// Render inside an <svg>. sy / sxLabel are the chart's scale functions.
|
|
5
|
+
defineProps({ w: Number, h: Number, pad: Object, ticks: { type: Array, default: () => [] }, sy: Function, xLabels: { type: Array, default: () => [] }, sxLabel: Function, showAxisLine: Boolean, yFormat: { type: Function, default: fmtNum } })
|
|
6
|
+
</script>
|
|
7
|
+
<template>
|
|
8
|
+
<g>
|
|
9
|
+
<g v-for="t in ticks" :key="t">
|
|
10
|
+
<line :x1="pad.l" :x2="w - pad.r" :y1="sy(t)" :y2="sy(t)" :stroke="t === 0 ? 'var(--chart-axis)' : 'var(--chart-grid)'" stroke-width="1" />
|
|
11
|
+
<text :x="pad.l - 8" :y="sy(t) + 3" text-anchor="end" style="font-family:var(--font-mono);font-size:var(--text-2xs);fill:var(--chart-label)">{{ yFormat(t) }}</text>
|
|
12
|
+
</g>
|
|
13
|
+
<line v-if="showAxisLine" :x1="pad.l" :x2="pad.l" :y1="pad.t" :y2="h - pad.b" stroke="var(--chart-axis)" stroke-width="1" />
|
|
14
|
+
<template v-for="(lb, i) in xLabels" :key="'x' + i">
|
|
15
|
+
<text v-if="lb != null" :x="sxLabel(i)" :y="h - pad.b + 16" text-anchor="middle" style="font-family:var(--font-sans);font-size:var(--text-2xs);fill:var(--chart-label)">{{ lb }}</text>
|
|
16
|
+
</template>
|
|
17
|
+
</g>
|
|
18
|
+
</template>
|
|
@@ -51,7 +51,7 @@ export function RadarChart({ axes = [], series = [], size = 260, levels = 4, leg
|
|
|
51
51
|
<g key={a.label}>
|
|
52
52
|
<line x1={cx} y1={cy} x2={x} y2={y} stroke={on ? "var(--chart-guide)" : "var(--chart-axis)"} strokeWidth="1" />
|
|
53
53
|
<text x={lx} y={ly + 3} textAnchor={anchor}
|
|
54
|
-
style={{ fontFamily: "var(--font-sans)", fontSize:
|
|
54
|
+
style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-2xs)", fill: on ? "var(--text-heading)" : "var(--chart-label)" }}>{a.label}</text>
|
|
55
55
|
</g>
|
|
56
56
|
);
|
|
57
57
|
})}
|
|
@@ -47,7 +47,7 @@ function toggle(name){
|
|
|
47
47
|
<path v-for="(d,i) in g.rings" :key="'r'+i" :d="d" fill="none" stroke="var(--chart-grid)" stroke-width="1"/>
|
|
48
48
|
<g v-for="(sp,i) in g.spokes" :key="sp.label">
|
|
49
49
|
<line :x1="g.cx" :y1="g.cy" :x2="sp.x" :y2="sp.y" :stroke="hover===i?'var(--chart-guide)':'var(--chart-axis)'" stroke-width="1"/>
|
|
50
|
-
<text :x="sp.lx" :y="sp.ly+3" :text-anchor="sp.anchor" :style="{fontFamily:'var(--font-sans)',fontSize:'
|
|
50
|
+
<text :x="sp.lx" :y="sp.ly+3" :text-anchor="sp.anchor" :style="{fontFamily:'var(--font-sans)',fontSize:'var(--text-2xs)',fill:hover===i?'var(--text-heading)':'var(--chart-label)'}">{{ sp.label }}</text>
|
|
51
51
|
</g>
|
|
52
52
|
<g v-for="sh in g.shapes" :key="sh.s.name">
|
|
53
53
|
<path :d="sh.d" :fill="sh.color" fill-opacity="0.14" :stroke="sh.color" stroke-width="1.5" stroke-linejoin="round"/>
|
|
@@ -47,7 +47,7 @@ export function Ribbon3D({ series = [], xLabels = [], width = 460, height = 300,
|
|
|
47
47
|
{vTicks.map((t, i) => (
|
|
48
48
|
<g key={"vt" + i}>
|
|
49
49
|
<line x1={t.p.x - 4} y1={t.p.y} x2={t.p.x} y2={t.p.y} stroke="var(--chart-guide)" strokeWidth="1" />
|
|
50
|
-
<text x={t.p.x - 7} y={t.p.y + 3} textAnchor="end" style={{ fontFamily: "var(--font-mono)", fontSize:
|
|
50
|
+
<text x={t.p.x - 7} y={t.p.y + 3} textAnchor="end" style={{ fontFamily: "var(--font-mono)", fontSize: "var(--text-2xs)", fill: "var(--chart-label)" }}>{t.v}</text>
|
|
51
51
|
</g>
|
|
52
52
|
))}
|
|
53
53
|
{xLabels.map((lb, i) => {
|
|
@@ -57,7 +57,7 @@ export function Ribbon3D({ series = [], xLabels = [], width = 460, height = 300,
|
|
|
57
57
|
const p0 = P(i / (n - 1) - 0.5, -0.45, zE);
|
|
58
58
|
const ctr = P(0, -0.45, 0);
|
|
59
59
|
const dx = p0.x - ctr.x, dy = p0.y - ctr.y, len = Math.hypot(dx, dy) || 1;
|
|
60
|
-
return <text key={"x" + i} x={p0.x + (dx / len) * 14} y={p0.y + (dy / len) * 14 + 3} textAnchor="middle" style={{ fontFamily: "var(--font-sans)", fontSize:
|
|
60
|
+
return <text key={"x" + i} x={p0.x + (dx / len) * 14} y={p0.y + (dy / len) * 14 + 3} textAnchor="middle" style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-2xs)", fill: "var(--chart-label)" }}>{lb}</text>;
|
|
61
61
|
})}
|
|
62
62
|
{rows.map((r) => (
|
|
63
63
|
<g key={r.s.name} opacity={hover == null || hover === r.si ? 1 : 0.4}
|
|
@@ -55,9 +55,9 @@ const g = computed(() => {
|
|
|
55
55
|
<line :x1="g.vAxis[0].x" :y1="g.vAxis[0].y" :x2="g.vAxis[1].x" :y2="g.vAxis[1].y" stroke="var(--chart-guide)" stroke-width="1"/>
|
|
56
56
|
<g v-for="(t,i) in g.vTicks" :key="'vt'+i">
|
|
57
57
|
<line :x1="t.p.x-4" :y1="t.p.y" :x2="t.p.x" :y2="t.p.y" stroke="var(--chart-guide)" stroke-width="1"/>
|
|
58
|
-
<text :x="t.p.x-7" :y="t.p.y+3" text-anchor="end" style="font-family:var(--font-mono);font-size:
|
|
58
|
+
<text :x="t.p.x-7" :y="t.p.y+3" text-anchor="end" style="font-family:var(--font-mono);font-size:var(--text-2xs);fill:var(--chart-label)">{{ t.v }}</text>
|
|
59
59
|
</g>
|
|
60
|
-
<text v-for="(l,i) in g.labels" :key="'x'+i" :x="l.x" :y="l.y" text-anchor="middle" style="font-family:var(--font-sans);font-size:
|
|
60
|
+
<text v-for="(l,i) in g.labels" :key="'x'+i" :x="l.x" :y="l.y" text-anchor="middle" style="font-family:var(--font-sans);font-size:var(--text-2xs);fill:var(--chart-label)">{{ l.lb }}</text>
|
|
61
61
|
<g v-for="r in g.rows" :key="r.s.name" :opacity="hover==null||hover===r.si?1:0.4"
|
|
62
62
|
@mouseenter="interactive && (hover=r.si)" @mouseleave="interactive && (hover=null)"
|
|
63
63
|
style="transition:opacity var(--dur-fast) var(--ease-out)">
|
|
@@ -45,9 +45,9 @@ export function SankeyChart({ nodes = [], links = [], width = 620, height = 320,
|
|
|
45
45
|
style={{ cursor: interactive ? "default" : undefined }}>
|
|
46
46
|
<rect x={n.x} y={n.y} width={n.w} height={n.h} rx="2" fill={c} opacity={hover == null || (hover.kind === "node" && hover.id === n.id) ? 1 : 0.55} />
|
|
47
47
|
<text x={rightSide ? n.x + n.w + 6 : n.x + n.w + 6} y={n.y + n.h / 2 + 3.5}
|
|
48
|
-
style={{ fontFamily: "var(--font-sans)", fontSize:
|
|
48
|
+
style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-xs)", fill: "var(--text-heading)" }}>{n.label}</text>
|
|
49
49
|
<text x={n.x + n.w + 6} y={n.y + n.h / 2 + 15}
|
|
50
|
-
style={{ fontFamily: "var(--font-mono)", fontSize:
|
|
50
|
+
style={{ fontFamily: "var(--font-mono)", fontSize: "var(--text-2xs)", fill: "var(--chart-label)" }}>{valueFormat(n.value)}</text>
|
|
51
51
|
</g>
|
|
52
52
|
);
|
|
53
53
|
})}
|
|
@@ -40,8 +40,8 @@ const tip = computed(()=>{
|
|
|
40
40
|
style="transition:opacity var(--dur-fast) var(--ease-out)"/>
|
|
41
41
|
<g v-for="n in g.laid.nodes" :key="n.id" @mouseenter="interactive && (hover={kind:'node',id:n.id})" @mouseleave="interactive && (hover=null)">
|
|
42
42
|
<rect :x="n.x" :y="n.y" :width="n.w" :height="n.h" rx="2" :fill="g.color(n)" :opacity="hover==null||(hover.kind==='node'&&hover.id===n.id)?1:0.55"/>
|
|
43
|
-
<text :x="n.x+n.w+6" :y="n.y+n.h/2+3.5" style="font-family:var(--font-sans);font-size:
|
|
44
|
-
<text :x="n.x+n.w+6" :y="n.y+n.h/2+15" style="font-family:var(--font-mono);font-size:
|
|
43
|
+
<text :x="n.x+n.w+6" :y="n.y+n.h/2+3.5" style="font-family:var(--font-sans);font-size:var(--text-xs);fill:var(--text-heading)">{{ n.label }}</text>
|
|
44
|
+
<text :x="n.x+n.w+6" :y="n.y+n.h/2+15" style="font-family:var(--font-mono);font-size:var(--text-2xs);fill:var(--chart-label)">{{ valueFormat(n.value) }}</text>
|
|
45
45
|
</g>
|
|
46
46
|
</g>
|
|
47
47
|
</svg>
|
|
@@ -40,7 +40,7 @@ export function Scatter3D({ points = [], width = 420, height = 300, yaw: yaw0 =
|
|
|
40
40
|
{edges.map(([a, b], i) => <line key={i} x1={a.x} y1={a.y} x2={b.x} y2={b.y} stroke="var(--chart-axis)" strokeWidth="1" />)}
|
|
41
41
|
{axes3.map((ax, i) => <line key={"ae" + i} x1={ax.a.x} y1={ax.a.y} x2={ax.b.x} y2={ax.b.y} stroke="var(--chart-guide)" strokeWidth="1" />)}
|
|
42
42
|
{axes3.map((ax, i) => (
|
|
43
|
-
<text key={"at" + i} x={ax.nx} y={ax.ny + 3} textAnchor="middle" style={{ fontFamily: "var(--font-sans)", fontSize:
|
|
43
|
+
<text key={"at" + i} x={ax.nx} y={ax.ny + 3} textAnchor="middle" style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-2xs)", fill: "var(--text-secondary)" }}>{ax.name}</text>
|
|
44
44
|
))}
|
|
45
45
|
{dots.map((d) => (
|
|
46
46
|
<circle key={d.i} cx={d.x} cy={d.y} r={r * (1.18 - (d.depth + 0.75) * 0.35) * (hover === d.i ? 1.5 : 1)}
|
|
@@ -38,7 +38,7 @@ const g = computed(() => {
|
|
|
38
38
|
role="img" :style="{cursor:interactive?'grab':'default',touchAction:'none'}">
|
|
39
39
|
<line v-for="(e,i) in g.edges" :key="'e'+i" :x1="e[0].x" :y1="e[0].y" :x2="e[1].x" :y2="e[1].y" stroke="var(--chart-axis)" stroke-width="1"/>
|
|
40
40
|
<line v-for="(ax,i) in g.axes3" :key="'ae'+i" :x1="ax.a.x" :y1="ax.a.y" :x2="ax.b.x" :y2="ax.b.y" stroke="var(--chart-guide)" stroke-width="1"/>
|
|
41
|
-
<text v-for="(ax,i) in g.axes3" :key="'at'+i" :x="ax.nx" :y="ax.ny+3" text-anchor="middle" style="font-family:var(--font-sans);font-size:
|
|
41
|
+
<text v-for="(ax,i) in g.axes3" :key="'at'+i" :x="ax.nx" :y="ax.ny+3" text-anchor="middle" style="font-family:var(--font-sans);font-size:var(--text-2xs);fill:var(--text-secondary)">{{ ax.name }}</text>
|
|
42
42
|
<circle v-for="d in g.dots" :key="d.i" :cx="d.x" :cy="d.y"
|
|
43
43
|
:r="r*(1.18-(d.depth+0.75)*0.35)*(hover===d.i?1.5:1)" :fill="d.color"
|
|
44
44
|
:opacity="hover===d.i ? 1 : (0.85-(d.depth+0.75)*0.28)*(hover==null?1:0.45)"
|
|
@@ -33,9 +33,9 @@ export function ScatterChart({ points = [], width = 560, height = 260, xFormat =
|
|
|
33
33
|
<svg width={width} height={height} onMouseMove={move} onMouseLeave={() => setHover(null)} role="img">
|
|
34
34
|
{axes ? <g>
|
|
35
35
|
<PlotGrid w={width} h={height} pad={pad} ticks={ty.ticks} sy={sy} xLabels={[]} sxLabel={() => 0} yFormat={yFormat} />
|
|
36
|
-
{tx.ticks.map((t) => <text key={t} x={sx(t)} y={height - pad.b + 16} textAnchor="middle" style={{ fontFamily: "var(--font-mono)", fontSize:
|
|
37
|
-
{xLabel ? <text x={width - pad.r} y={height - 2} textAnchor="end" style={{ fontFamily: "var(--font-sans)", fontSize:
|
|
38
|
-
{yLabel ? <text x={pad.l} y={pad.t - 1} style={{ fontFamily: "var(--font-sans)", fontSize:
|
|
36
|
+
{tx.ticks.map((t) => <text key={t} x={sx(t)} y={height - pad.b + 16} textAnchor="middle" style={{ fontFamily: "var(--font-mono)", fontSize: "var(--text-2xs)", fill: "var(--chart-label)" }}>{xFormat(t)}</text>)}
|
|
37
|
+
{xLabel ? <text x={width - pad.r} y={height - 2} textAnchor="end" style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-2xs)", fill: "var(--chart-label)" }}>{xLabel}</text> : null}
|
|
38
|
+
{yLabel ? <text x={pad.l} y={pad.t - 1} style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-2xs)", fill: "var(--chart-label)" }}>{yLabel}</text> : null}
|
|
39
39
|
</g> : null}
|
|
40
40
|
{points.map((p, i) => (
|
|
41
41
|
<circle key={i} cx={sx(p.x)} cy={sy(p.y)} r={sr(p.r != null ? p.r : 1)} fill={colorOf(p)}
|
|
@@ -33,11 +33,11 @@ function move(e){
|
|
|
33
33
|
<template v-if="axes">
|
|
34
34
|
<g v-for="t in g.ty.ticks" :key="t">
|
|
35
35
|
<line :x1="g.pad.l" :x2="width-g.pad.r" :y1="g.sy(t)" :y2="g.sy(t)" :stroke="t===0?'var(--chart-axis)':'var(--chart-grid)'" stroke-width="1"/>
|
|
36
|
-
<text :x="g.pad.l-8" :y="g.sy(t)+3" text-anchor="end" style="font-family:var(--font-mono);font-size:
|
|
36
|
+
<text :x="g.pad.l-8" :y="g.sy(t)+3" text-anchor="end" style="font-family:var(--font-mono);font-size:var(--text-2xs);fill:var(--chart-label)">{{ yFormat(t) }}</text>
|
|
37
37
|
</g>
|
|
38
|
-
<text v-for="t in g.tx.ticks" :key="'x'+t" :x="g.sx(t)" :y="height-g.pad.b+16" text-anchor="middle" style="font-family:var(--font-mono);font-size:
|
|
39
|
-
<text v-if="xLabel" :x="width-g.pad.r" :y="height-2" text-anchor="end" style="font-family:var(--font-sans);font-size:
|
|
40
|
-
<text v-if="yLabel" :x="g.pad.l" :y="g.pad.t-1" style="font-family:var(--font-sans);font-size:
|
|
38
|
+
<text v-for="t in g.tx.ticks" :key="'x'+t" :x="g.sx(t)" :y="height-g.pad.b+16" text-anchor="middle" style="font-family:var(--font-mono);font-size:var(--text-2xs);fill:var(--chart-label)">{{ xFormat(t) }}</text>
|
|
39
|
+
<text v-if="xLabel" :x="width-g.pad.r" :y="height-2" text-anchor="end" style="font-family:var(--font-sans);font-size:var(--text-2xs);fill:var(--chart-label)">{{ xLabel }}</text>
|
|
40
|
+
<text v-if="yLabel" :x="g.pad.l" :y="g.pad.t-1" style="font-family:var(--font-sans);font-size:var(--text-2xs);fill:var(--chart-label)">{{ yLabel }}</text>
|
|
41
41
|
</template>
|
|
42
42
|
<circle v-for="d in g.dots" :key="d.i" :cx="d.cx" :cy="d.cy" :r="d.r" :fill="d.color"
|
|
43
43
|
:opacity="hover==null?.55:hover===d.i?.9:.2" :stroke="hover===d.i?'var(--bg-surface)':'none'" stroke-width="1.5"
|
|
@@ -28,7 +28,7 @@ export function Sparkline({ values = [], mode = "line", curve = "linear", tone =
|
|
|
28
28
|
setHover(Math.max(0, Math.min(values.length - 1, i)));
|
|
29
29
|
};
|
|
30
30
|
const chip = hover != null && interactive ? (
|
|
31
|
-
<span style={{ position: "absolute", left: Math.min(Math.max(sx(hover), 18), width - 18), top: -4, transform: "translate(-50%,-100%)", pointerEvents: "none", whiteSpace: "nowrap", background: "var(--bg-surface)", border: "1px solid var(--border-card)", borderRadius: "var(--radius-sm)", boxShadow: "var(--shadow-menu)", padding: "2px 6px", fontFamily: "var(--font-mono)", fontSize:
|
|
31
|
+
<span style={{ position: "absolute", left: Math.min(Math.max(sx(hover), 18), width - 18), top: -4, transform: "translate(-50%,-100%)", pointerEvents: "none", whiteSpace: "nowrap", background: "var(--bg-surface)", border: "1px solid var(--border-card)", borderRadius: "var(--radius-sm)", boxShadow: "var(--shadow-menu)", padding: "2px 6px", fontFamily: "var(--font-mono)", fontSize: "var(--text-2xs)", lineHeight: "14px", color: "var(--text-heading)", zIndex: 5 }}>
|
|
32
32
|
{labels && labels[hover] ? <span style={{ color: "var(--text-muted)", paddingRight: 5 }}>{labels[hover]}</span> : null}
|
|
33
33
|
{valueFormat(values[hover])}
|
|
34
34
|
</span>
|
|
@@ -47,7 +47,7 @@ const g = computed(() => {
|
|
|
47
47
|
<circle v-if="hover!=null && interactive" :cx="g.sx(hover)" :cy="g.sy(values[hover])" :r="strokeWidth+1.4" :fill="g.color" stroke="var(--bg-surface)" stroke-width="1.5"/>
|
|
48
48
|
</template>
|
|
49
49
|
</svg>
|
|
50
|
-
<span v-if="hover!=null && interactive" :style="{position:'absolute',left:Math.min(Math.max(g.sx(hover),18),width-18)+'px',top:'-4px',transform:'translate(-50%,-100%)',pointerEvents:'none',whiteSpace:'nowrap',background:'var(--bg-surface)',border:'1px solid var(--border-card)',borderRadius:'var(--radius-sm)',boxShadow:'var(--shadow-menu)',padding:'2px 6px',fontFamily:'var(--font-mono)',fontSize:'
|
|
50
|
+
<span v-if="hover!=null && interactive" :style="{position:'absolute',left:Math.min(Math.max(g.sx(hover),18),width-18)+'px',top:'-4px',transform:'translate(-50%,-100%)',pointerEvents:'none',whiteSpace:'nowrap',background:'var(--bg-surface)',border:'1px solid var(--border-card)',borderRadius:'var(--radius-sm)',boxShadow:'var(--shadow-menu)',padding:'2px 6px',fontFamily:'var(--font-mono)',fontSize:'var(--text-2xs)',lineHeight:'14px',color:'var(--text-heading)',zIndex:5}">
|
|
51
51
|
<span v-if="labels && labels[hover]" style="color:var(--text-muted);padding-right:5px">{{ labels[hover] }}</span>{{ valueFormat(values[hover]) }}
|
|
52
52
|
</span>
|
|
53
53
|
</span>
|
|
@@ -49,7 +49,7 @@ export function SunburstChart({ data, size = 320, ringWidth, valueFormat = fmtNu
|
|
|
49
49
|
<span style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-2xs)", color: "var(--text-muted)", maxWidth: rInner * 1.7, textAlign: "center", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>
|
|
50
50
|
{zoom.length ? focus.label : focus.label || "Total"}
|
|
51
51
|
</span>
|
|
52
|
-
{zoom.length ? <span style={{ fontFamily: "var(--font-sans)", fontSize:
|
|
52
|
+
{zoom.length ? <span style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-2xs)", color: "var(--action-primary)" }}>↑ back</span> : null}
|
|
53
53
|
</div>
|
|
54
54
|
{h && interactive ? (
|
|
55
55
|
<ChartTooltip x={tipAt[0]} y={tipAt[1]} flip={tipAt[0] > size * 0.55} title={h.node.label}
|
|
@@ -49,7 +49,7 @@ const tip = computed(()=>{
|
|
|
49
49
|
<div style="position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;pointer-events:none;line-height:normal;gap:2px">
|
|
50
50
|
<span :style="{fontFamily:'var(--font-sans)',fontWeight:'var(--weight-light)',fontSize:Math.round(size/13)+'px',color:'var(--text-heading)'}">{{ valueFormat(g.focus.value) }}</span>
|
|
51
51
|
<span :style="{fontFamily:'var(--font-sans)',fontSize:'var(--text-2xs)',color:'var(--text-muted)',maxWidth:g.rInner*1.7+'px',textAlign:'center',whiteSpace:'nowrap',overflow:'hidden',textOverflow:'ellipsis'}">{{ g.focus.label || 'Total' }}</span>
|
|
52
|
-
<span v-if="zoom.length" style="font-family:var(--font-sans);font-size:
|
|
52
|
+
<span v-if="zoom.length" style="font-family:var(--font-sans);font-size:var(--text-2xs);color:var(--action-primary)">↑ back</span>
|
|
53
53
|
</div>
|
|
54
54
|
<div v-if="tip && interactive" :style="{position:'absolute',left:tip.x+'px',top:tip.y+'px',transform:tip.x>size*0.55?'translate(calc(-100% - 10px),-50%)':'translate(10px,-50%)',pointerEvents:'none',zIndex:5,background:'var(--bg-surface)',border:'1px solid var(--border-card)',borderRadius:'var(--radius-md)',boxShadow:'var(--shadow-menu)',padding:'7px 10px',lineHeight:'normal',whiteSpace:'nowrap'}">
|
|
55
55
|
<div style="font-family:var(--font-sans);font-size:var(--text-2xs);color:var(--text-muted);padding-bottom:3px">{{ tip.title }}</div>
|
|
@@ -47,11 +47,11 @@ export function Surface3D({ values = [], width = 420, height = 300, yaw: yaw0 =
|
|
|
47
47
|
<svg width={width} height={height} {...handlers} role="img" style={{ cursor: interactive ? "grab" : "default", touchAction: "none" }}>
|
|
48
48
|
<path d={basePath} fill="var(--bg-inset)" stroke="var(--chart-axis)" strokeWidth="1" />
|
|
49
49
|
{axes3.map((ax, i) => <line key={"ae" + i} x1={ax.a.x} y1={ax.a.y} x2={ax.b.x} y2={ax.b.y} stroke="var(--chart-guide)" strokeWidth="1" />)}
|
|
50
|
-
{axes3.map((ax, i) => ax.label ? <text key={"al" + i} x={ax.lp.x} y={ax.lp.y + 3} textAnchor={ax.anchor} style={{ fontFamily: "var(--font-sans)", fontSize:
|
|
50
|
+
{axes3.map((ax, i) => ax.label ? <text key={"al" + i} x={ax.lp.x} y={ax.lp.y + 3} textAnchor={ax.anchor} style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-2xs)", fill: "var(--text-secondary)" }}>{ax.label}</text> : null)}
|
|
51
51
|
{zTicks.map((t, i) => (
|
|
52
52
|
<g key={"zt" + i}>
|
|
53
53
|
<line x1={t.p.x - 4} y1={t.p.y} x2={t.p.x} y2={t.p.y} stroke="var(--chart-guide)" strokeWidth="1" />
|
|
54
|
-
<text x={t.p.x - 7} y={t.p.y + 3} textAnchor="end" style={{ fontFamily: "var(--font-mono)", fontSize:
|
|
54
|
+
<text x={t.p.x - 7} y={t.p.y + 3} textAnchor="end" style={{ fontFamily: "var(--font-mono)", fontSize: "var(--text-2xs)", fill: "var(--chart-label)" }}>{t.v}</text>
|
|
55
55
|
</g>
|
|
56
56
|
))}
|
|
57
57
|
{quads.map((q, i) => (
|
|
@@ -47,10 +47,10 @@ function fill(q){ return shade(heatColor(q.t), Math.max(-0.35, Math.min(0.3, q.l
|
|
|
47
47
|
<path :d="g.basePath" fill="var(--bg-inset)" stroke="var(--chart-axis)" stroke-width="1"/>
|
|
48
48
|
<line v-for="(ax,i) in g.axes3" :key="'ae'+i" :x1="ax.a.x" :y1="ax.a.y" :x2="ax.b.x" :y2="ax.b.y" stroke="var(--chart-guide)" stroke-width="1"/>
|
|
49
49
|
<text v-for="(ax,i) in g.axes3.filter(a=>a.label)" :key="'al'+i" :x="ax.lp.x" :y="ax.lp.y+3" :text-anchor="ax.anchor"
|
|
50
|
-
style="font-family:var(--font-sans);font-size:
|
|
50
|
+
style="font-family:var(--font-sans);font-size:var(--text-2xs);fill:var(--text-secondary)">{{ ax.label }}</text>
|
|
51
51
|
<g v-for="(t,i) in g.zTicks" :key="'zt'+i">
|
|
52
52
|
<line :x1="t.p.x-4" :y1="t.p.y" :x2="t.p.x" :y2="t.p.y" stroke="var(--chart-guide)" stroke-width="1"/>
|
|
53
|
-
<text :x="t.p.x-7" :y="t.p.y+3" text-anchor="end" style="font-family:var(--font-mono);font-size:
|
|
53
|
+
<text :x="t.p.x-7" :y="t.p.y+3" text-anchor="end" style="font-family:var(--font-mono);font-size:var(--text-2xs);fill:var(--chart-label)">{{ t.v }}</text>
|
|
54
54
|
</g>
|
|
55
55
|
<path v-for="(q,i) in g.quads" :key="i" :d="q.d" :fill="fill(q)" :stroke="wire?'var(--bg-surface)':'none'" stroke-width="0.5"
|
|
56
56
|
@mouseenter="interactive && (hover=q)" @mouseleave="interactive && (hover=null)"/>
|
|
@@ -20,8 +20,8 @@ export function TreemapChart({ items = [], width = 560, height = 260, valueForma
|
|
|
20
20
|
<rect x={c.x + 1} y={c.y + 1} width={Math.max(1, c.w - 2)} height={Math.max(1, c.h - 2)} rx="3" fill={colorOf(c.item)}
|
|
21
21
|
opacity={hover == null ? 0.85 : hover === i ? 1 : 0.35} style={{ transition: "opacity var(--dur-fast) var(--ease-out)" }} />
|
|
22
22
|
{c.w > 74 && c.h > 34 ? <>
|
|
23
|
-
<text x={c.x + 9} y={c.y + 18} style={{ fontFamily: "var(--font-sans)", fontSize:
|
|
24
|
-
<text x={c.x + 9} y={c.y + 32} style={{ fontFamily: "var(--font-mono)", fontSize:
|
|
23
|
+
<text x={c.x + 9} y={c.y + 18} style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-xs)", fill: "var(--on-accent)" }}>{c.item.label}</text>
|
|
24
|
+
<text x={c.x + 9} y={c.y + 32} style={{ fontFamily: "var(--font-mono)", fontSize: "var(--text-2xs)", fill: "var(--on-accent)", opacity: 0.85 }}>{valueFormat(c.item.value)}</text>
|
|
25
25
|
</> : null}
|
|
26
26
|
</g>
|
|
27
27
|
))}
|
|
@@ -14,8 +14,8 @@ const total = computed(() => props.items.reduce((s,i)=>s+i.value,0)||1)
|
|
|
14
14
|
<rect :x="c.x+1" :y="c.y+1" :width="Math.max(1,c.w-2)" :height="Math.max(1,c.h-2)" rx="3" :fill="c.color"
|
|
15
15
|
:opacity="hover==null?.85:hover===i?1:.35" style="transition:opacity var(--dur-fast) var(--ease-out)"/>
|
|
16
16
|
<template v-if="c.w>74 && c.h>34">
|
|
17
|
-
<text :x="c.x+9" :y="c.y+18" style="font-family:var(--font-sans);font-size:
|
|
18
|
-
<text :x="c.x+9" :y="c.y+32" style="font-family:var(--font-mono);font-size:
|
|
17
|
+
<text :x="c.x+9" :y="c.y+18" style="font-family:var(--font-sans);font-size:var(--text-xs);fill:var(--on-accent)">{{ c.item.label }}</text>
|
|
18
|
+
<text :x="c.x+9" :y="c.y+32" style="font-family:var(--font-mono);font-size:var(--text-2xs);fill:var(--on-accent);opacity:.85">{{ valueFormat(c.item.value) }}</text>
|
|
19
19
|
</template>
|
|
20
20
|
</g>
|
|
21
21
|
</svg>
|
|
@@ -38,8 +38,8 @@ export function WaterfallChart({ steps = [], width = 560, height = 260, axes = t
|
|
|
38
38
|
<g key={i} opacity={hover == null || hover === i ? 1 : 0.45} style={{ transition: "opacity var(--dur-fast) var(--ease-out)" }}>
|
|
39
39
|
<rect x={x - bw / 2} y={y} width={bw} height={hgt} rx="2" fill={fill[b.kind]} />
|
|
40
40
|
{i < bars.length - 1 ? <line x1={x + bw / 2} x2={pad.l + slot * (i + 1) + slot / 2 - bw / 2} y1={sy(runEnd)} y2={sy(runEnd)} stroke="var(--chart-guide)" strokeWidth="1" strokeDasharray="2 3" /> : null}
|
|
41
|
-
{showValues ? <text x={x} y={y - 5} textAnchor="middle" style={{ fontFamily: "var(--font-mono)", fontSize:
|
|
42
|
-
<text x={x} y={height - pad.b + 15} textAnchor="middle" style={{ fontFamily: "var(--font-sans)", fontSize:
|
|
41
|
+
{showValues ? <text x={x} y={y - 5} textAnchor="middle" style={{ fontFamily: "var(--font-mono)", fontSize: "var(--text-2xs)", fill: b.kind === "neg" ? "var(--chart-neg)" : "var(--text-heading)" }}>{(b.kind === "pos" ? "+" : "") + valueFormat(b.value)}</text> : null}
|
|
42
|
+
<text x={x} y={height - pad.b + 15} textAnchor="middle" style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-2xs)", fill: "var(--chart-label)" }}>
|
|
43
43
|
{String(b.label).split("\n").map((ln, li) => <tspan key={li} x={x} dy={li ? 11 : 0}>{ln}</tspan>)}
|
|
44
44
|
</text>
|
|
45
45
|
</g>
|
|
@@ -26,14 +26,14 @@ const g = computed(() => {
|
|
|
26
26
|
<template v-if="axes">
|
|
27
27
|
<g v-for="t in g.ticks" :key="t">
|
|
28
28
|
<line :x1="g.pad.l" :x2="width-g.pad.r" :y1="g.sy(t)" :y2="g.sy(t)" :stroke="t===0?'var(--chart-axis)':'var(--chart-grid)'" stroke-width="1"/>
|
|
29
|
-
<text :x="g.pad.l-8" :y="g.sy(t)+3" text-anchor="end" style="font-family:var(--font-mono);font-size:
|
|
29
|
+
<text :x="g.pad.l-8" :y="g.sy(t)+3" text-anchor="end" style="font-family:var(--font-mono);font-size:var(--text-2xs);fill:var(--chart-label)">{{ valueFormat(t) }}</text>
|
|
30
30
|
</g>
|
|
31
31
|
</template>
|
|
32
32
|
<g v-for="(b,i) in g.out" :key="i" :opacity="hover==null||hover===i?1:0.45" style="transition:opacity var(--dur-fast) var(--ease-out)">
|
|
33
33
|
<rect :x="b.x-b.bw/2" :y="b.y" :width="b.bw" :height="b.h" rx="2" :fill="b.fill"/>
|
|
34
34
|
<line v-if="!b.last" :x1="b.x+b.bw/2" :x2="b.nextX" :y1="b.run" :y2="b.run" stroke="var(--chart-guide)" stroke-width="1" stroke-dasharray="2 3"/>
|
|
35
|
-
<text v-if="showValues" :x="b.x" :y="b.y-5" text-anchor="middle" :style="{fontFamily:'var(--font-mono)',fontSize:'
|
|
36
|
-
<text :x="b.x" :y="height-g.pad.b+15" text-anchor="middle" style="font-family:var(--font-sans);font-size:
|
|
35
|
+
<text v-if="showValues" :x="b.x" :y="b.y-5" text-anchor="middle" :style="{fontFamily:'var(--font-mono)',fontSize:'var(--text-2xs)',fill:b.kind==='neg'?'var(--chart-neg)':'var(--text-heading)'}">{{ (b.kind==='pos'?'+':'')+valueFormat(b.value) }}</text>
|
|
36
|
+
<text :x="b.x" :y="height-g.pad.b+15" text-anchor="middle" style="font-family:var(--font-sans);font-size:var(--text-2xs);fill:var(--chart-label)">
|
|
37
37
|
<tspan v-for="(ln,li) in b.lines" :key="li" :x="b.x" :dy="li?11:0">{{ ln }}</tspan>
|
|
38
38
|
</text>
|
|
39
39
|
</g>
|
|
@@ -91,11 +91,11 @@ export function WorldMap({ values = {}, width = 660, height = 340, projection =
|
|
|
91
91
|
</svg>
|
|
92
92
|
{legend ? (
|
|
93
93
|
<div style={{ display: "flex", alignItems: "center", gap: 6, paddingTop: 6, lineHeight: "normal" }}>
|
|
94
|
-
<span style={{ fontFamily: "var(--font-mono)", fontSize:
|
|
94
|
+
<span style={{ fontFamily: "var(--font-mono)", fontSize: "var(--text-2xs)", color: "var(--chart-label)" }}>{valueFormat(lo)}</span>
|
|
95
95
|
{(scale === "diverging" ? ["var(--chart-neg)", "color-mix(in srgb, var(--chart-neg) 40%, var(--bg-surface))", "var(--chart-track)", "color-mix(in srgb, var(--chart-pos) 40%, var(--bg-surface))", "var(--chart-pos)"] : HEAT).map((c, i) => (
|
|
96
96
|
<span key={i} style={{ width: 22, height: 8, borderRadius: 2, background: c }} />
|
|
97
97
|
))}
|
|
98
|
-
<span style={{ fontFamily: "var(--font-mono)", fontSize:
|
|
98
|
+
<span style={{ fontFamily: "var(--font-mono)", fontSize: "var(--text-2xs)", color: "var(--chart-label)" }}>{valueFormat(hi)}{unit ? " " + unit : ""}</span>
|
|
99
99
|
</div>
|
|
100
100
|
) : null}
|
|
101
101
|
{h && interactive ? (
|
|
@@ -61,9 +61,9 @@ const swatches = computed(() => props.scale==='diverging'
|
|
|
61
61
|
<path v-if="hover!=null" :d="paths[hover].d" fill="none" stroke="var(--action-primary)" stroke-width="1.4" pointer-events="none"/>
|
|
62
62
|
</svg>
|
|
63
63
|
<div v-if="legend" style="display:flex;align-items:center;gap:6px;padding-top:6px;line-height:normal">
|
|
64
|
-
<span style="font-family:var(--font-mono);font-size:
|
|
64
|
+
<span style="font-family:var(--font-mono);font-size:var(--text-2xs);color:var(--chart-label)">{{ valueFormat(lo) }}</span>
|
|
65
65
|
<span v-for="(c,i) in swatches" :key="i" :style="{width:'22px',height:'8px',borderRadius:'2px',background:c}"/>
|
|
66
|
-
<span style="font-family:var(--font-mono);font-size:
|
|
66
|
+
<span style="font-family:var(--font-mono);font-size:var(--text-2xs);color:var(--chart-label)">{{ valueFormat(hi) }}{{ unit ? ' '+unit : '' }}</span>
|
|
67
67
|
</div>
|
|
68
68
|
<div v-if="hover!=null && interactive" :style="{position:'absolute',left:paths[hover].c[0]+'px',top:paths[hover].c[1]+'px',transform:paths[hover].c[0]>width*0.62?'translate(calc(-100% - 10px),-50%)':'translate(10px,-50%)',pointerEvents:'none',zIndex:5,background:'var(--bg-surface)',border:'1px solid var(--border-card)',borderRadius:'var(--radius-md)',boxShadow:'var(--shadow-menu)',padding:'7px 10px',lineHeight:'normal',whiteSpace:'nowrap'}">
|
|
69
69
|
<div style="font-family:var(--font-sans);font-size:var(--text-2xs);color:var(--text-muted);padding-bottom:3px">{{ paths[hover].name }}</div>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
// Thin x-axis category labels only (small charts with no y axis). Render inside an <svg>.
|
|
3
|
+
defineProps({ h: Number, pad: Object, xLabels: { type: Array, default: () => [] }, sxLabel: Function })
|
|
4
|
+
</script>
|
|
5
|
+
<template>
|
|
6
|
+
<g>
|
|
7
|
+
<template v-for="(lb, i) in xLabels" :key="i">
|
|
8
|
+
<text v-if="lb != null" :x="sxLabel(i)" :y="h - pad.b + 16" text-anchor="middle" style="font-family:var(--font-sans);font-size:var(--text-2xs);fill:var(--chart-label)">{{ lb }}</text>
|
|
9
|
+
</template>
|
|
10
|
+
</g>
|
|
11
|
+
</template>
|
|
@@ -9,7 +9,7 @@ export function CodeBlock({ code = "", language, height, style }) {
|
|
|
9
9
|
<div style={{ background: "var(--bg-inset)", border: "1px solid var(--border-subtle)", borderRadius: "var(--radius-md)", ...style }}>
|
|
10
10
|
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", padding: "7px 10px", borderBottom: "1px solid var(--border-subtle)" }}>
|
|
11
11
|
<span style={{ fontFamily: "var(--font-mono)", fontSize: "var(--text-xs)", color: "var(--text-muted)" }}>{language || "code"}</span>
|
|
12
|
-
<button type="button" onClick={copy} style={{ display: "flex", alignItems: "center", gap: 4, border: "none", background: "transparent", cursor: "pointer", color: copied ? "var(--success-strong)" : "var(--text-secondary)", fontFamily: "var(--font-sans)", fontSize: "var(--text-xs)", padding: 0 }}>
|
|
12
|
+
<button type="button" onClick={copy} data-ink="" style={{ display: "flex", alignItems: "center", gap: 4, border: "none", background: "transparent", cursor: "pointer", color: copied ? "var(--success-strong)" : "var(--ink, var(--text-secondary))", fontFamily: "var(--font-sans)", fontSize: "var(--text-xs)", padding: 0 }}>
|
|
13
13
|
<Icon name={copied ? "check" : "copy"} size={12} />{copied ? "Copied" : "Copy"}
|
|
14
14
|
</button>
|
|
15
15
|
</div>
|
|
@@ -13,7 +13,7 @@ function copy() {
|
|
|
13
13
|
<div :style="{ background: 'var(--bg-inset)', border: '1px solid var(--border-subtle)', borderRadius: 'var(--radius-md)', ...style }">
|
|
14
14
|
<div style="display:flex;justify-content:space-between;align-items:center;padding:7px 10px;border-bottom:1px solid var(--border-subtle)">
|
|
15
15
|
<span style="font-family:var(--font-mono);font-size:var(--text-xs);color:var(--text-muted)">{{ language || 'code' }}</span>
|
|
16
|
-
<button type="button" @click="copy" :style="{ display: 'flex', alignItems: 'center', gap:
|
|
16
|
+
<button type="button" @click="copy" data-ink="" :style="{ display: 'flex', alignItems: 'center', gap: '4px', border: 'none', background: 'transparent', cursor: 'pointer', color: copied ? 'var(--success-strong)' : 'var(--ink, var(--text-secondary))', fontFamily: 'var(--font-sans)', fontSize: 'var(--text-xs)', padding: 0 }">
|
|
17
17
|
<Icon :name="copied ? 'check' : 'copy'" :size="12" />{{ copied ? 'Copied' : 'Copy' }}
|
|
18
18
|
</button>
|
|
19
19
|
</div>
|