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.
- irie/apps/inventory/filters.py +11 -29
- irie/apps/inventory/models.py +3 -3
- irie/apps/inventory/views.py +9 -2
- irie/apps/prediction/admin.py +2 -1
- irie/apps/prediction/migrations/0004_sensorassignment.py +31 -0
- irie/apps/prediction/migrations/0005_remove_sensorassignment_offset_x_and_more.py +53 -0
- irie/apps/prediction/migrations/0006_remove_sensorassignment_show_x_and_more.py +25 -0
- irie/apps/prediction/models.py +22 -3
- irie/apps/prediction/runners/__init__.py +11 -2
- irie/apps/prediction/runners/opensees/__init__.py +114 -62
- irie/apps/prediction/runners/ssid.py +9 -10
- irie/apps/prediction/urls.py +12 -7
- irie/apps/prediction/views.py +81 -24
- irie/apps/static/assets/css/brace.css +5 -31
- irie/apps/static/assets/css/brace.css.map +1 -1
- irie/apps/static/assets/css/brace.min.css +2 -2
- irie/apps/templates/components/json-table.html +1 -0
- irie/apps/templates/includes/paginate.js +6 -0
- irie/apps/templates/includes/scripts.html +7 -20
- irie/apps/templates/inventory/asset-on-map.html +5 -5
- irie/apps/templates/inventory/sensor-upload.html +97 -262
- irie/apps/templates/networks/{networks.html → _networks.html} +0 -1
- irie/apps/templates/networks/networks.js +6 -4
- irie/apps/templates/prediction/asset-predictors.html +41 -47
- irie/apps/templates/prediction/{form-submission.html → create-mdof.html} +0 -21
- irie/apps/templates/prediction/new-runner.html +0 -20
- irie/apps/templates/prediction/predictor-profile.html +8 -134
- irie/apps/templates/prediction/viewer/veux-viewer.js +186 -0
- irie/apps/templates/prediction/xara-profile.html +221 -0
- irie/apps/templates/sensors/render-sensors.js +152 -0
- irie/init/management/commands/init_cesmd.py +2 -2
- {irie-0.0.49.dist-info → irie-0.0.51.dist-info}/METADATA +2 -3
- {irie-0.0.49.dist-info → irie-0.0.51.dist-info}/RECORD +37 -30
- {irie-0.0.49.dist-info → irie-0.0.51.dist-info}/WHEEL +1 -1
- /irie/apps/templates/prediction/{predictor-upload.html → create-model.html} +0 -0
- {irie-0.0.49.dist-info → irie-0.0.51.dist-info}/entry_points.txt +0 -0
- {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 }} | {{
|
|
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
|
-
|
|
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
|
-
{{
|
|
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,{{
|
|
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
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
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 %}
|