pmx-canvas 0.1.10 → 0.1.12

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.
@@ -84,6 +84,8 @@ interface PieChartProps {
84
84
  nameKey: string;
85
85
  valueKey: string;
86
86
  height?: number | null;
87
+ showLegend?: boolean | null;
88
+ showLabels?: boolean | null;
87
89
  }
88
90
 
89
91
  export const axisStyle = {
@@ -99,6 +101,11 @@ export const tooltipStyle = {
99
101
  fontSize: 13,
100
102
  };
101
103
 
104
+ export const chartMargin = { top: 14, right: 28, bottom: 28, left: 10 };
105
+ export const polarChartMargin = { top: 18, right: 40, bottom: 30, left: 40 };
106
+ export const axisTickMargin = 8;
107
+ export const legendMargin = { top: 10 };
108
+
102
109
  /** Shared wrapper for cartesian charts (Line + Bar). */
103
110
  export function CartesianChart({
104
111
  props,
@@ -127,10 +134,10 @@ function ChartLineChart({ props }: BaseComponentProps<CartesianChartProps>) {
127
134
  return (
128
135
  <CartesianChart props={props} className="pmx-chart--line">
129
136
  {(data) => (
130
- <RechartsLineChart data={data}>
137
+ <RechartsLineChart data={data} margin={chartMargin}>
131
138
  <CartesianGrid strokeDasharray="3 3" stroke="var(--border, #e5e5e5)" />
132
- <XAxis dataKey={props.xKey} tick={axisStyle} />
133
- <YAxis tick={axisStyle} />
139
+ <XAxis dataKey={props.xKey} tick={axisStyle} tickMargin={axisTickMargin} />
140
+ <YAxis tick={axisStyle} tickMargin={axisTickMargin} />
134
141
  <Tooltip contentStyle={tooltipStyle} />
135
142
  <Line
136
143
  type="monotone"
@@ -151,10 +158,10 @@ function ChartBarChart({ props }: BaseComponentProps<CartesianChartProps>) {
151
158
  return (
152
159
  <CartesianChart props={props} className="pmx-chart--bar">
153
160
  {(data) => (
154
- <RechartsBarChart data={data}>
161
+ <RechartsBarChart data={data} margin={chartMargin}>
155
162
  <CartesianGrid strokeDasharray="3 3" stroke="var(--border, #e5e5e5)" />
156
- <XAxis dataKey={props.xKey} tick={axisStyle} />
157
- <YAxis tick={axisStyle} />
163
+ <XAxis dataKey={props.xKey} tick={axisStyle} tickMargin={axisTickMargin} />
164
+ <YAxis tick={axisStyle} tickMargin={axisTickMargin} />
158
165
  <Tooltip contentStyle={tooltipStyle} cursor={false} />
159
166
  <Bar dataKey={props.yKey} fill={fill} radius={[4, 4, 0, 0]} />
160
167
  </RechartsBarChart>
@@ -171,17 +178,18 @@ function ChartPieChart({ props }: BaseComponentProps<PieChartProps>) {
171
178
  <div className="pmx-chart pmx-chart--pie">
172
179
  {props.title && <div className="pmx-chart__title">{props.title}</div>}
173
180
  <ResponsiveContainer width="100%" height={h}>
174
- <RechartsPieChart>
181
+ <RechartsPieChart margin={polarChartMargin}>
175
182
  <Tooltip contentStyle={tooltipStyle} />
176
- <Legend />
183
+ {props.showLegend !== false && <Legend wrapperStyle={legendMargin} />}
177
184
  <Pie
178
185
  data={data}
179
186
  dataKey={props.valueKey}
180
187
  nameKey={props.nameKey}
181
188
  cx="50%"
182
189
  cy="50%"
183
- outerRadius="80%"
184
- label
190
+ outerRadius="64%"
191
+ label={props.showLabels !== false}
192
+ labelLine={false}
185
193
  >
186
194
  {data.map((_, i) => (
187
195
  <Cell key={i} fill={CHART_COLORS[i % CHART_COLORS.length]} />
@@ -63,6 +63,8 @@ export const chartComponentDefinitions = {
63
63
  nameKey: z.string(),
64
64
  valueKey: z.string(),
65
65
  height: z.number().nullable(),
66
+ showLegend: z.boolean().optional(),
67
+ showLabels: z.boolean().optional(),
66
68
  }),
67
69
  description:
68
70
  'Pie chart for showing proportions. Provide data as an array of objects with nameKey and valueKey fields.',
@@ -76,6 +78,8 @@ export const chartComponentDefinitions = {
76
78
  nameKey: 'name',
77
79
  valueKey: 'share',
78
80
  height: null,
81
+ showLegend: true,
82
+ showLabels: true,
79
83
  },
80
84
  },
81
85
  } as const;
@@ -34,7 +34,11 @@ import {
34
34
  import {
35
35
  CHART_COLORS,
36
36
  CartesianChart,
37
+ axisTickMargin,
37
38
  axisStyle,
39
+ chartMargin,
40
+ legendMargin,
41
+ polarChartMargin,
38
42
  tooltipStyle,
39
43
  type CartesianChartProps,
40
44
  } from './components';
@@ -47,7 +51,7 @@ function ChartAreaChart({ props }: BaseComponentProps<AreaChartProps>) {
47
51
  return (
48
52
  <CartesianChart props={props} className="pmx-chart--area">
49
53
  {(data) => (
50
- <RechartsAreaChart data={data}>
54
+ <RechartsAreaChart data={data} margin={chartMargin}>
51
55
  <defs>
52
56
  <linearGradient id={gradientId} x1="0" y1="0" x2="0" y2="1">
53
57
  <stop offset="0%" stopColor={stroke} stopOpacity={0.45} />
@@ -55,8 +59,8 @@ function ChartAreaChart({ props }: BaseComponentProps<AreaChartProps>) {
55
59
  </linearGradient>
56
60
  </defs>
57
61
  <CartesianGrid strokeDasharray="3 3" stroke="var(--border, #e5e5e5)" />
58
- <XAxis dataKey={props.xKey} tick={axisStyle} />
59
- <YAxis tick={axisStyle} />
62
+ <XAxis dataKey={props.xKey} tick={axisStyle} tickMargin={axisTickMargin} />
63
+ <YAxis tick={axisStyle} tickMargin={axisTickMargin} />
60
64
  <Tooltip contentStyle={tooltipStyle} />
61
65
  <Area
62
66
  type="monotone"
@@ -91,10 +95,10 @@ function ChartScatterChart({ props }: BaseComponentProps<ScatterChartProps>) {
91
95
  <div className="pmx-chart pmx-chart--scatter">
92
96
  {props.title && <div className="pmx-chart__title">{props.title}</div>}
93
97
  <ResponsiveContainer width="100%" height={h}>
94
- <RechartsScatterChart>
98
+ <RechartsScatterChart margin={chartMargin}>
95
99
  <CartesianGrid strokeDasharray="3 3" stroke="var(--border, #e5e5e5)" />
96
- <XAxis type="number" dataKey={props.xKey} tick={axisStyle} name={props.xKey} />
97
- <YAxis type="number" dataKey={props.yKey} tick={axisStyle} name={props.yKey} />
100
+ <XAxis type="number" dataKey={props.xKey} tick={axisStyle} tickMargin={axisTickMargin} name={props.xKey} />
101
+ <YAxis type="number" dataKey={props.yKey} tick={axisStyle} tickMargin={axisTickMargin} name={props.yKey} />
98
102
  {props.zKey && <ZAxis type="number" dataKey={props.zKey} range={[40, 400]} name={props.zKey} />}
99
103
  <Tooltip contentStyle={tooltipStyle} cursor={{ strokeDasharray: '3 3' }} />
100
104
  <Scatter data={data} fill={fill} />
@@ -110,6 +114,7 @@ interface RadarChartProps {
110
114
  axisKey: string;
111
115
  metrics: string[];
112
116
  height?: number | null;
117
+ showLegend?: boolean | null;
113
118
  }
114
119
 
115
120
  function ChartRadarChart({ props }: BaseComponentProps<RadarChartProps>) {
@@ -121,12 +126,12 @@ function ChartRadarChart({ props }: BaseComponentProps<RadarChartProps>) {
121
126
  <div className="pmx-chart pmx-chart--radar">
122
127
  {props.title && <div className="pmx-chart__title">{props.title}</div>}
123
128
  <ResponsiveContainer width="100%" height={h}>
124
- <RechartsRadarChart data={data} outerRadius="75%">
129
+ <RechartsRadarChart data={data} outerRadius="66%" margin={polarChartMargin}>
125
130
  <PolarGrid stroke="var(--border, #e5e5e5)" />
126
131
  <PolarAngleAxis dataKey={props.axisKey} tick={axisStyle} />
127
132
  <PolarRadiusAxis tick={axisStyle} />
128
133
  <Tooltip contentStyle={tooltipStyle} />
129
- <Legend />
134
+ {props.showLegend !== false && <Legend wrapperStyle={legendMargin} />}
130
135
  {metrics.map((metric, i) => {
131
136
  const color = CHART_COLORS[i % CHART_COLORS.length];
132
137
  return (
@@ -153,6 +158,7 @@ interface StackedBarChartProps {
153
158
  series: string[];
154
159
  aggregate?: 'sum' | 'count' | 'avg' | null;
155
160
  height?: number | null;
161
+ showLegend?: boolean | null;
156
162
  }
157
163
 
158
164
  function ChartStackedBarChart({ props }: BaseComponentProps<StackedBarChartProps>) {
@@ -166,12 +172,12 @@ function ChartStackedBarChart({ props }: BaseComponentProps<StackedBarChartProps
166
172
  <div className="pmx-chart pmx-chart--stacked-bar">
167
173
  {props.title && <div className="pmx-chart__title">{props.title}</div>}
168
174
  <ResponsiveContainer width="100%" height={h}>
169
- <RechartsBarChart data={chartData}>
175
+ <RechartsBarChart data={chartData} margin={chartMargin}>
170
176
  <CartesianGrid strokeDasharray="3 3" stroke="var(--border, #e5e5e5)" />
171
- <XAxis dataKey={props.xKey} tick={axisStyle} />
172
- <YAxis tick={axisStyle} />
177
+ <XAxis dataKey={props.xKey} tick={axisStyle} tickMargin={axisTickMargin} />
178
+ <YAxis tick={axisStyle} tickMargin={axisTickMargin} />
173
179
  <Tooltip contentStyle={tooltipStyle} cursor={false} />
174
- <Legend />
180
+ {props.showLegend !== false && <Legend wrapperStyle={legendMargin} />}
175
181
  {series.map((key, i) => (
176
182
  <Bar
177
183
  key={key}
@@ -225,6 +231,7 @@ interface ComposedChartProps {
225
231
  barColor?: string | null;
226
232
  lineColor?: string | null;
227
233
  height?: number | null;
234
+ showLegend?: boolean | null;
228
235
  }
229
236
 
230
237
  function ChartComposedChart({ props }: BaseComponentProps<ComposedChartProps>) {
@@ -237,12 +244,12 @@ function ChartComposedChart({ props }: BaseComponentProps<ComposedChartProps>) {
237
244
  <div className="pmx-chart pmx-chart--composed">
238
245
  {props.title && <div className="pmx-chart__title">{props.title}</div>}
239
246
  <ResponsiveContainer width="100%" height={h}>
240
- <RechartsComposedChart data={data}>
247
+ <RechartsComposedChart data={data} margin={chartMargin}>
241
248
  <CartesianGrid strokeDasharray="3 3" stroke="var(--border, #e5e5e5)" />
242
- <XAxis dataKey={props.xKey} tick={axisStyle} />
243
- <YAxis tick={axisStyle} />
249
+ <XAxis dataKey={props.xKey} tick={axisStyle} tickMargin={axisTickMargin} />
250
+ <YAxis tick={axisStyle} tickMargin={axisTickMargin} />
244
251
  <Tooltip contentStyle={tooltipStyle} cursor={false} />
245
- <Legend />
252
+ {props.showLegend !== false && <Legend wrapperStyle={legendMargin} />}
246
253
  <Bar dataKey={props.barKey} fill={barFill} radius={[4, 4, 0, 0]} />
247
254
  <Line
248
255
  type="monotone"
@@ -73,6 +73,7 @@ export const extraChartComponentDefinitions = {
73
73
  axisKey: z.string(),
74
74
  metrics: z.array(z.string()),
75
75
  height: z.number().nullable(),
76
+ showLegend: z.boolean().optional(),
76
77
  }),
77
78
  description:
78
79
  'Radar chart for comparing multiple metrics across categories. Each metric in `metrics` is plotted as its own polygon.',
@@ -86,6 +87,7 @@ export const extraChartComponentDefinitions = {
86
87
  axisKey: 'skill',
87
88
  metrics: ['alice', 'bob'],
88
89
  height: null,
90
+ showLegend: true,
89
91
  },
90
92
  },
91
93
 
@@ -97,6 +99,7 @@ export const extraChartComponentDefinitions = {
97
99
  series: z.array(z.string()),
98
100
  aggregate: z.enum(['sum', 'count', 'avg']).nullable(),
99
101
  height: z.number().nullable(),
102
+ showLegend: z.boolean().optional(),
100
103
  }),
101
104
  description:
102
105
  'Stacked bar chart for compositional data. Each entry in `series` is plotted as its own bar segment per x value.',
@@ -111,6 +114,7 @@ export const extraChartComponentDefinitions = {
111
114
  series: ['north', 'south', 'east'],
112
115
  aggregate: null,
113
116
  height: null,
117
+ showLegend: true,
114
118
  },
115
119
  },
116
120
 
@@ -124,6 +128,7 @@ export const extraChartComponentDefinitions = {
124
128
  barColor: z.string().nullable(),
125
129
  lineColor: z.string().nullable(),
126
130
  height: z.number().nullable(),
131
+ showLegend: z.boolean().optional(),
127
132
  }),
128
133
  description:
129
134
  'Combined bar + line chart for paired metrics (e.g. counts + a derived rate) on the same axis.',
@@ -140,6 +145,7 @@ export const extraChartComponentDefinitions = {
140
145
  barColor: null,
141
146
  lineColor: null,
142
147
  height: null,
148
+ showLegend: true,
143
149
  },
144
150
  },
145
151
  } as const;
@@ -17,6 +17,7 @@ export interface JsonRenderNodeInput {
17
17
  y?: number;
18
18
  width?: number;
19
19
  height?: number;
20
+ strictSize?: boolean;
20
21
  }
21
22
 
22
23
  export interface GraphNodeInput {
@@ -38,10 +39,13 @@ export interface GraphNodeInput {
38
39
  barColor?: string;
39
40
  lineColor?: string;
40
41
  height?: number;
42
+ showLegend?: boolean;
43
+ showLabels?: boolean;
41
44
  x?: number;
42
45
  y?: number;
43
46
  width?: number;
44
47
  heightPx?: number;
48
+ strictSize?: boolean;
45
49
  }
46
50
 
47
51
  export const JSON_RENDER_NODE_SIZE = { width: 840, height: 620 };
@@ -514,6 +518,8 @@ export function buildGraphSpec(input: GraphNodeInput): JsonRenderSpec {
514
518
  case 'PieChart': {
515
519
  chartProps.nameKey = input.nameKey ?? 'name';
516
520
  chartProps.valueKey = input.valueKey ?? 'value';
521
+ chartProps.showLegend = input.showLegend !== false;
522
+ chartProps.showLabels = input.showLabels !== false;
517
523
  break;
518
524
  }
519
525
  case 'ScatterChart': {
@@ -533,6 +539,7 @@ export function buildGraphSpec(input: GraphNodeInput): JsonRenderSpec {
533
539
  }
534
540
  chartProps.axisKey = axisKey;
535
541
  chartProps.metrics = metrics;
542
+ chartProps.showLegend = input.showLegend !== false;
536
543
  break;
537
544
  }
538
545
  case 'StackedBarChart': {
@@ -546,6 +553,7 @@ export function buildGraphSpec(input: GraphNodeInput): JsonRenderSpec {
546
553
  chartProps.xKey = xKey;
547
554
  chartProps.series = series;
548
555
  chartProps.aggregate = input.aggregate ?? null;
556
+ chartProps.showLegend = input.showLegend !== false;
549
557
  break;
550
558
  }
551
559
  case 'ComposedChart': {
@@ -556,6 +564,7 @@ export function buildGraphSpec(input: GraphNodeInput): JsonRenderSpec {
556
564
  ?? 'rate';
557
565
  chartProps.barColor = input.barColor ?? null;
558
566
  chartProps.lineColor = input.lineColor ?? null;
567
+ chartProps.showLegend = input.showLegend !== false;
559
568
  break;
560
569
  }
561
570
  case 'AreaChart':
@@ -613,6 +622,8 @@ export function buildGraphConfig(input: GraphNodeInput): Record<string, unknown>
613
622
  ...(input.barColor ? { barColor: input.barColor } : {}),
614
623
  ...(input.lineColor ? { lineColor: input.lineColor } : {}),
615
624
  ...(typeof input.height === 'number' ? { height: input.height } : {}),
625
+ ...(typeof input.showLegend === 'boolean' ? { showLegend: input.showLegend } : {}),
626
+ ...(typeof input.showLabels === 'boolean' ? { showLabels: input.showLabels } : {}),
616
627
  };
617
628
  }
618
629