irie 0.0.41__py3-none-any.whl → 0.0.43__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 (56) hide show
  1. irie/apps/inventory/archive/CESMD.py +0 -0
  2. irie/apps/inventory/filters.py +1 -1
  3. irie/apps/inventory/models.py +27 -0
  4. irie/apps/inventory/services/render.py +0 -0
  5. irie/apps/inventory/urls.py +3 -0
  6. irie/apps/inventory/views.py +57 -0
  7. irie/apps/prediction/forms.py +2 -1
  8. irie/apps/prediction/models.py +24 -0
  9. irie/apps/prediction/runners/hazus.py +33 -19
  10. irie/apps/prediction/urls.py +5 -3
  11. irie/apps/prediction/views.py +101 -8
  12. irie/apps/static/assets/css/brace.css +0 -33
  13. irie/apps/static/assets/css/brace.css.map +1 -1
  14. irie/apps/static/assets/css/brace.min.css +1 -1
  15. irie/apps/static/assets/js/brace.js +2 -1
  16. irie/apps/templates/includes/scripts.html +10 -1
  17. irie/apps/templates/includes/sidebar.html +19 -11
  18. irie/apps/templates/inventory/asset-on-map.html +457 -0
  19. irie/apps/templates/inventory/asset-profile.html +1 -2
  20. irie/apps/templates/inventory/map-inventory.html +136 -0
  21. irie/apps/templates/inventory/map-inventory2.html +143 -0
  22. irie/apps/templates/inventory/map-single-asset.html +0 -0
  23. irie/apps/templates/inventory/map-single-asset2.html +618 -0
  24. irie/apps/templates/inventory/map-terrain.html +214 -0
  25. irie/apps/templates/inventory/sensor-upload.html +1 -0
  26. irie/apps/templates/inventory/three-maps.html +229 -0
  27. irie/apps/templates/layouts/base.html +2 -1
  28. irie/apps/templates/prediction/predictor-upload.html +68 -22
  29. irie/apps/templates/site/index.html +36 -27
  30. irie/apps/templates/site/page-400-sidebar.html +31 -0
  31. irie/apps/templates/site/page-400.html +29 -0
  32. irie/apps/templates/site/page-404-sidebar.html +1 -1
  33. irie/apps/templates/site/page-404.html +1 -1
  34. irie/fhwa/__init__.py +132 -0
  35. irie/fhwa/__main__.py +79 -0
  36. irie/fhwa/fields/nbi001.py +61 -0
  37. irie/fhwa/fields/nbi001b.py +1 -0
  38. irie/fhwa/fields/nbi002.py +0 -0
  39. irie/fhwa/fields.py +32 -0
  40. irie/init/__main__.py +0 -4
  41. irie/init/calid.py +86 -3
  42. irie/init/getNBIData.py +1 -1
  43. irie/init/getNBIData2.py +304 -0
  44. irie/init/management/commands/init_assets.py +11 -11
  45. irie/init/management/commands/init_predictors.py +1 -1
  46. irie/init/management/commands/make_asset.py +0 -0
  47. irie/pull/nbi.py +304 -0
  48. {irie-0.0.41.dist-info → irie-0.0.43.dist-info}/METADATA +1 -1
  49. {irie-0.0.41.dist-info → irie-0.0.43.dist-info}/RECORD +53 -36
  50. {irie-0.0.41.dist-info → irie-0.0.43.dist-info}/WHEEL +1 -1
  51. irie/apps/inventory/CESMD.py +0 -81
  52. irie/apps/inventory/archive/arcGIS.py +0 -1175
  53. irie/apps/inventory/traffic.py +0 -175052
  54. /irie/apps/inventory/{calid.py → archive/calid.py} +0 -0
  55. {irie-0.0.41.dist-info → irie-0.0.43.dist-info}/entry_points.txt +0 -0
  56. {irie-0.0.41.dist-info → irie-0.0.43.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,214 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <title>Adding 3D models using three.js on terrain</title>
6
+ <meta property="og:description" content="Use a custom style layer with three.js to add 3D models to a map with 3d terrain." />
7
+ <meta charset='utf-8'>
8
+ <meta name="viewport" content="width=device-width, initial-scale=1">
9
+ <link rel='stylesheet' href='https://unpkg.com/maplibre-gl@5.2.0/dist/maplibre-gl.css' />
10
+ <script src='https://unpkg.com/maplibre-gl@5.2.0/dist/maplibre-gl.js'></script>
11
+ <style>
12
+ body {
13
+ margin: 0;
14
+ padding: 0;
15
+ }
16
+
17
+ html,
18
+ body,
19
+ #map {
20
+ height: 100%;
21
+ }
22
+ </style>
23
+ <script type="importmap">
24
+ {
25
+ "imports": {
26
+ "three": "https://cdn.jsdelivr.net/npm/three@0.169.0/build/three.module.js",
27
+ "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.169.0/examples/jsm/"
28
+ }
29
+ }
30
+ </script>
31
+ </head>
32
+ <body>
33
+ <div id="map"></div>
34
+
35
+ <script type="module">
36
+ import * as THREE from 'three';
37
+ import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
38
+
39
+ /**
40
+ * Objective:
41
+ * Given two known world-locations `model1Location` and `model2Location`,
42
+ * place two three.js objects on those locations at the appropriate height of
43
+ * the terrain.
44
+ */
45
+
46
+ async function main() {
47
+
48
+ const map = new maplibregl.Map({
49
+ container: 'map',
50
+ center: [11.5257, 47.668],
51
+ zoom: 16.27,
52
+ pitch: 60,
53
+ bearing: -28.5,
54
+ canvasContextAttributes: {antialias: true},
55
+ style: {
56
+ version: 8,
57
+ layers: [
58
+ {
59
+ id: 'baseColor', // Hides edges of terrain tiles, which have 'walls' going down to 0.
60
+ type: 'background',
61
+ paint: {
62
+ 'background-color': '#fff',
63
+ 'background-opacity': 1.0,
64
+ },
65
+ }, {
66
+ id: 'hills',
67
+ type: 'hillshade',
68
+ source: 'hillshadeSource',
69
+ layout: {visibility: 'visible'},
70
+ paint: {'hillshade-shadow-color': '#473B24'}
71
+ }
72
+ ],
73
+ terrain: {
74
+ source: 'terrainSource',
75
+ exaggeration: 1,
76
+ },
77
+ sources: {
78
+ terrainSource: {
79
+ type: 'raster-dem',
80
+ url: 'https://demotiles.maplibre.org/terrain-tiles/tiles.json',
81
+ tileSize: 256
82
+ },
83
+ hillshadeSource: {
84
+ type: 'raster-dem',
85
+ url: 'https://demotiles.maplibre.org/terrain-tiles/tiles.json',
86
+ tileSize: 256
87
+ }
88
+ },
89
+ }
90
+ });
91
+
92
+ /*
93
+ * Helper function used to get threejs-scene-coordinates from mercator coordinates.
94
+ * This is just a quick and dirty solution - it won't work if points are far away from each other
95
+ * because a meter near the north-pole covers more mercator-units
96
+ * than a meter near the equator.
97
+ */
98
+ function calculateDistanceMercatorToMeters(from, to) {
99
+ const mercatorPerMeter = from.meterInMercatorCoordinateUnits();
100
+ // mercator x: 0=west, 1=east
101
+ const dEast = to.x - from.x;
102
+ const dEastMeter = dEast / mercatorPerMeter;
103
+ // mercator y: 0=north, 1=south
104
+ const dNorth = from.y - to.y;
105
+ const dNorthMeter = dNorth / mercatorPerMeter;
106
+ return {dEastMeter, dNorthMeter};
107
+ }
108
+
109
+ async function loadModel() {
110
+ const loader = new GLTFLoader();
111
+ const gltf = await loader.loadAsync('https://maplibre.org/maplibre-gl-js/docs/assets/34M_17/34M_17.gltf');
112
+ const model = gltf.scene;
113
+ return model;
114
+ }
115
+
116
+ // Known locations. We'll infer the elevation of those locations once terrain is loaded.
117
+ const sceneOrigin = new maplibregl.LngLat(11.5255, 47.6677);
118
+ const model1Location = new maplibregl.LngLat(11.527, 47.6678);
119
+ const model2Location = new maplibregl.LngLat(11.5249, 47.6676);
120
+
121
+ // Configuration of the custom layer for a 3D model, implementing `CustomLayerInterface`.
122
+ const customLayer = {
123
+ id: '3d-model',
124
+ type: 'custom',
125
+ renderingMode: '3d',
126
+
127
+ onAdd(map, gl) {
128
+ /**
129
+ * Setting up three.js scene.
130
+ * We're placing model1 and model2 in such a way that the whole scene fits over the terrain.
131
+ */
132
+
133
+ this.camera = new THREE.Camera();
134
+ this.scene = new THREE.Scene();
135
+ // In threejs, y points up - we're rotating the scene such that it's y points along maplibre's up.
136
+ this.scene.rotateX(Math.PI / 2);
137
+ // In threejs, z points toward the viewer - mirroring it such that z points along maplibre's north.
138
+ this.scene.scale.multiply(new THREE.Vector3(1, 1, -1));
139
+ // We now have a scene with (x=east, y=up, z=north)
140
+
141
+ const light = new THREE.DirectionalLight(0xffffff);
142
+ // Making it just before noon - light coming from south-east.
143
+ light.position.set(50, 70, -30).normalize();
144
+ this.scene.add(light);
145
+
146
+ // Axes helper to show how threejs scene is oriented.
147
+ const axesHelper = new THREE.AxesHelper(60);
148
+ this.scene.add(axesHelper);
149
+
150
+ // Getting model elevations in meters above sea level
151
+ const sceneElevation = map.queryTerrainElevation(sceneOrigin) || 0;
152
+ const model1Elevation = map.queryTerrainElevation(model1Location) || 0;
153
+ const model2Elevation = map.queryTerrainElevation(model2Location) || 0;
154
+ const model1up = model1Elevation - sceneElevation;
155
+ const model2up = model2Elevation - sceneElevation;
156
+
157
+ // Getting model x and y (in meters) relative to scene origin.
158
+ const sceneOriginMercator = maplibregl.MercatorCoordinate.fromLngLat(sceneOrigin);
159
+ const model1Mercator = maplibregl.MercatorCoordinate.fromLngLat(model1Location);
160
+ const model2Mercator = maplibregl.MercatorCoordinate.fromLngLat(model2Location);
161
+ const {dEastMeter: model1east, dNorthMeter: model1north} = calculateDistanceMercatorToMeters(sceneOriginMercator, model1Mercator);
162
+ const {dEastMeter: model2east, dNorthMeter: model2north} = calculateDistanceMercatorToMeters(sceneOriginMercator, model2Mercator);
163
+
164
+ model1.position.set(model1east, model1up, model1north);
165
+ model2.position.set(model2east, model2up, model2north);
166
+
167
+ this.scene.add(model1);
168
+ this.scene.add(model2);
169
+
170
+ // Use the MapLibre GL JS map canvas for three.js.
171
+ this.renderer = new THREE.WebGLRenderer({
172
+ canvas: map.getCanvas(),
173
+ context: gl,
174
+ antialias: true
175
+ });
176
+
177
+ this.renderer.autoClear = false;
178
+ },
179
+
180
+ render(gl, args) {
181
+ const offsetFromCenterElevation = map.queryTerrainElevation(sceneOrigin) || 0;
182
+ const sceneOriginMercator = maplibregl.MercatorCoordinate.fromLngLat(sceneOrigin, offsetFromCenterElevation);
183
+
184
+ const sceneTransform = {
185
+ translateX: sceneOriginMercator.x,
186
+ translateY: sceneOriginMercator.y,
187
+ translateZ: sceneOriginMercator.z,
188
+ scale: sceneOriginMercator.meterInMercatorCoordinateUnits()
189
+ };
190
+
191
+ const m = new THREE.Matrix4().fromArray(args.defaultProjectionData.mainMatrix);
192
+ const l = new THREE.Matrix4()
193
+ .makeTranslation(sceneTransform.translateX, sceneTransform.translateY, sceneTransform.translateZ)
194
+ .scale(new THREE.Vector3(sceneTransform.scale, -sceneTransform.scale, sceneTransform.scale));
195
+
196
+ this.camera.projectionMatrix = m.multiply(l);
197
+ this.renderer.resetState();
198
+ this.renderer.render(this.scene, this.camera);
199
+ map.triggerRepaint();
200
+ }
201
+ };
202
+
203
+ const results = await Promise.all([map.once('load'), loadModel()]);
204
+ const model1 = results[1];
205
+ const model2 = model1.clone();
206
+
207
+ map.addLayer(customLayer);
208
+ }
209
+
210
+ main();
211
+ </script>
212
+ </body>
213
+
214
+ </html>
@@ -387,6 +387,7 @@ document.addEventListener('DOMContentLoaded', () => {
387
387
  (error) => {
388
388
  console.error('Error loading GLB:', error);
389
389
  });
390
+
390
391
  } else {
391
392
  const axesHelper = new THREE.AxesHelper(1);
392
393
  scene.add(axesHelper);
@@ -0,0 +1,229 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <title>Test Maps</title>
5
+ <meta property="og:description" content="Use a custom style layer with three.js to add a 3D model with shadow to the map." />
6
+ <meta charset='utf-8'>
7
+ <meta name="viewport" content="width=device-width, initial-scale=1">
8
+ <link rel='stylesheet' href='https://unpkg.com/maplibre-gl@5.2.0/dist/maplibre-gl.css' />
9
+ <script src='https://unpkg.com/maplibre-gl@5.2.0/dist/maplibre-gl.js'></script>
10
+ <style>
11
+ body { margin: 0; padding: 0; }
12
+ html, body, #map { height: 100%; }
13
+ </style>
14
+ <script type="importmap">
15
+ {
16
+ "imports": {
17
+ "three": "https://cdn.jsdelivr.net/npm/three@0.169.0/build/three.module.js",
18
+ "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.169.0/examples/jsm/"
19
+ }
20
+ }
21
+ </script>
22
+ </head>
23
+
24
+ <body>
25
+ <div id="map"></div>
26
+
27
+ <script type="module">
28
+ import * as THREE from 'three';
29
+ import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
30
+
31
+ const modelOrigin = [-124.1014, 40.50303]; // [148.9819, -35.39847];
32
+ // const modelSource = 'https://maplibre.org/maplibre-gl-js/docs/assets/34M_17/34M_17.gltf';
33
+ const modelSource = '/uploads/renderings/painter.glb';
34
+ const unitToMeter = 1/3.2808;
35
+ const MAPTILER_KEY = 'get_your_own_OpIi9ZULNHzrESv6T2vL';
36
+
37
+ //
38
+ // Initialize Map
39
+ //
40
+ const map = new maplibregl.Map({
41
+ container: 'map',
42
+
43
+ style: `https://api.maptiler.com/maps/basic-v2/style.json?key=${MAPTILER_KEY}`,
44
+ center: modelOrigin,
45
+ zoom: 18,
46
+ maxZoom: 30,
47
+ maxPitch: 85,
48
+ pitch: 77,
49
+ canvasContextAttributes: {antialias: true}
50
+ });
51
+
52
+ //
53
+ // Add Buildings
54
+ //
55
+
56
+ // The 'building' layer in the streets vector source contains building-height
57
+ // data from OpenStreetMap.
58
+ map.on('load', () => {
59
+ // Insert the layer beneath any symbol layer.
60
+ const layers = map.getStyle().layers;
61
+
62
+ let labelLayerId;
63
+ for (let i = 0; i < layers.length; i++) {
64
+ if (layers[i].type === 'symbol' && layers[i].layout['text-field']) {
65
+ labelLayerId = layers[i].id;
66
+ break;
67
+ }
68
+ }
69
+
70
+ map.addSource('openmaptiles', {
71
+ url: `https://api.maptiler.com/tiles/v3/tiles.json?key=${MAPTILER_KEY}`,
72
+ type: 'vector',
73
+ });
74
+
75
+ map.addLayer(
76
+ {
77
+ 'id': '3d-buildings',
78
+ 'source': 'openmaptiles',
79
+ 'source-layer': 'building',
80
+ 'type': 'fill-extrusion',
81
+ 'minzoom': 15,
82
+ 'filter': ['!=', ['get', 'hide_3d'], true],
83
+ 'paint': {
84
+ 'fill-extrusion-color': [
85
+ 'interpolate',
86
+ ['linear'],
87
+ ['get', 'render_height'], 0, 'lightgray', 200, 'royalblue', 400, 'lightblue'
88
+ ],
89
+ 'fill-extrusion-height': [
90
+ 'interpolate',
91
+ ['linear'],
92
+ ['zoom'],
93
+ 15,
94
+ 0,
95
+ 16,
96
+ ['get', 'render_height']
97
+ ],
98
+ 'fill-extrusion-base': ['case',
99
+ ['>=', ['get', 'zoom'], 16],
100
+ ['get', 'render_min_height'], 0
101
+ ]
102
+ }
103
+ },
104
+ labelLayerId
105
+ );
106
+ });
107
+
108
+ //
109
+ // Add Asset
110
+ //
111
+ const modelAltitude = 0;
112
+ const modelRotate = [Math.PI / 2, 0, 0];
113
+ const modelCoord = maplibregl.MercatorCoordinate.fromLngLat(
114
+ modelOrigin,
115
+ modelAltitude
116
+ );
117
+ const modelScale = modelCoord.meterInMercatorCoordinateUnits()*unitToMeter;
118
+ const modelTransform = {
119
+ translateX: modelCoord.x,
120
+ translateY: modelCoord.y-25*modelScale,
121
+ translateZ: modelCoord.z+35*modelScale,
122
+ rotateX: modelRotate[0],
123
+ rotateY: modelRotate[1],
124
+ rotateZ: modelRotate[2],
125
+ scale: modelScale
126
+ };
127
+
128
+ const customLayer = {
129
+ id: '3d-model',
130
+ type: 'custom',
131
+ renderingMode: '3d',
132
+ onAdd(map, gl) {
133
+ this.camera = new THREE.Camera();
134
+ this.scene = new THREE.Scene();
135
+
136
+ const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
137
+ directionalLight.position.set(100, 100, 100);
138
+ directionalLight.castShadow = true;
139
+ this.scene.add(directionalLight);
140
+
141
+ directionalLight.shadow.camera.near = 0.1;
142
+ directionalLight.shadow.camera.far = 2000;
143
+ directionalLight.shadow.camera.left = -500;
144
+ directionalLight.shadow.camera.right = 500;
145
+ directionalLight.shadow.camera.top = 500;
146
+ directionalLight.shadow.camera.bottom = -500;
147
+
148
+ directionalLight.shadow.mapSize.width = 4096;
149
+ directionalLight.shadow.mapSize.height = 4096;
150
+
151
+ const groundGeometry = new THREE.PlaneGeometry(1000, 1000);
152
+ const groundMaterial = new THREE.ShadowMaterial({ opacity: 0.5 });
153
+ const ground = new THREE.Mesh(groundGeometry, groundMaterial);
154
+ ground.rotation.x = -Math.PI / 2;
155
+ ground.position.y = modelCoord.z;
156
+ ground.receiveShadow = true;
157
+ this.scene.add(ground);
158
+
159
+ const loader = new GLTFLoader();
160
+ loader.load(
161
+ modelSource,
162
+ (gltf) => {
163
+ gltf.scene.traverse(function (node) {
164
+ if (node.isMesh || node.isLight) {
165
+ node.castShadow = true;
166
+ node.receiveShadow = true;
167
+ }
168
+ });
169
+ this.scene.add(gltf.scene);
170
+ }
171
+ );
172
+ this.map = map;
173
+
174
+ this.renderer = new THREE.WebGLRenderer({
175
+ canvas: map.getCanvas(),
176
+ context: gl,
177
+ antialias: true
178
+ });
179
+ this.renderer.shadowMap.enabled = true;
180
+ this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
181
+
182
+ this.renderer.autoClear = false;
183
+ },
184
+ render(gl, args) {
185
+ const rotationX = new THREE.Matrix4().makeRotationAxis(
186
+ new THREE.Vector3(1, 0, 0),
187
+ modelTransform.rotateX
188
+ );
189
+ const rotationY = new THREE.Matrix4().makeRotationAxis(
190
+ new THREE.Vector3(0, 1, 0),
191
+ modelTransform.rotateY
192
+ );
193
+ const rotationZ = new THREE.Matrix4().makeRotationAxis(
194
+ new THREE.Vector3(0, 0, 1),
195
+ modelTransform.rotateZ
196
+ );
197
+
198
+ const m = new THREE.Matrix4().fromArray(args.defaultProjectionData.mainMatrix);
199
+ const l = new THREE.Matrix4()
200
+ .makeTranslation(
201
+ modelTransform.translateX,
202
+ modelTransform.translateY,
203
+ modelTransform.translateZ
204
+ )
205
+ .scale(
206
+ new THREE.Vector3(
207
+ modelTransform.scale,
208
+ -modelTransform.scale,
209
+ modelTransform.scale
210
+ )
211
+ )
212
+ .multiply(rotationX)
213
+ .multiply(rotationY)
214
+ .multiply(rotationZ);
215
+
216
+ this.camera.projectionMatrix = m.multiply(l);
217
+ this.renderer.resetState();
218
+ this.renderer.render(this.scene, this.camera);
219
+ this.map.triggerRepaint();
220
+ }
221
+ };
222
+
223
+ map.on('style.load', () => {
224
+ map.addLayer(customLayer);
225
+ });
226
+ </script>
227
+ </body>
228
+
229
+ </html>
@@ -43,8 +43,9 @@
43
43
  <link type="text/css" href="{{ ASSETS_ROOT }}/css/brace.css" media="screen" rel="stylesheet">
44
44
 
45
45
  {% block stylesheets %}{% endblock stylesheets %}
46
+
46
47
  </head>
47
- <body>
48
+ <body class="g-sidenav-show">
48
49
  {% include 'includes/sidebar.html' %}
49
50
 
50
51
  <main class="content">
@@ -1,35 +1,81 @@
1
1
  {% extends "layouts/base.html" %}
2
- {# load predictor #}
3
2
  {% block title %} {{ asset.calid }} | Upload {% endblock %}
4
- {% block stylesheets %}
5
3
 
4
+ {% block stylesheets %}
6
5
  {% endblock stylesheets %}
7
6
 
8
7
  {% block content %}
9
8
  <div class="print">
10
- <h1 class="fs-2 lh-2 me-3">Uploads</h1>
11
- <span id="predictorProfile" class="fs-2 lh-2 me-3">{{ title }}</span>
12
-
13
- <form method="POST" enctype="multipart/form-data">
14
- {% csrf_token %}
15
- {{ form.as_p}}
16
- <button type="submit" class="btn btn-primary">Submit</button>
17
- </form>
9
+ <div class="col-10 mb-4 d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center py-4">
10
+ <div class="d-block mb-4 mb-md-0">
11
+ <nav aria-label="breadcrumb" class="d-none d-md-inline-block">
12
+ <ol class="breadcrumb breadcrumb-dark breadcrumb-transparent">
13
+ <li class="breadcrumb-item">
14
+ <a href="{% url 'dashboard' %}">
15
+ <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>
16
+ </a>
17
+ </li>
18
+ <li class="breadcrumb-item text-dark" aria-current="page"><a href="{% url 'asset_table' %}">Inventory</a></li>
19
+ <li class="breadcrumb-item"><a href="{% url 'asset_profile' calid=asset.calid %}"><code>{{ asset.calid }}</code></a></li>
20
+ <li class="breadcrumb-item"><a href="/inventory/{{ asset.calid }}/predictors/">Predictors</a></li>
21
+ <li class="breadcrumb-item active">Upload</li>
22
+ </ol>
23
+ </nav>
24
+ <h1 class="h4"><samp>{{ asset.id }}</samp> / {{ asset.calid }} Predictor Upload</h1>
25
+ </div>
26
+ <div class="btn-toolbar mb-2 mb-md-0">
27
+ <a role="button"
28
+ href="/inventory/{{ asset.calid }}/predictors/"
29
+ class="btn btn-sm btn-outline-primary d-inline-flex align-items-center mx-1">
30
+ Predictors
31
+ </a>
32
+ <a role="button"
33
+ href="{% url 'asset_sensors' calid=asset.calid %}"
34
+ class="btn btn-sm btn-outline-primary d-inline-flex align-items-center mx-1">
35
+ Sensors
36
+ </a>
37
+ </div>
38
+ </div>
39
+ <div class="row">
40
+ <div class="col">
41
+ <form method="POST" enctype="multipart/form-data">
42
+ {% csrf_token %}
43
+ {{ form.as_p}}
44
+ <button id="render" type="button" class="btn btn-outline-primary" >Validate</button>
45
+ <button type="submit" class="btn btn-primary" name="action" value="commit">Submit</button>
46
+ </form>
47
+ </div>
48
+ </div>
49
+ <div class="row">
50
+ <iframe
51
+ id="map"
52
+ width="100%"
53
+ height="400"
54
+ >
55
+ </iframe>
56
+ </div>
18
57
  </div>
19
58
  {% endblock content %}
20
59
 
21
- <script>
22
- const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]')
23
- const tooltipList = [...tooltipTriggerList].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl))
24
- </script>
25
60
  {% block javascripts %}
26
-
27
- <script type="text/javascript">
28
- function printTables() {
29
- var myWindow = window.open('','','width=200,height=100')
30
- myWindow.document.write("This is 'myWindow'")
31
- myWindow.print();
32
- }
61
+ <script>
62
+ const button = document.getElementById('render');
63
+ const form = document.querySelector('form');
64
+ const map = document.getElementById('map');
65
+ button.addEventListener('click', function(event) {
66
+ event.preventDefault();
67
+ fetch('/inventory/{{ asset.calid }}/predictors/create/map/', {
68
+ method: 'POST',
69
+ body: new FormData(form)
70
+ }).then(response => response.text())
71
+ .then(data => {
72
+ const blob = new Blob([data], { type: 'text/html' });
73
+ const url = window.URL.createObjectURL(blob);
74
+ map.src = url;
75
+ })
76
+ .catch(error => {
77
+ console.error('Error fetching map:', error);
78
+ });
79
+ });
33
80
  </script>
34
-
35
81
  {% endblock javascripts %}