chartjs-plugin-chart2music 0.0.3 → 0.0.4

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 CHANGED
@@ -39,7 +39,8 @@ new Chart(canvasElement, {
39
39
  This plugin is currently in beta, so not all of the chart.js features are currently supported.
40
40
 
41
41
  A quick list of chart.js features we currently support includes:
42
- * Chart types: bar, line, pie, doughnut, polar, and combinations therein.
42
+ * Chart types: bar, line, pie, doughnut, polar, radar, and combinations therein.
43
+ * Boxplots using the `@sgratzl/chartjs-chart-boxplot` plugin (only support boxplots when there are no other chart types present)
43
44
  * Axes options: `title`, `min`, `max`, `type="linear"`, `type="logarithmic"`.
44
45
  * Chart title
45
46
  * Most data structures (not including `parsing` or non-standard axes identifiers)
@@ -55,4 +56,11 @@ Things we plan to support in the future:
55
56
  * Locale
56
57
  * Dataset visibility (when you show/hide a category from the legend)
57
58
  * Radar charts
58
- * Custom formatting for axis tick values
59
+ * Custom formatting for axis tick values
60
+
61
+ Plugins we plan to support in the future:
62
+ * [chartjs-char-error-bars](https://www.npmjs.com/package/chartjs-chart-error-bars)
63
+ * [chartjs-chart-matrix](https://www.npmjs.com/package/chartjs-chart-matrix)
64
+ * [chartjs-chart-pcp](https://www.npmjs.com/package/chartjs-chart-pcp)
65
+ * [chartjs-chart-wordcloud](https://www.npmjs.com/package/chartjs-chart-wordcloud)
66
+ * [chartjs-plugin-zoom](https://www.npmjs.com/package/chartjs-plugin-zoom)
package/dist/plugin.js CHANGED
@@ -1,13 +1,90 @@
1
1
  var chartjs2music = (function (c2mChart) {
2
2
  'use strict';
3
3
 
4
+ const calcMedian = (nums) => (nums.length % 2) ? nums[Math.floor(nums.length / 2)] : (nums[nums.length / 2] + nums[nums.length / 2 - 1]) / 2;
5
+ const fiveNumberSummary = (nums) => {
6
+ const sortedNumbers = nums.sort();
7
+ let min, max, q1, q3;
8
+ const datamin = Math.min(...sortedNumbers);
9
+ const datamax = Math.max(...sortedNumbers);
10
+ const median = calcMedian(sortedNumbers);
11
+ const length = sortedNumbers.length;
12
+ if (length % 2) {
13
+ q1 = calcMedian(sortedNumbers.slice(0, Math.floor(length / 2)));
14
+ q3 = calcMedian(sortedNumbers.slice(Math.ceil(length % 2)));
15
+ }
16
+ else {
17
+ q1 = calcMedian(sortedNumbers.slice(0, length / 2 - 1));
18
+ q3 = calcMedian(sortedNumbers.slice(length / 2));
19
+ }
20
+ const iqr = q3 - q1;
21
+ if (datamax < q3 + iqr) {
22
+ max = datamax;
23
+ }
24
+ else {
25
+ max = sortedNumbers.reverse().find((num) => num < datamax) ?? datamax;
26
+ }
27
+ if (datamin < q1 - iqr) {
28
+ min = datamin;
29
+ }
30
+ else {
31
+ min = sortedNumbers.reverse().find((num) => num < datamin) ?? datamin;
32
+ }
33
+ const outlier = sortedNumbers.filter((num) => num < min || num > max);
34
+ return {
35
+ low: min,
36
+ high: max,
37
+ median,
38
+ q1,
39
+ q3,
40
+ ...(outlier.length > 0 ? { outlier } : {})
41
+ };
42
+ };
43
+ const whichBoxData = (data) => {
44
+ return data.map((row, index) => {
45
+ if (typeof row === "object" && "min" in row) {
46
+ return {
47
+ ...row,
48
+ low: row.min,
49
+ high: row.max,
50
+ x: index,
51
+ ...("outliers" in row ? { outlier: row.outliers } : {})
52
+ };
53
+ }
54
+ if (Array.isArray(row)) {
55
+ return {
56
+ ...fiveNumberSummary(row),
57
+ x: index
58
+ };
59
+ }
60
+ });
61
+ };
62
+ const processBoxData = (data) => {
63
+ if (data.datasets.length === 1) {
64
+ return {
65
+ data: whichBoxData(data.datasets[0].data)
66
+ };
67
+ }
68
+ const groups = [];
69
+ const result = {};
70
+ data.datasets.forEach((obj, index) => {
71
+ const groupName = obj.label ?? `Group ${index + 1}`;
72
+ groups.push(groupName);
73
+ result[groupName] = whichBoxData(obj.data);
74
+ });
75
+ return { groups, data: result };
76
+ };
77
+
4
78
  // let lastDataObj = "";
5
79
  const chartjs_c2m_converter = {
6
80
  bar: "bar",
7
81
  line: "line",
8
82
  pie: "pie",
9
83
  polarArea: "bar",
10
- doughnut: "pie"
84
+ doughnut: "pie",
85
+ boxplot: "box",
86
+ radar: "bar",
87
+ wordCloud: "bar"
11
88
  };
12
89
  const processChartType = (chart) => {
13
90
  const topLevelType = chart.config.type;
@@ -94,7 +171,10 @@ var chartjs2music = (function (c2mChart) {
94
171
  return { labels, data: blackboard };
95
172
  }
96
173
  };
97
- const processData = (data) => {
174
+ const processData = (data, c2m_types) => {
175
+ if (c2m_types === "box") {
176
+ return processBoxData(data);
177
+ }
98
178
  let groups = [];
99
179
  if (data.datasets.length === 1) {
100
180
  return {
@@ -135,9 +215,21 @@ var chartjs2music = (function (c2mChart) {
135
215
  return;
136
216
  }
137
217
  const axes = generateAxes(chart);
218
+ if (chart.config.type === "wordCloud") {
219
+ delete axes.x.minimum;
220
+ delete axes.x.maximum;
221
+ delete axes.y.minimum;
222
+ delete axes.y.maximum;
223
+ if (!axes.x.label) {
224
+ axes.x.label = "Word";
225
+ }
226
+ if (!axes.y.label) {
227
+ axes.y.label = "Emphasis";
228
+ }
229
+ }
138
230
  // Generate CC element
139
231
  const cc = determineCCElement(chart.canvas, options.cc);
140
- const { data, groups } = processData(chart.data);
232
+ const { data, groups } = processData(chart.data, c2m_types);
141
233
  // lastDataObj = JSON.stringify(data);
142
234
  let scrub = scrubX(data);
143
235
  if (scrub?.labels && scrub?.labels?.length > 0) { // Something was scrubbed
package/dist/plugin.mjs CHANGED
@@ -1,12 +1,89 @@
1
1
  import c2mChart from 'chart2music';
2
2
 
3
+ const calcMedian = (nums) => (nums.length % 2) ? nums[Math.floor(nums.length / 2)] : (nums[nums.length / 2] + nums[nums.length / 2 - 1]) / 2;
4
+ const fiveNumberSummary = (nums) => {
5
+ const sortedNumbers = nums.sort();
6
+ let min, max, q1, q3;
7
+ const datamin = Math.min(...sortedNumbers);
8
+ const datamax = Math.max(...sortedNumbers);
9
+ const median = calcMedian(sortedNumbers);
10
+ const length = sortedNumbers.length;
11
+ if (length % 2) {
12
+ q1 = calcMedian(sortedNumbers.slice(0, Math.floor(length / 2)));
13
+ q3 = calcMedian(sortedNumbers.slice(Math.ceil(length % 2)));
14
+ }
15
+ else {
16
+ q1 = calcMedian(sortedNumbers.slice(0, length / 2 - 1));
17
+ q3 = calcMedian(sortedNumbers.slice(length / 2));
18
+ }
19
+ const iqr = q3 - q1;
20
+ if (datamax < q3 + iqr) {
21
+ max = datamax;
22
+ }
23
+ else {
24
+ max = sortedNumbers.reverse().find((num) => num < datamax) ?? datamax;
25
+ }
26
+ if (datamin < q1 - iqr) {
27
+ min = datamin;
28
+ }
29
+ else {
30
+ min = sortedNumbers.reverse().find((num) => num < datamin) ?? datamin;
31
+ }
32
+ const outlier = sortedNumbers.filter((num) => num < min || num > max);
33
+ return {
34
+ low: min,
35
+ high: max,
36
+ median,
37
+ q1,
38
+ q3,
39
+ ...(outlier.length > 0 ? { outlier } : {})
40
+ };
41
+ };
42
+ const whichBoxData = (data) => {
43
+ return data.map((row, index) => {
44
+ if (typeof row === "object" && "min" in row) {
45
+ return {
46
+ ...row,
47
+ low: row.min,
48
+ high: row.max,
49
+ x: index,
50
+ ...("outliers" in row ? { outlier: row.outliers } : {})
51
+ };
52
+ }
53
+ if (Array.isArray(row)) {
54
+ return {
55
+ ...fiveNumberSummary(row),
56
+ x: index
57
+ };
58
+ }
59
+ });
60
+ };
61
+ const processBoxData = (data) => {
62
+ if (data.datasets.length === 1) {
63
+ return {
64
+ data: whichBoxData(data.datasets[0].data)
65
+ };
66
+ }
67
+ const groups = [];
68
+ const result = {};
69
+ data.datasets.forEach((obj, index) => {
70
+ const groupName = obj.label ?? `Group ${index + 1}`;
71
+ groups.push(groupName);
72
+ result[groupName] = whichBoxData(obj.data);
73
+ });
74
+ return { groups, data: result };
75
+ };
76
+
3
77
  // let lastDataObj = "";
4
78
  const chartjs_c2m_converter = {
5
79
  bar: "bar",
6
80
  line: "line",
7
81
  pie: "pie",
8
82
  polarArea: "bar",
9
- doughnut: "pie"
83
+ doughnut: "pie",
84
+ boxplot: "box",
85
+ radar: "bar",
86
+ wordCloud: "bar"
10
87
  };
11
88
  const processChartType = (chart) => {
12
89
  const topLevelType = chart.config.type;
@@ -93,7 +170,10 @@ const scrubX = (data) => {
93
170
  return { labels, data: blackboard };
94
171
  }
95
172
  };
96
- const processData = (data) => {
173
+ const processData = (data, c2m_types) => {
174
+ if (c2m_types === "box") {
175
+ return processBoxData(data);
176
+ }
97
177
  let groups = [];
98
178
  if (data.datasets.length === 1) {
99
179
  return {
@@ -134,9 +214,21 @@ const plugin = {
134
214
  return;
135
215
  }
136
216
  const axes = generateAxes(chart);
217
+ if (chart.config.type === "wordCloud") {
218
+ delete axes.x.minimum;
219
+ delete axes.x.maximum;
220
+ delete axes.y.minimum;
221
+ delete axes.y.maximum;
222
+ if (!axes.x.label) {
223
+ axes.x.label = "Word";
224
+ }
225
+ if (!axes.y.label) {
226
+ axes.y.label = "Emphasis";
227
+ }
228
+ }
137
229
  // Generate CC element
138
230
  const cc = determineCCElement(chart.canvas, options.cc);
139
- const { data, groups } = processData(chart.data);
231
+ const { data, groups } = processData(chart.data, c2m_types);
140
232
  // lastDataObj = JSON.stringify(data);
141
233
  let scrub = scrubX(data);
142
234
  if (scrub?.labels && scrub?.labels?.length > 0) { // Something was scrubbed
package/package.json CHANGED
@@ -1,55 +1,59 @@
1
- {
2
- "name": "chartjs-plugin-chart2music",
3
- "version": "0.0.3",
4
- "type": "module",
5
- "description": "Chart.js plugin for Chart2Music. Turns chart.js charts into music so the blind can hear data.",
6
- "main": "dist/plugin.js",
7
- "module": "dist/plugin.mjs",
8
- "exports": {
9
- "import": "./dist/plugin.mjs"
10
- },
11
- "files": ["dist/*"],
12
- "keywords": [
13
- "a11y",
14
- "accessibility",
15
- "chart.js",
16
- "chart",
17
- "dataviz",
18
- "screen reader",
19
- "sonification"
20
- ],
21
- "repository": {
22
- "type": "git",
23
- "url": "https://github.com/julianna-langston/chartjs2music"
24
- },
25
- "bugs": {
26
- "url": "https://github.com/julianna-langston/chartjs2music/issues"
27
- },
28
- "license": "MIT",
29
- "scripts": {
30
- "start": "vite",
31
- "build": "rollup -c rollup.config.js --silent",
32
- "test": "cross-env NODE_OPTIONS=--experimental-vm-modules jest",
33
- "depcheck": "depcheck",
34
- "clean": "rimraf dist coverage"
35
- },
36
- "devDependencies": {
37
- "@rollup/plugin-typescript": "^11.0.0",
38
- "@types/jest": "^29.4.0",
39
- "canvas": "^2.11.0",
40
- "cross-env": "^7.0.3",
41
- "depcheck": "^1.4.3",
42
- "jest": "^29.4.2",
43
- "jest-environment-jsdom": "^29.4.2",
44
- "rimraf": "^4.1.2",
45
- "rollup": "^3.15.0",
46
- "ts-jest": "^29.0.5",
47
- "tslib": "^2.5.0",
48
- "typescript": "^4.9.3",
49
- "vite": "^4.1.0"
50
- },
51
- "dependencies": {
52
- "chart.js": "^4.2.1",
53
- "chart2music": "^1.8.2"
54
- }
55
- }
1
+ {
2
+ "name": "chartjs-plugin-chart2music",
3
+ "version": "0.0.4",
4
+ "type": "module",
5
+ "description": "Chart.js plugin for Chart2Music. Turns chart.js charts into music so the blind can hear data.",
6
+ "main": "dist/plugin.js",
7
+ "module": "dist/plugin.mjs",
8
+ "exports": {
9
+ "import": "./dist/plugin.mjs"
10
+ },
11
+ "files": [
12
+ "dist/*"
13
+ ],
14
+ "keywords": [
15
+ "a11y",
16
+ "accessibility",
17
+ "chart.js",
18
+ "chart",
19
+ "dataviz",
20
+ "screen reader",
21
+ "sonification"
22
+ ],
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "https://github.com/julianna-langston/chartjs2music"
26
+ },
27
+ "bugs": {
28
+ "url": "https://github.com/julianna-langston/chartjs2music/issues"
29
+ },
30
+ "license": "MIT",
31
+ "scripts": {
32
+ "start": "vite",
33
+ "build": "rollup -c rollup.config.js --silent",
34
+ "test": "cross-env NODE_OPTIONS=--experimental-vm-modules jest",
35
+ "depcheck": "depcheck",
36
+ "clean": "rimraf dist coverage"
37
+ },
38
+ "devDependencies": {
39
+ "@rollup/plugin-typescript": "^11.0.0",
40
+ "@sgratzl/chartjs-chart-boxplot": "^4.1.1",
41
+ "@types/jest": "^29.4.0",
42
+ "canvas": "^2.11.0",
43
+ "chartjs-chart-wordcloud": "^4.1.1",
44
+ "cross-env": "^7.0.3",
45
+ "depcheck": "^1.4.3",
46
+ "jest": "^29.4.2",
47
+ "jest-environment-jsdom": "^29.4.2",
48
+ "rimraf": "^4.1.2",
49
+ "rollup": "^3.15.0",
50
+ "ts-jest": "^29.0.5",
51
+ "tslib": "^2.5.0",
52
+ "typescript": "^4.9.3",
53
+ "vite": "^4.1.0"
54
+ },
55
+ "dependencies": {
56
+ "chart.js": "^4.2.1",
57
+ "chart2music": "^1.8.2"
58
+ }
59
+ }