data-plotter 1.1.0 → 1.2.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 CHANGED
@@ -1,82 +1,82 @@
1
- # OHZI Data Plotter
2
-
3
- Data Plotter is a tiny javascript library that allows you to draw live data in a 2D graph.
4
-
5
-
6
- ### Dependencies
7
-
8
- Data Plotter has no external dependencies
9
-
10
- ### Installation
11
-
12
- ```sh
13
- $ npm install data-plotter --save
14
- ```
15
-
16
-
17
- ### Usage
18
-
19
- ```javascript
20
- import { DataPlotter } from 'data-plotter';
21
-
22
- class AwesomeGraph
23
- {
24
- constructor()
25
- {
26
- this.graph = new DataPlotter({ name:'Graph of Sine function' });
27
- }
28
-
29
- update(sample)
30
- {
31
- this.graph.draw_dynamic_live_array(sample, 0, true, '#70b9fc');
32
- }
33
- }
34
-
35
- class RenderLoop
36
- {
37
- start()
38
- {
39
- this.awesome_graph = new AwesomeGraph();
40
- this.t = 0;
41
-
42
- this.update();
43
- }
44
-
45
- update()
46
- {
47
- this.awesome_graph.update(Math.sin(this.t));
48
-
49
- this.t += 0.016;
50
-
51
- requestAnimationFrame(this.update.bind(this));
52
- }
53
- }
54
-
55
- new RenderLoop().start();
56
- ```
57
-
58
- ### API
59
-
60
- - `draw_function(func: any, min_x?: number, max_x?: number, graph_height?: number, color?: string, thick?: number): void;`
61
-
62
- - `draw_array(array: any, graph_height?: number, baseline?: number, centered_origin?: boolean, color?: string, thick?: number): void;`
63
-
64
- - `draw_static_live_array(value: any, graph_height?: number, baseline?: number, centered_origin?: boolean, color?: string, thick?: number): void;`
65
-
66
- - `draw_dynamic_live_array(value: any, baseline?: number, centered_origin?: boolean, color?: string, thick?: number): void;`
67
-
68
-
69
- ### Running the examples
70
- You can check out the examples folder, all you need to do is set up an http server for it to work, using something like `http-server` package.
71
-
72
- ```sh
73
- npm install -g http-server
74
- cd examples
75
- http-server -p 1234
76
- ```
77
- This will mount an http server on the examples folder on port 1234
78
-
79
- License
80
- ----
81
-
82
- MIT
1
+ # OHZI Data Plotter
2
+
3
+ Data Plotter is a tiny javascript library that allows you to draw live data in a 2D graph.
4
+
5
+
6
+ ### Dependencies
7
+
8
+ Data Plotter has no external dependencies
9
+
10
+ ### Installation
11
+
12
+ ```sh
13
+ $ npm install data-plotter --save
14
+ ```
15
+
16
+
17
+ ### Usage
18
+
19
+ ```javascript
20
+ import { DataPlotter } from 'data-plotter';
21
+
22
+ class AwesomeGraph
23
+ {
24
+ constructor()
25
+ {
26
+ this.graph = new DataPlotter({ name:'Graph of Sine function' });
27
+ }
28
+
29
+ update(sample)
30
+ {
31
+ this.graph.draw_dynamic_live_array(sample, 0, true, '#70b9fc');
32
+ }
33
+ }
34
+
35
+ class RenderLoop
36
+ {
37
+ start()
38
+ {
39
+ this.awesome_graph = new AwesomeGraph();
40
+ this.t = 0;
41
+
42
+ this.update();
43
+ }
44
+
45
+ update()
46
+ {
47
+ this.awesome_graph.update(Math.sin(this.t));
48
+
49
+ this.t += 0.016;
50
+
51
+ requestAnimationFrame(this.update.bind(this));
52
+ }
53
+ }
54
+
55
+ new RenderLoop().start();
56
+ ```
57
+
58
+ ### API
59
+
60
+ - `draw_function(func: any, min_x?: number, max_x?: number, graph_height?: number, color?: string, thick?: number): void;`
61
+
62
+ - `draw_array(array: any, graph_height?: number, baseline?: number, centered_origin?: boolean, color?: string, thick?: number): void;`
63
+
64
+ - `draw_static_live_array(value: any, graph_height?: number, baseline?: number, centered_origin?: boolean, color?: string, thick?: number): void;`
65
+
66
+ - `draw_dynamic_live_array(value: any, baseline?: number, centered_origin?: boolean, color?: string, thick?: number): void;`
67
+
68
+
69
+ ### Running the examples
70
+ You can check out the examples folder, all you need to do is set up an http server for it to work, using something like `http-server` package.
71
+
72
+ ```sh
73
+ npm install -g http-server
74
+ cd examples
75
+ http-server -p 1234
76
+ ```
77
+ This will mount an http server on the examples folder on port 1234
78
+
79
+ License
80
+ ----
81
+
82
+ MIT
@@ -1,244 +1,252 @@
1
- class DataPlotter
2
- {
3
- constructor({
4
- id = '',
5
- name = '',
6
- container_selector = undefined,
7
- width = 400,
8
- height = 100,
9
- raw_data_suffix = ''
10
- })
11
- {
12
- let parent = document.querySelector(container_selector);
13
-
14
- if (!parent)
15
- {
16
- parent = document.createElement('div');
17
- parent.classList.add('data-plotter');
18
- parent.style.display = 'flex';
19
-
20
- parent.style['flex-direction'] = 'column';
21
- parent.style['z-index'] = 999;
22
- parent.style['pointer-events'] = 'none';
23
- parent.style['flex-wrap'] = 'wrap';
24
-
25
- parent.style.width = 'fit-content';
26
-
27
- document.body.appendChild(parent);
28
- }
29
-
30
- this.container = document.createElement('div');
31
-
32
- if (id)
33
- {
34
- this.container.dataset.id = id;
35
- }
36
-
37
- this.container.style.position = 'relative';
38
- this.container.style.margin = '5px';
39
- this.container.style.marginTop = '2px';
40
- parent.appendChild(this.container);
41
-
42
- const name_label = document.createElement('div');
43
- name_label.textContent = name;
44
- name_label.style.color = '#000000';
45
- name_label.style.marginLeft = '5px';
46
- name_label.style.marginTop = '5px';
47
- name_label.style.marginBottom = '5px';
48
- name_label.style.fontFamily = 'Arial';
49
- this.container.appendChild(name_label);
50
-
51
- this.canvas = document.createElement('canvas');
52
- this.canvas.style.display = 'flex';
53
-
54
- this.on_resize(width, height);
55
-
56
- this.container.appendChild(this.canvas);
57
-
58
- this.raw_data_label = document.createElement('div');
59
- this.raw_data_label.classList.add('data-plotter__raw-data');
60
- this.raw_data_label.style.position = 'absolute';
61
- this.raw_data_label.style.bottom = '4px';
62
- this.raw_data_label.style.right = '4px';
63
- this.raw_data_label.style['font-family'] = 'Arial';
64
- this.raw_data_label.style['font-size'] = '12px';
65
- this.container.appendChild(this.raw_data_label);
66
-
67
- this.raw_data_suffix = raw_data_suffix;
68
-
69
- this.ctx = this.canvas.getContext('2d');
70
-
71
- this.live_data_array = [];
72
-
73
- for (let i = 0; i < width; i++)
74
- {
75
- this.live_data_array.push(0);
76
- }
77
- }
78
-
79
- on_resize(width, height)
80
- {
81
- this.canvas.width = width * window.devicePixelRatio;
82
- this.canvas.height = height * window.devicePixelRatio;
83
-
84
- this.canvas.style.width = width + 'px';
85
- this.canvas.style.height = height + 'px';
86
- }
87
-
88
- draw_function(func, min_x = 0, max_x = 1, graph_height = 1, color = '#FF0000', thick = 1)
89
- {
90
- let ctx = this.ctx;
91
- let canvas_length = ctx.canvas.width;
92
-
93
- ctx.fillStyle = '#888888';
94
- ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
95
-
96
- this.showAxes();
97
-
98
- ctx.beginPath();
99
- ctx.lineWidth = thick;
100
- ctx.strokeStyle = color;
101
-
102
- for (let i = 0; i < canvas_length; i++)
103
- {
104
- let result = func(this.lerp(min_x, max_x, i / canvas_length)) / graph_height;
105
-
106
- let y = ctx.canvas.height - result * (ctx.canvas.height - thick);
107
-
108
- if (i === 0)
109
- {
110
- ctx.moveTo(i, y);
111
- }
112
- else
113
- {
114
- ctx.lineTo(i, y);
115
- }
116
- }
117
-
118
- ctx.stroke();
119
- }
120
-
121
- draw_array(array, graph_height = 1, baseline = 0, centered_origin = false, color = '#70b9fc', thick = 1)
122
- {
123
- let ctx = this.ctx;
124
- let canvas_length = ctx.canvas.width;
125
-
126
- ctx.fillStyle = '#f2f2f2';
127
- ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
128
-
129
- ctx.beginPath();
130
- ctx.lineWidth = thick;
131
- ctx.strokeStyle = color;
132
-
133
- let use_center = centered_origin === true ? 0.5 : 1;
134
-
135
- for (let i = 0; i < canvas_length; i++)
136
- {
137
- let array_i = Math.floor((i / canvas_length) * array.length);
138
- let result = (array[array_i] - baseline) / graph_height;
139
-
140
- let y = ctx.canvas.height * use_center - result * (ctx.canvas.height * use_center - thick);
141
-
142
- if (i === 0)
143
- {
144
- ctx.moveTo(i, y);
145
- }
146
- else
147
- {
148
- ctx.lineTo(i, y);
149
- }
150
- }
151
-
152
- ctx.stroke();
153
-
154
- if (centered_origin)
155
- {
156
- this.draw_min_max_labels(graph_height);
157
- }
158
- else
159
- {
160
- this.draw_max_label(graph_height);
161
- }
162
- }
163
-
164
- draw_static_live_array(value, graph_height = 1, baseline = 0, centered_origin = false, color = '#70b9fc', thick = 1)
165
- {
166
- this.raw_data_label.textContent = `${value.toFixed(2)}${this.raw_data_suffix}`;
167
-
168
- this.live_data_array.push(value);
169
- this.live_data_array.shift();
170
- this.draw_array(this.live_data_array, graph_height, baseline, centered_origin, color, thick);
171
- if (centered_origin)
172
- {
173
- this.draw_min_max_labels(graph_height);
174
- }
175
- else
176
- {
177
- this.draw_max_label(graph_height);
178
- }
179
- }
180
-
181
- draw_dynamic_live_array(value, baseline = 0, centered_origin = false, color = '#70b9fc', thick = 1)
182
- {
183
- this.raw_data_label.textContent = `${value.toFixed(2)}${this.raw_data_suffix}`;
184
-
185
- this.live_data_array.push(value);
186
- this.live_data_array.shift();
187
-
188
- let max_value = 1;
189
- for (let i = 0; i < this.live_data_array.length; i++)
190
- {
191
- if (Math.abs(this.live_data_array[i]) > max_value)
192
- {
193
- max_value = Math.abs(this.live_data_array[i]);
194
- }
195
- }
196
-
197
- this.draw_array(this.live_data_array, max_value, baseline, centered_origin, color, thick);
198
-
199
- if (centered_origin)
200
- {
201
- this.draw_min_max_labels(max_value);
202
- }
203
- else
204
- {
205
- this.draw_max_label(max_value);
206
- }
207
- }
208
-
209
- draw_min_max_labels(value)
210
- {
211
- const top_bottom_padding = 12;
212
- const left_right_padding = 10;
213
-
214
- this.ctx.font = '20px Arial';
215
- this.ctx.fillStyle = '#000000';
216
- this.ctx.textBaseline = 'alphabetic';
217
- this.ctx.fillText('-' + value.toFixed(1), left_right_padding, this.ctx.canvas.height - top_bottom_padding);
218
- this.ctx.textBaseline = 'hanging';
219
- this.ctx.fillText(value.toFixed(1), left_right_padding, top_bottom_padding);
220
-
221
- // Center line
222
- this.ctx.beginPath();
223
- this.ctx.lineWidth = 1;
224
- this.ctx.strokeStyle = '#BBBBBB';
225
- this.ctx.moveTo(0, this.ctx.canvas.height / 2);
226
- this.ctx.lineTo(this.ctx.canvas.width, this.ctx.canvas.height / 2);
227
- this.ctx.stroke();
228
- }
229
-
230
- draw_max_label(value)
231
- {
232
- this.ctx.font = '20px Arial';
233
- this.ctx.fillStyle = '#000000';
234
- this.ctx.textBaseline = 'hanging';
235
- this.ctx.fillText(value.toFixed(1), 5, 8);
236
- }
237
-
238
- lerp(a, b, t)
239
- {
240
- return (1 - t) * a + b * t;
241
- }
1
+ class DataPlotter
2
+ {
3
+ constructor({
4
+ id = '',
5
+ name = '',
6
+ container_selector = undefined,
7
+ width = 400,
8
+ height = 100,
9
+ raw_data_suffix = '',
10
+ background_color = '#FFFFFF',
11
+ text_color = '#000000',
12
+ center_line_color = '#808080'
13
+ })
14
+ {
15
+ let parent = document.querySelector(container_selector);
16
+ if (!parent)
17
+ {
18
+ parent = document.createElement('div');
19
+ parent.classList.add('data-plotter');
20
+ parent.style.display = 'flex';
21
+
22
+ parent.style['flex-direction'] = 'column';
23
+ parent.style['z-index'] = 999;
24
+ parent.style['pointer-events'] = 'none';
25
+ parent.style['flex-wrap'] = 'wrap';
26
+
27
+ parent.style.width = 'fit-content';
28
+
29
+ document.body.appendChild(parent);
30
+ }
31
+
32
+ this.background_color = background_color;
33
+ this.text_color = text_color;
34
+ this.center_line_color = center_line_color;
35
+
36
+ this.container = document.createElement('div');
37
+
38
+ if (id)
39
+ {
40
+ this.container.dataset.id = id;
41
+ }
42
+
43
+ this.container.style.position = 'relative';
44
+ this.container.style.margin = '5px';
45
+ this.container.style.marginTop = '2px';
46
+ parent.appendChild(this.container);
47
+
48
+ const name_label = document.createElement('div');
49
+ name_label.textContent = name;
50
+ name_label.style.color = text_color;
51
+ name_label.style.marginLeft = '5px';
52
+ name_label.style.marginTop = '5px';
53
+ name_label.style.marginBottom = '5px';
54
+ name_label.style.fontFamily = 'Arial';
55
+ this.container.appendChild(name_label);
56
+
57
+ this.canvas = document.createElement('canvas');
58
+ this.canvas.style.display = 'flex';
59
+
60
+ this.on_resize(width, height);
61
+
62
+ this.container.appendChild(this.canvas);
63
+
64
+ this.raw_data_label = document.createElement('div');
65
+ this.raw_data_label.classList.add('data-plotter__raw-data');
66
+ this.raw_data_label.style.position = 'absolute';
67
+ this.raw_data_label.style.bottom = '4px';
68
+ this.raw_data_label.style.right = '4px';
69
+ this.raw_data_label.style.color = text_color;
70
+ this.raw_data_label.style['font-family'] = 'Arial';
71
+ this.raw_data_label.style['font-size'] = '12px';
72
+ this.container.appendChild(this.raw_data_label);
73
+
74
+ this.raw_data_suffix = raw_data_suffix;
75
+
76
+ this.ctx = this.canvas.getContext('2d');
77
+
78
+ this.live_data_array = [];
79
+
80
+ for (let i = 0; i < width; i++)
81
+ {
82
+ this.live_data_array.push(0);
83
+ }
84
+ }
85
+
86
+ on_resize(width, height)
87
+ {
88
+ this.canvas.width = width * window.devicePixelRatio;
89
+ this.canvas.height = height * window.devicePixelRatio;
90
+
91
+ this.canvas.style.width = width + 'px';
92
+ this.canvas.style.height = height + 'px';
93
+ }
94
+
95
+ draw_function(func, min_x = 0, max_x = 1, graph_height = 1, color = '#FF0000', thick = 1)
96
+ {
97
+ let ctx = this.ctx;
98
+ let canvas_length = ctx.canvas.width;
99
+
100
+ ctx.fillStyle = this.background_color;
101
+ ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
102
+
103
+ this.showAxes();
104
+
105
+ ctx.beginPath();
106
+ ctx.lineWidth = thick;
107
+ ctx.strokeStyle = color;
108
+
109
+ for (let i = 0; i < canvas_length; i++)
110
+ {
111
+ let result = func(this.lerp(min_x, max_x, i / canvas_length)) / graph_height;
112
+
113
+ let y = ctx.canvas.height - result * (ctx.canvas.height - thick);
114
+
115
+ if (i === 0)
116
+ {
117
+ ctx.moveTo(i, y);
118
+ }
119
+ else
120
+ {
121
+ ctx.lineTo(i, y);
122
+ }
123
+ }
124
+
125
+ ctx.stroke();
126
+ }
127
+
128
+ draw_array(array, graph_height = 1, baseline = 0, centered_origin = false, color = '#70b9fc', thick = 1)
129
+ {
130
+ let ctx = this.ctx;
131
+ let canvas_length = ctx.canvas.width;
132
+
133
+ ctx.fillStyle = this.background_color;
134
+
135
+ ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
136
+
137
+ ctx.beginPath();
138
+ ctx.lineWidth = thick;
139
+ ctx.strokeStyle = color;
140
+
141
+ let use_center = centered_origin === true ? 0.5 : 1;
142
+
143
+ for (let i = 0; i < canvas_length; i++)
144
+ {
145
+ let array_i = Math.floor((i / canvas_length) * array.length);
146
+ let result = (array[array_i] - baseline) / graph_height;
147
+
148
+ let y = ctx.canvas.height * use_center - result * (ctx.canvas.height * use_center - thick);
149
+
150
+ if (i === 0)
151
+ {
152
+ ctx.moveTo(i, y);
153
+ }
154
+ else
155
+ {
156
+ ctx.lineTo(i, y);
157
+ }
158
+ }
159
+
160
+ ctx.stroke();
161
+
162
+ if (centered_origin)
163
+ {
164
+ this.draw_min_max_labels(graph_height);
165
+ }
166
+ else
167
+ {
168
+ this.draw_max_label(graph_height);
169
+ }
170
+ }
171
+
172
+ draw_static_live_array(value, graph_height = 1, baseline = 0, centered_origin = false, color = '#70b9fc', thick = 1)
173
+ {
174
+ this.raw_data_label.textContent = `${value.toFixed(2)}${this.raw_data_suffix}`;
175
+
176
+ this.live_data_array.push(value);
177
+ this.live_data_array.shift();
178
+ this.draw_array(this.live_data_array, graph_height, baseline, centered_origin, color, thick);
179
+ if (centered_origin)
180
+ {
181
+ this.draw_min_max_labels(graph_height);
182
+ }
183
+ else
184
+ {
185
+ this.draw_max_label(graph_height);
186
+ }
187
+ }
188
+
189
+ draw_dynamic_live_array(value, baseline = 0, centered_origin = false, color = '#70b9fc', thick = 1)
190
+ {
191
+ this.raw_data_label.textContent = `${value.toFixed(2)}${this.raw_data_suffix}`;
192
+
193
+ this.live_data_array.push(value);
194
+ this.live_data_array.shift();
195
+
196
+ let max_value = 1;
197
+ for (let i = 0; i < this.live_data_array.length; i++)
198
+ {
199
+ if (Math.abs(this.live_data_array[i]) > max_value)
200
+ {
201
+ max_value = Math.abs(this.live_data_array[i]);
202
+ }
203
+ }
204
+
205
+ this.draw_array(this.live_data_array, max_value, baseline, centered_origin, color, thick);
206
+
207
+ if (centered_origin)
208
+ {
209
+ this.draw_min_max_labels(max_value);
210
+ }
211
+ else
212
+ {
213
+ this.draw_max_label(max_value);
214
+ }
215
+ }
216
+
217
+ draw_min_max_labels(value)
218
+ {
219
+ const top_bottom_padding = 12;
220
+ const left_right_padding = 10;
221
+
222
+ this.ctx.font = '20px Arial';
223
+ this.ctx.fillStyle = this.text_color;
224
+ this.ctx.textBaseline = 'alphabetic';
225
+ this.ctx.fillText('-' + value.toFixed(1), left_right_padding, this.ctx.canvas.height - top_bottom_padding);
226
+ this.ctx.textBaseline = 'hanging';
227
+ this.ctx.fillText(value.toFixed(1), left_right_padding, top_bottom_padding);
228
+
229
+ // Center line
230
+ this.ctx.beginPath();
231
+ this.ctx.lineWidth = 1;
232
+ this.ctx.strokeStyle = this.center_line_color;
233
+ this.ctx.moveTo(0, this.ctx.canvas.height / 2);
234
+ this.ctx.lineTo(this.ctx.canvas.width, this.ctx.canvas.height / 2);
235
+ this.ctx.stroke();
236
+ }
237
+
238
+ draw_max_label(value)
239
+ {
240
+ this.ctx.font = '20px Arial';
241
+ this.ctx.fillStyle = this.text_color;
242
+ this.ctx.textBaseline = 'hanging';
243
+ this.ctx.fillText(value.toFixed(1), 5, 8);
244
+ }
245
+
246
+ lerp(a, b, t)
247
+ {
248
+ return (1 - t) * a + b * t;
249
+ }
242
250
  }
243
251
 
244
252
  export { DataPlotter };