Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
iCity
EnergyDashboard
Commits
86bff050
Commit
86bff050
authored
Jun 25, 2021
by
Sven Schneider
Browse files
added aggregation method into appCharts.js
parent
02bd3700
Changes
3
Hide whitespace changes
Inline
Side-by-side
index.html
View file @
86bff050
<!DOCTYPE html>
<!DOCTYPE html>
<html
lang=
"en"
>
<html
lang=
"en"
>
<head>
<head>
<meta
charset=
"utf-8"
/>
<meta
charset=
"utf-8"
/>
<meta
http-equiv=
"X-UA-Compatible"
content=
"IE=edge"
/>
<meta
http-equiv=
"X-UA-Compatible"
content=
"IE=edge"
/>
<meta
<meta
name=
"viewport"
content=
"width=device-width, initial-scale=1, shrink-to-fit=no"
/>
name=
"viewport"
content=
"width=device-width, initial-scale=1, shrink-to-fit=no"
/>
<meta
name=
"description"
content=
""
/>
<meta
name=
"description"
content=
""
/>
<meta
name=
"author"
content=
""
/>
<meta
name=
"author"
content=
""
/>
<title>
Dashboard - iCity Bosch
</title>
<title>
Dashboard - iCity Bosch
</title>
<link
href=
"css/styles.css"
rel=
"stylesheet"
/>
<link
href=
"css/styles.css"
rel=
"stylesheet"
/>
<link
<link
href=
"https://cdn.datatables.net/1.10.20/css/dataTables.bootstrap4.min.css"
rel=
"stylesheet"
crossorigin=
"anonymous"
/>
href=
"https://cdn.datatables.net/1.10.20/css/dataTables.bootstrap4.min.css"
rel=
"stylesheet"
crossorigin=
"anonymous"
/>
<!-- Font Awesome icons -->
<!-- Font Awesome icons -->
<script
<script
src=
"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/js/all.min.js"
crossorigin=
"anonymous"
></script>
src=
"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/js/all.min.js"
crossorigin=
"anonymous"
></script>
<!-- Axios -->
<!-- Axios -->
<!-- <script src="./node_modules/axios/dist/axios.min.js"></script> -->
<!-- <script src="./node_modules/axios/dist/axios.min.js"></script> -->
...
@@ -46,122 +37,100 @@
...
@@ -46,122 +37,100 @@
<!-- Cesium lib -->
<!-- Cesium lib -->
<script
src=
"https://cesium.com/downloads/cesiumjs/releases/1.48/Build/Cesium/Cesium.js"
></script>
<script
src=
"https://cesium.com/downloads/cesiumjs/releases/1.48/Build/Cesium/Cesium.js"
></script>
<link
<link
href=
"https://cesium.com/downloads/cesiumjs/releases/1.48/Build/Cesium/Widgets/widgets.css"
rel=
"stylesheet"
/>
href=
"https://cesium.com/downloads/cesiumjs/releases/1.48/Build/Cesium/Widgets/widgets.css"
rel=
"stylesheet"
/>
<!-- Bootstrap dashboard template -->
<!-- Bootstrap dashboard template -->
<script
<script
defer
src=
"https://code.jquery.com/jquery-3.5.1.slim.min.js"
crossorigin=
"anonymous"
></script>
defer
<script
defer
src=
"https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.bundle.min.js"
crossorigin=
"anonymous"
></script>
src=
"https://code.jquery.com/jquery-3.5.1.slim.min.js"
crossorigin=
"anonymous"
></script>
<script
defer
src=
"https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.bundle.min.js"
crossorigin=
"anonymous"
></script>
<script
defer
src=
"js/thirdparty/scripts.js"
></script>
<script
defer
src=
"js/thirdparty/scripts.js"
></script>
<!--
<!--
Custom JS -->
Custom JS -->
<script
defer
type=
"module"
src=
"js/appCesium.js"
></script>
<script
defer
type=
"module"
src=
"js/appCesium.js"
></script>
<script
defer
type=
"module"
src=
"js/appChart.js"
></script>
<script
defer
type=
"module"
src=
"js/appChart.js"
></script>
</head>
</head>
<body
class=
"sb-nav-fixed"
>
<body
class=
"sb-nav-fixed"
>
<nav
class=
"sb-topnav navbar navbar-expand navbar-dark bg-dark"
>
<nav
class=
"sb-topnav navbar navbar-expand navbar-dark bg-dark"
>
<a
class=
"navbar-brand"
href=
"index.html"
>
iCity Bosch Dashboard
</a>
<a
class=
"navbar-brand"
href=
"index.html"
>
iCity Bosch Dashboard
</a>
<button
<button
class=
"btn btn-link btn-sm order-1 order-lg-0"
id=
"sidebarToggle"
href=
"#"
>
class=
"btn btn-link btn-sm order-1 order-lg-0"
id=
"sidebarToggle"
href=
"#"
>
<i
class=
"fas fa-bars"
></i>
<i
class=
"fas fa-bars"
></i>
</button>
</button>
</nav>
</nav>
<div
id=
"layoutSidenav"
>
<div
id=
"layoutSidenav"
>
<div
id=
"layoutSidenav_nav"
>
<div
id=
"layoutSidenav_nav"
>
<nav
class=
"sb-sidenav accordion sb-sidenav-dark"
id=
"sidenavAccordion"
>
<nav
class=
"sb-sidenav accordion sb-sidenav-dark"
id=
"sidenavAccordion"
>
<div
class=
"sb-sidenav-menu"
>
<div
class=
"sb-sidenav-menu"
>
<div
class=
"nav"
>
<div
class=
"nav"
>
<div
class=
"sb-sidenav-menu-heading"
>
Core
</div>
<div
class=
"sb-sidenav-menu-heading"
>
Core
</div>
<a
class=
"nav-link"
href=
"index.html"
>
<a
class=
"nav-link"
href=
"index.html"
>
<div
class=
"sb-nav-link-icon"
>
<div
class=
"sb-nav-link-icon"
>
<i
class=
"fas fa-tachometer-alt"
></i>
<i
class=
"fas fa-tachometer-alt"
></i>
</div>
Dashboard
</a>
</div>
</div>
</div>
Dashboard
</nav>
</a>
</div>
</div>
<div
id=
"layoutSidenav_content"
>
</div>
<main>
</nav>
<div
class=
"container-fluid"
>
</div>
<h1
class=
"mt-4"
>
Dashboard
</h1>
<div
id=
"layoutSidenav_content"
>
<ol
class=
"breadcrumb mb-4"
>
<main>
<li
class=
"breadcrumb-item active"
>
Dashboard
</li>
<div
class=
"container-fluid"
>
</ol>
<h1
class=
"mt-4"
>
Dashboard
</h1>
<ol
class=
"breadcrumb mb-4"
>
<li
class=
"breadcrumb-item active"
>
Dashboard
</li>
</ol>
<div
class=
"row"
>
<div
class=
"row"
>
<div
class=
"col-xl-12"
>
<div
class=
"col-xl-12"
>
<div
class=
"card mb-4"
>
<div
class=
"card mb-4"
>
<div
class=
"card-header"
>
<div
class=
"card-header"
>
<i
class=
"fas fa-globe mr-1"
></i>
<i
class=
"fas fa-globe mr-1"
></i>
3D Visualization
3D Visualization
</div>
</div>
<div
class=
"card-body"
>
<div
class=
"card-body"
>
<div
id=
"cesiumGlobeContainer"
width=
"100%"
height=
"40"
>
<div
</div>
id=
"cesiumGlobeContainer"
</div>
width=
"100%"
</div>
height=
"40"
</div>
></div>
</div>
</div>
<div
class=
"row"
>
<div
class=
"col-xl-6"
>
<div
class=
"card mb-4"
>
<div
class=
"card-header"
>
<i
class=
"fas fa-chart-line mr-1"
></i>
Line Chart Example
</div>
<div
class=
"card-body"
>
<div
id=
"chart-line"
width=
"100%"
height=
"40"
></div>
</div>
</div>
</div>
<div
class=
"col-xl-6"
>
<div
class=
"card mb-4"
>
<div
class=
"card-header"
>
<i
class=
"fas fa-chart-area mr-1"
></i>
Area Chart Example
</div>
<div
class=
"card-body"
>
<div
id=
"chart-heatmap"
width=
"100%"
height=
"40"
></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</main>
</div>
<footer
class=
"py-4 bg-light mt-auto"
>
<div
class=
"row"
>
<div
class=
"container-fluid"
>
<div
class=
"col-xl-6"
>
<div
class=
"d-flex align-items-center justify-content-between small"
>
<div
class=
"card mb-4"
>
<div
class=
"text-muted"
>
Copyright
©
HfT Stuttgart 2021
</div>
<div
class=
"card-header"
>
<div>
<i
class=
"fas fa-chart-line mr-1"
></i>
<a
href=
"#"
>
Privacy Policy
</a>
·
Line Chart Example
<a
href=
"#"
>
Terms
&
Conditions
</a>
</div>
</div>
<div
class=
"card-body"
>
</div>
<div
id=
"chart-line"
width=
"100%"
height=
"40"
></div>
</div>
</div>
</div>
</div>
</footer>
<div
class=
"col-xl-6"
>
</div>
<div
class=
"card mb-4"
>
<div
class=
"card-header"
>
<i
class=
"fas fa-chart-area mr-1"
></i>
Area Chart Example
</div>
<div
class=
"card-body"
>
<div
id=
"chart-heatmap"
width=
"100%"
height=
"40"
></div>
</div>
</div>
</div>
</div>
</div>
</main>
<footer
class=
"py-4 bg-light mt-auto"
>
<div
class=
"container-fluid"
>
<div
class=
"d-flex align-items-center justify-content-between small"
>
<div
class=
"text-muted"
>
Copyright
©
HfT Stuttgart 2021
</div>
<div>
<a
href=
"#"
>
Privacy Policy
</a>
·
<a
href=
"#"
>
Terms
&
Conditions
</a>
</div>
</div>
</div>
</footer>
</div>
</div>
</div>
</body>
</body>
</html>
</html>
\ No newline at end of file
public/js/appCesium.js
View file @
86bff050
...
@@ -2,26 +2,27 @@
...
@@ -2,26 +2,27 @@
// Functions
// Functions
import
{
import
{
getDatastreamIdFromBuildingNumber
,
getDatastreamIdFromBuildingNumber
,
getObservationsUrl
,
getObservationsUrl
,
createTemporalFilterString
,
createTemporalFilterString
,
formatSTAResponseForHeatMap
,
formatSTAResponseForHeatMap
,
drawHeatMapHC
,
drawHeatMapHC
,
formatSTAResponseForLineChart
,
formatSTAResponseForLineChart
,
drawLineChartHC
,
drawLineChartHC
,
followNextLink
,
followNextLink
,
aggregateResponse
,
}
from
"
./appChart.js
"
;
}
from
"
./appChart.js
"
;
// Constants
// Constants
import
{
import
{
BASE_URL
,
BASE_URL
,
PARAM_RESULT_FORMAT
,
PARAM_RESULT_FORMAT
,
PARAM_ORDER_BY
,
PARAM_ORDER_BY
,
PARAM_SELECT
,
PARAM_SELECT
,
}
from
"
./appChart.js
"
;
}
from
"
./appChart.js
"
;
Cesium
.
Ion
.
defaultAccessToken
=
Cesium
.
Ion
.
defaultAccessToken
=
"
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyODgxYzJlNi1kNDZiLTQ3ZmQtYmUxYy0yMWI0OGM3NDA5MzAiLCJpZCI6NDczOSwic2NvcGVzIjpbImFzciIsImdjIl0sImlhdCI6MTU0MTUyMzU0MX0.shj2hM3pvsvcmE_wMb2aBDuk_cKWmFmbolltInGImwU
"
;
"
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyODgxYzJlNi1kNDZiLTQ3ZmQtYmUxYy0yMWI0OGM3NDA5MzAiLCJpZCI6NDczOSwic2NvcGVzIjpbImFzciIsImdjIl0sImlhdCI6MTU0MTUyMzU0MX0.shj2hM3pvsvcmE_wMb2aBDuk_cKWmFmbolltInGImwU
"
;
// Flag to determine models that will be loaded
// Flag to determine models that will be loaded
// Set to `true` or `false`
// Set to `true` or `false`
...
@@ -29,10 +30,10 @@ const LOAD_DETAILED_BLDG225 = false;
...
@@ -29,10 +30,10 @@ const LOAD_DETAILED_BLDG225 = false;
// Global variable
// Global variable
const
viewer
=
new
Cesium
.
Viewer
(
"
cesiumGlobeContainer
"
,
{
const
viewer
=
new
Cesium
.
Viewer
(
"
cesiumGlobeContainer
"
,
{
scene3DOnly
:
true
,
scene3DOnly
:
true
,
imageryProvider
:
Cesium
.
createOpenStreetMapImageryProvider
({
imageryProvider
:
Cesium
.
createOpenStreetMapImageryProvider
({
url
:
"
https://a.tile.openstreetmap.org/
"
,
url
:
"
https://a.tile.openstreetmap.org/
"
,
}),
}),
});
});
/**
/**
...
@@ -40,26 +41,25 @@ const viewer = new Cesium.Viewer("cesiumGlobeContainer", {
...
@@ -40,26 +41,25 @@ const viewer = new Cesium.Viewer("cesiumGlobeContainer", {
* @param {String} urlTiles URL to the 3DTiles to be loaded
* @param {String} urlTiles URL to the 3DTiles to be loaded
* @returns {undefined} undefined
* @returns {undefined} undefined
*/
*/
const
loadTiles
=
function
(
urlTiles
)
{
const
loadTiles
=
function
(
urlTiles
)
{
const
tileset
=
new
Cesium
.
Cesium3DTileset
({
const
tileset
=
new
Cesium
.
Cesium3DTileset
({
url
:
urlTiles
,
url
:
urlTiles
,
});
});
viewer
.
scene
.
primitives
.
add
(
tileset
);
viewer
.
scene
.
primitives
.
add
(
tileset
);
tileset
.
readyPromise
.
then
(
function
()
{
tileset
.
readyPromise
.
then
(
function
()
{
viewer
viewer
.
zoomTo
(
.
zoomTo
(
tileset
,
tileset
,
new
Cesium
.
HeadingPitchRange
(
new
Cesium
.
HeadingPitchRange
(
0.0
,
0.0
,
-
0.5
,
-
0.5
,
tileset
.
boundingSphere
.
radius
/
0.5
tileset
.
boundingSphere
.
radius
/
0.5
)
)
)
)
.
otherwise
(
function
(
err
)
{
.
otherwise
(
function
(
err
)
{
throw
err
;
throw
err
;
});
});
});
});
};
};
/**
/**
...
@@ -67,12 +67,12 @@ const loadTiles = function (urlTiles) {
...
@@ -67,12 +67,12 @@ const loadTiles = function (urlTiles) {
* @param{*}
* @param{*}
* @returns {undefined} undefined
* @returns {undefined} undefined
*/
*/
const
loadNonDetailed
=
function
()
{
const
loadNonDetailed
=
function
()
{
// Paths to data sources
// Paths to data sources
const
URL_3DTILES
=
"
data_3d/3dtiles/1_full/tileset.json
"
;
const
URL_3DTILES
=
"
data_3d/3dtiles/1_full/tileset.json
"
;
// Tileset with all buildings
// Tileset with all buildings
loadTiles
(
URL_3DTILES
);
loadTiles
(
URL_3DTILES
);
};
};
/**
/**
...
@@ -81,19 +81,19 @@ const loadNonDetailed = function () {
...
@@ -81,19 +81,19 @@ const loadNonDetailed = function () {
* @param {String} gltfId Name of the glTF model file without the extension i.e. exclude the `.gltf` suffix
* @param {String} gltfId Name of the glTF model file without the extension i.e. exclude the `.gltf` suffix
* @returns {undefined} undefined
* @returns {undefined} undefined
*/
*/
const
gltfLoad
=
function
(
gltfUrl
,
gltfId
)
{
const
gltfLoad
=
function
(
gltfUrl
,
gltfId
)
{
const
modelMatrix
=
Cesium
.
Transforms
.
eastNorthUpToFixedFrame
(
const
modelMatrix
=
Cesium
.
Transforms
.
eastNorthUpToFixedFrame
(
Cesium
.
Cartesian3
.
fromDegrees
(
9.083385
,
48.881342
,
0
)
Cesium
.
Cartesian3
.
fromDegrees
(
9.083385
,
48.881342
,
0
)
);
);
viewer
.
scene
.
primitives
.
add
(
viewer
.
scene
.
primitives
.
add
(
Cesium
.
Model
.
fromGltf
({
Cesium
.
Model
.
fromGltf
({
url
:
`
${
gltfUrl
}
/
${
gltfId
}
.gltf`
,
url
:
`
${
gltfUrl
}
/
${
gltfId
}
.gltf`
,
modelMatrix
:
modelMatrix
,
modelMatrix
:
modelMatrix
,
scale
:
0.0254
,
scale
:
0.0254
,
allowPicking
:
true
,
allowPicking
:
true
,
})
})
);
);
};
};
/**
/**
...
@@ -101,64 +101,64 @@ const gltfLoad = function (gltfUrl, gltfId) {
...
@@ -101,64 +101,64 @@ const gltfLoad = function (gltfUrl, gltfId) {
* @param{*}
* @param{*}
* @returns {undefined} undefined
* @returns {undefined} undefined
*/
*/
const
loadDetailed
=
function
()
{
const
loadDetailed
=
function
()
{
// Paths to data sources
// Paths to data sources
const
URL_3DTILES
=
"
data_3d/3dtiles/2_partial/tileset.json
"
;
const
URL_3DTILES
=
"
data_3d/3dtiles/2_partial/tileset.json
"
;
const
URL_GLTF
=
"
data_3d/gltf
"
;
const
URL_GLTF
=
"
data_3d/gltf
"
;
// Tileset without building 225
// Tileset without building 225
loadTiles
(
URL_3DTILES
);
loadTiles
(
URL_3DTILES
);
// Load Building 225
// Load Building 225
gltfLoad
(
URL_GLTF
,
"
bosch_si225_3
"
);
gltfLoad
(
URL_GLTF
,
"
bosch_si225_3
"
);
// Load sensors in Building 225
// Load sensors in Building 225
const
gltfArray
=
[
const
gltfArray
=
[
"
sensor_013
"
,
"
sensor_013
"
,
"
sensor_023
"
,
"
sensor_023
"
,
"
sensor_033
"
,
"
sensor_033
"
,
"
sensor_053
"
,
"
sensor_053
"
,
"
sensor_063
"
,
"
sensor_063
"
,
"
sensor_073
"
,
"
sensor_073
"
,
"
sensor_083
"
,
"
sensor_083
"
,
"
sensor_093
"
,
"
sensor_093
"
,
"
sensor_103
"
,
"
sensor_103
"
,
"
sensor_113
"
,
"
sensor_113
"
,
"
sensor_123
"
,
"
sensor_123
"
,
"
sensor_133
"
,
"
sensor_133
"
,
"
sensor_143
"
,
"
sensor_143
"
,
"
sensor_153
"
,
"
sensor_153
"
,
"
sensor_163
"
,
"
sensor_163
"
,
"
sensor_173
"
,
"
sensor_173
"
,
"
sensor_183
"
,
"
sensor_183
"
,
"
sensor_213
"
,
"
sensor_213
"
,
"
sensor_223
"
,
"
sensor_223
"
,
"
sensor_233
"
,
"
sensor_233
"
,
"
sensor_253
"
,
"
sensor_253
"
,
"
sensor_263
"
,
"
sensor_263
"
,
"
sensor_273
"
,
"
sensor_273
"
,
"
sensor_283
"
,
"
sensor_283
"
,
"
sensor_293
"
,
"
sensor_293
"
,
"
sensor_303
"
,
"
sensor_303
"
,
"
sensor_313
"
,
"
sensor_313
"
,
"
sensor_323
"
,
"
sensor_323
"
,
"
sensor_333
"
,
"
sensor_333
"
,
"
sensor_343
"
,
"
sensor_343
"
,
"
sensor_353
"
,
"
sensor_353
"
,
"
sensor_363
"
,
"
sensor_363
"
,
"
sensor_373
"
,
"
sensor_373
"
,
"
sensor_383_v2
"
,
"
sensor_383_v2
"
,
];
];
gltfArray
.
forEach
((
sensor
)
=>
gltfLoad
(
URL_GLTF
,
sensor
));
gltfArray
.
forEach
((
sensor
)
=>
gltfLoad
(
URL_GLTF
,
sensor
));
};
};
if
(
!
LOAD_DETAILED_BLDG225
)
{
if
(
!
LOAD_DETAILED_BLDG225
)
{
// Default case: load only 3dTiles
// Default case: load only 3dTiles
loadNonDetailed
();
loadNonDetailed
();
}
else
{
}
else
{
// Alternative case: load 3dTiles + glTF
// Alternative case: load 3dTiles + glTF
loadDetailed
();
loadDetailed
();
}
}
/**
/**
...
@@ -166,109 +166,109 @@ if (!LOAD_DETAILED_BLDG225) {
...
@@ -166,109 +166,109 @@ if (!LOAD_DETAILED_BLDG225) {
* @param {*}
* @param {*}
* @returns {undefined}
* @returns {undefined}
*/
*/
const
activate3DTileFeaturePicking
=
function
()
{
const
activate3DTileFeaturePicking
=
function
()
{
// HTML overlay for showing feature name on mouseover
// HTML overlay for showing feature name on mouseover
const
nameOverlay
=
document
.
createElement
(
"
div
"
);
const
nameOverlay
=
document
.
createElement
(
"
div
"
);
viewer
.
container
.
appendChild
(
nameOverlay
);
viewer
.
container
.
appendChild
(
nameOverlay
);
nameOverlay
.
className
=
"
backdrop
"
;
nameOverlay
.
className
=
"
backdrop
"
;
nameOverlay
.
style
.
display
=
"
none
"
;
nameOverlay
.
style
.
display
=
"
none
"
;
nameOverlay
.
style
.
position
=
"
absolute
"
;
nameOverlay
.
style
.
position
=
"
absolute
"
;
nameOverlay
.
style
.
bottom
=
"
0
"
;
nameOverlay
.
style
.
bottom
=
"
0
"
;
nameOverlay
.
style
.
left
=
"
0
"
;
nameOverlay
.
style
.
left
=
"
0
"
;
nameOverlay
.
style
[
"
pointer-events
"
]
=
"
none
"
;
nameOverlay
.
style
[
"
pointer-events
"
]
=
"
none
"
;
nameOverlay
.
style
.
padding
=
"
4px
"
;
nameOverlay
.
style
.
padding
=
"
4px
"
;
nameOverlay
.
style
.
backgroundColor
=
"
black
"
;
nameOverlay
.
style
.
backgroundColor
=
"
black
"
;
nameOverlay
.
style
.
color
=
"
white
"
;
nameOverlay
.
style
.
color
=
"
white
"
;
nameOverlay
.
style
.
fontFamily
=
"
Fira Sans, sans-serif
"
;
nameOverlay
.
style
.
fontFamily
=
"
Fira Sans, sans-serif
"
;
nameOverlay
.
style
.
fontSize
=
"
0.75em
"
;
nameOverlay
.
style
.
fontSize
=
"
0.75em
"
;
// Information about the currently selected feature
// Information about the currently selected feature
const
selected
=
{
const
selected
=
{
feature
:
undefined
,
feature
:
undefined
,
originalColor
:
new
Cesium
.
Color
(),
originalColor
:
new
Cesium
.
Color
(),
};
};
// An entity object which will hold info about the currently selected feature for infobox display
// An entity object which will hold info about the currently selected feature for infobox display
const
selectedEntity
=
new
Cesium
.
Entity
();
const
selectedEntity
=
new
Cesium
.
Entity
();
// Get default left click handler for when a feature is not picked on left click
// Get default left click handler for when a feature is not picked on left click
const
clickHandler
=
viewer
.
screenSpaceEventHandler
.
getInputAction
(
const
clickHandler
=
viewer
.
screenSpaceEventHandler
.
getInputAction
(
Cesium
.
ScreenSpaceEventType
.
LEFT_CLICK
Cesium
.
ScreenSpaceEventType
.
LEFT_CLICK
);
);
// Change the feature color on mouse over
// Change the feature color on mouse over
// Information about the currently highlighted feature
// Information about the currently highlighted feature
const
highlighted
=
{
const
highlighted
=
{
feature
:
undefined
,
feature
:
undefined
,
originalColor
:
new
Cesium
.
Color
(),
originalColor
:
new
Cesium
.
Color
(),
};
};
// Color a feature on hover.
// Color a feature on hover.
viewer
.
screenSpaceEventHandler
.
setInputAction
(
function
onMouseMove
(
movement
)
{
viewer
.
screenSpaceEventHandler
.
setInputAction
(
function
onMouseMove
(
movement
)
{
// If a feature was previously highlighted, undo the highlight
// If a feature was previously highlighted, undo the highlight
if
(
Cesium
.
defined
(
highlighted
.
feature
))
{
if
(
Cesium
.
defined
(
highlighted
.
feature
))
{
highlighted
.
feature
.
color
=
highlighted
.
originalColor
;
highlighted
.
feature
.
color
=
highlighted
.
originalColor
;
highlighted
.
feature
=
undefined
;
highlighted
.
feature
=
undefined
;
}
}
// Pick a new feature
// Pick a new feature
const
pickedFeature
=
viewer
.
scene
.
pick
(
movement
.
endPosition
);
const
pickedFeature
=
viewer
.
scene
.
pick
(
movement
.
endPosition
);
if
(
!
Cesium
.
defined
(
pickedFeature
))
{
if
(
!
Cesium
.
defined
(
pickedFeature
))
{
nameOverlay
.
style
.
display
=
"
none
"
;
nameOverlay
.
style
.
display
=
"
none
"
;
return
;
return
;
}
}
// A feature was picked, so show it's overlay content
// A feature was picked, so show it's overlay content
nameOverlay
.
style
.
display
=
"
block
"
;
nameOverlay
.
style
.
display
=
"
block
"
;
nameOverlay
.
style
.
bottom
=
nameOverlay
.
style
.
bottom
=
viewer
.
canvas
.
clientHeight
-
movement
.
endPosition
.
y
+
"
px
"
;
viewer
.
canvas
.
clientHeight
-
movement
.
endPosition
.
y
+
"
px
"
;
nameOverlay
.
style
.
left
=
movement
.
endPosition
.
x
+
"
px
"
;
nameOverlay
.
style
.
left
=
movement
.
endPosition
.
x
+
"
px
"
;
let
name
=
pickedFeature
.
getProperty
(
"
_gebaeude
"
);
let
name
=
pickedFeature
.
getProperty
(
"
_gebaeude
"
);
if
(
!
Cesium
.
defined
(
name
))
{
if
(
!
Cesium
.
defined
(
name
))
{
name
=
pickedFeature
.
getProperty
(
"
id
"
);
name
=
pickedFeature
.
getProperty
(
"
id
"
);
}
}
nameOverlay
.
textContent
=
name
;
nameOverlay
.
textContent
=
name
;
// Highlight the feature if it's not already selected.
// Highlight the feature if it's not already selected.
if
(
pickedFeature
!==
selected
.
feature
)
{
if
(
pickedFeature
!==
selected
.
feature
)
{
highlighted
.
feature
=
pickedFeature
;
highlighted
.
feature
=
pickedFeature
;
Cesium
.
Color
.
clone
(
pickedFeature
.
color
,
highlighted
.
originalColor
);
Cesium
.
Color
.
clone
(
pickedFeature
.
color
,
highlighted
.
originalColor
);
pickedFeature
.
color
=
Cesium
.
Color
.
GREY
;
pickedFeature
.
color
=
Cesium
.
Color
.
GREY
;
}
}
},
Cesium
.
ScreenSpaceEventType
.
MOUSE_MOVE
);
},
Cesium
.
ScreenSpaceEventType
.
MOUSE_MOVE
);
// Color a feature on selection and show metadata in the InfoBox.
// Color a feature on selection and show metadata in the InfoBox.
viewer
.
screenSpaceEventHandler
.
setInputAction
(
function
onLeftClick
(
movement
)
{
viewer
.
screenSpaceEventHandler
.
setInputAction
(
function
onLeftClick
(
movement
)
{
// If a feature was previously selected, undo the highlight
// If a feature was previously selected, undo the highlight
if
(
Cesium
.
defined
(
selected
.
feature
))
{
if
(
Cesium
.
defined
(
selected
.
feature
))
{
selected
.
feature
.
color
=
selected
.
originalColor
;
selected
.
feature
.
color
=
selected
.
originalColor
;
selected
.
feature
=
undefined
;
selected
.
feature
=
undefined
;
}
}
// Pick a new feature
// Pick a new feature
const
pickedFeature
=
viewer
.
scene
.
pick
(
movement
.
position
);
const
pickedFeature
=
viewer
.
scene
.
pick
(
movement
.
position
);
if
(
!
Cesium
.
defined
(
pickedFeature
))
{
if
(
!
Cesium
.
defined
(
pickedFeature
))
{
clickHandler
(
movement
);
clickHandler
(
movement
);
return
;
return
;
}
}
// Select the feature if it's not already selected
// Select the feature if it's not already selected
if
(
selected
.
feature
===
pickedFeature
)
{
if
(
selected
.
feature
===
pickedFeature
)
{
return
;
return
;
}
}
selected
.
feature
=
pickedFeature
;
selected
.
feature
=
pickedFeature
;
// Save the selected feature's original color
// Save the selected feature's original color
if
(
pickedFeature
===
highlighted
.
feature
)
{
if
(
pickedFeature
===
highlighted
.
feature
)
{
Cesium
.
Color
.
clone
(
highlighted
.
originalColor
,
selected
.
originalColor
);
Cesium
.
Color
.
clone
(
highlighted
.
originalColor
,
selected
.
originalColor
);
highlighted
.
feature
=
undefined
;
highlighted
.
feature
=
undefined
;
}
else
{
}
else
{
Cesium
.
Color
.
clone
(
pickedFeature
.
color
,
selected
.
originalColor
);
Cesium
.
Color
.
clone
(
pickedFeature
.
color
,
selected
.
originalColor
);
}
}
// Highlight newly selected feature
// Highlight newly selected feature
pickedFeature
.
color
=
Cesium
.
Color
.
LIME
;
pickedFeature
.
color
=
Cesium
.
Color
.
LIME
;
// Set feature infobox description
// Set feature infobox description
const
featureName
=
pickedFeature
.
getProperty
(
"
name
"
);
const
featureName
=
pickedFeature
.
getProperty
(
"
name
"
);
selectedEntity
.
name
=
featureName
;
selectedEntity
.
name
=
featureName
;
selectedEntity
.
description
=
selectedEntity
.
description
=
'
Loading <div class="cesium-infoBox-loading"></div>
'
;
'
Loading <div class="cesium-infoBox-loading"></div>
'
;
viewer
.
selectedEntity
=
selectedEntity
;
viewer
.
selectedEntity
=
selectedEntity
;
selectedEntity
.
description
=
`
selectedEntity
.
description
=
`
<table class="cesium-infoBox-defaultTable">
<table class="cesium-infoBox-defaultTable">
<tbody>
<tbody>
<tr><th>Bau</th><td>
<tr><th>Bau</th><td>
...
@@ -290,57 +290,62 @@ const activate3DTileFeaturePicking = function () {
...
@@ -290,57 +290,62 @@ const activate3DTileFeaturePicking = function () {
</table>
</table>
`
;
`
;
const
clickedBuilding
=
pickedFeature
.
getProperty
(
"
_gebaeude
"
);
const
clickedBuilding
=
pickedFeature
.
getProperty
(
"
_gebaeude
"
);
const
clickedBuildingDatastreamId
=
getDatastreamIdFromBuildingNumber
(
const
clickedBuildingDatastreamId
=
getDatastreamIdFromBuildingNumber
(
clickedBuilding
,
clickedBuilding
,
"
vl
"
,
"
vl
"
,
"
60min
"
"
60min
"
);
);
const
BASE_URL_OBSERVATIONS
=
getObservationsUrl
(
BASE_URL
,
clickedBuildingDatastreamId
);
const
PARAM_FILTER
=
createTemporalFilterString
(
"
2020-01-01
"
,
"
2021-01-01
"
);
const
axiosGetRequest
=
axios
.
get
(
BASE_URL_OBSERVATIONS
,
{
params
:
{
"
$resultFormat
"
:
PARAM_RESULT_FORMAT
,
"
$orderBy
"
:
PARAM_ORDER_BY
,
"
$filter
"
:
PARAM_FILTER
,
"
$select
"
:
PARAM_SELECT
,
},
});
const
BASE_URL_OBSERVATIONS
=
getObservationsUrl
(
BASE_URL
,
clickedBuildingDatastreamId
);
const
PARAM_FILTER
=
createTemporalFilterString
(
"
2020-01-01
"
,
"
2021-01-01
"
);
const
axiosGetRequest
=
axios
.
get
(
BASE_URL_OBSERVATIONS
,
{
params
:
{
"
$resultFormat
"
:
PARAM_RESULT_FORMAT
,
"
$orderBy
"
:
PARAM_ORDER_BY
,
"
$filter
"
:
PARAM_FILTER
,
"
$select
"
:
PARAM_SELECT
,
},
});
// Get "ALL" the Observations that satisfy our query
// Get "ALL" the Observations that satisfy our query
followNextLink
(
axiosGetRequest
)
followNextLink
(
axiosGetRequest
)
.
then
((
success
)
=>
{
.
then
((
success
)
=>
{
const
successValue
=
success
.
data
.
value
;
const
successValue
=
success
.
data
.
value
;
// Array that will hold the combined observations
// Array that will hold the combined observations
const
combinedObservations
=
[];
const
combinedObservations
=
[];
successValue
.
forEach
((
dataObj
)
=>
{
successValue
.
forEach
((
dataObj
)
=>
{
// Each page of results will have a dataArray that holds the observations
// Each page of results will have a dataArray that holds the observations
const
dataArrays
=
dataObj
.
dataArray
;
const
dataArrays
=
dataObj
.
dataArray
;
combinedObservations
.
push
(...
dataArrays
);
});
// DEBUG: Check total number of observations
console
.
log
(
combinedObservations
.
length
);
// DEBUG: Print the array of observations
console
.
log
(
combinedObservations
);
return
combinedObservations
;
})
.
catch
((
err
)
=>
{
console
.
log
(
err
);
})
.
then
((
observationArr
)
=>
{
var
agg
=
aggregateResponse
(
observationArr
,
0
,
'
mean
'
);
console
.
log
(
agg
);
drawHeatMapHC
(
formatSTAResponseForHeatMap
(
observationArr
));
drawLineChartHC
(
formatSTAResponseForLineChart
(
observationArr
));
});
},
Cesium
.
ScreenSpaceEventType
.
LEFT_CLICK
);
combinedObservations
.
push
(...
dataArrays
);
});
// DEBUG: Check total number of observations
console
.
log
(
combinedObservations
.
length
);
// DEBUG: Print the array of observations
console
.
log
(
combinedObservations
);
return
combinedObservations
;
})
.
catch
((
err
)
=>
{
console
.
log
(
err
);
})
.
then
((
observationArr
)
=>
{
drawHeatMapHC
(
formatSTAResponseForHeatMap
(
observationArr
));
drawLineChartHC
(
formatSTAResponseForLineChart
(
observationArr
));
});
},
Cesium
.
ScreenSpaceEventType
.
LEFT_CLICK
);
};
};
activate3DTileFeaturePicking
();
activate3DTileFeaturePicking
();
\ No newline at end of file
public/js/appChart.js
View file @
86bff050
...
@@ -13,72 +13,72 @@ export const BASE_URL = "http://193.196.39.91:8080/frost-icity-tp31/v1.1";
...
@@ -13,72 +13,72 @@ export const BASE_URL = "http://193.196.39.91:8080/frost-icity-tp31/v1.1";
* @param {*} samplingRate String representing the sampling rate of the observations
* @param {*} samplingRate String representing the sampling rate of the observations
* @returns {Number} Datastream corresponding to the input building
* @returns {Number} Datastream corresponding to the input building
*/
*/
export
const
getDatastreamIdFromBuildingNumber
=
function
(
export
const
getDatastreamIdFromBuildingNumber
=
function
(
buildingNumber
,
buildingNumber
,
phenomenon
,
phenomenon
,
samplingRate
samplingRate
)
{
)
{
const
buildingToDatastreamMapping
=
{
const
buildingToDatastreamMapping
=
{
101
:
{
101
:
{
vl
:
{
"
15min
"
:
"
69
"
,
"
60min
"
:
"
75
"
},
vl
:
{
"
15min
"
:
"
69
"
,
"
60min
"
:
"
75
"
},
rl
:
{
"
15min
"
:
"
81
"
,
"
60min
"
:
"
87
"
},
rl
:
{
"
15min
"
:
"
81
"
,
"
60min
"
:
"
87
"
},
flow
:
{
"
15min
"
:
"
93
"
,
"
60min
"
:
"
99
"
},
flow
:
{
"
15min
"
:
"
93
"
,
"
60min
"
:
"
99
"
},
power
:
{
"
15min
"
:
"
105
"
,
"
60min
"
:
"
111
"
},
power
:
{
"
15min
"
:
"
105
"
,
"
60min
"
:
"
111
"
},
energy
:
{
"
15min
"
:
"
117
"
,
"
60min
"
:
"
123
"
},
energy
:
{
"
15min
"
:
"
117
"
,
"
60min
"
:
"
123
"
},
energy_verb
:
{
"
15min
"
:
"
129
"
,
"
60min
"
:
"
135
"
},
energy_verb
:
{
"
15min
"
:
"
129
"
,
"
60min
"
:
"
135
"
},
},
},
102
:
{
102
:
{
vl
:
{
"
15min
"
:
"
70
"
,
"
60min
"
:
"
76
"
},
vl
:
{
"
15min
"
:
"
70
"
,
"
60min
"
:
"
76
"
},
rl
:
{
"
15min
"
:
"
82
"
,
"
60min
"
:
"
88
"
},
rl
:
{
"
15min
"
:
"
82
"
,
"
60min
"
:
"
88
"
},
flow
:
{
"
15min
"
:
"
94
"
,
"
60min
"
:
"
100
"
},
flow
:
{
"
15min
"
:
"
94
"
,
"
60min
"
:
"
100
"
},
power
:
{
"
15min
"
:
"
106
"
,
"
60min
"
:
"
112
"
},
power
:
{
"
15min
"
:
"
106
"
,
"
60min
"
:
"
112
"
},
energy
:
{
"
15min
"
:
"
118
"
,
"
60min
"
:
"
124
"
},
energy
:
{
"
15min
"
:
"
118
"
,
"
60min
"
:
"
124
"
},
energy_verb
:
{
"
15min
"
:
"
130
"
,
"
60min
"
:
"
136
"
},
energy_verb
:
{
"
15min
"
:
"
130
"
,
"
60min
"
:
"
136
"
},
},
},
107
:
{
107
:
{
vl
:
{
"
15min
"
:
"
71
"
,
"
60min
"
:
"
77
"
},
vl
:
{
"
15min
"
:
"
71
"
,
"
60min
"
:
"
77
"
},
rl
:
{
"
15min
"
:
"
83
"
,
"
60min
"
:
"
89
"
},
rl
:
{
"
15min
"
:
"
83
"
,
"
60min
"
:
"
89
"
},
flow
:
{
"
15min
"
:
"
95
"
,
"
60min
"
:
"
101
"
},
flow
:
{
"
15min
"
:
"
95
"
,
"
60min
"
:
"
101
"
},
power
:
{
"
15min
"
:
"
107
"
,
"
60min
"
:
"
113
"
},
power
:
{
"
15min
"
:
"
107
"
,
"
60min
"
:
"
113
"
},
energy
:
{
"
15min
"
:
"
119
"
,
"
60min
"
:
"
125
"
},
energy
:
{
"
15min
"
:
"
119
"
,
"
60min
"
:
"
125
"
},
energy_verb
:
{
"
15min
"
:
"
131
"
,
"
60min
"
:
"
137
"
},
energy_verb
:
{
"
15min
"
:
"
131
"
,
"
60min
"
:
"
137
"
},
},
},
"
112, 118
"
:
{
"
112, 118
"
:
{
vl
:
{
"
15min
"
:
"
72
"
,
"
60min
"
:
"
78
"
},
vl
:
{
"
15min
"
:
"
72
"
,
"
60min
"
:
"
78
"
},
rl
:
{
"
15min
"
:
"
84
"
,
"
60min
"
:
"
90
"
},
rl
:
{
"
15min
"
:
"
84
"
,
"
60min
"
:
"
90
"
},
flow
:
{
"
15min
"
:
"
96
"
,
"
60min
"
:
"
102
"
},
flow
:
{
"
15min
"
:
"
96
"
,
"
60min
"
:
"
102
"
},
power
:
{
"
15min
"
:
"
108
"
,
"
60min
"
:
"
114
"
},
power
:
{
"
15min
"
:
"
108
"
,
"
60min
"
:
"
114
"
},
energy
:
{
"
15min
"
:
"
120
"
,
"
60min
"
:
"
126
"
},
energy
:
{
"
15min
"
:
"
120
"
,
"
60min
"
:
"
126
"
},
energy_verb
:
{
"
15min
"
:
"
132
"
,
"
60min
"
:
"
138
"
},
energy_verb
:
{
"
15min
"
:
"
132
"
,
"
60min
"
:
"
138
"
},
},
},
125
:
{
125
:
{
vl
:
{
"
15min
"
:
"
73
"
,
"
60min
"
:
"
79
"
},
vl
:
{
"
15min
"
:
"
73
"
,
"
60min
"
:
"
79
"
},
rl
:
{
"
15min
"
:
"
85
"
,
"
60min
"
:
"
91
"
},
rl
:
{
"
15min
"
:
"
85
"
,
"
60min
"
:
"
91
"
},
flow
:
{
"
15min
"
:
"
97
"
,
"
60min
"
:
"
103
"
},
flow
:
{
"
15min
"
:
"
97
"
,
"
60min
"
:
"
103
"
},
power
:
{
"
15min
"
:
"
109
"
,
"
60min
"
:
"
115
"
},
power
:
{
"
15min
"
:
"
109
"
,
"
60min
"
:
"
115
"
},
energy
:
{
"
15min
"
:
"
121
"
,
"
60min
"
:
"
127
"
},
energy
:
{
"
15min
"
:
"
121
"
,
"
60min
"
:
"
127
"
},
energy_verb
:
{
"
15min
"
:
"
133
"
,
"
60min
"
:
"
139
"
},
energy_verb
:
{
"
15min
"
:
"
133
"
,
"
60min
"
:
"
139
"
},
},
},
225
:
{
225
:
{
vl
:
{
"
15min
"
:
"
74
"
,
"
60min
"
:
"
80
"
},
vl
:
{
"
15min
"
:
"
74
"
,
"
60min
"
:
"
80
"
},
rl
:
{
"
15min
"
:
"
86
"
,
"
60min
"
:
"
92
"
},
rl
:
{
"
15min
"
:
"
86
"
,
"
60min
"
:
"
92
"
},
flow
:
{
"
15min
"
:
"
98
"
,
"
60min
"
:
"
104
"
},
flow
:
{
"
15min
"
:
"
98
"
,
"
60min
"
:
"
104
"
},
power
:
{
"
15min
"
:
"
110
"
,
"
60min
"
:
"
116
"
},
power
:
{
"
15min
"
:
"
110
"
,
"
60min
"
:
"
116
"
},
energy
:
{
"
15min
"
:
"
122
"
,
"
60min
"
:
"
128
"
},
energy
:
{
"
15min
"
:
"
122
"
,
"
60min
"
:
"
128
"
},
energy_verb
:
{
"
15min
"
:
"
134
"
,
"
60min
"
:
"
140
"
},
energy_verb
:
{
"
15min
"
:
"
134
"
,
"
60min
"
:
"
140
"
},
},
},
};
};
if
(
!
buildingNumber
)
return
;
if
(
!
buildingNumber
)
return
;
// check if building is contained in mapping object
// check if building is contained in mapping object
if
(
!
(
buildingNumber
in
buildingToDatastreamMapping
))
return
;
if
(
!
(
buildingNumber
in
buildingToDatastreamMapping
))
return
;
const
datastreamIdMatched
=
Number
(
const
datastreamIdMatched
=
Number
(
buildingToDatastreamMapping
[
buildingNumber
][
phenomenon
][
samplingRate
]
buildingToDatastreamMapping
[
buildingNumber
][
phenomenon
][
samplingRate
]
);
);
return
datastreamIdMatched
;
return
datastreamIdMatched
;
};
};
/**
/**
...
@@ -86,10 +86,10 @@ export const getDatastreamIdFromBuildingNumber = function (
...
@@ -86,10 +86,10 @@ export const getDatastreamIdFromBuildingNumber = function (
* @param {Number} datastreamID - Integer representing the Datastream ID
* @param {Number} datastreamID - Integer representing the Datastream ID
* @returns {String} URL string for fetching the Observations corresponding to a Datastream
* @returns {String} URL string for fetching the Observations corresponding to a Datastream
*/
*/
export
const
getObservationsUrl
=
function
(
baseUrl
,
datastreamID
)
{
export
const
getObservationsUrl
=
function
(
baseUrl
,
datastreamID
)
{
if
(
!
datastreamID
)
return
;
if
(
!
datastreamID
)
return
;
const
fullDatastreamURL
=
`
${
baseUrl
}
/Datastreams(
${
datastreamID
}
)/Observations`
;
const
fullDatastreamURL
=
`
${
baseUrl
}
/Datastreams(
${
datastreamID
}
)/Observations`
;
return
fullDatastreamURL
;
return
fullDatastreamURL
;
};
};
/**
/**
...
@@ -98,10 +98,10 @@ export const getObservationsUrl = function (baseUrl, datastreamID) {
...
@@ -98,10 +98,10 @@ export const getObservationsUrl = function (baseUrl, datastreamID) {
* @param {String} dateStop Stop date in YYYY-MM-DD format
* @param {String} dateStop Stop date in YYYY-MM-DD format
* @returns {String} Temporal filter string
* @returns {String} Temporal filter string
*/
*/
export
const
createTemporalFilterString
=
function
(
dateStart
,
dateStop
)
{
export
const
createTemporalFilterString
=
function
(
dateStart
,
dateStop
)
{
if
(
!
dateStart
||
!
dateStop
)
return
;
if
(
!
dateStart
||
!
dateStop
)
return
;
const
filterString
=
`resultTime ge
${
dateStart
}
T00:00:00.000Z and resultTime le
${
dateStop
}
T00:00:00.000Z`
;
const
filterString
=
`resultTime ge
${
dateStart
}
T00:00:00.000Z and resultTime le
${
dateStop
}
T00:00:00.000Z`
;
return
filterString
;
return
filterString
;
};
};
// const BASE_URL_OBSERVATIONS = getObservationsUrl(80);
// const BASE_URL_OBSERVATIONS = getObservationsUrl(80);
...
@@ -119,31 +119,218 @@ export const PARAM_SELECT = "result,phenomenonTime";
...
@@ -119,31 +119,218 @@ export const PARAM_SELECT = "result,phenomenonTime";
// },
// },
// });
// });
/**
*
* @param {JSON} obj JSON object on which to replace a specific key.
* @param {String} oldKey is the old key in the JSON to be renamed to newKey
* @param {String} newKey is the key that should replace the oldKey
* usage: myjson.forEach((obj) => renameKey(obj, "oldkey", "newkey"));
*/
function
renameKey
(
obj
,
oldKey
,
newKey
)
{
obj
[
newKey
]
=
obj
[
oldKey
];
delete
obj
[
oldKey
];
}
/**
*
* @param {Array} arr is the Array to be converted into a JSON
* @returns {JSON} stringToJsonObject
*/
function
convertArray2JSON
(
arr
)
{
var
arrayToString
=
JSON
.
stringify
(
Object
.
assign
({},
arr
));
// convert array to string
var
stringToJsonObject
=
JSON
.
parse
(
arrayToString
);
// convert string to json object
return
stringToJsonObject
;
}
function
createDateFromDateTimeString
(
jsonData
)
{
let
datx
=
[];
let
daty
=
[];
const
MONTH
=
[
'
Jan
'
,
'
Feb
'
,
'
Mar
'
,
'
Apr
'
,
'
May
'
,
'
Jun
'
,
'
Jul
'
,
'
Aug
'
,
'
Sep
'
,
'
Oct
'
,
'
Nov
'
,
'
Dec
'
];
for
(
var
u
=
0
;
u
<
jsonData
.
length
;
u
++
)
{
daty
.
push
(
jsonData
[
u
].
temperature
);
let
date
=
new
Date
(
jsonData
[
u
].
datetime
);
let
datum
=
date
.
getDate
();
let
month
=
MONTH
[
date
.
getMonth
()];
let
hour
=
date
.
getHours
()
+
"
:00
"
;
let
newDateStr
=
datum
+
"
/
"
+
month
+
"
-
"
+
hour
;
datx
.
push
(
newDateStr
);
}
return
[
datx
,
daty
];
}
/**
* Format the response from SensorThings API to make it suitable for heatmap
* @param {Array} obsArray Response from SensorThings API as array
* @param {Int8} hours Number of hours to aggregate over. If hours=0,
* it will be aggregated by date (e.g. all values recorded on 1st of May etc...)
* if hours to any number (also hours=24) data will be aggregated over every 24hours,
* even if the date changes (e.g. data from 1st of May from 10pm up 9pm on 2nd of May etc.)
* @param {String} method Specify how to aggregate date. Use: 'mean' = default, 'sum', 'min' or 'max'
* @returns {Array} Aggregated Response
*/
export
const
aggregateResponse
=
function
(
obsArray
,
hours
,
method
)
{
if
(
!
obsArray
)
return
;
if
(
hours
<
0
)
return
;
// check if we have a defined method or the method specified is accepted, rest is handeled in switch/case below
if
(
method
==
undefined
)
method
=
'
mean
'
;
// convert obsArray to json
let
jsonFromArr
=
[];
for
(
var
i
=
0
;
i
<
obsArray
.
length
;
i
++
)
{
jsonFromArr
.
push
(
convertArray2JSON
(
obsArray
[
i
]));
}
// rename the keys in the jason
jsonFromArr
.
forEach
((
obj
)
=>
renameKey
(
obj
,
"
0
"
,
"
datetime
"
));
let
jsonData
=
jsonFromArr
;
jsonData
.
forEach
((
obj
)
=>
renameKey
(
obj
,
"
1
"
,
"
temperature
"
));
let
newOutput
=
[];
var
aggDates
=
[];
var
aggregatedVals
=
[];
var
vals
=
[];
// store values temporarily to use for processing
if
(
hours
==
0
)
{
// i.e. aggregate over one Date / Day
var
currentDate
;
var
oldDate
;
for
(
var
d
=
0
;
d
<
jsonData
.
length
;
d
++
)
{
let
tmpDate
=
new
Date
(
jsonData
[
d
].
datetime
);
currentDate
=
tmpDate
.
getDate
();
// gets the day of the month 1...31
if
(
d
===
0
)
oldDate
=
currentDate
;
if
(
currentDate
==
oldDate
)
{
vals
.
push
(
jsonData
[
d
].
temperature
);
}
else
{
aggDates
.
push
(
new
Date
(
tmpDate
-
1
));
if
(
vals
.
length
==
0
)
{
aggregatedVals
.
push
(
-
1
);
oldDate
=
currentDate
;
continue
;
}
switch
(
method
)
{
case
'
mean
'
:
aggregatedVals
.
push
(
vals
.
reduce
(
function
(
a
,
b
)
{
return
a
+
b
/
vals
.
length
;
},
0
));
break
;
case
'
sum
'
:
aggregatedVals
.
push
(
vals
.
reduce
(
function
(
a
,
b
)
{
return
a
+
b
;
},
0
));
break
;
case
'
min
'
:
aggregatedVals
.
push
(
vals
.
reduce
(
function
(
a
,
b
)
{
return
Math
.
min
(
a
,
b
);
}));
break
;
case
'
max
'
:
aggregatedVals
.
push
(
vals
.
reduce
(
function
(
a
,
b
)
{
return
Math
.
max
(
a
,
b
);
}));
break
;
default
:
aggregatedVals
.
push
(
vals
.
reduce
(
function
(
a
,
b
)
{
return
a
+
b
/
vals
.
length
;
},
0
));
}
vals
=
[];
// clear the daily value vector
vals
.
push
(
jsonData
[
d
].
temperature
);
// now push first entry of new day into my temp value vector.
}
oldDate
=
currentDate
;
}
// end of for loop
// create output to be in the same List format as the original data from obsArray.
for
(
let
i
=
0
;
i
<
aggregatedVals
.
length
;
i
++
)
{
newOutput
.
push
([
aggDates
[
i
].
toISOString
(),
aggregatedVals
[
i
]]);
}
}
else
{
// i.e. aggregate over X hours, irrespective of the day.
let
cnt
=
0
;
let
cumHours
=
0
;
for
(
var
d
=
0
;
d
<
jsonData
.
length
;
d
++
)
{
if
(
cnt
<
hours
)
{
vals
.
push
(
jsonData
[
d
].
temperature
);
cnt
++
;
}
else
{
cumHours
+=
cnt
;
cnt
=
0
;
aggDates
.
push
(
cumHours
);
if
(
vals
.
length
==
0
)
{
aggregatedVals
.
push
(
-
1
);
continue
;
}
switch
(
method
)
{
case
'
mean
'
:
aggregatedVals
.
push
(
vals
.
reduce
(
function
(
a
,
b
)
{
return
a
+
b
/
vals
.
length
;
},
0
));
break
;
case
'
sum
'
:
aggregatedVals
.
push
(
vals
.
reduce
(
function
(
a
,
b
)
{
return
a
+
b
;
},
0
));
break
;
case
'
min
'
:
aggregatedVals
.
push
(
vals
.
reduce
(
function
(
a
,
b
)
{
return
Math
.
min
(
a
,
b
);
}));
break
;
case
'
max
'
:
aggregatedVals
.
push
(
vals
.
reduce
(
function
(
a
,
b
)
{
return
Math
.
max
(
a
,
b
);
}));
break
;
default
:
aggregatedVals
.
push
(
vals
.
reduce
(
function
(
a
,
b
)
{
return
a
+
b
/
vals
.
length
;
},
0
));
}
vals
=
[];
// clear the daily value vector
vals
.
push
(
jsonData
[
d
].
temperature
);
// now push first entry of new day into my temp value vector.
cnt
++
;
}
oldDate
=
currentDate
;
}
// end of for loop
// create output to be in the same List format as the original data from obsArray.
for
(
let
i
=
0
;
i
<
aggregatedVals
.
length
;
i
++
)
{
newOutput
.
push
([
aggDates
[
i
],
aggregatedVals
[
i
]]);
}
}
// end else
return
newOutput
;
}
/**
/**
* Format the response from SensorThings API to make it suitable for heatmap
* Format the response from SensorThings API to make it suitable for heatmap
* @param {Array} obsArray Response from SensorThings API as array
* @param {Array} obsArray Response from SensorThings API as array
* @returns {Array} Array of formatted observations suitable for use in a heatmap
* @returns {Array} Array of formatted observations suitable for use in a heatmap
*/
*/
export
const
formatSTAResponseForHeatMap
=
function
(
obsArray
)
{
export
const
formatSTAResponseForHeatMap
=
function
(
obsArray
)
{
if
(
!
obsArray
)
return
;
if
(
!
obsArray
)
return
;
const
dataSTAFormatted
=
[];
const
dataSTAFormatted
=
[];
obsArray
.
forEach
((
obs
)
=>
{
obsArray
.
forEach
((
obs
)
=>
{
// Get the date/time string; first element in input array; remove trailing "Z"
// Get the date/time string; first element in input array; remove trailing "Z"
const
obsDateTimeInput
=
obs
[
0
].
slice
(
0
,
-
1
);
const
obsDateTimeInput
=
obs
[
0
].
slice
(
0
,
-
1
);
// Get the "date" part of an observation
// Get the "date" part of an observation
const
obsDateInput
=
obs
[
0
].
slice
(
0
,
10
);
const
obsDateInput
=
obs
[
0
].
slice
(
0
,
10
);
// Create Date objects
// Create Date objects
const
obsDateTime
=
new
Date
(
obsDateTimeInput
);
const
obsDateTime
=
new
Date
(
obsDateTimeInput
);
const
obsDate
=
new
Date
(
obsDateInput
);
const
obsDate
=
new
Date
(
obsDateInput
);
// x-axis -> timestamp; will be the same for observations from the same date
// x-axis -> timestamp; will be the same for observations from the same date
const
timestamp
=
Date
.
parse
(
obsDate
);
const
timestamp
=
Date
.
parse
(
obsDate
);
// y-axis -> hourOfDay
// y-axis -> hourOfDay
const
hourOfDay
=
obsDateTime
.
getHours
();
const
hourOfDay
=
obsDateTime
.
getHours
();
// value -> the observation's value; second element in input array
// value -> the observation's value; second element in input array
const
value
=
obs
[
1
];
const
value
=
obs
[
1
];
dataSTAFormatted
.
push
([
timestamp
,
hourOfDay
,
value
]);
dataSTAFormatted
.
push
([
timestamp
,
hourOfDay
,
value
]);
});
});
return
dataSTAFormatted
;
return
dataSTAFormatted
;
};
};
/**
/**
...
@@ -151,94 +338,91 @@ export const formatSTAResponseForHeatMap = function (obsArray) {
...
@@ -151,94 +338,91 @@ export const formatSTAResponseForHeatMap = function (obsArray) {
* @param {Array} formattedObsArrayForHeatmap Response from SensorThings API formatted for use in a heatmap
* @param {Array} formattedObsArrayForHeatmap Response from SensorThings API formatted for use in a heatmap
* @returns {Object} Highcharts library heatmap object
* @returns {Object} Highcharts library heatmap object
*/
*/
export
const
drawHeatMapHC
=
function
(
formattedObsArrayForHeatmap
)
{
export
const
drawHeatMapHC
=
function
(
formattedObsArrayForHeatmap
)
{
Highcharts
.
chart
(
"
chart-heatmap
"
,
{
Highcharts
.
chart
(
"
chart-heatmap
"
,
{
chart
:
{
chart
:
{
type
:
"
heatmap
"
,
type
:
"
heatmap
"
,
zoomType
:
"
x
"
,
zoomType
:
"
x
"
,
},
},
boost
:
{
boost
:
{
useGPUTranslations
:
true
,
useGPUTranslations
:
true
,
},
},
title
:
{
title
:
{
text
:
"
Inlet flow (Vorlauf)
"
,
text
:
"
Inlet flow (Vorlauf)
"
,
align
:
"
left
"
,
align
:
"
left
"
,
x
:
40
,
x
:
40
,
},
},
subtitle
:
{
subtitle
:
{
text
:
"
Temperature variation by day and hour in 2020
"
,
text
:
"
Temperature variation by day and hour in 2020
"
,
align
:
"
left
"
,
align
:
"
left
"
,
x
:
40
,
x
:
40
,
},
},
xAxis
:
{
xAxis
:
{
type
:
"
datetime
"
,
type
:
"
datetime
"
,
// min: Date.UTC(2017, 0, 1),
// min: Date.UTC(2017, 0, 1),
// max: Date.UTC(2017, 11, 31, 23, 59, 59),
// max: Date.UTC(2017, 11, 31, 23, 59, 59),
labels
:
{
labels
:
{
align
:
"
left
"
,
align
:
"
left
"
,
x
:
5
,
x
:
5
,
y
:
14
,
y
:
14
,
format
:
"
{value:%B}
"
,
// long month
format
:
"
{value:%B}
"
,
// long month
},
},
showLastLabel
:
false
,
showLastLabel
:
false
,
tickLength
:
16
,
tickLength
:
16
,
},
},
yAxis
:
{
yAxis
:
{
title
:
{
title
:
{
text
:
null
,
text
:
null
,
},
},
labels
:
{
labels
:
{
format
:
"
{value}:00
"
,
format
:
"
{value}:00
"
,
},
},
minPadding
:
0
,
minPadding
:
0
,
maxPadding
:
0
,
maxPadding
:
0
,
startOnTick
:
false
,
startOnTick
:
false
,
endOnTick
:
false
,
endOnTick
:
false
,
// tickPositions: [0, 6, 12, 18, 24],
// tickPositions: [0, 6, 12, 18, 24],
tickPositions
:
[
0
,
3
,
6
,
9
,
12
,
15
,
18
,
21
,
24
],
tickPositions
:
[
0
,
3
,
6
,
9
,
12
,
15
,
18
,
21
,
24
],
tickWidth
:
1
,
tickWidth
:
1
,
min
:
0
,
min
:
0
,
max
:
23
,
max
:
23
,
reversed
:
true
,
reversed
:
true
,
},
colorAxis
:
{
stops
:
[
[
0
,
"
#3060cf
"
],
[
0.5
,
"
#fffbbc
"
],
[
0.9
,
"
#c4463a
"
],
[
1
,
"
#c4463a
"
],
],
min
:
60
,
max
:
85
,
startOnTick
:
false
,
endOnTick
:
false
,
labels
:
{
format
:
"
{value}℃
"
,
},
},
series
:
[
{
data
:
formattedObsArrayForHeatmap
,
boostThreshold
:
100
,
borderWidth
:
0
,
nullColor
:
"
#525252
"
,
colsize
:
24
*
36
e5
,
// one day
tooltip
:
{
headerFormat
:
"
Temperature<br/>
"
,
pointFormat
:
"
{point.x:%e %b, %Y} {point.y}:00: <b>{point.value} ℃</b>
"
,
},
},
turboThreshold
:
Number
.
MAX_VALUE
,
// #3404, remove after 4.0.5 release
},
colorAxis
:
{
],
stops
:
[
});
[
0
,
"
#3060cf
"
],
[
0.5
,
"
#fffbbc
"
],
[
0.9
,
"
#c4463a
"
],
[
1
,
"
#c4463a
"
],
],
min
:
60
,
max
:
85
,
startOnTick
:
false
,
endOnTick
:
false
,
labels
:
{
format
:
"
{value}℃
"
,
},
},
series
:
[{
data
:
formattedObsArrayForHeatmap
,
boostThreshold
:
100
,
borderWidth
:
0
,
nullColor
:
"
#525252
"
,
colsize
:
24
*
36
e5
,
// one day
tooltip
:
{
headerFormat
:
"
Temperature<br/>
"
,
pointFormat
:
"
{point.x:%e %b, %Y} {point.y}:00: <b>{point.value} ℃</b>
"
,
},
turboThreshold
:
Number
.
MAX_VALUE
,
// #3404, remove after 4.0.5 release
},
],
});
};
};
/**
/**
...
@@ -246,15 +430,15 @@ export const drawHeatMapHC = function (formattedObsArrayForHeatmap) {
...
@@ -246,15 +430,15 @@ export const drawHeatMapHC = function (formattedObsArrayForHeatmap) {
* @param {Array} obsArray Response from SensorThings API as array
* @param {Array} obsArray Response from SensorThings API as array
* @returns {Array} Array of formatted observations suitable for use in a line chart
* @returns {Array} Array of formatted observations suitable for use in a line chart
*/
*/
export
const
formatSTAResponseForLineChart
=
function
(
obsArray
)
{
export
const
formatSTAResponseForLineChart
=
function
(
obsArray
)
{
if
(
!
obsArray
)
return
;
if
(
!
obsArray
)
return
;
const
dataSTAFormatted
=
[];
const
dataSTAFormatted
=
[];
obsArray
.
forEach
((
result
)
=>
{
obsArray
.
forEach
((
result
)
=>
{
const
timestampObs
=
new
Date
(
result
[
0
].
slice
(
0
,
-
1
)).
getTime
();
// slice() removes trailing "Z" character in timestamp
const
timestampObs
=
new
Date
(
result
[
0
].
slice
(
0
,
-
1
)).
getTime
();
// slice() removes trailing "Z" character in timestamp
const
valueObs
=
result
[
1
];
const
valueObs
=
result
[
1
];
dataSTAFormatted
.
push
([
timestampObs
,
valueObs
]);
dataSTAFormatted
.
push
([
timestampObs
,
valueObs
]);
});
});
return
dataSTAFormatted
;
return
dataSTAFormatted
;
};
};
/**
/**
...
@@ -262,38 +446,36 @@ export const formatSTAResponseForLineChart = function (obsArray) {
...
@@ -262,38 +446,36 @@ export const formatSTAResponseForLineChart = function (obsArray) {
* @param {Array} formattedObsArrayForLineChart - Response from SensorThings API formatted for use in a line chart
* @param {Array} formattedObsArrayForLineChart - Response from SensorThings API formatted for use in a line chart
* @returns {Object} Highcharts library line chart object
* @returns {Object} Highcharts library line chart object
*/
*/
export
const
drawLineChartHC
=
function
(
formattedObsArrayForLineChart
)
{
export
const
drawLineChartHC
=
function
(
formattedObsArrayForLineChart
)
{
// Create the chart
// Create the chart
Highcharts
.
stockChart
(
"
chart-line
"
,
{
Highcharts
.
stockChart
(
"
chart-line
"
,
{
chart
:
{
chart
:
{
zoomType
:
"
x
"
,
zoomType
:
"
x
"
,
},
},
rangeSelector
:
{
rangeSelector
:
{
selected
:
1
,
selected
:
1
,
},
title
:
{
text
:
"
Inlet flow (Vorlauf)
"
,
"
align
"
:
"
left
"
,
},
subtitle
:
{
text
:
"
Temperature variation by hour in 2020
"
,
align
:
"
left
"
,
},
series
:
[
{
name
:
"
AAPL
"
,
data
:
formattedObsArrayForLineChart
,
tooltip
:
{
valueDecimals
:
2
,
},
},
turboThreshold
:
Number
.
MAX_VALUE
,
// #3404, remove after 4.0.5 release
},
title
:
{
],
text
:
"
Inlet flow (Vorlauf)
"
,
});
"
align
"
:
"
left
"
,
},
subtitle
:
{
text
:
"
Temperature variation by hour in 2020
"
,
align
:
"
left
"
,
},
series
:
[{
name
:
"
AAPL
"
,
data
:
formattedObsArrayForLineChart
,
tooltip
:
{
valueDecimals
:
2
,
},
turboThreshold
:
Number
.
MAX_VALUE
,
// #3404, remove after 4.0.5 release
},
],
});
};
};
/**
/**
...
@@ -303,26 +485,26 @@ export const drawLineChartHC = function (formattedObsArrayForLineChart) {
...
@@ -303,26 +485,26 @@ export const drawLineChartHC = function (formattedObsArrayForLineChart) {
* @param {Object} responsePromise Promise object
* @param {Object} responsePromise Promise object
* @returns {Object} - Object containing results from all the "@iot.nextLink" links
* @returns {Object} - Object containing results from all the "@iot.nextLink" links
*/
*/
export
const
followNextLink
=
function
(
responsePromise
)
{
export
const
followNextLink
=
function
(
responsePromise
)
{
if
(
!
responsePromise
)
return
;
if
(
!
responsePromise
)
return
;
return
responsePromise
return
responsePromise
.
then
(
function
(
lastSuccess
)
{
.
then
(
function
(
lastSuccess
)
{
if
(
lastSuccess
.
data
[
"
@iot.nextLink
"
])
{
if
(
lastSuccess
.
data
[
"
@iot.nextLink
"
])
{
return
followNextLink
(
return
followNextLink
(
axios
.
get
(
lastSuccess
.
data
[
"
@iot.nextLink
"
])
axios
.
get
(
lastSuccess
.
data
[
"
@iot.nextLink
"
])
).
then
(
function
(
nextLinkSuccess
)
{
).
then
(
function
(
nextLinkSuccess
)
{
nextLinkSuccess
.
data
.
value
=
lastSuccess
.
data
.
value
.
concat
(
nextLinkSuccess
.
data
.
value
=
lastSuccess
.
data
.
value
.
concat
(
nextLinkSuccess
.
data
.
value
nextLinkSuccess
.
data
.
value
);
);
return
nextLinkSuccess
;
return
nextLinkSuccess
;
});
}
else
{
return
lastSuccess
;
}
})
.
catch
(
function
(
err
)
{
console
.
log
(
err
);
});
});
}
else
{
return
lastSuccess
;
}
})
.
catch
(
function
(
err
)
{
console
.
log
(
err
);
});
};
};
// Get "ALL" the Observations that satisfy our query
// Get "ALL" the Observations that satisfy our query
...
@@ -352,4 +534,4 @@ export const followNextLink = function (responsePromise) {
...
@@ -352,4 +534,4 @@ export const followNextLink = function (responsePromise) {
// .then((observationArr) => {
// .then((observationArr) => {
// drawHeatMapHC(observationArr);
// drawHeatMapHC(observationArr);
// drawLineChartHC(observationArr);
// drawLineChartHC(observationArr);
// });
// });
\ No newline at end of file
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment