OzoneAsai commited on
Commit
d9cdcf5
·
verified ·
1 Parent(s): b5f6f02

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +305 -18
index.html CHANGED
@@ -1,19 +1,306 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  </html>
 
1
+ <!DOCTYPE html>
2
+ <html lang="ja">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>リアルタイムセンサーデータプロット</title>
6
+ <style>
7
+ body {
8
+ font-family: Arial, sans-serif;
9
+ text-align: center;
10
+ }
11
+ .chart-container {
12
+ display: inline-block;
13
+ margin: 20px;
14
+ }
15
+ svg {
16
+ border: 1px solid #ccc;
17
+ }
18
+ button {
19
+ padding: 10px 20px;
20
+ font-size: 16px;
21
+ margin: 10px;
22
+ }
23
+ .regex-container {
24
+ margin: 20px;
25
+ text-align: center;
26
+ }
27
+ .regex-container textarea {
28
+ width: 80%;
29
+ height: 60px;
30
+ font-size: 16px;
31
+ }
32
+ .message {
33
+ color: red;
34
+ font-weight: bold;
35
+ }
36
+ </style>
37
+ <!-- D3.jsの読み込み -->
38
+ <script src="https://d3js.org/d3.v7.min.js"></script>
39
+ </head>
40
+ <body>
41
+ <h1>リアルタイムセンサーデータプロット</h1>
42
+ <button id="connectButton">シリアルポートに接続</button>
43
+
44
+ <div class="regex-container">
45
+ <h2>正規表現設定</h2>
46
+ <p>以下の正規表現を使用してシリアルデータを解析します。3つのキャプチャグループ(左、中央、右センサー)を含むように設定してください。</p>
47
+ <textarea id="regexInput">Left Sensor:\s*(\d+)\s*\|\s*Center Sensor:\s*(\d+)\s*\|\s*Right Sensor:\s*(\d+)</textarea><br>
48
+ <button id="applyRegexButton">適用</button>
49
+ <div id="regexMessage" class="message"></div>
50
+ </div>
51
+
52
+ <div id="charts">
53
+ <div class="chart-container">
54
+ <h3>左センサー</h3>
55
+ <svg id="leftChart" width="500" height="200"></svg>
56
+ </div>
57
+ <div class="chart-container">
58
+ <h3>中央センサー</h3>
59
+ <svg id="centerChart" width="500" height="200"></svg>
60
+ </div>
61
+ <div class="chart-container">
62
+ <h3>右センサー</h3>
63
+ <svg id="rightChart" width="500" height="200"></svg>
64
+ </div>
65
+ </div>
66
+
67
+ <script>
68
+ // -------------------------------
69
+ // グローバル変数の設定
70
+ // -------------------------------
71
+ const MAX_POINTS = 75; // データ保持数
72
+
73
+ const leftData = [];
74
+ const centerData = [];
75
+ const rightData = [];
76
+ const timeData = [];
77
+
78
+ let currentTime = 0;
79
+ let sensorPattern = /Left Sensor:\s*(\d+)\s*\|\s*Center Sensor:\s*(\d+)\s*\|\s*Right Sensor:\s*(\d+)/;
80
+
81
+ // -------------------------------
82
+ // D3.jsによるグラフの初期設定
83
+ // -------------------------------
84
+ const charts = {
85
+ left: {
86
+ svg: d3.select("#leftChart"),
87
+ data: leftData,
88
+ color: "red",
89
+ path: null,
90
+ xScale: null,
91
+ yScale: null,
92
+ line: null
93
+ },
94
+ center: {
95
+ svg: d3.select("#centerChart"),
96
+ data: centerData,
97
+ color: "green",
98
+ path: null,
99
+ xScale: null,
100
+ yScale: null,
101
+ line: null
102
+ },
103
+ right: {
104
+ svg: d3.select("#rightChart"),
105
+ data: rightData,
106
+ color: "blue",
107
+ path: null,
108
+ xScale: null,
109
+ yScale: null,
110
+ line: null
111
+ }
112
+ };
113
+
114
+ const width = 500;
115
+ const height = 200;
116
+ const margin = {top: 20, right: 30, bottom: 30, left: 50};
117
+
118
+ // 初期化関数
119
+ function initCharts() {
120
+ for (let key in charts) {
121
+ const chart = charts[key];
122
+ // スケールの設定
123
+ chart.xScale = d3.scaleLinear().domain([0, MAX_POINTS - 1]).range([margin.left, width - margin.right]);
124
+ chart.yScale = d3.scaleLinear().domain([0, 1023]).range([height - margin.bottom, margin.top]); // センサー値の範囲に応じて調整
125
+
126
+ // 軸の追加
127
+ chart.svg.append("g")
128
+ .attr("transform", `translate(0,${height - margin.bottom})`)
129
+ .attr("class", "x-axis")
130
+ .call(d3.axisBottom(chart.xScale));
131
+
132
+ chart.svg.append("g")
133
+ .attr("transform", `translate(${margin.left},0)`)
134
+ .attr("class", "y-axis")
135
+ .call(d3.axisLeft(chart.yScale));
136
+
137
+ // パスの生成
138
+ chart.line = d3.line()
139
+ .x((d, i) => chart.xScale(i))
140
+ .y(d => chart.yScale(d))
141
+ .curve(d3.curveBasis); // スプライン曲線
142
+
143
+ chart.path = chart.svg.append("path")
144
+ .datum(chart.data)
145
+ .attr("fill", "none")
146
+ .attr("stroke", chart.color)
147
+ .attr("stroke-width", 2)
148
+ .attr("d", chart.line);
149
+ }
150
+ }
151
+
152
+ initCharts();
153
+
154
+ // -------------------------------
155
+ // シリアルポートへの接続とデータ読み取り
156
+ // -------------------------------
157
+ const connectButton = document.getElementById('connectButton');
158
+
159
+ connectButton.addEventListener('click', async () => {
160
+ try {
161
+ // シリアルポートのリクエスト
162
+ const port = await navigator.serial.requestPort();
163
+ // シリアルポートを開く
164
+ await port.open({ baudRate: 9600 });
165
+
166
+ // テキストストリームの作成
167
+ const textDecoder = new TextDecoderStream();
168
+ const readableStreamClosed = port.readable.pipeTo(textDecoder.writable);
169
+ const reader = textDecoder.readable.getReader();
170
+
171
+ // データの読み取り
172
+ while (true) {
173
+ const { value, done } = await reader.read();
174
+ if (done) {
175
+ // 読み取りストリームが終了した場合
176
+ break;
177
+ }
178
+ if (value) {
179
+ // 改行でデータを分割
180
+ const lines = value.split('\n');
181
+ lines.forEach(line => processData(line.trim()));
182
+ }
183
+ }
184
+ } catch (error) {
185
+ console.error('シリアルポート接続エラー:', error);
186
+ alert('シリアルポートの接続に失敗しました。コンソールを確認してください。');
187
+ }
188
+ });
189
+
190
+ // -------------------------------
191
+ // 正規表現の適用
192
+ // -------------------------------
193
+ const applyRegexButton = document.getElementById('applyRegexButton');
194
+ const regexInput = document.getElementById('regexInput');
195
+ const regexMessage = document.getElementById('regexMessage');
196
+
197
+ applyRegexButton.addEventListener('click', () => {
198
+ const userRegex = regexInput.value.trim();
199
+ if (!userRegex) {
200
+ regexMessage.textContent = '正規表現を入力してください。';
201
+ return;
202
+ }
203
+ try {
204
+ // 新しい正規表現をコンパイル
205
+ const newPattern = new RegExp(userRegex);
206
+ // テストデータで正規表現を確認(3つのキャプチャグループがあるか)
207
+ const testMatch = newPattern.exec('Left Sensor: 123 | Center Sensor: 456 | Right Sensor: 789');
208
+ if (!testMatch || testMatch.length < 4) {
209
+ throw new Error('正規表現には3つのキャプチャグループが必要です。');
210
+ }
211
+ // 正規表現を更新
212
+ sensorPattern = newPattern;
213
+ regexMessage.style.color = 'green';
214
+ regexMessage.textContent = '正規表現が正常に適用されました。';
215
+ } catch (e) {
216
+ console.error('正規表現エラー:', e);
217
+ regexMessage.style.color = 'red';
218
+ regexMessage.textContent = `正規表現エラー: ${e.message}`;
219
+ }
220
+ });
221
+
222
+ // -------------------------------
223
+ // データの処理関数
224
+ // -------------------------------
225
+ function processData(line) {
226
+ if (!line) return; // 空行は無視
227
+
228
+ const match = sensorPattern.exec(line);
229
+ if (match) {
230
+ if (match.length < 4) {
231
+ console.warn('正規表現が期待するキャプチャグループを含んでいません。');
232
+ return;
233
+ }
234
+ const left = parseInt(match[1], 10);
235
+ const center = parseInt(match[2], 10);
236
+ const right = parseInt(match[3], 10);
237
+
238
+ // データの追加
239
+ leftData.push(left);
240
+ centerData.push(center);
241
+ rightData.push(right);
242
+ timeData.push(currentTime);
243
+ currentTime += 1;
244
+
245
+ // データの保持数を制限
246
+ if (leftData.length > MAX_POINTS) {
247
+ leftData.shift();
248
+ centerData.shift();
249
+ rightData.shift();
250
+ timeData.shift();
251
+ }
252
+
253
+ // グラフの更新
254
+ updateCharts();
255
+ } else {
256
+ console.warn('不正なデータ形式:', line);
257
+ }
258
+ }
259
+
260
+ // -------------------------------
261
+ // グラフの更新関数
262
+ // -------------------------------
263
+ function updateCharts() {
264
+ for (let key in charts) {
265
+ const chart = charts[key];
266
+ // Yスケールの更新
267
+ const yMin = d3.min(chart.data.concat([0])) || 0;
268
+ const yMax = d3.max(chart.data.concat([0])) || 1023;
269
+ chart.yScale.domain([Math.min(yMin, 0), Math.max(yMax, 0)]);
270
+
271
+ // Y軸の再描画
272
+ chart.svg.select(".y-axis")
273
+ .transition()
274
+ .duration(500)
275
+ .call(d3.axisLeft(chart.yScale));
276
+
277
+ // パスの更新
278
+ chart.path
279
+ .datum(chart.data)
280
+ .attr("d", chart.line);
281
+ }
282
+
283
+ // Xスケールの更新
284
+ const currentLength = Math.max(leftData.length, centerData.length, rightData.length);
285
+ charts.left.xScale.domain([0, MAX_POINTS - 1]);
286
+ charts.center.xScale.domain([0, MAX_POINTS - 1]);
287
+ charts.right.xScale.domain([0, MAX_POINTS - 1]);
288
+
289
+ // X軸の再描画
290
+ for (let key in charts) {
291
+ const chart = charts[key];
292
+ chart.svg.select(".x-axis")
293
+ .transition()
294
+ .duration(500)
295
+ .call(d3.axisBottom(chart.xScale));
296
+ }
297
+ }
298
+
299
+ // -------------------------------
300
+ // 初期データの保持とグラフのリセット
301
+ // -------------------------------
302
+ // 必要に応じて追加
303
+
304
+ </script>
305
+ </body>
306
  </html>