@taylorwong/ichartjs 2.0.6 → 2.0.8
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/CHANGELOG.md +13 -0
- package/README.md +2 -2
- package/agent-recipes/minimal-specs.json +25 -0
- package/docs/agent/README.md +3 -1
- package/docs/agent/charting-scenario.md +46 -1
- package/docs/agent/coding-agent-integration.md +1 -1
- package/docs/agent/development/iteration-12.md +101 -0
- package/docs/agent/development/roadmap.md +2 -1
- package/docs/agent/development-guide.md +1 -1
- package/docs/agent/diagram-scenario.md +39 -11
- package/docs/agent/editing-contract.md +5 -0
- package/docs/agent/frontend-integration.md +1 -1
- package/docs/agent/project-scenario.md +1 -0
- package/docs/agent/quickstart.md +30 -0
- package/docs/agent/runtime-contract.md +19 -2
- package/docs/agent/theme-guide.md +33 -1
- package/docs/agent/usage-scenarios.md +3 -1
- package/docs/agent/zh-CN/README.md +1 -1
- package/docs/agent/zh-CN/charting-scenario.md +31 -1
- package/docs/agent/zh-CN/coding-agent-integration.md +1 -1
- package/docs/agent/zh-CN/diagram-scenario.md +32 -3
- package/docs/agent/zh-CN/editing-contract.md +2 -0
- package/docs/agent/zh-CN/frontend-integration.md +1 -1
- package/docs/agent/zh-CN/iteration-12.md +98 -0
- package/docs/agent/zh-CN/quickstart.md +30 -0
- package/docs/agent/zh-CN/runtime-contract.md +7 -1
- package/docs/agent/zh-CN/theme-guide.md +33 -1
- package/docs/agent/zh-CN/usage-scenarios.md +3 -1
- package/docs/manifests/capabilities.json +42 -3
- package/docs/manifests/commands.json +10 -9
- package/docs/manifests/schemas.json +5 -2
- package/examples/agent-workflow.mjs +2 -1
- package/package.json +1 -1
- package/skills/ichartjs/SKILL.md +19 -9
- package/skills/ichartjs/references/agent-contract.md +5 -2
- package/skills/ichartjs/references/chart-selection.md +2 -0
- package/src/capabilities.mjs +83 -13
- package/src/charts.mjs +202 -58
- package/src/command.mjs +4 -3
- package/src/diagram-interaction.mjs +55 -11
- package/src/diagram.mjs +149 -36
- package/src/edit-controller.mjs +6 -3
- package/src/edit.mjs +17 -7
- package/src/index.mjs +44 -17
- package/src/layout.mjs +39 -0
- package/src/preferences-ui.mjs +73 -24
- package/src/project.mjs +64 -24
- package/src/renderer.mjs +2 -2
- package/src/scene.mjs +32 -1
- package/src/schema.mjs +7 -2
- package/src/spec.mjs +88 -6
- package/src/theme.mjs +1 -1
- package/types/index.d.ts +28 -7
|
@@ -11,11 +11,11 @@ getCapabilities → inspectData → planChart → build Spec → validateSpec
|
|
|
11
11
|
- `getCapabilities()`: global and per-chart discoverability.
|
|
12
12
|
- `getChartCapability(type)`: required roles, interactions, renderers, features, exports, and limits.
|
|
13
13
|
- `inspectData(input)`: field roles, identifiers, cardinality, missingness, temporal coverage, and warnings.
|
|
14
|
-
- `planChart(input, options)`: primary type, alternatives, confidence, reasons, required fields, suggested encodings, assumptions, warnings, unsupported requests, and
|
|
14
|
+
- `planChart(input, options)`: primary type, alternatives, confidence, reasons, required fields, suggested encodings, assumptions, warnings, unsupported requests, next actions, and `intentKnown`/`intentSuggestions`/`fallbackUsed` metadata.
|
|
15
15
|
- `validateSpec(spec)`: errors, warnings, normalizations, and normalized Spec.
|
|
16
16
|
- `createChart(spec)`: headless or mounted chart lifecycle.
|
|
17
17
|
- `chart.explain()`: semantics, encodings, interactions, lineage, warnings, and accessibility summary.
|
|
18
|
-
- `chart.getState()`: renderer, dimensions, warnings, assumptions, selection, view, project analytics,
|
|
18
|
+
- `chart.getState()`: renderer, dimensions, warnings, assumptions, selection, view, project analytics, linked state, and `health`.
|
|
19
19
|
- `chart.export({ type: 'json' })`: JSON-safe Spec and state.
|
|
20
20
|
|
|
21
21
|
## Stop conditions
|
|
@@ -24,6 +24,8 @@ Do not render when:
|
|
|
24
24
|
|
|
25
25
|
- `plan.requiredFields` is non-empty;
|
|
26
26
|
- `validateSpec().valid` is false;
|
|
27
|
+
- chart-specific encoding channels are unsupported or reference missing fields;
|
|
28
|
+
- a Gauge has no explicit `domain`;
|
|
27
29
|
- the requested chart, renderer, interaction, or export is not declared;
|
|
28
30
|
- required project dates, diagram endpoints, ports, lanes, or business schema rules are invalid.
|
|
29
31
|
|
|
@@ -35,5 +37,6 @@ Verify that:
|
|
|
35
37
|
- validation passed without ignored errors;
|
|
36
38
|
- explanation lineage preserves stable source IDs;
|
|
37
39
|
- warnings and assumptions are visible in the response;
|
|
40
|
+
- `health.renderable` is true and `health.status` is reported; `VALUE_CLAMPED`, `LABELS_SUPPRESSED`, and `ZERO_TOTAL` are not hidden;
|
|
38
41
|
- the preview uses a maintained URL;
|
|
39
42
|
- replaced charts are destroyed.
|
|
@@ -20,3 +20,5 @@
|
|
|
20
20
|
| Responsibility | Swimlane | Require valid lane membership. |
|
|
21
21
|
|
|
22
22
|
Always prefer `planChart()` over this table when runtime capability output is available. Treat alternatives as tradeoffs, not automatic fallbacks.
|
|
23
|
+
|
|
24
|
+
`planChart()` accepts the exact registered intent token, not the user's full sentence. For example, map “show the sales trend over time” to `trend`; if an unknown token is passed, inspect and surface the returned `UNKNOWN_INTENT` warning instead of accepting the fallback silently.
|
package/src/capabilities.mjs
CHANGED
|
@@ -3,12 +3,13 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { inspectData } from './data.mjs';
|
|
5
5
|
import { planStyle, styleCapabilities } from './theme.mjs';
|
|
6
|
+
import { defaultPreferences, preferenceDensities, preferenceMotions, preferenceTriStates } from './preferences.mjs';
|
|
6
7
|
|
|
7
|
-
export const chartTypes = ['line', 'area', 'bar', 'column', 'pie', 'scatter', 'funnel', 'gauge', 'heatmap', 'radar', 'gantt', 'timeline', 'milestone', 'burndown', 'flow', 'swimlane'];
|
|
8
|
+
export const chartTypes = ['line', 'area', 'bar', 'column', 'pie', 'scatter', 'funnel', 'gauge', 'heatmap', 'radar', 'gantt', 'timeline', 'milestone', 'burndown', 'flow', 'swimlane', 'architecture', 'mindmap'];
|
|
8
9
|
|
|
9
10
|
const cartesian = ['line', 'area', 'bar', 'column', 'scatter'];
|
|
10
11
|
const project = ['gantt', 'timeline', 'milestone', 'burndown'];
|
|
11
|
-
const diagrams = ['flow', 'swimlane'];
|
|
12
|
+
const diagrams = ['flow', 'swimlane', 'architecture', 'mindmap'];
|
|
12
13
|
const status = (supported, notApplicable = []) => Object.fromEntries(supported.map(name => [name, 'supported']).concat(notApplicable.map(name => [name, 'not-applicable'])));
|
|
13
14
|
const commonPresentation = ['title', 'subtitle', 'theme', 'responsive', 'empty-state', 'invalid-data-state', 'export', 'branding'];
|
|
14
15
|
|
|
@@ -27,8 +28,10 @@ const definitions = {
|
|
|
27
28
|
timeline: { family: 'project', intents: ['timeline', 'milestone'], required: ['date', 'label'], optional: ['status'], interactions: ['hover', 'tooltip', 'selection', 'zoom', 'pan', 'keyboard'], features: status([...commonPresentation, 'labels', 'formatting']) },
|
|
28
29
|
milestone: { family: 'project', intents: ['milestone'], required: ['date', 'label'], optional: ['baseline', 'actual'], interactions: ['hover', 'tooltip', 'selection', 'zoom', 'pan', 'keyboard'], features: status([...commonPresentation, 'labels', 'formatting', 'baseline-actual-variance']) },
|
|
29
30
|
burndown: { family: 'project', intents: ['progress', 'release'], required: ['date', 'remaining'], optional: ['ideal', 'scopeChange'], interactions: ['hover', 'tooltip', 'selection', 'zoom', 'pan', 'keyboard'], features: status([...commonPresentation, 'axes', 'labels', 'formatting', 'scope-change', 'release-forecast']) },
|
|
30
|
-
flow: { family: 'diagram', intents: ['workflow'], required: ['nodes'], optional: ['edges', 'groups', 'ports'], interactions: ['hover', 'selection', 'drag', 'keyboard-edit', 'keyboard-port-connect', '
|
|
31
|
-
swimlane: { family: 'diagram', intents: ['responsibility'], required: ['nodes', 'lanes'], optional: ['edges', 'groups', 'ports'], interactions: ['hover', 'selection', 'drag', 'keyboard-edit', 'keyboard-port-connect', '
|
|
31
|
+
flow: { family: 'diagram', intents: ['workflow'], required: ['nodes'], optional: ['edges', 'groups', 'ports'], interactions: ['hover', 'tooltip', 'selection', 'edge-selection', 'drag', 'edgeDrag', 'zoom', 'pan', 'keyboard', 'keyboard-edit', 'keyboard-port-connect', 'portConnect', 'copy-paste'], features: status([...commonPresentation, 'labels', 'routing', 'manual-routing', 'layout', 'groups', 'ports', 'history'], ['axes', 'grid', 'legend']) },
|
|
32
|
+
swimlane: { family: 'diagram', intents: ['responsibility'], required: ['nodes', 'lanes'], optional: ['edges', 'groups', 'ports'], interactions: ['hover', 'tooltip', 'selection', 'edge-selection', 'drag', 'edgeDrag', 'zoom', 'pan', 'keyboard', 'keyboard-edit', 'keyboard-port-connect', 'portConnect', 'copy-paste'], features: status([...commonPresentation, 'labels', 'routing', 'manual-routing', 'layout', 'groups', 'ports', 'lanes', 'history'], ['axes', 'grid', 'legend']) },
|
|
33
|
+
architecture: { family: 'diagram', intents: ['architecture', 'business-architecture', 'data-architecture', 'technical-architecture'], required: ['nodes'], optional: ['edges', 'layers', 'boundaries', 'groups', 'ports'], interactions: ['hover', 'tooltip', 'selection', 'edge-selection', 'drag', 'edgeDrag', 'zoom', 'pan', 'keyboard', 'keyboard-edit', 'keyboard-port-connect', 'portConnect', 'copy-paste'], features: status([...commonPresentation, 'labels', 'routing', 'manual-routing', 'layout', 'layers', 'boundaries', 'groups', 'ports', 'history'], ['axes', 'grid', 'legend']) },
|
|
34
|
+
mindmap: { family: 'diagram', intents: ['mindmap', 'hierarchy', 'brainstorm'], required: ['nodes'], optional: ['parentId', 'edges', 'groups'], interactions: ['hover', 'tooltip', 'selection', 'edge-selection', 'drag', 'edgeDrag', 'zoom', 'pan', 'keyboard', 'keyboard-edit', 'keyboard-port-connect', 'portConnect', 'copy-paste'], features: status([...commonPresentation, 'labels', 'routing', 'cubic-bezier', 'curve-tension', 'obstacle-fallback', 'manual-routing', 'layout', 'tree-layout', 'radial-layout', 'history'], ['axes', 'grid', 'legend']) }
|
|
32
35
|
};
|
|
33
36
|
|
|
34
37
|
export const chartProfiles = Object.fromEntries(chartTypes.map(type => [type, {
|
|
@@ -41,27 +44,87 @@ export const chartProfiles = Object.fromEntries(chartTypes.map(type => [type, {
|
|
|
41
44
|
}]));
|
|
42
45
|
|
|
43
46
|
const intentMap = {
|
|
44
|
-
schedule: 'gantt', variance: 'gantt', timeline: 'timeline', milestone: 'milestone', progress: 'burndown', release: 'burndown', capacity: 'column', risk: 'scatter', aging: 'bar', matrix: 'heatmap', 'correlation-grid': 'heatmap', multidimensional: 'radar', profile: 'radar', workflow: 'flow', responsibility: 'swimlane', trend: 'line', 'time-series': 'line', 'part-to-whole': 'pie', distribution: 'column', relationship: 'scatter', correlation: 'scatter', funnel: 'funnel', conversion: 'funnel', 'single-value': 'gauge', ranking: 'bar', comparison: 'bar', composition: 'column'
|
|
47
|
+
schedule: 'gantt', variance: 'gantt', timeline: 'timeline', milestone: 'milestone', progress: 'burndown', release: 'burndown', capacity: 'column', risk: 'scatter', aging: 'bar', matrix: 'heatmap', 'correlation-grid': 'heatmap', multidimensional: 'radar', profile: 'radar', workflow: 'flow', responsibility: 'swimlane', architecture: 'architecture', 'business-architecture': 'architecture', 'data-architecture': 'architecture', 'technical-architecture': 'architecture', mindmap: 'mindmap', hierarchy: 'mindmap', brainstorm: 'mindmap', trend: 'line', 'time-series': 'line', 'part-to-whole': 'pie', distribution: 'column', relationship: 'scatter', correlation: 'scatter', funnel: 'funnel', conversion: 'funnel', 'single-value': 'gauge', ranking: 'bar', comparison: 'bar', composition: 'column'
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const intentAliases = {
|
|
51
|
+
trend: ['trend', 'time-series'], time: ['trend', 'time-series'], compare: ['comparison', 'ranking'], rank: ['ranking', 'comparison'],
|
|
52
|
+
distribution: ['distribution', 'comparison'], relationship: ['relationship', 'correlation'], correlation: ['correlation', 'relationship'],
|
|
53
|
+
matrix: ['matrix', 'correlation-grid'], profile: ['multidimensional', 'profile'], architecture: ['architecture', 'business-architecture', 'data-architecture', 'technical-architecture'],
|
|
54
|
+
mind: ['mindmap', 'hierarchy', 'brainstorm']
|
|
45
55
|
};
|
|
46
56
|
|
|
47
57
|
const alternatives = {
|
|
48
|
-
heatmap: ['scatter', 'column'], radar: ['bar', 'line'], gantt: ['timeline', 'milestone'], timeline: ['milestone', 'gantt'], milestone: ['timeline', 'gantt'], burndown: ['line', 'gantt'], column: ['bar', 'line'], scatter: ['bar', 'line'], bar: ['column', 'line'], flow: ['swimlane', '
|
|
58
|
+
heatmap: ['scatter', 'column'], radar: ['bar', 'line'], gantt: ['timeline', 'milestone'], timeline: ['milestone', 'gantt'], milestone: ['timeline', 'gantt'], burndown: ['line', 'gantt'], column: ['bar', 'line'], scatter: ['bar', 'line'], bar: ['column', 'line'], flow: ['swimlane', 'architecture'], swimlane: ['flow', 'architecture'], architecture: ['flow', 'mindmap'], mindmap: ['architecture', 'flow'], line: ['area', 'column'], pie: ['bar', 'column'], funnel: ['bar', 'column'], gauge: ['column', 'bar']
|
|
49
59
|
};
|
|
50
60
|
|
|
51
61
|
function warning(code, path, message, suggestion) { return { code, path, message, ...(suggestion ? { suggestion } : {}) }; }
|
|
52
62
|
|
|
63
|
+
function suggestIntents(requested) {
|
|
64
|
+
const value = String(requested || '').trim().toLowerCase();
|
|
65
|
+
if (!value) return ['comparison'];
|
|
66
|
+
if (intentAliases[value]) return intentAliases[value];
|
|
67
|
+
const tokens = value.split(/[^a-z0-9-]+/).filter(Boolean);
|
|
68
|
+
return [...new Set(tokens.flatMap(token => intentAliases[token] || (intentMap[token] ? [token] : [])))].slice(0, 5);
|
|
69
|
+
}
|
|
70
|
+
|
|
53
71
|
export function getChartCapability(type) {
|
|
54
72
|
return chartProfiles[type] ? JSON.parse(JSON.stringify(chartProfiles[type])) : null;
|
|
55
73
|
}
|
|
56
74
|
|
|
75
|
+
const preferenceMessages = {
|
|
76
|
+
en: {
|
|
77
|
+
groups: { theme: 'Theme', typography: 'Typography', components: 'Components', behavior: 'Behavior' },
|
|
78
|
+
fields: { mode: 'Theme', preset: 'Style preset', palette: 'Palette', scale: 'Font size', density: 'Density', legend: 'Legend', labels: 'Data labels', grid: 'Grid lines', branding: 'Branding', motion: 'Motion' },
|
|
79
|
+
descriptions: { mode: 'Select automatic, light, dark, or high-contrast rendering.', preset: 'Select a semantic visual preset.', palette: 'Select a semantic color palette.', scale: 'Scale chart typography without changing business data.', density: 'Adjust chart spacing and padding density.', legend: 'Show, hide, or automatically resolve the legend.', labels: 'Show, hide, or automatically resolve data labels.', grid: 'Show, hide, or automatically resolve grid lines.', branding: 'Control the Powered by iChart.js signature.', motion: 'Control animation and motion preference.' },
|
|
80
|
+
options: { auto: 'Auto', light: 'Light', dark: 'Dark', contrast: 'High contrast', analysis: 'Analysis', dashboard: 'Dashboard', report: 'Report', presentation: 'Presentation', project: 'Project', diagram: 'Diagram', categorical: 'Categorical', sequential: 'Sequential', diverging: 'Diverging', status: 'Status', compact: 'Compact', comfortable: 'Comfortable', spacious: 'Spacious', full: 'Full', reduced: 'Reduced', off: 'Off', true: 'Show', false: 'Hide', '0.85': 'Small', '1': 'Default', '1.15': 'Large', '1.3': 'Extra large' }
|
|
81
|
+
},
|
|
82
|
+
'zh-CN': {
|
|
83
|
+
groups: { theme: '主题', typography: '排版', components: '显示内容', behavior: '行为' },
|
|
84
|
+
fields: { mode: '主题', preset: '样式预设', palette: '配色', scale: '字号', density: '布局密度', legend: '图例', labels: '数据标签', grid: '网格线', branding: '品牌署名', motion: '动效' },
|
|
85
|
+
descriptions: { mode: '选择自动、浅色、深色或高对比度主题。', preset: '选择语义化视觉预设。', palette: '选择语义化配色方案。', scale: '在不改变业务数据的情况下缩放图表字体。', density: '调整图表间距与内边距密度。', legend: '显示、隐藏或自动判断图例。', labels: '显示、隐藏或自动判断数据标签。', grid: '显示、隐藏或自动判断网格线。', branding: '控制 Powered by iChart.js 品牌署名。', motion: '控制动画和动效偏好。' },
|
|
86
|
+
options: { auto: '自动', light: '浅色', dark: '深色', contrast: '高对比度', analysis: '分析', dashboard: '仪表盘', report: '报告', presentation: '演示', project: '项目', diagram: '图表结构', categorical: '分类', sequential: '渐变', diverging: '发散', status: '状态', compact: '紧凑', comfortable: '舒适', spacious: '宽松', full: '完整', reduced: '减少', off: '关闭', true: '显示', false: '隐藏', '0.85': '小', '1': '默认', '1.15': '大', '1.3': '特大' }
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
function preferenceLocale(locale) {
|
|
91
|
+
const normalized = String(locale || 'en').toLowerCase();
|
|
92
|
+
return normalized === 'zh' || normalized.startsWith('zh-') ? 'zh-CN' : 'en';
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function getPreferenceCapabilities(chartType = null, { locale = 'en' } = {}) {
|
|
96
|
+
const resolvedLocale = preferenceLocale(locale), text = preferenceMessages[resolvedLocale], profile = chartType ? chartProfiles[chartType] || null : null;
|
|
97
|
+
const option = value => ({ value, label: text.options[String(value ?? 'auto')] || String(value ?? 'auto') });
|
|
98
|
+
const feature = name => chartType == null ? { supported: true, applicability: 'chart-dependent' } : { supported: profile?.features?.[name] === 'supported', applicability: profile?.features?.[name] || 'not-applicable' };
|
|
99
|
+
const scopes = ['global', 'chart'];
|
|
100
|
+
const field = ({ path, group, key, type, values, defaultValue, menu = false, control = 'select', support = { supported: true, applicability: 'all-charts' }, minimum, maximum }) => ({
|
|
101
|
+
path, group, groupLabel: text.groups[group], type, label: text.fields[key], description: text.descriptions[key], default: defaultValue, options: values.map(option), scopes: [...scopes], supported: support.supported, applicability: support.applicability, menu: { visible: menu && support.supported, control }, ...(minimum == null ? {} : { minimum }), ...(maximum == null ? {} : { maximum })
|
|
102
|
+
});
|
|
103
|
+
const fields = [
|
|
104
|
+
field({ path: 'theme.mode', group: 'theme', key: 'mode', type: 'enum', values: [null, ...styleCapabilities.modes.filter(value => value !== 'auto')], defaultValue: defaultPreferences.theme.mode, menu: true }),
|
|
105
|
+
field({ path: 'theme.preset', group: 'theme', key: 'preset', type: 'enum', values: [null, ...styleCapabilities.presets.filter(value => value !== 'auto')], defaultValue: defaultPreferences.theme.preset }),
|
|
106
|
+
field({ path: 'theme.palette', group: 'theme', key: 'palette', type: 'enum', values: [null, ...styleCapabilities.palettes.filter(value => value !== 'auto')], defaultValue: defaultPreferences.theme.palette, menu: true }),
|
|
107
|
+
field({ path: 'typography.scale', group: 'typography', key: 'scale', type: 'number', values: [0.85, 1, 1.15, 1.3], defaultValue: defaultPreferences.typography.scale, menu: true, minimum: 0.75, maximum: 1.5 }),
|
|
108
|
+
field({ path: 'density', group: 'typography', key: 'density', type: 'enum', values: preferenceDensities, defaultValue: defaultPreferences.density }),
|
|
109
|
+
field({ path: 'components.legend', group: 'components', key: 'legend', type: 'tri-state', values: preferenceTriStates, defaultValue: defaultPreferences.components.legend, menu: true, control: 'toggle', support: feature('legend') }),
|
|
110
|
+
field({ path: 'components.labels', group: 'components', key: 'labels', type: 'tri-state', values: preferenceTriStates, defaultValue: defaultPreferences.components.labels, menu: true, control: 'toggle', support: feature('labels') }),
|
|
111
|
+
field({ path: 'components.grid', group: 'components', key: 'grid', type: 'tri-state', values: preferenceTriStates, defaultValue: defaultPreferences.components.grid, menu: true, control: 'toggle', support: feature('grid') }),
|
|
112
|
+
field({ path: 'branding.enabled', group: 'components', key: 'branding', type: 'tri-state', values: preferenceTriStates, defaultValue: defaultPreferences.branding.enabled }),
|
|
113
|
+
field({ path: 'motion', group: 'behavior', key: 'motion', type: 'enum', values: preferenceMotions, defaultValue: defaultPreferences.motion })
|
|
114
|
+
];
|
|
115
|
+
return { version: '1.0', locale: resolvedLocale, chartType: profile?.type || null, scopes, persistence: ['memory', 'localStorage', 'adapter'], precedence: ['defaults', 'global', 'chart', 'temporary-agent-patch'], fields };
|
|
116
|
+
}
|
|
117
|
+
|
|
57
118
|
export function planChart(input, options = {}) {
|
|
58
119
|
const report = inspectData(input);
|
|
59
120
|
const requestedIntent = options.intent || 'comparison';
|
|
60
121
|
const warnings = [...report.warnings];
|
|
122
|
+
const intentKnown = Boolean(intentMap[requestedIntent]);
|
|
123
|
+
const intentSuggestions = intentKnown ? [] : suggestIntents(requestedIntent);
|
|
61
124
|
let primary = intentMap[requestedIntent];
|
|
62
125
|
if (!primary) {
|
|
63
126
|
primary = report.fields.some(field => field.type === 'temporal') ? 'line' : report.measures.length >= 2 && report.dimensions.length === 0 ? 'scatter' : 'bar';
|
|
64
|
-
warnings.push(warning('UNKNOWN_INTENT', 'intent', `Intent ${requestedIntent} is not registered.`, 'Use an intent returned by getCapabilities().intents.'));
|
|
127
|
+
warnings.push(warning('UNKNOWN_INTENT', 'intent', `Intent ${requestedIntent} is not registered.`, intentSuggestions.length ? `Use one of: ${intentSuggestions.join(', ')}.` : 'Use an intent returned by getCapabilities().intents.'));
|
|
65
128
|
}
|
|
66
129
|
const profile = chartProfiles[primary];
|
|
67
130
|
const requiredFields = [];
|
|
@@ -92,6 +155,9 @@ export function planChart(input, options = {}) {
|
|
|
92
155
|
return {
|
|
93
156
|
version: '1.0',
|
|
94
157
|
intent: requestedIntent,
|
|
158
|
+
intentKnown,
|
|
159
|
+
intentSuggestions,
|
|
160
|
+
fallbackUsed: !intentKnown,
|
|
95
161
|
primary,
|
|
96
162
|
alternatives: alternatives[primary] || ['column', 'line'],
|
|
97
163
|
confidence,
|
|
@@ -124,6 +190,7 @@ export function explainChart(spec, model = {}) {
|
|
|
124
190
|
interactions: Object.keys(spec.interaction || {}).filter(key => spec.interaction[key]),
|
|
125
191
|
assumptions: [...(model.data?.assumptions || []), ...(model.state?.projectAnalytics?.assumptions || [])],
|
|
126
192
|
warnings,
|
|
193
|
+
axes: model.state?.axes || null,
|
|
127
194
|
style: spec.theme && typeof spec.theme === 'object' ? { name: spec.theme.name, preset: spec.theme.preset, mode: spec.theme.mode, resolvedMode: spec.theme.resolvedMode, palette: spec.theme.palette, reasons: spec.theme.reasons || [], warnings: spec.theme.warnings || [] } : planStyle(spec),
|
|
128
195
|
lineage: { recordIds: (model.data?.rows || []).map((row, index) => String(row.id ?? row.key ?? `record-${index}`)), sourcePreserved: true },
|
|
129
196
|
accessibility: { enabled: Boolean(spec.accessibility?.enabled), summary: spec.accessibility?.description || spec.title?.text || `${spec.type} chart with ${model.data?.rows?.length || 0} data items.` }
|
|
@@ -132,6 +199,7 @@ export function explainChart(spec, model = {}) {
|
|
|
132
199
|
|
|
133
200
|
export function getCapabilities() {
|
|
134
201
|
const intents = [...new Set(Object.values(chartProfiles).flatMap(profile => profile.intents))];
|
|
202
|
+
const preferenceCapabilities = getPreferenceCapabilities();
|
|
135
203
|
const exp = {
|
|
136
204
|
types: ['png', 'jpeg', 'svg', 'json'],
|
|
137
205
|
mime: { png: 'image/png', jpeg: 'image/jpeg', svg: 'image/svg+xml', json: 'application/json' },
|
|
@@ -161,10 +229,11 @@ export function getCapabilities() {
|
|
|
161
229
|
chartTypes,
|
|
162
230
|
charts: JSON.parse(JSON.stringify(chartProfiles)),
|
|
163
231
|
intents,
|
|
164
|
-
|
|
232
|
+
locale: { default: 'en-US', recommended: ['en-US', 'zh-CN'], appliesTo: ['axis', 'labels', 'tooltip', 'export'], inputDates: 'ISO-8601 strings; natural-language date parsing is not supported.' },
|
|
233
|
+
chartModes: { stack: ['stacked', 'percent'], pie: ['standard', 'donut'], composition: ['multi-series', 'mixed-line-column', 'dual-axis'], transforms: ['bin'], diagrams: ['process', 'architecture', 'mindmap'], mindmapLayouts: ['tree', 'radial'], mindmapEdges: ['curved', 'straight', 'orthogonal'] },
|
|
165
234
|
projectManagement: project,
|
|
166
235
|
projectIntelligence: {
|
|
167
|
-
intents: ['schedule', 'milestone', 'progress', 'variance', 'capacity', 'release', 'risk', 'aging', 'workflow', 'responsibility'],
|
|
236
|
+
intents: ['schedule', 'milestone', 'progress', 'variance', 'capacity', 'release', 'risk', 'aging', 'workflow', 'responsibility', 'architecture', 'mindmap'],
|
|
168
237
|
views: ['gantt', 'burndown', 'column', 'area', 'scatter', 'bar'],
|
|
169
238
|
analytics: ['calendar', 'dependency-normalization', 'critical-path', 'slack', 'baseline-actual-variance', 'capacity', 'cumulative-flow', 'velocity', 'release-forecast', 'risk-matrix', 'issue-aging'],
|
|
170
239
|
linkedState: ['owner', 'status', 'priority', 'sprint', 'label'],
|
|
@@ -186,12 +255,13 @@ export function getCapabilities() {
|
|
|
186
255
|
styleSystem: JSON.parse(JSON.stringify(styleCapabilities)),
|
|
187
256
|
preferences: {
|
|
188
257
|
version: '1.0',
|
|
189
|
-
scopes:
|
|
190
|
-
persistence:
|
|
191
|
-
fields:
|
|
258
|
+
scopes: preferenceCapabilities.scopes,
|
|
259
|
+
persistence: preferenceCapabilities.persistence,
|
|
260
|
+
fields: preferenceCapabilities.fields.map(field => field.path),
|
|
192
261
|
agentAdjustable: true,
|
|
193
262
|
interactiveSettingsUI: true,
|
|
194
|
-
precedence:
|
|
263
|
+
precedence: preferenceCapabilities.precedence,
|
|
264
|
+
schema: preferenceCapabilities
|
|
195
265
|
},
|
|
196
266
|
plugins: true,
|
|
197
267
|
branding: { defaultEnabled: true, signature: 'Powered by iChart.js', options: [{ name: 'enabled', type: 'boolean', default: true }] },
|