chartjs-plugin-chart2music 0.6.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +93 -77
- package/dist/plugin.amd.js +174 -43
- package/dist/plugin.cjs +333 -230
- package/dist/plugin.d.ts +8 -1
- package/dist/plugin.js +174 -43
- package/dist/plugin.mjs +174 -43
- package/package.json +52 -23
package/dist/plugin.cjs
CHANGED
|
@@ -3,35 +3,17 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports
|
|
6
|
+
exports.default = void 0;
|
|
7
7
|
var _chart2music = _interopRequireDefault(require("chart2music"));
|
|
8
|
-
function _interopRequireDefault(e) { return e && e.__esModule ? e : {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
|
|
18
|
-
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
19
|
-
function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); }
|
|
20
|
-
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
21
|
-
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
22
|
-
function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
|
|
23
|
-
function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); }
|
|
24
|
-
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
25
|
-
var calcMedian = function calcMedian(nums) {
|
|
26
|
-
return nums.length % 2 ? nums[Math.floor(nums.length / 2)] : (nums[nums.length / 2] + nums[nums.length / 2 - 1]) / 2;
|
|
27
|
-
};
|
|
28
|
-
var fiveNumberSummary = function fiveNumberSummary(nums) {
|
|
29
|
-
var sortedNumbers = nums.sort();
|
|
30
|
-
var min, max, q1, q3;
|
|
31
|
-
var datamin = Math.min.apply(Math, _toConsumableArray(sortedNumbers));
|
|
32
|
-
var datamax = Math.max.apply(Math, _toConsumableArray(sortedNumbers));
|
|
33
|
-
var median = calcMedian(sortedNumbers);
|
|
34
|
-
var length = sortedNumbers.length;
|
|
8
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
|
+
const calcMedian = nums => nums.length % 2 ? nums[Math.floor(nums.length / 2)] : (nums[nums.length / 2] + nums[nums.length / 2 - 1]) / 2;
|
|
10
|
+
const fiveNumberSummary = nums => {
|
|
11
|
+
const sortedNumbers = nums.sort();
|
|
12
|
+
let min, max, q1, q3;
|
|
13
|
+
const datamin = Math.min(...sortedNumbers);
|
|
14
|
+
const datamax = Math.max(...sortedNumbers);
|
|
15
|
+
const median = calcMedian(sortedNumbers);
|
|
16
|
+
const length = sortedNumbers.length;
|
|
35
17
|
if (length % 2) {
|
|
36
18
|
q1 = calcMedian(sortedNumbers.slice(0, Math.floor(length / 2)));
|
|
37
19
|
q3 = calcMedian(sortedNumbers.slice(Math.ceil(length % 2)));
|
|
@@ -39,75 +21,70 @@ var fiveNumberSummary = function fiveNumberSummary(nums) {
|
|
|
39
21
|
q1 = calcMedian(sortedNumbers.slice(0, length / 2 - 1));
|
|
40
22
|
q3 = calcMedian(sortedNumbers.slice(length / 2));
|
|
41
23
|
}
|
|
42
|
-
|
|
24
|
+
const iqr = q3 - q1;
|
|
43
25
|
if (datamax < q3 + iqr) {
|
|
44
26
|
max = datamax;
|
|
45
27
|
} else {
|
|
46
|
-
|
|
47
|
-
max = (_sortedNumbers$revers = sortedNumbers.reverse().find(function (num) {
|
|
48
|
-
return num < datamax;
|
|
49
|
-
})) !== null && _sortedNumbers$revers !== void 0 ? _sortedNumbers$revers : datamax;
|
|
28
|
+
max = sortedNumbers.reverse().find(num => num < datamax) ?? datamax;
|
|
50
29
|
}
|
|
51
30
|
if (datamin < q1 - iqr) {
|
|
52
31
|
min = datamin;
|
|
53
32
|
} else {
|
|
54
|
-
|
|
55
|
-
min = (_sortedNumbers$revers2 = sortedNumbers.reverse().find(function (num) {
|
|
56
|
-
return num < datamin;
|
|
57
|
-
})) !== null && _sortedNumbers$revers2 !== void 0 ? _sortedNumbers$revers2 : datamin;
|
|
33
|
+
min = sortedNumbers.reverse().find(num => num < datamin) ?? datamin;
|
|
58
34
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
});
|
|
62
|
-
return _objectSpread({
|
|
35
|
+
const outlier = sortedNumbers.filter(num => num < min || num > max);
|
|
36
|
+
return {
|
|
63
37
|
low: min,
|
|
64
38
|
high: max,
|
|
65
|
-
median
|
|
66
|
-
q1
|
|
67
|
-
q3
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
39
|
+
median,
|
|
40
|
+
q1,
|
|
41
|
+
q3,
|
|
42
|
+
...(outlier.length > 0 ? {
|
|
43
|
+
outlier
|
|
44
|
+
} : {})
|
|
45
|
+
};
|
|
71
46
|
};
|
|
72
|
-
|
|
73
|
-
return data.map(
|
|
74
|
-
if (
|
|
75
|
-
return
|
|
47
|
+
const whichBoxData = data => {
|
|
48
|
+
return data.map((row, index) => {
|
|
49
|
+
if (typeof row === "object" && "min" in row) {
|
|
50
|
+
return {
|
|
51
|
+
...row,
|
|
76
52
|
low: row.min,
|
|
77
53
|
high: row.max,
|
|
78
|
-
x: index
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
54
|
+
x: index,
|
|
55
|
+
...("outliers" in row ? {
|
|
56
|
+
outlier: row.outliers
|
|
57
|
+
} : {})
|
|
58
|
+
};
|
|
82
59
|
}
|
|
83
60
|
if (Array.isArray(row)) {
|
|
84
|
-
return
|
|
61
|
+
return {
|
|
62
|
+
...fiveNumberSummary(row),
|
|
85
63
|
x: index
|
|
86
|
-
}
|
|
64
|
+
};
|
|
87
65
|
}
|
|
88
66
|
});
|
|
89
67
|
};
|
|
90
|
-
|
|
68
|
+
const processBoxData = data => {
|
|
91
69
|
if (data.datasets.length === 1) {
|
|
92
70
|
return {
|
|
93
71
|
data: whichBoxData(data.datasets[0].data)
|
|
94
72
|
};
|
|
95
73
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
data.datasets.forEach(
|
|
99
|
-
|
|
100
|
-
var groupName = (_obj$label = obj.label) !== null && _obj$label !== void 0 ? _obj$label : "Group ".concat(index + 1);
|
|
74
|
+
const groups = [];
|
|
75
|
+
const result = {};
|
|
76
|
+
data.datasets.forEach((obj, index) => {
|
|
77
|
+
const groupName = obj.label ?? `Group ${index + 1}`;
|
|
101
78
|
groups.push(groupName);
|
|
102
79
|
result[groupName] = whichBoxData(obj.data);
|
|
103
80
|
});
|
|
104
81
|
return {
|
|
105
|
-
groups
|
|
82
|
+
groups,
|
|
106
83
|
data: result
|
|
107
84
|
};
|
|
108
85
|
};
|
|
109
|
-
|
|
110
|
-
|
|
86
|
+
const chartStates = new Map();
|
|
87
|
+
const chartjs_c2m_converter = {
|
|
111
88
|
bar: "bar",
|
|
112
89
|
line: "line",
|
|
113
90
|
pie: "pie",
|
|
@@ -116,24 +93,22 @@ var chartjs_c2m_converter = {
|
|
|
116
93
|
boxplot: "box",
|
|
117
94
|
radar: "bar",
|
|
118
95
|
wordCloud: "bar",
|
|
119
|
-
scatter: "scatter"
|
|
96
|
+
scatter: "scatter",
|
|
97
|
+
matrix: "matrix"
|
|
120
98
|
};
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
var invalid = panelTypes.find(function (t) {
|
|
128
|
-
return !(t in chartjs_c2m_converter);
|
|
129
|
-
});
|
|
99
|
+
const processChartType = chart => {
|
|
100
|
+
const topLevelType = chart.config.type;
|
|
101
|
+
const panelTypes = chart.data.datasets.map(({
|
|
102
|
+
type
|
|
103
|
+
}) => type ?? topLevelType);
|
|
104
|
+
const invalid = panelTypes.find(t => !(t in chartjs_c2m_converter));
|
|
130
105
|
if (invalid) {
|
|
131
106
|
return {
|
|
132
107
|
valid: false,
|
|
133
108
|
invalidType: invalid
|
|
134
109
|
};
|
|
135
110
|
}
|
|
136
|
-
if (
|
|
111
|
+
if ([...new Set(panelTypes)].length === 1) {
|
|
137
112
|
return {
|
|
138
113
|
valid: true,
|
|
139
114
|
c2m_types: chartjs_c2m_converter[panelTypes[0]]
|
|
@@ -141,112 +116,160 @@ var processChartType = function processChartType(chart) {
|
|
|
141
116
|
}
|
|
142
117
|
return {
|
|
143
118
|
valid: true,
|
|
144
|
-
c2m_types: panelTypes.map(
|
|
145
|
-
return chartjs_c2m_converter[t];
|
|
146
|
-
})
|
|
119
|
+
c2m_types: panelTypes.map(t => chartjs_c2m_converter[t])
|
|
147
120
|
};
|
|
148
121
|
};
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
if ((chartAxisInfo === null || chartAxisInfo === void 0 ? void 0 : chartAxisInfo.min) !== undefined) {
|
|
122
|
+
const generateAxisInfo = (chartAxisInfo, chart) => {
|
|
123
|
+
const axis = {};
|
|
124
|
+
if (chartAxisInfo?.min !== undefined) {
|
|
153
125
|
if (typeof chartAxisInfo.min === "string") {
|
|
154
126
|
axis.minimum = chart.data.labels.indexOf(chartAxisInfo.min);
|
|
155
127
|
} else {
|
|
156
128
|
axis.minimum = chartAxisInfo.min;
|
|
157
129
|
}
|
|
158
130
|
}
|
|
159
|
-
if (
|
|
131
|
+
if (chartAxisInfo?.max !== undefined) {
|
|
160
132
|
if (typeof chartAxisInfo.max === "string") {
|
|
161
133
|
axis.maximum = chart.data.labels.indexOf(chartAxisInfo.max);
|
|
162
134
|
} else {
|
|
163
135
|
axis.maximum = chartAxisInfo.max;
|
|
164
136
|
}
|
|
165
137
|
}
|
|
166
|
-
|
|
138
|
+
const label = chartAxisInfo?.title?.text;
|
|
167
139
|
if (label) {
|
|
168
140
|
axis.label = label;
|
|
169
141
|
}
|
|
170
|
-
if (
|
|
142
|
+
if (chartAxisInfo?.type === "logarithmic") {
|
|
171
143
|
axis.type = "log10";
|
|
172
144
|
}
|
|
173
145
|
return axis;
|
|
174
146
|
};
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
}
|
|
147
|
+
const generateAxes = (chart, options) => {
|
|
148
|
+
const axes = {
|
|
149
|
+
x: {
|
|
150
|
+
...generateAxisInfo(chart.options?.scales?.x, chart)
|
|
151
|
+
},
|
|
152
|
+
y: {
|
|
153
|
+
format: options?.axes?.y?.format || (value => value.toLocaleString()),
|
|
154
|
+
...generateAxisInfo(chart.options?.scales?.y, chart)
|
|
155
|
+
}
|
|
184
156
|
};
|
|
185
|
-
|
|
157
|
+
const xAxisValueLabels = chart.data.labels.slice(0);
|
|
186
158
|
if (xAxisValueLabels.length > 0) {
|
|
187
159
|
axes.x.valueLabels = xAxisValueLabels;
|
|
188
160
|
}
|
|
189
161
|
return axes;
|
|
190
162
|
};
|
|
191
|
-
|
|
163
|
+
const whichDataStructure = data => {
|
|
192
164
|
if (Array.isArray(data[0])) {
|
|
193
|
-
return data.map(
|
|
194
|
-
|
|
195
|
-
_arr$sort2 = _slicedToArray(_arr$sort, 2),
|
|
196
|
-
low = _arr$sort2[0],
|
|
197
|
-
high = _arr$sort2[1];
|
|
165
|
+
return data.map((arr, x) => {
|
|
166
|
+
let [low, high] = arr.sort();
|
|
198
167
|
return {
|
|
199
|
-
x
|
|
200
|
-
low
|
|
201
|
-
high
|
|
168
|
+
x,
|
|
169
|
+
low,
|
|
170
|
+
high
|
|
202
171
|
};
|
|
203
172
|
});
|
|
204
173
|
}
|
|
205
174
|
return data;
|
|
206
175
|
};
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
176
|
+
const labelIndex = (labels, value) => {
|
|
177
|
+
let index = labels.indexOf(value);
|
|
178
|
+
if (index === -1) {
|
|
179
|
+
labels.push(value);
|
|
180
|
+
index = labels.length - 1;
|
|
181
|
+
}
|
|
182
|
+
return index;
|
|
183
|
+
};
|
|
184
|
+
const processMatrixDataPoints = (data, datasetIndex, xLabels, yLabels) => {
|
|
185
|
+
return data.map((point, index) => {
|
|
186
|
+
const x = typeof point.x === "string" ? labelIndex(xLabels, point.x) : point.x;
|
|
187
|
+
const y = typeof point.y === "string" ? labelIndex(yLabels, point.y) : point.y;
|
|
188
|
+
return {
|
|
189
|
+
...point,
|
|
190
|
+
x,
|
|
191
|
+
y,
|
|
192
|
+
custom: {
|
|
193
|
+
...point.custom,
|
|
194
|
+
group: datasetIndex,
|
|
195
|
+
datasetIndex,
|
|
196
|
+
index
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
});
|
|
200
|
+
};
|
|
201
|
+
const processMatrixData = data => {
|
|
202
|
+
const xLabels = [];
|
|
203
|
+
const yLabels = [];
|
|
204
|
+
// Chart2Music represents matrix rows as groups and columns as points within
|
|
205
|
+
// each group. This preserves two-dimensional keyboard navigation.
|
|
206
|
+
const result = {};
|
|
207
|
+
data.datasets.forEach((obj, index) => {
|
|
208
|
+
const points = processMatrixDataPoints(obj.data, index, xLabels, yLabels);
|
|
209
|
+
points.forEach(point => {
|
|
210
|
+
const rowLabel = typeof point.y === "number" && yLabels[point.y] !== undefined ? yLabels[point.y] : String(point.y);
|
|
211
|
+
const groupName = data.datasets.length === 1 ? rowLabel : `${obj.label ?? `Group ${index + 1}`}: ${rowLabel}`;
|
|
212
|
+
if (!result[groupName]) {
|
|
213
|
+
result[groupName] = [];
|
|
214
|
+
}
|
|
215
|
+
result[groupName].push(point);
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
Object.values(result).forEach(row => row.sort((a, b) => a.x - b.x));
|
|
219
|
+
return {
|
|
220
|
+
groups: Object.keys(result),
|
|
221
|
+
data: result,
|
|
222
|
+
xLabels,
|
|
223
|
+
yLabels
|
|
224
|
+
};
|
|
225
|
+
};
|
|
226
|
+
const scrubX = data => {
|
|
227
|
+
const blackboard = JSON.parse(JSON.stringify(data));
|
|
228
|
+
let labels = [];
|
|
210
229
|
if (Array.isArray(data)) {
|
|
211
230
|
// console.log("not grouped");
|
|
212
231
|
// Not grouped
|
|
213
|
-
blackboard.forEach(
|
|
214
|
-
if (
|
|
232
|
+
blackboard.forEach((item, x) => {
|
|
233
|
+
if (typeof item === "object" && item !== null && "x" in item) {
|
|
215
234
|
labels.push(item.x);
|
|
216
235
|
item.x = x;
|
|
217
236
|
}
|
|
218
237
|
});
|
|
219
238
|
return {
|
|
220
|
-
labels
|
|
239
|
+
labels,
|
|
221
240
|
data: blackboard
|
|
222
241
|
};
|
|
242
|
+
} else {
|
|
243
|
+
// Grouped
|
|
244
|
+
return undefined;
|
|
223
245
|
}
|
|
224
246
|
};
|
|
225
|
-
|
|
247
|
+
const processData = (data, c2m_types) => {
|
|
226
248
|
if (c2m_types === "box") {
|
|
227
249
|
return processBoxData(data);
|
|
228
250
|
}
|
|
229
|
-
|
|
251
|
+
if (c2m_types === "matrix") {
|
|
252
|
+
return processMatrixData(data);
|
|
253
|
+
}
|
|
254
|
+
let groups = [];
|
|
230
255
|
if (data.datasets.length === 1) {
|
|
231
256
|
return {
|
|
232
257
|
data: whichDataStructure(data.datasets[0].data)
|
|
233
258
|
};
|
|
234
259
|
}
|
|
235
|
-
|
|
236
|
-
data.datasets.forEach(
|
|
237
|
-
|
|
238
|
-
var groupName = (_obj$label2 = obj.label) !== null && _obj$label2 !== void 0 ? _obj$label2 : "Group ".concat(index + 1);
|
|
260
|
+
const result = {};
|
|
261
|
+
data.datasets.forEach((obj, index) => {
|
|
262
|
+
const groupName = obj.label ?? `Group ${index + 1}`;
|
|
239
263
|
groups.push(groupName);
|
|
240
264
|
result[groupName] = whichDataStructure(obj.data);
|
|
241
265
|
});
|
|
242
266
|
return {
|
|
243
|
-
groups
|
|
267
|
+
groups,
|
|
244
268
|
data: result
|
|
245
269
|
};
|
|
246
270
|
};
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
if ((_options$plugins = options.plugins) !== null && _options$plugins !== void 0 && (_options$plugins = _options$plugins.title) !== null && _options$plugins !== void 0 && _options$plugins.text) {
|
|
271
|
+
const determineChartTitle = options => {
|
|
272
|
+
if (options.plugins?.title?.text) {
|
|
250
273
|
if (Array.isArray(options.plugins.title.text)) {
|
|
251
274
|
return options.plugins.title.text.join(", ");
|
|
252
275
|
}
|
|
@@ -254,62 +277,70 @@ var determineChartTitle = function determineChartTitle(options) {
|
|
|
254
277
|
}
|
|
255
278
|
return "";
|
|
256
279
|
};
|
|
257
|
-
|
|
280
|
+
const determineCCElement = (canvas, provided) => {
|
|
258
281
|
if (provided) {
|
|
259
282
|
return provided;
|
|
260
283
|
}
|
|
261
|
-
|
|
284
|
+
const cc = document.createElement("div");
|
|
262
285
|
canvas.insertAdjacentElement("afterend", cc);
|
|
263
286
|
return cc;
|
|
264
287
|
};
|
|
265
|
-
|
|
288
|
+
const createDataSnapshot = chart => {
|
|
289
|
+
return JSON.stringify({
|
|
290
|
+
datasets: chart.data.datasets.map(ds => ds.data),
|
|
291
|
+
labels: chart.data.labels
|
|
292
|
+
});
|
|
293
|
+
};
|
|
294
|
+
const displayPoint = chart => {
|
|
266
295
|
if (!chartStates.has(chart)) {
|
|
267
296
|
return;
|
|
268
297
|
}
|
|
269
|
-
|
|
270
|
-
ref
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
point
|
|
274
|
-
index
|
|
298
|
+
const {
|
|
299
|
+
c2m: ref
|
|
300
|
+
} = chartStates.get(chart);
|
|
301
|
+
const {
|
|
302
|
+
point,
|
|
303
|
+
index
|
|
304
|
+
} = ref.getCurrent();
|
|
305
|
+
// Use Chart2Music's internal visible group tracking
|
|
306
|
+
// @ts-ignore - accessing internal Chart2Music property
|
|
307
|
+
const visibleGroupIndices = ref._visible_group_indices?.slice(1) || [];
|
|
275
308
|
try {
|
|
276
|
-
|
|
277
|
-
var highlightElements = [];
|
|
309
|
+
const highlightElements = [];
|
|
278
310
|
if ("custom" in point) {
|
|
311
|
+
const customPoint = point;
|
|
279
312
|
highlightElements.push({
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
// @ts-ignore
|
|
283
|
-
index: point.custom.index
|
|
313
|
+
datasetIndex: customPoint.custom.datasetIndex ?? customPoint.custom.group,
|
|
314
|
+
index: customPoint.custom.index
|
|
284
315
|
});
|
|
285
316
|
} else {
|
|
286
|
-
|
|
317
|
+
// For stacked charts, Chart2Music includes an "All" group at index 0,
|
|
318
|
+
// so we subtract 1 to get the actual dataset index
|
|
319
|
+
visibleGroupIndices.forEach(groupIndex => {
|
|
287
320
|
highlightElements.push({
|
|
288
|
-
datasetIndex:
|
|
289
|
-
index
|
|
321
|
+
datasetIndex: groupIndex - 1,
|
|
322
|
+
index
|
|
290
323
|
});
|
|
291
324
|
});
|
|
292
325
|
}
|
|
293
|
-
chart
|
|
294
|
-
chart
|
|
295
|
-
chart
|
|
326
|
+
chart?.setActiveElements(highlightElements);
|
|
327
|
+
chart?.tooltip?.setActiveElements(highlightElements, {});
|
|
328
|
+
chart?.update();
|
|
296
329
|
} catch (e) {
|
|
297
330
|
// console.warn(e);
|
|
298
331
|
}
|
|
299
332
|
};
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
333
|
+
const generateChart = (chart, options) => {
|
|
334
|
+
const {
|
|
335
|
+
valid,
|
|
336
|
+
c2m_types,
|
|
337
|
+
invalidType
|
|
338
|
+
} = processChartType(chart);
|
|
306
339
|
if (!valid) {
|
|
307
|
-
|
|
308
|
-
// @ts-ignore
|
|
309
|
-
(_options$errorCallbac = options.errorCallback) === null || _options$errorCallbac === void 0 || _options$errorCallbac.call(options, "Unable to connect chart2music to chart. The chart is of type \"".concat(invalidType, "\", which is not one of the supported chart types for this plugin. This plugin supports: ").concat(Object.keys(chartjs_c2m_converter).join(", ")));
|
|
340
|
+
options.errorCallback?.(`Unable to connect chart2music to chart. The chart is of type "${invalidType}", which is not one of the supported chart types for this plugin. This plugin supports: ${Object.keys(chartjs_c2m_converter).join(", ")}`);
|
|
310
341
|
return;
|
|
311
342
|
}
|
|
312
|
-
|
|
343
|
+
let axes = generateAxes(chart, options);
|
|
313
344
|
if (chart.config.type === "wordCloud") {
|
|
314
345
|
delete axes.x.minimum;
|
|
315
346
|
delete axes.x.maximum;
|
|
@@ -323,96 +354,126 @@ var generateChart = function generateChart(chart, options) {
|
|
|
323
354
|
}
|
|
324
355
|
}
|
|
325
356
|
// Generate CC element
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
357
|
+
const cc = determineCCElement(chart.canvas, options.cc);
|
|
358
|
+
const processedData = processData(chart.data, c2m_types);
|
|
359
|
+
const {
|
|
360
|
+
data
|
|
361
|
+
} = processedData;
|
|
330
362
|
// lastDataObj = JSON.stringify(data);
|
|
331
|
-
|
|
332
|
-
|
|
363
|
+
if (c2m_types === "matrix") {
|
|
364
|
+
if (processedData.xLabels?.length > 0) {
|
|
365
|
+
axes.x.valueLabels = processedData.xLabels.slice(0);
|
|
366
|
+
}
|
|
367
|
+
if (processedData.yLabels?.length > 0) {
|
|
368
|
+
// Category labels provide the Matrix Plot's Y-axis formatter.
|
|
369
|
+
// The general numeric formatter would otherwise announce row indexes.
|
|
370
|
+
delete axes.y.format;
|
|
371
|
+
axes.y.valueLabels = processedData.yLabels.slice(0);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
let scrub = scrubX(data);
|
|
375
|
+
if (scrub?.labels && scrub?.labels?.length > 0) {
|
|
333
376
|
// Something was scrubbed
|
|
334
377
|
if (!chart.data.labels || chart.data.labels.length === 0) {
|
|
335
378
|
axes.x.valueLabels = scrub.labels.slice(0);
|
|
336
379
|
}
|
|
337
380
|
}
|
|
338
381
|
if (c2m_types === "scatter") {
|
|
339
|
-
|
|
382
|
+
delete scrub?.data;
|
|
340
383
|
delete axes.x.valueLabels;
|
|
341
384
|
}
|
|
342
|
-
axes =
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
385
|
+
axes = {
|
|
386
|
+
...axes,
|
|
387
|
+
x: {
|
|
388
|
+
...axes.x,
|
|
389
|
+
...options.axes?.x
|
|
390
|
+
},
|
|
391
|
+
y: {
|
|
392
|
+
...axes.y,
|
|
393
|
+
...options.axes?.y
|
|
394
|
+
}
|
|
395
|
+
};
|
|
396
|
+
// Start with plugin's internal onFocusCallback
|
|
397
|
+
const pluginOnFocusCallback = () => {
|
|
398
|
+
displayPoint(chart);
|
|
399
|
+
};
|
|
400
|
+
// Merge user's options, wrapping onFocusCallback if provided
|
|
401
|
+
const userOptions = options.options || {};
|
|
402
|
+
const userOnFocusCallback = userOptions.onFocusCallback;
|
|
403
|
+
const c2mOptions = {
|
|
404
|
+
cc,
|
|
348
405
|
element: chart.canvas,
|
|
349
406
|
type: c2m_types,
|
|
350
|
-
data:
|
|
407
|
+
data: scrub?.data ?? data,
|
|
351
408
|
title: determineChartTitle(chart.options),
|
|
352
|
-
axes
|
|
409
|
+
axes,
|
|
353
410
|
options: {
|
|
354
|
-
|
|
355
|
-
onFocusCallback:
|
|
356
|
-
|
|
357
|
-
|
|
411
|
+
...userOptions,
|
|
412
|
+
onFocusCallback: userOnFocusCallback ? point => {
|
|
413
|
+
pluginOnFocusCallback();
|
|
414
|
+
userOnFocusCallback(point);
|
|
415
|
+
} : pluginOnFocusCallback
|
|
358
416
|
}
|
|
359
417
|
};
|
|
360
418
|
if (Array.isArray(c2mOptions.data)) {
|
|
361
419
|
if (isNaN(c2mOptions.data[0])) {
|
|
362
|
-
c2mOptions.data = c2mOptions.data.map(
|
|
363
|
-
return
|
|
420
|
+
c2mOptions.data = c2mOptions.data.map((point, index) => {
|
|
421
|
+
return {
|
|
422
|
+
...point,
|
|
364
423
|
custom: {
|
|
365
|
-
|
|
366
|
-
|
|
424
|
+
...point.custom,
|
|
425
|
+
group: point.custom?.group ?? 0,
|
|
426
|
+
index: point.custom?.index ?? index
|
|
367
427
|
}
|
|
368
|
-
}
|
|
428
|
+
};
|
|
369
429
|
});
|
|
370
430
|
} else {
|
|
371
|
-
c2mOptions.data = c2mOptions.data.map(
|
|
431
|
+
c2mOptions.data = c2mOptions.data.map((num, index) => {
|
|
372
432
|
return {
|
|
373
433
|
x: index,
|
|
374
434
|
y: num,
|
|
375
435
|
custom: {
|
|
376
436
|
group: 0,
|
|
377
|
-
index
|
|
437
|
+
index
|
|
378
438
|
}
|
|
379
439
|
};
|
|
380
440
|
});
|
|
381
441
|
}
|
|
382
442
|
} else {
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
443
|
+
const dataObj = c2mOptions.data;
|
|
444
|
+
const groups = Object.keys(dataObj);
|
|
445
|
+
groups.forEach((groupName, groupNumber) => {
|
|
446
|
+
if (!isNaN(dataObj[groupName][0])) {
|
|
447
|
+
dataObj[groupName] = dataObj[groupName].map((num, index) => {
|
|
387
448
|
return {
|
|
388
449
|
x: index,
|
|
389
450
|
y: num,
|
|
390
451
|
custom: {
|
|
391
452
|
group: groupNumber,
|
|
392
|
-
index
|
|
453
|
+
index
|
|
393
454
|
}
|
|
394
455
|
};
|
|
395
456
|
});
|
|
396
457
|
} else {
|
|
397
|
-
|
|
398
|
-
return
|
|
458
|
+
dataObj[groupName] = dataObj[groupName].map((point, index) => {
|
|
459
|
+
return {
|
|
460
|
+
...point,
|
|
399
461
|
custom: {
|
|
400
|
-
|
|
401
|
-
|
|
462
|
+
...point.custom,
|
|
463
|
+
group: point.custom?.group ?? groupNumber,
|
|
464
|
+
index: point.custom?.index ?? index
|
|
402
465
|
}
|
|
403
|
-
}
|
|
466
|
+
};
|
|
404
467
|
});
|
|
405
468
|
}
|
|
406
469
|
});
|
|
407
470
|
}
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
471
|
+
if (chart.config.options?.scales?.x?.stacked) {
|
|
472
|
+
if (c2mOptions.options) {
|
|
473
|
+
c2mOptions.options.stack = true;
|
|
474
|
+
}
|
|
412
475
|
}
|
|
413
|
-
// @ts-ignore
|
|
414
476
|
if (options.audioEngine) {
|
|
415
|
-
// @ts-ignore
|
|
416
477
|
c2mOptions.audioEngine = options.audioEngine;
|
|
417
478
|
}
|
|
418
479
|
if (c2mOptions.data.length === 0) {
|
|
@@ -421,36 +482,51 @@ var generateChart = function generateChart(chart, options) {
|
|
|
421
482
|
if (options.lang) {
|
|
422
483
|
c2mOptions.lang = options.lang;
|
|
423
484
|
}
|
|
424
|
-
|
|
425
|
-
err
|
|
426
|
-
c2m
|
|
485
|
+
const {
|
|
486
|
+
err,
|
|
487
|
+
data: c2m
|
|
488
|
+
} = (0, _chart2music.default)(c2mOptions);
|
|
427
489
|
/* istanbul-ignore-next */
|
|
428
490
|
if (err) {
|
|
429
|
-
|
|
430
|
-
// @ts-ignore
|
|
431
|
-
(_options$errorCallbac2 = options.errorCallback) === null || _options$errorCallbac2 === void 0 || _options$errorCallbac2.call(options, err);
|
|
491
|
+
options.errorCallback?.(err);
|
|
432
492
|
return;
|
|
433
493
|
}
|
|
434
494
|
if (!c2m) {
|
|
435
495
|
return;
|
|
436
496
|
}
|
|
437
497
|
chartStates.set(chart, {
|
|
438
|
-
c2m
|
|
439
|
-
|
|
440
|
-
return i;
|
|
441
|
-
})) !== null && _groups$map !== void 0 ? _groups$map : []
|
|
498
|
+
c2m,
|
|
499
|
+
lastDataSnapshot: createDataSnapshot(chart)
|
|
442
500
|
});
|
|
501
|
+
if (c2m_types === "matrix") {
|
|
502
|
+
const matrixKeydown = event => {
|
|
503
|
+
if (event.key !== "ArrowUp" && event.key !== "ArrowDown") {
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
event.preventDefault();
|
|
507
|
+
event.stopImmediatePropagation();
|
|
508
|
+
const actions = c2m._availableActions;
|
|
509
|
+
if (event.key === "ArrowUp") {
|
|
510
|
+
actions.next_category();
|
|
511
|
+
} else {
|
|
512
|
+
actions.previous_category();
|
|
513
|
+
}
|
|
514
|
+
};
|
|
515
|
+
chart.canvas.addEventListener("keydown", matrixKeydown, true);
|
|
516
|
+
const state = chartStates.get(chart);
|
|
517
|
+
state.matrixKeydown = matrixKeydown;
|
|
518
|
+
state.matrixKeydownTarget = chart.canvas;
|
|
519
|
+
}
|
|
443
520
|
};
|
|
444
|
-
|
|
521
|
+
const plugin = exports.default = {
|
|
445
522
|
id: "chartjs2music",
|
|
446
|
-
afterInit:
|
|
523
|
+
afterInit: (chart, _args, options) => {
|
|
447
524
|
if (!chartStates.has(chart)) {
|
|
448
525
|
generateChart(chart, options);
|
|
449
526
|
// Remove tooltip when the chart blurs
|
|
450
|
-
chart.canvas.addEventListener("blur",
|
|
451
|
-
var _chart$tooltip2;
|
|
527
|
+
chart.canvas.addEventListener("blur", () => {
|
|
452
528
|
chart.setActiveElements([]);
|
|
453
|
-
|
|
529
|
+
chart.tooltip?.setActiveElements([], {});
|
|
454
530
|
try {
|
|
455
531
|
chart.update();
|
|
456
532
|
} catch (e) {
|
|
@@ -458,58 +534,85 @@ var plugin = exports["default"] = {
|
|
|
458
534
|
}
|
|
459
535
|
});
|
|
460
536
|
// Show tooltip when the chart receives focus
|
|
461
|
-
chart.canvas.addEventListener("focus",
|
|
537
|
+
chart.canvas.addEventListener("focus", () => {
|
|
462
538
|
displayPoint(chart);
|
|
463
539
|
});
|
|
464
540
|
}
|
|
465
541
|
},
|
|
466
|
-
afterDatasetUpdate:
|
|
542
|
+
afterDatasetUpdate: (chart, args, options) => {
|
|
467
543
|
if (!args.mode) {
|
|
468
544
|
return;
|
|
469
545
|
}
|
|
470
546
|
if (!chartStates.has(chart)) {
|
|
471
547
|
generateChart(chart, options);
|
|
472
548
|
}
|
|
473
|
-
|
|
474
|
-
ref
|
|
475
|
-
|
|
549
|
+
const {
|
|
550
|
+
c2m: ref
|
|
551
|
+
} = chartStates.get(chart);
|
|
476
552
|
if (!ref) {
|
|
477
553
|
return;
|
|
478
554
|
}
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
if (ref._options.stack) {
|
|
555
|
+
const refInternal = ref;
|
|
556
|
+
const groups = refInternal._groups.slice(0);
|
|
557
|
+
if (refInternal._options.stack) {
|
|
483
558
|
groups.shift();
|
|
484
559
|
}
|
|
485
560
|
if (args.mode === "hide") {
|
|
486
|
-
|
|
487
|
-
visible_groups.splice(args.index, 1);
|
|
561
|
+
const err = ref.setCategoryVisibility(groups[args.index], false);
|
|
488
562
|
if (err) {
|
|
489
563
|
console.error(err);
|
|
490
564
|
}
|
|
491
565
|
return;
|
|
492
566
|
}
|
|
493
567
|
if (args.mode === "show") {
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
console.error(_err);
|
|
568
|
+
const err = ref.setCategoryVisibility(groups[args.index], true);
|
|
569
|
+
if (err) {
|
|
570
|
+
console.error(err);
|
|
498
571
|
}
|
|
499
572
|
return;
|
|
500
573
|
}
|
|
501
574
|
},
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
if
|
|
575
|
+
afterDatasetsUpdate: (chart, _args, options) => {
|
|
576
|
+
const state = chartStates.get(chart);
|
|
577
|
+
if (!state?.c2m) return;
|
|
578
|
+
// Check if data has changed
|
|
579
|
+
const currentSnapshot = createDataSnapshot(chart);
|
|
580
|
+
if (currentSnapshot === state.lastDataSnapshot) {
|
|
581
|
+
return; // No data change, skip update
|
|
582
|
+
}
|
|
583
|
+
// Get chart type
|
|
584
|
+
const {
|
|
585
|
+
valid,
|
|
586
|
+
c2m_types
|
|
587
|
+
} = processChartType(chart);
|
|
588
|
+
if (!valid) return;
|
|
589
|
+
// Process data and generate axes
|
|
590
|
+
const {
|
|
591
|
+
data
|
|
592
|
+
} = processData(chart.data, c2m_types);
|
|
593
|
+
const axes = generateAxes(chart, options);
|
|
594
|
+
// Update Chart2Music with new data
|
|
595
|
+
state.c2m.setData(data, axes);
|
|
596
|
+
// Update snapshot
|
|
597
|
+
state.lastDataSnapshot = currentSnapshot;
|
|
598
|
+
},
|
|
599
|
+
afterDestroy: chart => {
|
|
600
|
+
const state = chartStates.get(chart);
|
|
601
|
+
if (!state?.c2m) {
|
|
506
602
|
return;
|
|
507
603
|
}
|
|
604
|
+
const {
|
|
605
|
+
c2m: ref
|
|
606
|
+
} = state;
|
|
607
|
+
if (state?.matrixKeydown && state.matrixKeydownTarget) {
|
|
608
|
+
state.matrixKeydownTarget.removeEventListener("keydown", state.matrixKeydown, true);
|
|
609
|
+
}
|
|
508
610
|
ref.cleanUp();
|
|
509
611
|
},
|
|
510
612
|
defaults: {
|
|
511
613
|
cc: null,
|
|
512
614
|
audioEngine: null,
|
|
513
|
-
errorCallback: null
|
|
615
|
+
errorCallback: null,
|
|
616
|
+
options: {}
|
|
514
617
|
}
|
|
515
618
|
};
|