chartjs-plugin-chart2music 0.6.0 → 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 +96 -71
- package/dist/plugin.amd.js +180 -46
- package/dist/plugin.cjs +336 -231
- package/dist/plugin.d.ts +8 -1
- package/dist/plugin.js +180 -46
- package/dist/plugin.mjs +180 -46
- package/package.json +58 -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,110 +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 && chartAxisInfo.min) {
|
|
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 (chartAxisInfo !==
|
|
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
|
-
|
|
184
|
-
}
|
|
185
|
-
})
|
|
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
|
+
}
|
|
186
156
|
};
|
|
157
|
+
const xAxisValueLabels = chart.data.labels.slice(0);
|
|
158
|
+
if (xAxisValueLabels.length > 0) {
|
|
159
|
+
axes.x.valueLabels = xAxisValueLabels;
|
|
160
|
+
}
|
|
187
161
|
return axes;
|
|
188
162
|
};
|
|
189
|
-
|
|
163
|
+
const whichDataStructure = data => {
|
|
190
164
|
if (Array.isArray(data[0])) {
|
|
191
|
-
return data.map(
|
|
192
|
-
|
|
193
|
-
_arr$sort2 = _slicedToArray(_arr$sort, 2),
|
|
194
|
-
low = _arr$sort2[0],
|
|
195
|
-
high = _arr$sort2[1];
|
|
165
|
+
return data.map((arr, x) => {
|
|
166
|
+
let [low, high] = arr.sort();
|
|
196
167
|
return {
|
|
197
|
-
x
|
|
198
|
-
low
|
|
199
|
-
high
|
|
168
|
+
x,
|
|
169
|
+
low,
|
|
170
|
+
high
|
|
200
171
|
};
|
|
201
172
|
});
|
|
202
173
|
}
|
|
203
174
|
return data;
|
|
204
175
|
};
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
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 = [];
|
|
208
229
|
if (Array.isArray(data)) {
|
|
209
230
|
// console.log("not grouped");
|
|
210
231
|
// Not grouped
|
|
211
|
-
blackboard.forEach(
|
|
212
|
-
if (
|
|
232
|
+
blackboard.forEach((item, x) => {
|
|
233
|
+
if (typeof item === "object" && item !== null && "x" in item) {
|
|
213
234
|
labels.push(item.x);
|
|
214
235
|
item.x = x;
|
|
215
236
|
}
|
|
216
237
|
});
|
|
217
238
|
return {
|
|
218
|
-
labels
|
|
239
|
+
labels,
|
|
219
240
|
data: blackboard
|
|
220
241
|
};
|
|
242
|
+
} else {
|
|
243
|
+
// Grouped
|
|
244
|
+
return undefined;
|
|
221
245
|
}
|
|
222
246
|
};
|
|
223
|
-
|
|
247
|
+
const processData = (data, c2m_types) => {
|
|
224
248
|
if (c2m_types === "box") {
|
|
225
249
|
return processBoxData(data);
|
|
226
250
|
}
|
|
227
|
-
|
|
251
|
+
if (c2m_types === "matrix") {
|
|
252
|
+
return processMatrixData(data);
|
|
253
|
+
}
|
|
254
|
+
let groups = [];
|
|
228
255
|
if (data.datasets.length === 1) {
|
|
229
256
|
return {
|
|
230
257
|
data: whichDataStructure(data.datasets[0].data)
|
|
231
258
|
};
|
|
232
259
|
}
|
|
233
|
-
|
|
234
|
-
data.datasets.forEach(
|
|
235
|
-
|
|
236
|
-
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}`;
|
|
237
263
|
groups.push(groupName);
|
|
238
264
|
result[groupName] = whichDataStructure(obj.data);
|
|
239
265
|
});
|
|
240
266
|
return {
|
|
241
|
-
groups
|
|
267
|
+
groups,
|
|
242
268
|
data: result
|
|
243
269
|
};
|
|
244
270
|
};
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
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) {
|
|
248
273
|
if (Array.isArray(options.plugins.title.text)) {
|
|
249
274
|
return options.plugins.title.text.join(", ");
|
|
250
275
|
}
|
|
@@ -252,62 +277,70 @@ var determineChartTitle = function determineChartTitle(options) {
|
|
|
252
277
|
}
|
|
253
278
|
return "";
|
|
254
279
|
};
|
|
255
|
-
|
|
280
|
+
const determineCCElement = (canvas, provided) => {
|
|
256
281
|
if (provided) {
|
|
257
282
|
return provided;
|
|
258
283
|
}
|
|
259
|
-
|
|
284
|
+
const cc = document.createElement("div");
|
|
260
285
|
canvas.insertAdjacentElement("afterend", cc);
|
|
261
286
|
return cc;
|
|
262
287
|
};
|
|
263
|
-
|
|
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 => {
|
|
264
295
|
if (!chartStates.has(chart)) {
|
|
265
296
|
return;
|
|
266
297
|
}
|
|
267
|
-
|
|
268
|
-
ref
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
point
|
|
272
|
-
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) || [];
|
|
273
308
|
try {
|
|
274
|
-
|
|
275
|
-
var highlightElements = [];
|
|
309
|
+
const highlightElements = [];
|
|
276
310
|
if ("custom" in point) {
|
|
311
|
+
const customPoint = point;
|
|
277
312
|
highlightElements.push({
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
// @ts-ignore
|
|
281
|
-
index: point.custom.index
|
|
313
|
+
datasetIndex: customPoint.custom.datasetIndex ?? customPoint.custom.group,
|
|
314
|
+
index: customPoint.custom.index
|
|
282
315
|
});
|
|
283
316
|
} else {
|
|
284
|
-
|
|
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 => {
|
|
285
320
|
highlightElements.push({
|
|
286
|
-
datasetIndex:
|
|
287
|
-
index
|
|
321
|
+
datasetIndex: groupIndex - 1,
|
|
322
|
+
index
|
|
288
323
|
});
|
|
289
324
|
});
|
|
290
325
|
}
|
|
291
|
-
chart
|
|
292
|
-
chart
|
|
293
|
-
chart
|
|
326
|
+
chart?.setActiveElements(highlightElements);
|
|
327
|
+
chart?.tooltip?.setActiveElements(highlightElements, {});
|
|
328
|
+
chart?.update();
|
|
294
329
|
} catch (e) {
|
|
295
330
|
// console.warn(e);
|
|
296
331
|
}
|
|
297
332
|
};
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
333
|
+
const generateChart = (chart, options) => {
|
|
334
|
+
const {
|
|
335
|
+
valid,
|
|
336
|
+
c2m_types,
|
|
337
|
+
invalidType
|
|
338
|
+
} = processChartType(chart);
|
|
304
339
|
if (!valid) {
|
|
305
|
-
|
|
306
|
-
// @ts-ignore
|
|
307
|
-
(_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(", ")}`);
|
|
308
341
|
return;
|
|
309
342
|
}
|
|
310
|
-
|
|
343
|
+
let axes = generateAxes(chart, options);
|
|
311
344
|
if (chart.config.type === "wordCloud") {
|
|
312
345
|
delete axes.x.minimum;
|
|
313
346
|
delete axes.x.maximum;
|
|
@@ -321,96 +354,126 @@ var generateChart = function generateChart(chart, options) {
|
|
|
321
354
|
}
|
|
322
355
|
}
|
|
323
356
|
// Generate CC element
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
357
|
+
const cc = determineCCElement(chart.canvas, options.cc);
|
|
358
|
+
const processedData = processData(chart.data, c2m_types);
|
|
359
|
+
const {
|
|
360
|
+
data
|
|
361
|
+
} = processedData;
|
|
328
362
|
// lastDataObj = JSON.stringify(data);
|
|
329
|
-
|
|
330
|
-
|
|
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) {
|
|
331
376
|
// Something was scrubbed
|
|
332
377
|
if (!chart.data.labels || chart.data.labels.length === 0) {
|
|
333
378
|
axes.x.valueLabels = scrub.labels.slice(0);
|
|
334
379
|
}
|
|
335
380
|
}
|
|
336
381
|
if (c2m_types === "scatter") {
|
|
337
|
-
|
|
382
|
+
delete scrub?.data;
|
|
338
383
|
delete axes.x.valueLabels;
|
|
339
384
|
}
|
|
340
|
-
axes =
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
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,
|
|
346
405
|
element: chart.canvas,
|
|
347
406
|
type: c2m_types,
|
|
348
|
-
data:
|
|
407
|
+
data: scrub?.data ?? data,
|
|
349
408
|
title: determineChartTitle(chart.options),
|
|
350
|
-
axes
|
|
409
|
+
axes,
|
|
351
410
|
options: {
|
|
352
|
-
|
|
353
|
-
onFocusCallback:
|
|
354
|
-
|
|
355
|
-
|
|
411
|
+
...userOptions,
|
|
412
|
+
onFocusCallback: userOnFocusCallback ? point => {
|
|
413
|
+
pluginOnFocusCallback();
|
|
414
|
+
userOnFocusCallback(point);
|
|
415
|
+
} : pluginOnFocusCallback
|
|
356
416
|
}
|
|
357
417
|
};
|
|
358
418
|
if (Array.isArray(c2mOptions.data)) {
|
|
359
419
|
if (isNaN(c2mOptions.data[0])) {
|
|
360
|
-
c2mOptions.data = c2mOptions.data.map(
|
|
361
|
-
return
|
|
420
|
+
c2mOptions.data = c2mOptions.data.map((point, index) => {
|
|
421
|
+
return {
|
|
422
|
+
...point,
|
|
362
423
|
custom: {
|
|
363
|
-
|
|
364
|
-
|
|
424
|
+
...point.custom,
|
|
425
|
+
group: point.custom?.group ?? 0,
|
|
426
|
+
index: point.custom?.index ?? index
|
|
365
427
|
}
|
|
366
|
-
}
|
|
428
|
+
};
|
|
367
429
|
});
|
|
368
430
|
} else {
|
|
369
|
-
c2mOptions.data = c2mOptions.data.map(
|
|
431
|
+
c2mOptions.data = c2mOptions.data.map((num, index) => {
|
|
370
432
|
return {
|
|
371
433
|
x: index,
|
|
372
434
|
y: num,
|
|
373
435
|
custom: {
|
|
374
436
|
group: 0,
|
|
375
|
-
index
|
|
437
|
+
index
|
|
376
438
|
}
|
|
377
439
|
};
|
|
378
440
|
});
|
|
379
441
|
}
|
|
380
442
|
} else {
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
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) => {
|
|
385
448
|
return {
|
|
386
449
|
x: index,
|
|
387
450
|
y: num,
|
|
388
451
|
custom: {
|
|
389
452
|
group: groupNumber,
|
|
390
|
-
index
|
|
453
|
+
index
|
|
391
454
|
}
|
|
392
455
|
};
|
|
393
456
|
});
|
|
394
457
|
} else {
|
|
395
|
-
|
|
396
|
-
return
|
|
458
|
+
dataObj[groupName] = dataObj[groupName].map((point, index) => {
|
|
459
|
+
return {
|
|
460
|
+
...point,
|
|
397
461
|
custom: {
|
|
398
|
-
|
|
399
|
-
|
|
462
|
+
...point.custom,
|
|
463
|
+
group: point.custom?.group ?? groupNumber,
|
|
464
|
+
index: point.custom?.index ?? index
|
|
400
465
|
}
|
|
401
|
-
}
|
|
466
|
+
};
|
|
402
467
|
});
|
|
403
468
|
}
|
|
404
469
|
});
|
|
405
470
|
}
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
471
|
+
if (chart.config.options?.scales?.x?.stacked) {
|
|
472
|
+
if (c2mOptions.options) {
|
|
473
|
+
c2mOptions.options.stack = true;
|
|
474
|
+
}
|
|
410
475
|
}
|
|
411
|
-
// @ts-ignore
|
|
412
476
|
if (options.audioEngine) {
|
|
413
|
-
// @ts-ignore
|
|
414
477
|
c2mOptions.audioEngine = options.audioEngine;
|
|
415
478
|
}
|
|
416
479
|
if (c2mOptions.data.length === 0) {
|
|
@@ -419,36 +482,51 @@ var generateChart = function generateChart(chart, options) {
|
|
|
419
482
|
if (options.lang) {
|
|
420
483
|
c2mOptions.lang = options.lang;
|
|
421
484
|
}
|
|
422
|
-
|
|
423
|
-
err
|
|
424
|
-
c2m
|
|
485
|
+
const {
|
|
486
|
+
err,
|
|
487
|
+
data: c2m
|
|
488
|
+
} = (0, _chart2music.default)(c2mOptions);
|
|
425
489
|
/* istanbul-ignore-next */
|
|
426
490
|
if (err) {
|
|
427
|
-
|
|
428
|
-
// @ts-ignore
|
|
429
|
-
(_options$errorCallbac2 = options.errorCallback) === null || _options$errorCallbac2 === void 0 || _options$errorCallbac2.call(options, err);
|
|
491
|
+
options.errorCallback?.(err);
|
|
430
492
|
return;
|
|
431
493
|
}
|
|
432
494
|
if (!c2m) {
|
|
433
495
|
return;
|
|
434
496
|
}
|
|
435
497
|
chartStates.set(chart, {
|
|
436
|
-
c2m
|
|
437
|
-
|
|
438
|
-
return i;
|
|
439
|
-
})) !== null && _groups$map !== void 0 ? _groups$map : []
|
|
498
|
+
c2m,
|
|
499
|
+
lastDataSnapshot: createDataSnapshot(chart)
|
|
440
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
|
+
}
|
|
441
520
|
};
|
|
442
|
-
|
|
521
|
+
const plugin = exports.default = {
|
|
443
522
|
id: "chartjs2music",
|
|
444
|
-
afterInit:
|
|
523
|
+
afterInit: (chart, _args, options) => {
|
|
445
524
|
if (!chartStates.has(chart)) {
|
|
446
525
|
generateChart(chart, options);
|
|
447
526
|
// Remove tooltip when the chart blurs
|
|
448
|
-
chart.canvas.addEventListener("blur",
|
|
449
|
-
var _chart$tooltip2;
|
|
527
|
+
chart.canvas.addEventListener("blur", () => {
|
|
450
528
|
chart.setActiveElements([]);
|
|
451
|
-
|
|
529
|
+
chart.tooltip?.setActiveElements([], {});
|
|
452
530
|
try {
|
|
453
531
|
chart.update();
|
|
454
532
|
} catch (e) {
|
|
@@ -456,58 +534,85 @@ var plugin = exports["default"] = {
|
|
|
456
534
|
}
|
|
457
535
|
});
|
|
458
536
|
// Show tooltip when the chart receives focus
|
|
459
|
-
chart.canvas.addEventListener("focus",
|
|
537
|
+
chart.canvas.addEventListener("focus", () => {
|
|
460
538
|
displayPoint(chart);
|
|
461
539
|
});
|
|
462
540
|
}
|
|
463
541
|
},
|
|
464
|
-
afterDatasetUpdate:
|
|
542
|
+
afterDatasetUpdate: (chart, args, options) => {
|
|
465
543
|
if (!args.mode) {
|
|
466
544
|
return;
|
|
467
545
|
}
|
|
468
546
|
if (!chartStates.has(chart)) {
|
|
469
547
|
generateChart(chart, options);
|
|
470
548
|
}
|
|
471
|
-
|
|
472
|
-
ref
|
|
473
|
-
|
|
549
|
+
const {
|
|
550
|
+
c2m: ref
|
|
551
|
+
} = chartStates.get(chart);
|
|
474
552
|
if (!ref) {
|
|
475
553
|
return;
|
|
476
554
|
}
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
if (ref._options.stack) {
|
|
555
|
+
const refInternal = ref;
|
|
556
|
+
const groups = refInternal._groups.slice(0);
|
|
557
|
+
if (refInternal._options.stack) {
|
|
481
558
|
groups.shift();
|
|
482
559
|
}
|
|
483
560
|
if (args.mode === "hide") {
|
|
484
|
-
|
|
485
|
-
visible_groups.splice(args.index, 1);
|
|
561
|
+
const err = ref.setCategoryVisibility(groups[args.index], false);
|
|
486
562
|
if (err) {
|
|
487
563
|
console.error(err);
|
|
488
564
|
}
|
|
489
565
|
return;
|
|
490
566
|
}
|
|
491
567
|
if (args.mode === "show") {
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
console.error(_err);
|
|
568
|
+
const err = ref.setCategoryVisibility(groups[args.index], true);
|
|
569
|
+
if (err) {
|
|
570
|
+
console.error(err);
|
|
496
571
|
}
|
|
497
572
|
return;
|
|
498
573
|
}
|
|
499
574
|
},
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
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) {
|
|
504
602
|
return;
|
|
505
603
|
}
|
|
604
|
+
const {
|
|
605
|
+
c2m: ref
|
|
606
|
+
} = state;
|
|
607
|
+
if (state?.matrixKeydown && state.matrixKeydownTarget) {
|
|
608
|
+
state.matrixKeydownTarget.removeEventListener("keydown", state.matrixKeydown, true);
|
|
609
|
+
}
|
|
506
610
|
ref.cleanUp();
|
|
507
611
|
},
|
|
508
612
|
defaults: {
|
|
509
613
|
cc: null,
|
|
510
614
|
audioEngine: null,
|
|
511
|
-
errorCallback: null
|
|
615
|
+
errorCallback: null,
|
|
616
|
+
options: {}
|
|
512
617
|
}
|
|
513
618
|
};
|