apexcharts-skill 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +100 -0
- package/SKILL.md +552 -0
- package/index.js +47 -0
- package/package.json +46 -0
- package/references/bar-charts.md +244 -0
- package/references/cartesian-charts.md +247 -0
- package/references/circular-charts.md +218 -0
- package/references/financial-charts.md +157 -0
- package/references/framework-wrappers.md +251 -0
- package/references/grid-charts.md +198 -0
- package/references/radar-charts.md +97 -0
- package/references/ssr.md +201 -0
- package/references/tree-shaking.md +154 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# Grid Charts Reference — ApexCharts
|
|
2
|
+
|
|
3
|
+
## Chart Types Covered
|
|
4
|
+
|
|
5
|
+
- **Heatmap** (`'heatmap'`) — Color-coded grid cells representing data intensity
|
|
6
|
+
- **Treemap** (`'treemap'`) — Nested rectangles with area proportional to value
|
|
7
|
+
|
|
8
|
+
## Tree-Shakeable Import
|
|
9
|
+
|
|
10
|
+
```js
|
|
11
|
+
import ApexCharts from 'apexcharts/heatmap' # heatmap only
|
|
12
|
+
import ApexCharts from 'apexcharts/treemap' # treemap only
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Data Formats
|
|
18
|
+
|
|
19
|
+
### Heatmap
|
|
20
|
+
|
|
21
|
+
Each series is a row; each data point is a cell. The `y` value determines the color intensity.
|
|
22
|
+
|
|
23
|
+
```js
|
|
24
|
+
{
|
|
25
|
+
chart: { type: 'heatmap', height: 350 },
|
|
26
|
+
series: [
|
|
27
|
+
{
|
|
28
|
+
name: 'Monday',
|
|
29
|
+
data: [
|
|
30
|
+
{ x: '9am', y: 20 },
|
|
31
|
+
{ x: '10am', y: 45 },
|
|
32
|
+
{ x: '11am', y: 80 },
|
|
33
|
+
{ x: '12pm', y: 65 }
|
|
34
|
+
]
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: 'Tuesday',
|
|
38
|
+
data: [
|
|
39
|
+
{ x: '9am', y: 35 },
|
|
40
|
+
{ x: '10am', y: 60 },
|
|
41
|
+
{ x: '11am', y: 40 },
|
|
42
|
+
{ x: '12pm', y: 55 }
|
|
43
|
+
]
|
|
44
|
+
}
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Treemap
|
|
50
|
+
|
|
51
|
+
Flat list of `{ x, y }` where `x` is the label and `y` is the value (determines area).
|
|
52
|
+
|
|
53
|
+
```js
|
|
54
|
+
{
|
|
55
|
+
chart: { type: 'treemap', height: 350 },
|
|
56
|
+
series: [{
|
|
57
|
+
data: [
|
|
58
|
+
{ x: 'New York', y: 218 },
|
|
59
|
+
{ x: 'Los Angeles', y: 149 },
|
|
60
|
+
{ x: 'Chicago', y: 106 },
|
|
61
|
+
{ x: 'Houston', y: 92 },
|
|
62
|
+
{ x: 'Phoenix', y: 65 }
|
|
63
|
+
]
|
|
64
|
+
}]
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Treemap with Groups (multiple series)
|
|
69
|
+
|
|
70
|
+
```js
|
|
71
|
+
{
|
|
72
|
+
chart: { type: 'treemap', height: 350 },
|
|
73
|
+
series: [
|
|
74
|
+
{
|
|
75
|
+
name: 'Fruits',
|
|
76
|
+
data: [
|
|
77
|
+
{ x: 'Apple', y: 100 },
|
|
78
|
+
{ x: 'Banana', y: 80 },
|
|
79
|
+
{ x: 'Orange', y: 60 }
|
|
80
|
+
]
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
name: 'Vegetables',
|
|
84
|
+
data: [
|
|
85
|
+
{ x: 'Carrot', y: 70 },
|
|
86
|
+
{ x: 'Potato', y: 90 }
|
|
87
|
+
]
|
|
88
|
+
}
|
|
89
|
+
]
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Key plotOptions
|
|
96
|
+
|
|
97
|
+
### Heatmap
|
|
98
|
+
|
|
99
|
+
```js
|
|
100
|
+
plotOptions: {
|
|
101
|
+
heatmap: {
|
|
102
|
+
radius: 0, // border radius of cells
|
|
103
|
+
enableShades: true, // shade intensity based on value
|
|
104
|
+
shadeIntensity: 0.5, // shade range (0-1)
|
|
105
|
+
distributed: false, // different color per series
|
|
106
|
+
|
|
107
|
+
colorScale: {
|
|
108
|
+
ranges: [
|
|
109
|
+
{ from: 0, to: 30, color: '#00A100', name: 'Low' },
|
|
110
|
+
{ from: 31, to: 60, color: '#128FD9', name: 'Medium' },
|
|
111
|
+
{ from: 61, to: 100, color: '#FFB200', name: 'High' }
|
|
112
|
+
],
|
|
113
|
+
inverse: false,
|
|
114
|
+
min: undefined, // override auto-detected min
|
|
115
|
+
max: undefined // override auto-detected max
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
useFillColorAsStroke: false
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Treemap
|
|
124
|
+
|
|
125
|
+
```js
|
|
126
|
+
plotOptions: {
|
|
127
|
+
treemap: {
|
|
128
|
+
enableShades: true,
|
|
129
|
+
shadeIntensity: 0.5,
|
|
130
|
+
distributed: false, // true = different color per cell
|
|
131
|
+
|
|
132
|
+
colorScale: {
|
|
133
|
+
ranges: [
|
|
134
|
+
{ from: 0, to: 50, color: '#CD363A' },
|
|
135
|
+
{ from: 51, to: 100, color: '#52B12C' }
|
|
136
|
+
]
|
|
137
|
+
},
|
|
138
|
+
|
|
139
|
+
useFillColorAsStroke: false
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Complete Working Example — Heatmap
|
|
147
|
+
|
|
148
|
+
```html
|
|
149
|
+
<div id="chart"></div>
|
|
150
|
+
<script type="module">
|
|
151
|
+
import ApexCharts from 'apexcharts'
|
|
152
|
+
|
|
153
|
+
// Generate sample heatmap data
|
|
154
|
+
function generateData(count, range) {
|
|
155
|
+
const hours = ['9am', '10am', '11am', '12pm', '1pm', '2pm', '3pm', '4pm', '5pm']
|
|
156
|
+
return hours.slice(0, count).map(hour => ({
|
|
157
|
+
x: hour,
|
|
158
|
+
y: Math.floor(Math.random() * (range.max - range.min + 1)) + range.min
|
|
159
|
+
}))
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const options = {
|
|
163
|
+
chart: { type: 'heatmap', height: 350 },
|
|
164
|
+
series: [
|
|
165
|
+
{ name: 'Monday', data: generateData(9, { min: 0, max: 90 }) },
|
|
166
|
+
{ name: 'Tuesday', data: generateData(9, { min: 0, max: 90 }) },
|
|
167
|
+
{ name: 'Wednesday', data: generateData(9, { min: 0, max: 90 }) },
|
|
168
|
+
{ name: 'Thursday', data: generateData(9, { min: 0, max: 90 }) },
|
|
169
|
+
{ name: 'Friday', data: generateData(9, { min: 0, max: 90 }) }
|
|
170
|
+
],
|
|
171
|
+
plotOptions: {
|
|
172
|
+
heatmap: {
|
|
173
|
+
colorScale: {
|
|
174
|
+
ranges: [
|
|
175
|
+
{ from: 0, to: 30, color: '#00A100', name: 'Low' },
|
|
176
|
+
{ from: 31, to: 60, color: '#128FD9', name: 'Medium' },
|
|
177
|
+
{ from: 61, to: 90, color: '#FFB200', name: 'High' }
|
|
178
|
+
]
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
dataLabels: { enabled: true },
|
|
183
|
+
title: { text: 'Office Activity Heatmap' }
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const chart = new ApexCharts(document.querySelector('#chart'), options)
|
|
187
|
+
await chart.render()
|
|
188
|
+
</script>
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## Family-Specific Pitfalls
|
|
194
|
+
|
|
195
|
+
1. **Heatmap with simple numeric arrays** — `data: [10, 20, 30]` does NOT work. Each point must be `{ x, y }` where `y` is the intensity value.
|
|
196
|
+
2. **Inconsistent x-values across heatmap series** — all series should have the same set of x-values to form a proper grid. Missing cells show as gaps.
|
|
197
|
+
3. **Treemap with negative values** — treemap `y` values must be positive (they represent area). Negative values cause rendering issues.
|
|
198
|
+
4. **Confusing heatmap `y` with position** — in heatmap data `{ x, y }`, the `y` is the VALUE (color intensity), NOT the y-axis position. The series `name` determines the row.
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Radar Charts Reference — ApexCharts
|
|
2
|
+
|
|
3
|
+
## Chart Types Covered
|
|
4
|
+
|
|
5
|
+
- **Radar** (`'radar'`) — Spider/web chart comparing multiple variables across categories
|
|
6
|
+
|
|
7
|
+
## Tree-Shakeable Import
|
|
8
|
+
|
|
9
|
+
```js
|
|
10
|
+
import ApexCharts from 'apexcharts/radar'
|
|
11
|
+
// Registers: radar only
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Data Format
|
|
17
|
+
|
|
18
|
+
Radar charts use the axis-chart series format with simple numeric arrays. Categories define the spoke labels.
|
|
19
|
+
|
|
20
|
+
```js
|
|
21
|
+
{
|
|
22
|
+
chart: { type: 'radar', height: 350 },
|
|
23
|
+
series: [
|
|
24
|
+
{ name: 'Player A', data: [80, 50, 30, 40, 100, 20] },
|
|
25
|
+
{ name: 'Player B', data: [60, 70, 90, 50, 40, 60] }
|
|
26
|
+
],
|
|
27
|
+
xaxis: {
|
|
28
|
+
categories: ['Speed', 'Strength', 'Agility', 'Endurance', 'Accuracy', 'Teamwork']
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**Important:** The number of values in each `data` array must match the number of `categories`.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Key plotOptions
|
|
38
|
+
|
|
39
|
+
```js
|
|
40
|
+
plotOptions: {
|
|
41
|
+
radar: {
|
|
42
|
+
size: undefined, // radar chart radius (auto-calculated if undefined)
|
|
43
|
+
offsetX: 0,
|
|
44
|
+
offsetY: 0,
|
|
45
|
+
|
|
46
|
+
polygons: {
|
|
47
|
+
strokeColors: '#e8e8e8', // polygon border color
|
|
48
|
+
strokeWidth: 1,
|
|
49
|
+
connectorColors: '#e8e8e8', // spoke line color
|
|
50
|
+
|
|
51
|
+
fill: {
|
|
52
|
+
colors: undefined // alternating fill colors for concentric rings
|
|
53
|
+
// e.g., ['#f8f8f8', '#fff'] for zebra striping
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Complete Working Example
|
|
63
|
+
|
|
64
|
+
```html
|
|
65
|
+
<div id="chart"></div>
|
|
66
|
+
<script type="module">
|
|
67
|
+
import ApexCharts from 'apexcharts'
|
|
68
|
+
|
|
69
|
+
const options = {
|
|
70
|
+
chart: { type: 'radar', height: 400 },
|
|
71
|
+
series: [
|
|
72
|
+
{ name: 'Budget', data: [80, 50, 30, 40, 100, 20] },
|
|
73
|
+
{ name: 'Actual', data: [60, 70, 90, 50, 40, 60] }
|
|
74
|
+
],
|
|
75
|
+
xaxis: {
|
|
76
|
+
categories: ['Marketing', 'Engineering', 'Sales', 'Support', 'R&D', 'Operations']
|
|
77
|
+
},
|
|
78
|
+
stroke: { width: 2 },
|
|
79
|
+
fill: { opacity: 0.2 },
|
|
80
|
+
markers: { size: 4 },
|
|
81
|
+
yaxis: { stepSize: 20 },
|
|
82
|
+
title: { text: 'Budget vs Actual Spend', align: 'center' }
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const chart = new ApexCharts(document.querySelector('#chart'), options)
|
|
86
|
+
await chart.render()
|
|
87
|
+
</script>
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Family-Specific Pitfalls
|
|
93
|
+
|
|
94
|
+
1. **Missing `xaxis.categories`** — without categories, spokes have no labels. Always provide category names.
|
|
95
|
+
2. **Data length mismatch** — each series `data` array must have exactly as many values as there are categories.
|
|
96
|
+
3. **Confusing with polar area** — radar uses `series: [{ data: [...] }]` (axis format), polar area uses `series: [num]` (flat array). They look similar but have completely different data shapes.
|
|
97
|
+
4. **Using `{ x, y }` format** — radar charts expect simple number arrays, NOT `{ x, y }` objects.
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
# Server-Side Rendering (SSR) — ApexCharts
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
ApexCharts supports SSR for generating chart SVGs on the server (Node.js) and hydrating them on the client for interactivity.
|
|
6
|
+
|
|
7
|
+
## Import Paths
|
|
8
|
+
|
|
9
|
+
```js
|
|
10
|
+
// Server (Node.js) — includes renderToString, renderToHTML
|
|
11
|
+
import ApexCharts from 'apexcharts/ssr'
|
|
12
|
+
|
|
13
|
+
// Client (Browser) — for hydration after SSR
|
|
14
|
+
import ApexCharts from 'apexcharts' // auto-detects browser
|
|
15
|
+
// or explicitly:
|
|
16
|
+
import ApexCharts from 'apexcharts/client'
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**Important:** The default `import ApexCharts from 'apexcharts'` uses Node.js conditional exports. In Node.js, it automatically resolves to the SSR bundle. In browsers (bundlers), it resolves to the client bundle.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Server-Side API
|
|
24
|
+
|
|
25
|
+
### renderToString(options)
|
|
26
|
+
|
|
27
|
+
Returns a raw SVG string suitable for embedding:
|
|
28
|
+
|
|
29
|
+
```js
|
|
30
|
+
import ApexCharts from 'apexcharts/ssr'
|
|
31
|
+
|
|
32
|
+
const svgString = await ApexCharts.renderToString({
|
|
33
|
+
chart: { type: 'line', height: 350, width: 600 },
|
|
34
|
+
series: [{ name: 'Sales', data: [30, 40, 35, 50] }],
|
|
35
|
+
xaxis: { categories: ['Q1', 'Q2', 'Q3', 'Q4'] }
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
// svgString is raw <svg>...</svg> markup
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### renderToHTML(options)
|
|
42
|
+
|
|
43
|
+
Returns an HTML string with a wrapper `<div>` containing the SVG, ready for hydration:
|
|
44
|
+
|
|
45
|
+
```js
|
|
46
|
+
const htmlString = await ApexCharts.renderToHTML({
|
|
47
|
+
chart: {
|
|
48
|
+
type: 'bar',
|
|
49
|
+
height: 350,
|
|
50
|
+
width: 600,
|
|
51
|
+
id: 'my-chart' // id is important for hydration targeting
|
|
52
|
+
},
|
|
53
|
+
series: [{ data: [44, 55, 41, 67] }],
|
|
54
|
+
xaxis: { categories: ['A', 'B', 'C', 'D'] }
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
// htmlString is <div id="my-chart" data-apexcharts>...<svg>...</svg></div>
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Client-Side Hydration
|
|
63
|
+
|
|
64
|
+
After the server-rendered HTML is in the DOM, hydrate it to make it interactive:
|
|
65
|
+
|
|
66
|
+
### hydrate(element)
|
|
67
|
+
|
|
68
|
+
```js
|
|
69
|
+
import ApexCharts from 'apexcharts'
|
|
70
|
+
|
|
71
|
+
// Hydrate a specific chart element
|
|
72
|
+
const chart = ApexCharts.hydrate(document.querySelector('#my-chart'))
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### hydrateAll()
|
|
76
|
+
|
|
77
|
+
```js
|
|
78
|
+
// Hydrate all server-rendered charts on the page
|
|
79
|
+
ApexCharts.hydrateAll()
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### isHydrated(element)
|
|
83
|
+
|
|
84
|
+
```js
|
|
85
|
+
// Check if an element has already been hydrated
|
|
86
|
+
if (!ApexCharts.isHydrated(el)) {
|
|
87
|
+
ApexCharts.hydrate(el)
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Full SSR + Hydration Example
|
|
94
|
+
|
|
95
|
+
### Server (Node.js / Express)
|
|
96
|
+
|
|
97
|
+
```js
|
|
98
|
+
import express from 'express'
|
|
99
|
+
import ApexCharts from 'apexcharts/ssr'
|
|
100
|
+
|
|
101
|
+
const app = express()
|
|
102
|
+
|
|
103
|
+
app.get('/', async (req, res) => {
|
|
104
|
+
const chartHTML = await ApexCharts.renderToHTML({
|
|
105
|
+
chart: { type: 'line', height: 350, width: 600, id: 'sales-chart' },
|
|
106
|
+
series: [{ name: 'Sales', data: [30, 40, 35, 50, 49, 60] }],
|
|
107
|
+
xaxis: { categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'] }
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
res.send(`
|
|
111
|
+
<!DOCTYPE html>
|
|
112
|
+
<html>
|
|
113
|
+
<head><title>Chart</title></head>
|
|
114
|
+
<body>
|
|
115
|
+
${chartHTML}
|
|
116
|
+
<script type="module">
|
|
117
|
+
import ApexCharts from '/node_modules/apexcharts/dist/apexcharts.esm.js'
|
|
118
|
+
ApexCharts.hydrateAll()
|
|
119
|
+
</script>
|
|
120
|
+
</body>
|
|
121
|
+
</html>
|
|
122
|
+
`)
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
app.listen(3000)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## SSR with Frameworks
|
|
131
|
+
|
|
132
|
+
### Next.js (React)
|
|
133
|
+
|
|
134
|
+
```jsx
|
|
135
|
+
// app/page.js (Server Component)
|
|
136
|
+
import ApexCharts from 'apexcharts/ssr'
|
|
137
|
+
|
|
138
|
+
export default async function Page() {
|
|
139
|
+
const chartHTML = await ApexCharts.renderToHTML({
|
|
140
|
+
chart: { type: 'line', height: 350, id: 'my-chart' },
|
|
141
|
+
series: [{ data: [10, 20, 30] }],
|
|
142
|
+
xaxis: { categories: ['A', 'B', 'C'] }
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
return (
|
|
146
|
+
<>
|
|
147
|
+
<div dangerouslySetInnerHTML={{ __html: chartHTML }} />
|
|
148
|
+
<HydrateCharts />
|
|
149
|
+
</>
|
|
150
|
+
)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// components/HydrateCharts.js (Client Component)
|
|
154
|
+
'use client'
|
|
155
|
+
import { useEffect } from 'react'
|
|
156
|
+
|
|
157
|
+
export default function HydrateCharts() {
|
|
158
|
+
useEffect(() => {
|
|
159
|
+
import('apexcharts').then(({ default: ApexCharts }) => {
|
|
160
|
+
ApexCharts.hydrateAll()
|
|
161
|
+
})
|
|
162
|
+
}, [])
|
|
163
|
+
return null
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Nuxt 3 (Vue)
|
|
168
|
+
|
|
169
|
+
```vue
|
|
170
|
+
<!-- pages/index.vue -->
|
|
171
|
+
<template>
|
|
172
|
+
<div v-html="chartHTML" />
|
|
173
|
+
</template>
|
|
174
|
+
|
|
175
|
+
<script setup>
|
|
176
|
+
// Server-side
|
|
177
|
+
const chartHTML = await useAsyncData('chart', async () => {
|
|
178
|
+
const ApexCharts = (await import('apexcharts/ssr')).default
|
|
179
|
+
return await ApexCharts.renderToHTML({
|
|
180
|
+
chart: { type: 'bar', height: 350, id: 'my-chart' },
|
|
181
|
+
series: [{ data: [44, 55, 41] }],
|
|
182
|
+
xaxis: { categories: ['A', 'B', 'C'] }
|
|
183
|
+
})
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
// Client-side hydration
|
|
187
|
+
onMounted(async () => {
|
|
188
|
+
const ApexCharts = (await import('apexcharts')).default
|
|
189
|
+
ApexCharts.hydrateAll()
|
|
190
|
+
})
|
|
191
|
+
</script>
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## Common Pitfalls
|
|
197
|
+
|
|
198
|
+
1. **Using `apexcharts` in Node.js without SSR methods** — the default export auto-resolves based on environment, but `renderToString` is only available via `apexcharts/ssr`.
|
|
199
|
+
2. **Forgetting to hydrate on the client** — server-rendered charts are static SVGs. Without `hydrate()`, they have no interactivity (no tooltips, zoom, click events).
|
|
200
|
+
3. **Missing `chart.width`** — SSR has no DOM to measure container width. Always provide explicit `width` for server rendering.
|
|
201
|
+
4. **Hydrating before DOM is ready** — call `hydrate()` after the server-rendered HTML is in the DOM (use `onMounted`, `useEffect`, or `DOMContentLoaded`).
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# Tree-Shaking & Bundle Optimization — ApexCharts
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
ApexCharts supports three import strategies with different bundle sizes:
|
|
6
|
+
|
|
7
|
+
| Strategy | Import | Includes |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| Full bundle | `import ApexCharts from 'apexcharts'` | All 16 chart types + all features |
|
|
10
|
+
| Per-type entry | `import ApexCharts from 'apexcharts/line'` | Specific chart family + core (no optional features) |
|
|
11
|
+
| Bare core | `import ApexCharts from 'apexcharts/core'` | Core class only — must manually register everything |
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Per-Type Entry Points
|
|
16
|
+
|
|
17
|
+
Each entry point registers a family of related chart types:
|
|
18
|
+
|
|
19
|
+
| Entry Point | Chart Types Registered |
|
|
20
|
+
|---|---|
|
|
21
|
+
| `apexcharts/line` | line, area, scatter, bubble, rangeArea |
|
|
22
|
+
| `apexcharts/area` | same as /line |
|
|
23
|
+
| `apexcharts/scatter` | same as /line |
|
|
24
|
+
| `apexcharts/bubble` | same as /line |
|
|
25
|
+
| `apexcharts/rangeArea` | same as /line |
|
|
26
|
+
| `apexcharts/bar` | bar, column, rangeBar |
|
|
27
|
+
| `apexcharts/column` | same as /bar |
|
|
28
|
+
| `apexcharts/rangeBar` | same as /bar |
|
|
29
|
+
| `apexcharts/candlestick` | candlestick, boxPlot |
|
|
30
|
+
| `apexcharts/boxPlot` | same as /candlestick |
|
|
31
|
+
| `apexcharts/pie` | pie, donut, polarArea |
|
|
32
|
+
| `apexcharts/donut` | same as /pie |
|
|
33
|
+
| `apexcharts/polarArea` | same as /pie |
|
|
34
|
+
| `apexcharts/radialBar` | radialBar |
|
|
35
|
+
| `apexcharts/radar` | radar |
|
|
36
|
+
| `apexcharts/heatmap` | heatmap |
|
|
37
|
+
| `apexcharts/treemap` | treemap |
|
|
38
|
+
|
|
39
|
+
### Using Multiple Chart Types
|
|
40
|
+
|
|
41
|
+
```js
|
|
42
|
+
// Import multiple entry points for a mixed chart
|
|
43
|
+
import ApexCharts from 'apexcharts/line'
|
|
44
|
+
import 'apexcharts/bar' // side-effect: registers bar types onto the same class
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Optional Features
|
|
50
|
+
|
|
51
|
+
Features are optional modules that add functionality. When using per-type entries or core, features must be explicitly imported.
|
|
52
|
+
|
|
53
|
+
| Feature | Import | What It Adds |
|
|
54
|
+
|---|---|---|
|
|
55
|
+
| Legend | `import 'apexcharts/features/legend'` | Interactive legend component |
|
|
56
|
+
| Toolbar | `import 'apexcharts/features/toolbar'` | Zoom, pan, download buttons |
|
|
57
|
+
| Annotations | `import 'apexcharts/features/annotations'` | X/Y/point/text/image annotations |
|
|
58
|
+
| Exports | `import 'apexcharts/features/exports'` | `dataURI()`, `getSvgString()`, `exportToCSV()` |
|
|
59
|
+
| Keyboard | `import 'apexcharts/features/keyboard'` | Keyboard navigation (accessibility) |
|
|
60
|
+
| All | `import 'apexcharts/features/all'` | All of the above |
|
|
61
|
+
|
|
62
|
+
**Important:** Tooltip is always included in core — it cannot be tree-shaken.
|
|
63
|
+
|
|
64
|
+
### What Happens If You Forget a Feature
|
|
65
|
+
|
|
66
|
+
Features fail **silently**. If you use a per-type entry without importing legend:
|
|
67
|
+
- No legend appears, no error thrown
|
|
68
|
+
- `chart.toolbar` is undefined, toolbar doesn't render
|
|
69
|
+
- `addXaxisAnnotation()` does nothing
|
|
70
|
+
- `dataURI()` / `exportToCSV()` throw because the feature isn't registered
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Bare Core Usage
|
|
75
|
+
|
|
76
|
+
For maximum control, import core and register everything manually:
|
|
77
|
+
|
|
78
|
+
```js
|
|
79
|
+
import ApexCharts from 'apexcharts/core'
|
|
80
|
+
|
|
81
|
+
// Register chart types manually
|
|
82
|
+
import { Line } from 'apexcharts/src/charts/Line.js'
|
|
83
|
+
ApexCharts.use({ line: Line, area: Line })
|
|
84
|
+
|
|
85
|
+
// Register features manually
|
|
86
|
+
import { Legend } from 'apexcharts/src/modules/legend/Legend.js'
|
|
87
|
+
ApexCharts.registerFeatures({ legend: Legend })
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
This approach is rarely needed — per-type entries with feature imports cover most use cases.
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Example: Minimal Line Chart Bundle
|
|
95
|
+
|
|
96
|
+
```js
|
|
97
|
+
import ApexCharts from 'apexcharts/line'
|
|
98
|
+
import 'apexcharts/features/legend'
|
|
99
|
+
import 'apexcharts/features/toolbar'
|
|
100
|
+
|
|
101
|
+
const chart = new ApexCharts(el, {
|
|
102
|
+
chart: { type: 'line', height: 350 },
|
|
103
|
+
series: [{ data: [10, 20, 30] }],
|
|
104
|
+
xaxis: { categories: ['A', 'B', 'C'] }
|
|
105
|
+
})
|
|
106
|
+
await chart.render()
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Example: Mixed Chart (Line + Bar)
|
|
110
|
+
|
|
111
|
+
```js
|
|
112
|
+
import ApexCharts from 'apexcharts/line'
|
|
113
|
+
import 'apexcharts/bar'
|
|
114
|
+
import 'apexcharts/features/legend'
|
|
115
|
+
|
|
116
|
+
const chart = new ApexCharts(el, {
|
|
117
|
+
chart: { type: 'line', height: 350 },
|
|
118
|
+
series: [
|
|
119
|
+
{ name: 'Revenue', type: 'column', data: [44, 55, 57] },
|
|
120
|
+
{ name: 'Profit', type: 'line', data: [15, 25, 35] }
|
|
121
|
+
],
|
|
122
|
+
xaxis: { categories: ['Q1', 'Q2', 'Q3'] }
|
|
123
|
+
})
|
|
124
|
+
await chart.render()
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Vite Configuration
|
|
130
|
+
|
|
131
|
+
When using Vite with tree-shaking entries, configure `optimizeDeps` to prevent duplicate bundles:
|
|
132
|
+
|
|
133
|
+
```js
|
|
134
|
+
// vite.config.js
|
|
135
|
+
export default {
|
|
136
|
+
optimizeDeps: {
|
|
137
|
+
include: [
|
|
138
|
+
'apexcharts/line',
|
|
139
|
+
'apexcharts/features/legend',
|
|
140
|
+
'apexcharts/features/toolbar'
|
|
141
|
+
// Add all apexcharts entries you use
|
|
142
|
+
]
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Common Pitfalls
|
|
150
|
+
|
|
151
|
+
1. **Missing feature imports** — features fail silently. If legend/toolbar/annotations don't appear, check imports.
|
|
152
|
+
2. **Importing `apexcharts` AND `apexcharts/line`** — creates duplicate bundles. Use one strategy.
|
|
153
|
+
3. **Vite duplicate bundle issue** — without `optimizeDeps.include`, Vite may bundle ApexCharts twice.
|
|
154
|
+
4. **Calling `dataURI()` without exports feature** — throws an error. Import `apexcharts/features/exports` first.
|