irie 0.0.49__py3-none-any.whl → 0.0.51__py3-none-any.whl

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.

Potentially problematic release.


This version of irie might be problematic. Click here for more details.

Files changed (37) hide show
  1. irie/apps/inventory/filters.py +11 -29
  2. irie/apps/inventory/models.py +3 -3
  3. irie/apps/inventory/views.py +9 -2
  4. irie/apps/prediction/admin.py +2 -1
  5. irie/apps/prediction/migrations/0004_sensorassignment.py +31 -0
  6. irie/apps/prediction/migrations/0005_remove_sensorassignment_offset_x_and_more.py +53 -0
  7. irie/apps/prediction/migrations/0006_remove_sensorassignment_show_x_and_more.py +25 -0
  8. irie/apps/prediction/models.py +22 -3
  9. irie/apps/prediction/runners/__init__.py +11 -2
  10. irie/apps/prediction/runners/opensees/__init__.py +114 -62
  11. irie/apps/prediction/runners/ssid.py +9 -10
  12. irie/apps/prediction/urls.py +12 -7
  13. irie/apps/prediction/views.py +81 -24
  14. irie/apps/static/assets/css/brace.css +5 -31
  15. irie/apps/static/assets/css/brace.css.map +1 -1
  16. irie/apps/static/assets/css/brace.min.css +2 -2
  17. irie/apps/templates/components/json-table.html +1 -0
  18. irie/apps/templates/includes/paginate.js +6 -0
  19. irie/apps/templates/includes/scripts.html +7 -20
  20. irie/apps/templates/inventory/asset-on-map.html +5 -5
  21. irie/apps/templates/inventory/sensor-upload.html +97 -262
  22. irie/apps/templates/networks/{networks.html → _networks.html} +0 -1
  23. irie/apps/templates/networks/networks.js +6 -4
  24. irie/apps/templates/prediction/asset-predictors.html +41 -47
  25. irie/apps/templates/prediction/{form-submission.html → create-mdof.html} +0 -21
  26. irie/apps/templates/prediction/new-runner.html +0 -20
  27. irie/apps/templates/prediction/predictor-profile.html +8 -134
  28. irie/apps/templates/prediction/viewer/veux-viewer.js +186 -0
  29. irie/apps/templates/prediction/xara-profile.html +221 -0
  30. irie/apps/templates/sensors/render-sensors.js +152 -0
  31. irie/init/management/commands/init_cesmd.py +2 -2
  32. {irie-0.0.49.dist-info → irie-0.0.51.dist-info}/METADATA +2 -3
  33. {irie-0.0.49.dist-info → irie-0.0.51.dist-info}/RECORD +37 -30
  34. {irie-0.0.49.dist-info → irie-0.0.51.dist-info}/WHEEL +1 -1
  35. /irie/apps/templates/prediction/{predictor-upload.html → create-model.html} +0 -0
  36. {irie-0.0.49.dist-info → irie-0.0.51.dist-info}/entry_points.txt +0 -0
  37. {irie-0.0.49.dist-info → irie-0.0.51.dist-info}/top_level.txt +0 -0
@@ -31,27 +31,6 @@
31
31
  </div>
32
32
  <div class="row">
33
33
  <div class="container">
34
- <p>
35
- From <a href="https://json-editor.github.io/json-editor/form-submission.html">source</a>
36
- See <a href="https://json-editor.github.io/json-editor/">also</a>
37
-
38
- </p>
39
- <p>
40
- The form is set to send a <code>GET</code> request to the same page.
41
- A change event listener has been added to the editor so that whenever the form changes, the editor value
42
- is stored in a hidden input using <code>JSON.stringify()</code>.
43
- </p>
44
-
45
- <p>
46
- The option <code>use_name_attributes</code> was set to <code>false</code>
47
- to avoid sending the other field with the request.
48
- </p>
49
- <p>
50
- When the form is submitted only the hidden input is sent in the request.
51
- This allows to send data structures like arrays and object.
52
- Also the same schema that is used to build the form can be used as parameter to backend json validators tools.
53
- Try yourself, submit the form and look in the network tab of the developer tool.
54
- </p>
55
34
  <div class="form-group"></div>
56
35
  <form action="/docs/form-submission.html" method="get">
57
36
  <input id="input" type="hidden" name="type" value="{{ runner. }}">
@@ -22,26 +22,6 @@
22
22
  <div class="modal-body">
23
23
  <div class="row">
24
24
  <div class="container">
25
- {% comment %}
26
- <!--
27
- From <a href="https://json-editor.github.io/json-editor/form-submission.html">source</a>
28
- See <a href="https://json-editor.github.io/json-editor/">also</a>
29
-
30
- The form is set to send a <code>GET</code> request to the same page.
31
- A change event listener has been added to the editor so that whenever the form changes, the editor value
32
- is stored in a hidden input using <code>JSON.stringify()</code>.
33
-
34
- The option <code>use_name_attributes</code> was set to <code>false</code>
35
- to avoid sending the other field with the request.
36
-
37
- When the form is submitted only the hidden input is sent in the request.
38
- This allows to send data structures like arrays and object.
39
- Also the same schema that is used to build the form can be used as parameter to backend json validators tools.
40
- Try yourself, submit the form and look in the network tab of the developer tool.
41
- -->
42
- {% endcomment %}
43
- {# form.as_p #}
44
-
45
25
  <div class="form-group"></div>
46
26
  <form id="{{runner.name}}" action="./create/" method="post" >
47
27
  {% csrf_token %}
@@ -1,132 +1,15 @@
1
1
  {% extends "layouts/base.html" %}
2
2
  {% load predictor %}
3
- {% block title %} {{ asset.calid }} | {{ predictor.name }} {% endblock %}
4
- {% block stylesheets %}
5
- <style>
6
- @media print {
7
- @page {
8
- /* size:210mm 297mm; */
9
- size: 8.5in 11in;
10
- }
11
- #event-table, #rendering, #predictorProfile {
12
- display: none;
13
- visibility: hidden;
14
- max-width: 0;
15
- }
16
- #page {
17
- width: 100%;
18
- margin-left: 0;
19
- margin-right: 0;
20
- margin-top: 0.5in;
21
- margin-bottom: 0.75in;
22
- float: none !important;
23
- }
24
- html, body {
25
- margin: 0 !important;
26
- padding: 0 !important;
27
- height: 99%;
28
- width: 100%;
29
- float: none !important;
30
- }
31
- body {
32
- font: 10pt "Computer Modern", Georgia, "Times New Roman", Times, serif;
33
- line-height: 1.1;
34
- background: #fff !important;
35
- color: #000;
36
- }
37
- h1 {
38
- font-size: 16pt;
39
- /* position: fixed;
40
- top: 0; */
41
- }
42
- h2, h3, h4 {
43
- font-size: 14pt;
44
- /* margin-top: 25px; */
45
- }
46
- main, div.print {
47
- visibility: visible;
48
- width: auto; /* 100%; */
49
- font-size: 10pt;
50
- margin: 0; /* 0.50in 0.5in 0.5in 0.5in; */
51
- float: none ! important;
52
- page-break-inside:auto ;
53
- /* height: 900px; */
54
- }
55
- tr { page-break-inside:avoid; page-break-after:auto }
56
- thead { display:table-header-group }
57
- tfoot { display:table-footer-group }
58
- table {
59
- border-bottom: 2px solid black;
60
- border-top: 2px solid black;
61
- font-size: 8pt;
62
- visibility: visible;
63
- width: 100%;
64
- margin: 0;
65
- float: none;
66
- page-break-inside:auto ;
67
- page-break-after:auto;
68
- }
69
- hr, img, nav, footer, .button, #rendering, #event-table {
70
- visibility: hidden;
71
- display: none;
72
- max-height: 0;
73
- max-width: 0;
74
- }
75
- details > summary {
76
- list-style: none;
77
- }
78
- details > summary::marker {
79
- display:none;
80
- }
81
-
82
- /*
83
- #header,
84
- #footer,
85
- #nav {
86
- display: none !important;
87
- }
88
- */
89
- .ssid-data {
90
- visibility: visible;
91
- display: block;
92
- }
93
- }
94
- .ct-series-a .ct-point, .ct-series-a .ct-line, .ct-series-a .ct-bar, .ct-series-a .ct-slice-donut{
95
- stroke: #506690;
96
- }
97
- .ct-series-b .ct-point, .ct-series-b .ct-line, .ct-series-b .ct-bar, .ct-series-b .ct-slice-donut {
98
- stroke: #61DAFB;
99
- }
100
- </style>
101
- {% endblock stylesheets %}
3
+ {% block title %} {{ asset.calid }} | {{ runner.name }} {% endblock %}
102
4
 
103
5
  {% block content %}
104
- <div class="print">
6
+
105
7
  <h1 class="fs-2 lh-2 me-3"><code>{{ asset.calid }}</code> {{ asset.name }}</h1>
106
8
  <span id="predictorProfile" class="fs-2 lh-2 me-3">Predictor Profile</span>
107
9
 
108
- {# BRIDGE RENDERING #}
109
- <div id="rendering" class="row">
110
- <div class="col-12 mb-4">
111
- <div class="card h-100 bg-white-100 border-0 shadow">
112
- <div class="card-header d-sm-flex flex-row align-items-center flex-0">
113
- </div>
114
- <div class="card-body p-2">
115
- {% if predictor.rendering %}
116
- <model-viewer alt="Model rendering"
117
- src="{{ predictor.rendering.path }}" ar
118
- style="width: 100%; height: 300px;"
119
- shadow-intensity="1" camera-controls touch-action="pan-y">
120
- </model-viewer>
121
- {% endif %}
122
- </div>
123
- </div>
124
- </div>
125
- </div>
126
-
127
10
  <details id="event-table" open><summary><h3>Configuraion</h3></summary>
128
11
  <div class="table-responsive">
129
- {{ predictor|display_predictor }}
12
+ {{ runner|display_predictor }}
130
13
  </div>
131
14
  <div class="row">
132
15
  <div class="col-12 mb-4">
@@ -139,28 +22,19 @@
139
22
  <div class="col-10 card bg-white-100 border-0 shadow mb-4">
140
23
  <div class="card-body">
141
24
  <div class="crop">
142
- <img src="data:image/jpeg;base64,{{ predictor.render }}" alt="Spectral content">
25
+ <img src="data:image/jpeg;base64,{{ runner.render }}" alt="Spectral content">
143
26
  </div>
144
27
  </div>
145
28
  <div class="card-footer">
146
29
  Powered by <a href="https://chrystalchern.github.io/mdof"><em>mdof</em></a>
147
30
  </div>
148
31
  </div>
149
- </div>
150
32
  {% endblock content %}
151
33
 
152
- <script>
153
- const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]')
154
- const tooltipList = [...tooltipTriggerList].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl))
155
- </script>
156
- {% block javascripts %}
157
34
 
158
- <script type="text/javascript">
159
- function printTables() {
160
- var myWindow = window.open('','','width=200,height=100')
161
- myWindow.document.write("This is 'myWindow'")
162
- myWindow.print();
163
- }
35
+ {% block javascripts %}
36
+ <script>
37
+ const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]')
38
+ const tooltipList = [...tooltipTriggerList].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl))
164
39
  </script>
165
-
166
40
  {% endblock javascripts %}
@@ -0,0 +1,186 @@
1
+ //===----------------------------------------------------------------------===//
2
+ //
3
+ // STAIRLab -- STructural Artificial Intelligence Laboratory
4
+ //
5
+ //===----------------------------------------------------------------------===//
6
+ //
7
+ class VeuxViewer {
8
+ #initializedTabs;
9
+ #table;
10
+ #tabLinkContainer;
11
+ #tabContentContainer;
12
+
13
+ constructor(table, tabLinkContainer, tabContentContainer) {
14
+ this.#table = table;
15
+ this.#initializedTabs = [];
16
+ this.#tabLinkContainer = tabLinkContainer;
17
+ this.#tabContentContainer = tabContentContainer;
18
+ }
19
+
20
+ initTabs(tab1, tabselector) {
21
+ this.#initializedTabs.push(tab1);
22
+
23
+ const tabs = this.#tabLinkContainer.querySelectorAll(tabselector);
24
+
25
+ tabs.forEach(tab => {
26
+ tab.addEventListener('click', (e) => {
27
+ e.preventDefault();
28
+ this.clickTab(tab);
29
+ });
30
+ });
31
+ }
32
+
33
+ select(elem) {
34
+ const sname = elem.dataset.section;
35
+
36
+ if (this.#initializedTabs.includes(sname)) {
37
+ const tabLink = this.#tabLinkContainer.querySelector(`#${sname}-tab`);
38
+ this.clickTab(tabLink);
39
+ return;
40
+ }
41
+
42
+ this.addTab(sname);
43
+ }
44
+
45
+ addTab(corr) {
46
+ const tab = `${corr}`;
47
+
48
+ //
49
+ //
50
+ //
51
+ const tabLink = document.createElement('a');
52
+ tabLink.id = `${tab}-tab`;
53
+ tabLink.classList.add("tab-link", "nav-link", "active");
54
+ tabLink.href = "#";
55
+ tabLink.setAttribute('data-tab', tab);
56
+ tabLink.setAttribute('data-section', corr);
57
+ tabLink.setAttribute('data-bs-toggle', 'tab');
58
+ tabLink.setAttribute('role', 'tab');
59
+ tabLink.innerHTML = `${corr} <button class="btn-close" type="button" aria-label="Close"></button>`;
60
+ const closeButton = tabLink.querySelector('.btn-close');
61
+ closeButton.addEventListener('click', (e) => {
62
+ this.delTab(tabLink);
63
+ });
64
+ tabLink.addEventListener('click', (e) => {
65
+ e.preventDefault();
66
+ this.clickTab(tabLink);
67
+ });
68
+
69
+ const tabItem = document.createElement('li');
70
+ tabItem.role = 'presentation';
71
+ tabItem.classList.add('nav-item');
72
+ tabItem.appendChild(tabLink);
73
+ // Add to list of tabs
74
+ this.#tabLinkContainer.appendChild(tabItem);
75
+
76
+ //
77
+ //
78
+ //
79
+ const tabContent = document.createElement('div');
80
+ tabContent.classList.add('tab-content', 'mt-3', 'card-body', 'p-2');
81
+ tabContent.id = `${tab}-content`;
82
+ tabContent.style.display = 'block';
83
+ this.#tabContentContainer.appendChild(tabContent);
84
+
85
+ // Get the data-tab attribute to know which content to load
86
+ const selectedTab = tabLink.getAttribute('data-tab');
87
+
88
+ this.#initializedTabs.push(tab);
89
+
90
+ this.clickTab(tabLink);
91
+
92
+ this.fetchAndUpdateTab(selectedTab, corr);
93
+ return tabLink;
94
+ }
95
+
96
+ clickTab(tabLink) {
97
+
98
+ const tabs = this.#tabLinkContainer.querySelectorAll('.tab-link');
99
+
100
+ // Remove 'active' class from all tabs
101
+ tabs.forEach(t => {
102
+ t.classList.remove('active');
103
+ });
104
+
105
+ // Add 'active' class to the clicked tab
106
+ tabLink.classList.add('active');
107
+
108
+ const tab = tabLink.getAttribute('data-tab');
109
+ const contentDiv = this.#tabContentContainer.querySelector(`#${tab}-content`);
110
+
111
+ contentDiv.style.display = 'block';
112
+ this.#tabContentContainer.querySelectorAll(".tab-content").forEach((el) => {
113
+ if (el.id != `${tab}-content`) {
114
+ el.style.display = 'none';
115
+ }
116
+ });
117
+ }
118
+
119
+ delTab(tabLink) {
120
+ const tab = tabLink.getAttribute('data-tab');
121
+ const corr = tabLink.getAttribute('data-corridor');
122
+ const tabContent = this.#tabContentContainer.querySelector(`#${tab}-content`);
123
+ tabContent.remove();
124
+
125
+ const tabItem = tabLink.parentElement;
126
+ tabItem.remove();
127
+
128
+ const idx = this.#initializedTabs.indexOf(tab);
129
+ if (idx > -1) {
130
+ this.#initializedTabs.splice(idx, 1);
131
+ }
132
+ this.clickTab(document.getElementById('tab1-tab'));
133
+ }
134
+
135
+ fetchAndUpdateTab(tab) {
136
+ const contentDiv = this.#tabContentContainer.querySelector(`#${tab}-content`);
137
+
138
+ // Show loading message while content is being fetched
139
+ contentDiv.innerHTML = `
140
+ <div class="text-center">
141
+ <div class="spinner-border" role="status">
142
+ <span class="visually-hidden">Loading...</span>
143
+ </div>
144
+ </div>
145
+ `;
146
+
147
+ let apiUrl = `/inventory/04-0236/predictors/1389/detail/?section=${tab}`;
148
+
149
+ if (true) {
150
+ contentDiv.innerHTML = "";
151
+ const mv = document.createElement('model-viewer');
152
+
153
+ mv.setAttribute('camera-controls', '');
154
+ mv.setAttribute('autoplay', '');
155
+ mv.setAttribute('interaction-prompt', 'none');
156
+ mv.style.width = '100%';
157
+ mv.style.height = '400px';
158
+
159
+ mv.src = apiUrl;
160
+ contentDiv.appendChild(mv);
161
+ return;
162
+ }
163
+ fetch(apiUrl)
164
+ .then(response => response.json())
165
+ .then(data => {
166
+ // Replace the loading message with the fetched content
167
+ // when we get it
168
+ contentDiv.innerHTML = "";
169
+ const mv = document.createElement('model-viewer');
170
+
171
+ mv.setAttribute('camera-controls', '');
172
+ mv.setAttribute('autoplay', '');
173
+ mv.setAttribute('interaction-prompt', 'none');
174
+ mv.style.width = '100%';
175
+ mv.style.height = '400px';
176
+
177
+ // set the data-URI source
178
+ mv.src = `data:model/gltf-binary;base64,${data.rendering}`;
179
+ contentDiv.appendChild(mv);
180
+ })
181
+ .catch(error => {
182
+ console.error('Error fetching content:', error);
183
+ document.getElementById('tab-content').innerHTML = '<p>Error loading content.</p>';
184
+ });
185
+ }
186
+ }
@@ -0,0 +1,221 @@
1
+ {% extends "layouts/base.html" %}
2
+ {% load predictor %}
3
+ {% block title %} {{ asset.calid }} | {{ runner.name }} {% endblock %}
4
+ {% block stylesheets %}
5
+ <!-- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.8.2/css/all.min.css" integrity="sha512-rqQltXRuHxtPWhktpAZxLHUVJ3Eombn3hvk9PHjV/N5DMUYnzKPC1i3ub0mEXgFzsaZNeJcoE0YHq0j/GFsdGg==" crossorigin="anonymous" referrerpolicy="no-referrer" /> -->
6
+ <script type="importmap">
7
+ {
8
+ "imports": {
9
+ "three": "https://cdn.jsdelivr.net/npm/three@0.172.0/build/three.module.js",
10
+ "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.172.0/examples/jsm/"
11
+ }
12
+ }
13
+ </script>
14
+ <script type="module" src="https://unpkg.com/@google/model-viewer/dist/model-viewer.min.js"></script>
15
+
16
+ {% endblock stylesheets %}
17
+
18
+ {% block content %}
19
+
20
+ <div class="col-10 mb-4 d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center py-4">
21
+ <div class="d-block mb-4 mb-md-0">
22
+ <nav aria-label="breadcrumb" class="d-none d-md-inline-block">
23
+ <ol class="breadcrumb breadcrumb-dark breadcrumb-transparent">
24
+ <li class="breadcrumb-item">
25
+ <a href="{% url 'dashboard' %}">
26
+ <svg class="icon icon-xxs" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"></path></svg>
27
+ </a>
28
+ </li>
29
+ <li class="breadcrumb-item" aria-current="page"><a href="{% url 'asset_table' %}">Inventory</a></li>
30
+ <li class="breadcrumb-item"><a href="{% url 'asset_profile' asset.calid %}"><code>{{ asset.calid }}</code></a></li>
31
+ <li class="breadcrumb-item"><a href="{% url 'asset_predictors' asset.calid %}">Predictors</a></li>
32
+ <li class="breadcrumb-item active"><code>{{ predictor.id }}</code></li>
33
+ </ol>
34
+ </nav>
35
+ <h1 class="fs-2 lh-2 me-3"><code>{{ asset.calid }}</code> {{ asset.name }}</h1>
36
+ </div>
37
+ </div>
38
+
39
+ <div class="">
40
+ <div class="row align-right">
41
+ <!-- Left Side: Sensor Form -->
42
+ <div class="col-md-4" >
43
+ <div class="card bg-white-100 border-1 rounded-0 shadow">
44
+ <div class="card-header d-sm-flex flex-row align-items-center flex-0">
45
+ <select id="table-switcher"
46
+ class="form-select form-select-sm me-2">
47
+ <option value="members">Members</option>
48
+ <option value="sensors">Sensors</option>
49
+ </select>
50
+ </div>
51
+ <div class="card-body">
52
+ <div class="table-response">
53
+ <table id="members"
54
+ class="table align-items-center table-flush">
55
+ <thead class="thead-light">
56
+ <tr>
57
+ <th class="border-bottom" scope="col">#</th>
58
+ <th class="border-bottom" scope="col">Type</th>
59
+ <th class="border-bottom" scope="col">Section</th>
60
+ </tr>
61
+ </thead>
62
+ <tbody>
63
+ {% for member in members %}
64
+ <tr id="veux-member-{{member.id}}"
65
+ data-section="{{ member.section }}"
66
+ style="cursor: pointer;"
67
+ onClick="handleMemberSelection(this)">
68
+ <td><code>{{ member.name }}</code></td>
69
+ <td>{{ member.type }}</td>
70
+ <td class="fw-bolder text-gray-800">
71
+ {{ member.section }}
72
+ </td>
73
+ </tr>
74
+ {% endfor %}
75
+ </tbody>
76
+ </table>
77
+
78
+ <table id="sensors" class="table align-items-center table-flush" hidden>
79
+ <thead class="thead-light">
80
+ <tr>
81
+ <th class="border-bottom" scope="col">#</th>
82
+ <th class="border-bottom" scope="col">Node</th>
83
+ <th class="border-bottom" scope="col">Type</th>
84
+ </tr>
85
+ </thead>
86
+ <tbody>
87
+ {% for sensor in sensors %}
88
+ <tr id="sensor-{{sensor.id}}"
89
+ data-sensor-x="{{ sensor.sensor.x }}"
90
+ data-sensor-y="{{ sensor.sensor.y }}"
91
+ data-sensor-z="{{ sensor.sensor.z }}"
92
+ data-sensor-dx="{{ sensor.sensor.dx }}"
93
+ data-sensor-dy="{{ sensor.sensor.dy }}"
94
+ data-sensor-dz="{{ sensor.sensor.dy }}">
95
+ <td><code>{{ sensor.id }}</code></td>
96
+ <td>{{ sensor.node }}</td>
97
+ <td>{{ sensor.role }}</td>
98
+ </tr>
99
+ {% endfor %}
100
+ </tbody>
101
+ </table>
102
+ <nav>
103
+ <ul class="pagination" id="pagination"></ul>
104
+ </nav>
105
+ </div>
106
+ </div>
107
+ </div>
108
+ </div>
109
+
110
+ <!-- Right Side: Predictor Rendering -->
111
+ <div class="col-md-8">
112
+ <div id="rendering" class="card bg-white-100 border-1 rounded-0 shadow">
113
+ <div class="card-header">
114
+ <ul id="tab-link-container" class="nav nav-tabs" id="myTab" role="tablist">
115
+ <li class="nav-item" role="presentation">
116
+ <a class="nav-link tab-link active"
117
+ id="tab1-tab"
118
+ data-bs-toggle="tab" href="#"
119
+ data-tab="tab1"
120
+ role="tab">Model</a>
121
+ </li>
122
+ </ul>
123
+ </div>
124
+ <div class="card-body text-center" style="background-color: #f0f0f0;">
125
+ <div id="tab-content-container">
126
+ <div id="tab1-content" class="tab-content">
127
+ <div id="main-viewer"
128
+ style="width: 100%; height: 300px; background-color: #f0f0f0; margin: 0 auto;">
129
+ </div>
130
+ </div>
131
+ </div>
132
+ </div>
133
+ <div class="card-footer text-center">
134
+ Powered by <a href="https://veux.io/">veux</a>
135
+ </div>
136
+ </div>
137
+ </div>
138
+ </div>
139
+ </div>
140
+ {% endblock content %}
141
+
142
+ {% block javascripts %}
143
+
144
+ <script>
145
+ {% include "prediction/viewer/veux-viewer.js" %}
146
+
147
+ const VIEWER = new VeuxViewer(document.querySelector('#members'),
148
+ document.querySelector('#tab-link-container'),
149
+ document.getElementById('tab-content-container'));
150
+
151
+ function handleMemberSelection(elem) {
152
+ VIEWER.select(elem);
153
+ }
154
+
155
+ document.addEventListener('DOMContentLoaded', function () {
156
+ VIEWER.initTabs('tab1', '.tab-link');
157
+ });
158
+
159
+ </script>
160
+
161
+ <script>
162
+ const select = document.getElementById('table-switcher');
163
+ const tables = Object.fromEntries(
164
+ Array.from(document.querySelectorAll('table')).map(t => [t.id, t])
165
+ );
166
+
167
+ select.addEventListener('change', e => {
168
+ const chosen = e.target.value;
169
+ for (const [id, tbl] of Object.entries(tables)) {
170
+ tbl.hidden = id !== chosen; // HTML `hidden` handles show/hide
171
+ }
172
+ });
173
+ </script>
174
+
175
+ <script type="module">
176
+ {% include "sensors/render-sensors.js" %}
177
+
178
+ document.addEventListener('DOMContentLoaded', () => {
179
+ const container = document.getElementById("main-viewer");
180
+
181
+ const modelPath = "{{ predictor.render_file.url|safe }}";
182
+
183
+ const scene = createSensorRenderer(container, modelPath);
184
+
185
+ const arrowObjects = [];
186
+
187
+ // Loop through each sensor form and create an arrow
188
+ document.querySelector('#sensors').querySelectorAll('tr').forEach((row) => {
189
+ const x = parseFloat(row.dataset.sensorX) || 0;
190
+ const y = parseFloat(row.dataset.sensorY) || 0;
191
+ const z = parseFloat(row.dataset.sensorZ) || 0;
192
+ const dx = parseFloat(row.dataset.sensorDx) || 0;
193
+ const dy = parseFloat(row.dataset.sensorDy) || 0;
194
+ const dz = parseFloat(row.dataset.sensorDz) || 0;
195
+ console.log(x, y, z, dx, dy, dz);
196
+ console.log(row)
197
+
198
+ // Create a direction vector from dx,dy,dz
199
+ const direction = new THREE.Vector3(dx, dy, dz);
200
+ const length = direction.length() || 0.1; // arrow length
201
+ direction.normalize();
202
+
203
+ const origin = new THREE.Vector3(x, y, z);
204
+ const color = 0xff0000;
205
+ const arrow = createArrow(
206
+ origin,
207
+ direction,
208
+ length,
209
+ color,
210
+ 0.3*length, // head length
211
+ 0.2*length, // head width
212
+ 0.1*length // shaft radius
213
+ );
214
+
215
+ scene.add(arrow);
216
+ arrowObjects.push(arrow);
217
+ });
218
+
219
+ });
220
+ </script>
221
+ {% endblock javascripts %}