Compare commits
1 Commits
main
...
refactor-t
Author | SHA1 | Date |
---|---|---|
![]() |
479feba6c2 |
|
@ -23,7 +23,6 @@
|
|||
*.ipr
|
||||
.idea/
|
||||
|
||||
|
||||
# eclipse project file
|
||||
.settings/
|
||||
.classpath
|
||||
|
@ -66,8 +65,3 @@ env3.*/
|
|||
# duckdb
|
||||
*.duckdb
|
||||
|
||||
# cache
|
||||
*.obj
|
||||
|
||||
/src/mauro/dok/
|
||||
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
# Consultancy 2
|
||||
|
||||
## Projektstruktur
|
||||
- etl: Enthält den Programmcode, welcher die Daten aufbereitet und via REST-API zur Verfügung stellt.
|
||||
- dashboard: Webapplikation zur Exploration und Visualisierung der Daten.
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
# Install
|
||||
## Prerequisites
|
||||
- In order to run this project please install all required software according to the laravel documentation: https://laravel.com/docs/11.x#installing-php
|
||||
|
||||
## Configuration & installation
|
||||
- Make a copy of the .env.example to .env
|
||||
- Run the following commands:
|
||||
```bash
|
||||
composer install && php artisan key:generate && npm i
|
||||
```
|
||||
|
||||
# Run server
|
||||
```bash
|
||||
composer run dev
|
||||
```
|
||||
|
|
@ -1,109 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
|
||||
class Api
|
||||
{
|
||||
|
||||
public static function get(string $path, string $query = ''): ?array
|
||||
{
|
||||
|
||||
$endpoint = env('FASTAPI_URI');
|
||||
$request = $endpoint.$path;
|
||||
|
||||
if (Cache::has($request)) {
|
||||
// return Cache::get($request);
|
||||
}
|
||||
|
||||
$get = Http::timeout(1600)->get($request);
|
||||
|
||||
if($get->successful()){
|
||||
$result = $get->json();
|
||||
Cache::put($request, $result);
|
||||
return $result;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static function propertiesPerRegion()
|
||||
{
|
||||
return self::get('/region/properties');
|
||||
}
|
||||
|
||||
public static function propertiesGrowth()
|
||||
{
|
||||
return self::get('/properties/growth');
|
||||
}
|
||||
|
||||
public static function propertiesGeo()
|
||||
{
|
||||
return self::get('/properties/geo');
|
||||
}
|
||||
|
||||
public static function propertyExtractions(int $id)
|
||||
{
|
||||
return self::get("/property/{$id}/extractions");
|
||||
}
|
||||
|
||||
public static function propertyCapacities(int $id)
|
||||
{
|
||||
return self::get("/property/{$id}/capacities");
|
||||
}
|
||||
|
||||
public static function propertyBase(int $id): mixed
|
||||
{
|
||||
return self::get("/property/{$id}/base");
|
||||
}
|
||||
|
||||
public static function regionBase(int $id): mixed
|
||||
{
|
||||
return self::get("/region/{$id}/base");
|
||||
}
|
||||
|
||||
public static function regionPropertiesCapacities(int $id): mixed
|
||||
{
|
||||
return self::get("/region/{$id}/properties/capacities");
|
||||
}
|
||||
|
||||
public static function regionCapacitiesMonthly(int $id, string $date): mixed
|
||||
{
|
||||
return self::get("/region/{$id}/capacities/monthly/{$date}");
|
||||
}
|
||||
|
||||
public static function propertyCapacitiesMonthly(int $id, string $date): mixed
|
||||
{
|
||||
return self::get("/property/{$id}/capacities/monthly/{$date}");
|
||||
}
|
||||
|
||||
public static function regionCapacitiesDaily(int $id, string $date): mixed
|
||||
{
|
||||
return self::get("/region/{$id}/capacities/weekdays/{$date}");
|
||||
}
|
||||
|
||||
public static function propertyCapacitiesDaily(int $id, string $date): mixed
|
||||
{
|
||||
return self::get("/property/{$id}/capacities/weekdays/{$date}");
|
||||
}
|
||||
|
||||
public static function propertyNeighbours(int $id): mixed
|
||||
{
|
||||
return self::get("/property/{$id}/neighbours");
|
||||
}
|
||||
|
||||
public static function regionCapacities(int $id): mixed
|
||||
{
|
||||
return self::get("/region/{$id}/capacities");
|
||||
}
|
||||
|
||||
public static function regionMovingAverage(int $id, string $date): mixed
|
||||
{
|
||||
return self::get("/region/{$id}/movingAverage/{$date}");
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
class Chart
|
||||
{
|
||||
public static function colors(int $count = 5){
|
||||
$colors = ['#9ebcda','#8c96c6','#88419d','#810f7c','#4d004b'];
|
||||
return json_encode($colors);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,287 +0,0 @@
|
|||
/* 1. Use a more-intuitive box-sizing model */
|
||||
|
||||
|
||||
*, *::before, *::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* 2. Remove default margin */
|
||||
* {
|
||||
margin: 0;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
body {
|
||||
/* 3. Add accessible line-height */
|
||||
line-height: 1.5;
|
||||
/* 4. Improve text rendering */
|
||||
-webkit-font-smoothing: antialiased;
|
||||
padding: 0 1em;
|
||||
height: 100vh;
|
||||
background-image: radial-gradient(73% 147%, #EADFDF 59%, #ECE2DF 100%), radial-gradient(91% 146%, rgba(255,255,255,0.50) 47%, rgba(0,0,0,0.50) 100%);
|
||||
background-blend-mode: screen;
|
||||
}
|
||||
|
||||
/* 5. Improve media defaults */
|
||||
img, picture, video, canvas, svg {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
/* 6. Inherit fonts for form controls */
|
||||
input, button, textarea, select {
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
/* 7. Avoid text overflows */
|
||||
p, h1, h2, h3, h4, h5, h6 {
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
/* 8. Improve line wrapping */
|
||||
p {
|
||||
text-wrap: pretty;
|
||||
}
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
text-wrap: balance;
|
||||
}
|
||||
|
||||
dt{
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
dd + dt{
|
||||
margin-top: .2em;
|
||||
}
|
||||
|
||||
nav + button,
|
||||
span + button{
|
||||
margin-left: .5em;
|
||||
}
|
||||
|
||||
ul{
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
p + ul{
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
button[popovertarget]{
|
||||
background: no-repeat center / .3em #4d004b url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 192 512'%3E%3C!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--%3E%3Cpath fill='%23fff' d='M48 80a48 48 0 1 1 96 0A48 48 0 1 1 48 80zM0 224c0-17.7 14.3-32 32-32l64 0c17.7 0 32 14.3 32 32l0 224 32 0c17.7 0 32 14.3 32 32s-14.3 32-32 32L32 512c-17.7 0-32-14.3-32-32s14.3-32 32-32l32 0 0-192-32 0c-17.7 0-32-14.3-32-32z'/%3E%3C/svg%3E%0A");
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
width: 1.5em;
|
||||
height: 1.5em;
|
||||
border-radius: 50%;
|
||||
border: 1px solid #fff;
|
||||
}
|
||||
|
||||
button[popovertarget]::before{
|
||||
color: #fff;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
button[popovertarget]>span{
|
||||
position: absolute;
|
||||
left: -999em;
|
||||
top: -999em;
|
||||
}
|
||||
|
||||
[popover] {
|
||||
border: none;
|
||||
border-radius: 1em;
|
||||
background: #fff;
|
||||
padding: 1.5em;
|
||||
border-radius: var(--small-border);
|
||||
box-shadow: .0625em .0625em .625em rgba(0, 0, 0, 0.1);
|
||||
max-width: 40em;
|
||||
top: 4em;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
[popover]::backdrop{
|
||||
background-color: rgba(0,0,0,.5);
|
||||
}
|
||||
|
||||
[popover] h2{
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
9. Create a root stacking context
|
||||
*/
|
||||
#root, #__next {
|
||||
isolation: isolate;
|
||||
}
|
||||
|
||||
body>header{
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 3em;
|
||||
background: #ccc;
|
||||
z-index: 99;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 1em;
|
||||
}
|
||||
|
||||
body>header>nav{
|
||||
text-align: center;
|
||||
min-width: 10em;
|
||||
background: #fff;
|
||||
border-radius: .2em;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
body>header>nav>ul{
|
||||
position: absolute;
|
||||
background: #fff;
|
||||
width: 100%;
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
top: -999em;
|
||||
left: -999em;
|
||||
}
|
||||
|
||||
body>header>nav:hover ul{
|
||||
top: initial;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
body>header>nav>ul>li a,
|
||||
body>header>nav>strong{
|
||||
display: inline-block;
|
||||
padding: .2em .4em;
|
||||
}
|
||||
|
||||
a{
|
||||
color: #000;
|
||||
}
|
||||
|
||||
a:hover,
|
||||
a:focus{
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
|
||||
main{
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
padding: 4em 0 1em;
|
||||
display: grid;
|
||||
gap: .5em;
|
||||
}
|
||||
|
||||
body.overview main{
|
||||
grid-template-columns: repeat(8, minmax(1%, 50%));
|
||||
grid-template-rows: repeat(4, 1fr);
|
||||
grid-template-areas:
|
||||
"chart3 chart3 chart3 chart1 chart1 chart1 chart4 chart4"
|
||||
"chart3 chart3 chart3 chart1 chart1 chart1 chart4 chart4"
|
||||
"chart3 chart3 chart3 chart2 chart2 chart2 chart4 chart4"
|
||||
"chart3 chart3 chart3 chart2 chart2 chart2 chart4 chart4"
|
||||
}
|
||||
|
||||
body.region main{
|
||||
grid-template-columns: repeat(4, minmax(10%, 50%));
|
||||
grid-template-rows: repeat(6, 1fr) 4em;
|
||||
grid-template-areas:
|
||||
"chart1 chart1 chart2 chart2"
|
||||
"chart1 chart1 chart2 chart2"
|
||||
"chart1 chart1 chart3 chart4"
|
||||
"chart1 chart1 chart3 chart4"
|
||||
"chart1 chart1 chart6 chart6"
|
||||
"chart1 chart1 chart6 chart6"
|
||||
"chart1 chart1 timeline timeline";
|
||||
}
|
||||
|
||||
body.property main{
|
||||
grid-template-columns: repeat(4, minmax(10%, 50%));
|
||||
grid-template-rows: repeat(4, 1fr) 4em;
|
||||
grid-template-areas:
|
||||
"chart2 chart2 chart1 chart1"
|
||||
"chart2 chart2 chart1 chart1"
|
||||
"chart5 chart5 chart3 chart4"
|
||||
"chart5 chart5 chart3 chart4"
|
||||
"chart5 chart5 timeline timeline";
|
||||
}
|
||||
|
||||
article{
|
||||
background: #f9f9f9;
|
||||
border: .0625em solid #ccc;
|
||||
box-shadow: 0 5px 10px rgba(154,160,185,.05), 0 15px 40px rgba(166,173,201,.2);
|
||||
border-radius: .2em;
|
||||
display: grid;
|
||||
}
|
||||
|
||||
article.header{
|
||||
grid-template-columns: 100%;
|
||||
grid-template-rows: minmax(1%, 2em) 1fr;
|
||||
padding: .5em 1em 1em .5em;
|
||||
}
|
||||
|
||||
article.map{
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
article.map>header{
|
||||
padding: .5em 1em 1em .5em;
|
||||
}
|
||||
|
||||
article>header{
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1em;
|
||||
grid-template-rows: 1fr;
|
||||
}
|
||||
|
||||
article>header>h2{
|
||||
font-size: .8em;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
@media(max-width: 960px){
|
||||
|
||||
body{
|
||||
height: auto;
|
||||
}
|
||||
|
||||
main{
|
||||
height: auto;
|
||||
grid-template-columns: 100%;
|
||||
grid-template-rows: repeat(4, minmax(20em, 25em));
|
||||
}
|
||||
}
|
||||
|
||||
.leaflet-marker-icon span{
|
||||
background: #4d004b;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
display: block;
|
||||
left: -1rem;
|
||||
top: -1rem;
|
||||
position: relative;
|
||||
border-radius: 50% 50% 0;
|
||||
transform: rotate(45deg);
|
||||
border: 2px solid #fff
|
||||
}
|
||||
|
||||
/*['#9ecae1','#6baed6','#4292c6','#2171b5','#084594'*/
|
||||
.leaflet-marker-icon.region1 span{
|
||||
background: #8c96c6;
|
||||
}
|
||||
|
||||
.leaflet-marker-icon.region2 span{
|
||||
background: #88419d;
|
||||
}
|
||||
|
||||
.leaflet-marker-icon.region3 span{
|
||||
background: #810f7c;
|
||||
}
|
||||
|
||||
.leaflet-marker-icon.region4 span{
|
||||
background: #4d004b;
|
||||
}
|
File diff suppressed because one or more lines are too long
|
@ -1,4 +0,0 @@
|
|||
import * as echarts from 'echarts';
|
||||
import 'leaflet'
|
||||
|
||||
window.echarts = echarts;
|
|
@ -1,17 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Dashboard</title>
|
||||
@vite(['resources/css/app.css', 'resources/js/app.js', 'node_modules/leaflet/dist/leaflet.css'])
|
||||
</head>
|
||||
<body class="@yield('body-class')">
|
||||
<header>
|
||||
@yield('header')
|
||||
</header>
|
||||
<main>
|
||||
@yield('main')
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
|
@ -1,329 +0,0 @@
|
|||
@extends('base')
|
||||
@section('body-class', 'overview')
|
||||
@section('header')
|
||||
<nav>
|
||||
<strong>Start</strong>
|
||||
<ul>
|
||||
@foreach($regions as $r)
|
||||
<li><a href="/region/{{ $r['region_id'] }}">{{ $r['region_name'] }}</a></li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</nav>
|
||||
@endsection
|
||||
@section('main')
|
||||
<article class="header" style="grid-area: chart3;">
|
||||
<header>
|
||||
<h2>Auslastung aller Mietobjekte über Gesamte Zeit</h2>
|
||||
<button popovertarget="pop1">
|
||||
<span>Erklärungen zum Diagramm</span>
|
||||
</button>
|
||||
<div popover id="pop1">
|
||||
<h2>Auslastung aller Mietobjekte über Gesamte Zeit</h2>
|
||||
<p>
|
||||
Das Diagramm gibt eine Übersicht, wie die Auslastung von Mietobjekten am Datum des Scrapings waren. Dazu wird für jedes Mietobjekt die durchschnittliche Verfügbarkeit ermittelt.
|
||||
</p>
|
||||
<ul>
|
||||
<li>X-Achse: Zeitpunkt Scraping.</li>
|
||||
<li>Y-Achse: Mietobjekte.</li>
|
||||
<li>Kategorien: 0% = Das Mietobjekt ist komplett verfügbar; 100% = Das Mietobjekt ist komplett ausgebucht.</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
</header>
|
||||
<div id="chart-heatmap"></div>
|
||||
</article>
|
||||
<article class="header" style="grid-area: chart1;">
|
||||
<header>
|
||||
<h2>
|
||||
Anzahl jemals gefundene Kurzzeitmietobjekte pro Region
|
||||
</h2>
|
||||
<button popovertarget="pop2">
|
||||
<span>Erklärungen zum Diagramm</span>
|
||||
</button>
|
||||
<div popover id="pop2">
|
||||
<h2>Anzahl jemals gefundene Kurzzeitmietobjekte pro Region</h2>
|
||||
<p>
|
||||
Das Balkendiagramm zeigt wieviele Kurzzeitmietobjekte insgesamt pro Region über den gesamten Datenerhebungszeitraum, gefunden wurden.
|
||||
</p>
|
||||
<ul>
|
||||
<li>X-Achse: Bezeichnung der Region.</li>
|
||||
<li>Y-Achse: Anzahl Mietobjekte.</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
</header>
|
||||
<div id="chart-props-per-region"></div>
|
||||
</article>
|
||||
<article class="header" style="grid-area: chart2;">
|
||||
<header>
|
||||
<h2>
|
||||
Entwicklung der Anzahl jemals gefunden Kurzzeitmietobjekte
|
||||
</h2>
|
||||
<button popovertarget="pop3">
|
||||
<span>Erklärungen zum Diagramm</span>
|
||||
</button>
|
||||
<div popover id="pop3">
|
||||
<h2>Entwicklung Anzahl jemals gefundener Kurzzeitmietobjekte pro Region</h2>
|
||||
<p>
|
||||
Das Liniendiagramm zeigt die Entwicklung der gefundenen Mietobjekte pro Region.
|
||||
</p>
|
||||
<ul>
|
||||
<li>X-Achse: Zeitpunkt Scraping.</li>
|
||||
<li>Y-Achse: Anzahl Mietobjekte.</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
</header>
|
||||
<div id="extractions"></div>
|
||||
</article>
|
||||
<article style="grid-area: chart4;">
|
||||
<div id="leaflet"></div>
|
||||
</article>
|
||||
<script type="module">
|
||||
const sharedOptions = {
|
||||
basic: {
|
||||
color: {!! $chartOptions['colors'] !!},
|
||||
grid: {
|
||||
top: 30,
|
||||
left: 70,
|
||||
right: 0,
|
||||
bottom: 45
|
||||
},
|
||||
name: (opt) => {
|
||||
return {
|
||||
name: opt.name,
|
||||
nameLocation: opt.location,
|
||||
nameGap: 50,
|
||||
nameTextStyle: {
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const extractionDates = {!! json_encode($regionPropertiesCapacities['scrapeDates']) !!};
|
||||
|
||||
const chartHeatmap = document.getElementById('chart-heatmap');
|
||||
const cHeatmap = echarts.init(chartHeatmap);
|
||||
const cHeatmapOptions = {
|
||||
animation: false,
|
||||
tooltip: {
|
||||
position: 'top'
|
||||
},
|
||||
grid: {
|
||||
top: 30,
|
||||
right: 45,
|
||||
bottom: 50,
|
||||
left: 5
|
||||
},
|
||||
dataZoom: [{
|
||||
type: 'slider'
|
||||
},
|
||||
{
|
||||
type: 'slider',
|
||||
show: true,
|
||||
yAxisIndex: 0,
|
||||
}],
|
||||
xAxis: {
|
||||
show: false,
|
||||
name: 'Kurzzeitmietobjekt',
|
||||
type: 'category',
|
||||
data: extractionDates,
|
||||
splitArea: {
|
||||
show: false
|
||||
},
|
||||
axisLabel: {
|
||||
show: true,
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
show: false,
|
||||
type: 'category',
|
||||
data: {!! json_encode($regionPropertiesCapacities['property_ids']) !!},
|
||||
splitArea: {
|
||||
show: true
|
||||
}
|
||||
},
|
||||
visualMap: {
|
||||
type: 'piecewise',
|
||||
min: 0,
|
||||
max: 100,
|
||||
calculable: true,
|
||||
orient: 'horizontal',
|
||||
left: 'center',
|
||||
top: 0,
|
||||
formatter: (v1, v2) => {
|
||||
return `${v1} – ${v2} %`;
|
||||
},
|
||||
inRange: {
|
||||
color: sharedOptions.basic.color,
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: 'Auslastung',
|
||||
type: 'heatmap',
|
||||
blurSize: 0,
|
||||
data: {!! json_encode($regionPropertiesCapacities['values']) !!},
|
||||
label: {
|
||||
show: false
|
||||
},
|
||||
tooltip: {
|
||||
formatter: (data) => {
|
||||
return `Kurzzeitmietobjekte-ID: ${data.data[1]}<br />Datum Scraping: ${data.data[0]}<br/>Auslastung: ${data.data[2].toFixed(2)} %`
|
||||
},
|
||||
},
|
||||
emphasis: {
|
||||
itemStyle: {
|
||||
borderColor: '#000',
|
||||
borderWidth: 2
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
cHeatmap.setOption(cHeatmapOptions);
|
||||
|
||||
const chartPropsPerRegion = document.getElementById('chart-props-per-region');
|
||||
const cPropsPerRegion = echarts.init(chartPropsPerRegion);
|
||||
const cPropsPerRegionOptions = {
|
||||
grid: sharedOptions.basic.grid,
|
||||
color: sharedOptions.basic.color,
|
||||
xAxis: {
|
||||
name: 'Region',
|
||||
nameLocation: 'center',
|
||||
nameGap: 30,
|
||||
nameTextStyle: {
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
type: 'category',
|
||||
data: {!! $propsPerRegion[1] !!}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
name: 'Anzahl Mietobjekte',
|
||||
nameLocation: 'middle',
|
||||
nameGap: 50,
|
||||
nameTextStyle: {
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
data: {!! $propsPerRegion[2] !!},
|
||||
type: 'bar',
|
||||
itemStyle: {
|
||||
color: (e) => {
|
||||
return sharedOptions.basic.color[e.dataIndex];
|
||||
}
|
||||
}
|
||||
},
|
||||
]
|
||||
};
|
||||
|
||||
cPropsPerRegion.setOption(cPropsPerRegionOptions);
|
||||
|
||||
const chartExtractions = document.getElementById('extractions');
|
||||
const cExtractions = echarts.init(chartExtractions);
|
||||
|
||||
const filters = {
|
||||
regions: ["Alle", "Davos", "Engadin", "Heidiland", "St. Moritz"]
|
||||
}
|
||||
|
||||
const cExtractionsOptions = {
|
||||
color: sharedOptions.basic.color,
|
||||
tooltip: {
|
||||
trigger: 'axis'
|
||||
},
|
||||
legend: {
|
||||
data: filters.regions
|
||||
},
|
||||
grid: sharedOptions.basic.grid,
|
||||
xAxis: {
|
||||
name: 'Zeitpunkt Scraping',
|
||||
nameLocation: 'center',
|
||||
nameGap: 24,
|
||||
nameTextStyle: {
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: extractionDates
|
||||
},
|
||||
yAxis: {
|
||||
name: 'Anzahl Mietobjekte',
|
||||
nameLocation: 'center',
|
||||
nameGap: 50,
|
||||
nameTextStyle: {
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
type: 'value'
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: 'Alle',
|
||||
type: 'line',
|
||||
stack: 'Total',
|
||||
data: {!! json_encode($growth['total_all']) !!},
|
||||
},
|
||||
{
|
||||
name: 'Davos',
|
||||
type: 'line',
|
||||
data: {!! json_encode($growth['total_davos']) !!}
|
||||
},
|
||||
{
|
||||
name: 'Engadin',
|
||||
type: 'line',
|
||||
data: {!! json_encode($growth['total_engadin']) !!}
|
||||
},
|
||||
{
|
||||
name: 'Heidiland',
|
||||
type: 'line',
|
||||
data: {!! json_encode($growth['total_heidiland']) !!}
|
||||
},
|
||||
{
|
||||
name: 'St. Moritz',
|
||||
type: 'line',
|
||||
data: {!! json_encode($growth['total_stmoritz']) !!}
|
||||
},
|
||||
]
|
||||
};
|
||||
|
||||
cExtractions.setOption(cExtractionsOptions);
|
||||
|
||||
const map = L.map('leaflet');
|
||||
|
||||
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||
maxZoom: 19,
|
||||
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
|
||||
}).addTo(map);
|
||||
|
||||
function icon(id){
|
||||
return L.divIcon({
|
||||
className: "region"+id,
|
||||
html: '<span></span>'
|
||||
})
|
||||
}
|
||||
|
||||
const markers = L.featureGroup([
|
||||
@foreach($geo as $g)
|
||||
L.marker([{{ $g['latlng'] }}], {icon: icon({{ $g['region_id'] }})}).bindPopup('<a href="/property/{{ $g['property_id'] }}">{{ $g['latlng'] }}</a>'),
|
||||
@endforeach
|
||||
]).addTo(map);
|
||||
|
||||
map.fitBounds(markers.getBounds(), {padding: [20,20]})
|
||||
|
||||
cHeatmap.on('click', 'series', (e) => {
|
||||
window.open(`/property/${e.value[1]}?date=${e.value[0]}`, '_self');
|
||||
})
|
||||
|
||||
cPropsPerRegion.on('click', 'series', (e) => {
|
||||
console.log(e.dataIndex);
|
||||
//window.open(`/property/${e.value[1]}?date=${e.value[0]}`, '_self');
|
||||
})
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
@endsection
|
|
@ -1,454 +0,0 @@
|
|||
@extends('base')
|
||||
@section('body-class', 'property')
|
||||
@section('header')
|
||||
<nav>
|
||||
<strong>Property: {{ $base['check_data'] }}</strong>
|
||||
<ul>
|
||||
<li><a href="/">Start</a></li>
|
||||
@foreach($regions as $r)
|
||||
<li><a href="/region/{{ $r['region_id'] }}">{{ $r['region_name'] }}</a></li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</nav>
|
||||
<button popovertarget="prop-details"></button>
|
||||
<div popover id="prop-details">
|
||||
<dl>
|
||||
<dt>Region</dt>
|
||||
<dd>{{ $base['region_name'] }}</dd>
|
||||
<dt>Zum ersten mal gefunden</dt>
|
||||
<dd>{{ $base['first_found'] }}</dd>
|
||||
<dt>Zum letzten mal gefunden</dt>
|
||||
<dd>{{ $base['last_found'] }}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section('main')
|
||||
<article style="grid-area: timeline;">
|
||||
<div id="timeline"></div>
|
||||
</article>
|
||||
<article class="header" style="grid-area: chart1;">
|
||||
<header>
|
||||
<h2 id="belegung-title">
|
||||
Kalenderansicht der Belegung am <span class="date">{{ $startDate }}</span>
|
||||
</h2><button popovertarget="popup-cal"></button>
|
||||
<div popover id="popup-cal">
|
||||
<p>
|
||||
Das Kalenderdiagram zeigt die drei Verfügbarkeitskategorien des Mietobjekts.
|
||||
</p>
|
||||
</div>
|
||||
</header>
|
||||
<div id="chart-calendar"></div>
|
||||
</article>
|
||||
<article class="header map" style="grid-area: chart5;">
|
||||
<header>
|
||||
<h2 id="belegung-title">
|
||||
Kurzzeitmietobjekte in der Nähe
|
||||
</h2>
|
||||
</header>
|
||||
<div id="chart-map"></div>
|
||||
</article>
|
||||
<article class="header" style="grid-area: chart3;">
|
||||
<header>
|
||||
<h2>
|
||||
Belegung Mietobjekt Monate am <span class="date">{{ $startDate }}</span>
|
||||
</h2>
|
||||
</header>
|
||||
<div id="chart-capacity-monthly">
|
||||
</div>
|
||||
</article>
|
||||
<article class="header" style="grid-area: chart2;">
|
||||
<header>
|
||||
<h2>
|
||||
Entwicklung der Verfügbarkeit
|
||||
</h2>
|
||||
<button popovertarget="chart-capacity-popover"></button>
|
||||
<div id="chart-capacity-popover" popover>
|
||||
<h2>Erkläung zum Diagramm</h2>
|
||||
<p>Das Liniendiagramm zeigt, wie sich die insgesamte Verfügbarkeit des Kurzzeitmietobjekts entwickelt hat.</p>
|
||||
</div>
|
||||
</header>
|
||||
<div id="chart-capacity"></div>
|
||||
</article>
|
||||
<article class="header" style="grid-area: chart4;">
|
||||
<header>
|
||||
<h2>
|
||||
Belegung Mietobjekt Tage am <span class="date">{{ $startDate }}</span>
|
||||
</h2>
|
||||
</header>
|
||||
<div id="chart-capacity-daily">
|
||||
</article>
|
||||
<script type="module">
|
||||
|
||||
const sharedOptions = {
|
||||
basic: {
|
||||
color: {!! $chartOptions['colors'] !!},
|
||||
grid: {
|
||||
top: 20,
|
||||
left: 60,
|
||||
right: 0,
|
||||
bottom: 50
|
||||
},
|
||||
tooltip: {
|
||||
show: true,
|
||||
trigger: 'axis',
|
||||
valueFormatter: (value) => value.toFixed(2)+' %'
|
||||
},
|
||||
name: (opt) => {
|
||||
return {
|
||||
name: opt.name,
|
||||
nameLocation: opt.location,
|
||||
nameGap: 24,
|
||||
nameTextStyle: {
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const chartTimeline = document.getElementById('timeline');
|
||||
const cTimeline = echarts.init(chartTimeline);
|
||||
|
||||
const cTimelineOptions = {
|
||||
grid: {
|
||||
show: false,
|
||||
},
|
||||
timeline: {
|
||||
data: {!! $extractiondates !!},
|
||||
playInterval: 1000,
|
||||
axisType: 'time',
|
||||
left: 8,
|
||||
right: 8,
|
||||
bottom: 0,
|
||||
label: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
cTimeline.setOption(cTimelineOptions);
|
||||
|
||||
const chartCapacityMonthly = document.getElementById('chart-capacity-monthly');
|
||||
const cCapacityMonthly = echarts.init(chartCapacityMonthly);
|
||||
|
||||
const cCapacityMonthlyOptions = {
|
||||
tooltip: sharedOptions.basic.tooltip,
|
||||
timeline: {
|
||||
show: false,
|
||||
data: {!! $extractiondates !!},
|
||||
axisType: 'time',
|
||||
},
|
||||
grid: {
|
||||
top: 5,
|
||||
bottom: 40,
|
||||
left: 70,
|
||||
right: 10
|
||||
},
|
||||
xAxis: {
|
||||
type: 'value',
|
||||
max: 100,
|
||||
name: 'Auslastung in %',
|
||||
nameLocation: 'center',
|
||||
nameGap: 25,
|
||||
nameTextStyle: {
|
||||
fontWeight: 'bold',
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'category',
|
||||
},
|
||||
options: [
|
||||
@foreach ($capacitiesMonthly as $cM)
|
||||
{
|
||||
yAxis: {
|
||||
data: {!! json_encode($cM['months']) !!}
|
||||
},
|
||||
series: [{
|
||||
type: 'bar',
|
||||
itemStyle: {
|
||||
color: sharedOptions.basic.color[3]
|
||||
},
|
||||
data: {!! json_encode($cM['capacities']) !!}
|
||||
}]
|
||||
},
|
||||
@endforeach
|
||||
]
|
||||
};
|
||||
|
||||
cCapacityMonthly.setOption(cCapacityMonthlyOptions);
|
||||
|
||||
const chartCapacityDaily = document.getElementById('chart-capacity-daily');
|
||||
const cCapacityDaily = echarts.init(chartCapacityDaily);
|
||||
|
||||
const cCapacityDailyOptions = {
|
||||
tooltip: sharedOptions.basic.tooltip,
|
||||
timeline: {
|
||||
show: false,
|
||||
data: {!! $extractiondates !!},
|
||||
axisType: 'time',
|
||||
},
|
||||
grid: {
|
||||
top: 5,
|
||||
bottom: 40,
|
||||
left: 70,
|
||||
right: 10
|
||||
},
|
||||
xAxis: {
|
||||
type: 'value',
|
||||
max: 100,
|
||||
name: 'Auslastung in %',
|
||||
nameLocation: 'center',
|
||||
nameGap: 25,
|
||||
nameTextStyle: {
|
||||
fontWeight: 'bold',
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'category',
|
||||
},
|
||||
options: [
|
||||
@foreach ($capacitiesDaily as $cD)
|
||||
{
|
||||
yAxis: {
|
||||
data: {!! json_encode($cD['weekdays']) !!}
|
||||
},
|
||||
series: [{
|
||||
type: 'bar',
|
||||
itemStyle: {
|
||||
color: sharedOptions.basic.color[3]
|
||||
},
|
||||
data: {!! json_encode($cD['capacities']) !!}
|
||||
}]
|
||||
},
|
||||
@endforeach
|
||||
]
|
||||
};
|
||||
|
||||
cCapacityDaily.setOption(cCapacityDailyOptions);
|
||||
|
||||
const chartCapacity = document.getElementById('chart-capacity');
|
||||
const cCapacity = echarts.init(chartCapacity);
|
||||
|
||||
const cCapacityOptions = {
|
||||
color: sharedOptions.basic.color,
|
||||
legend: {
|
||||
data: ['Auslastung Property', 'Auslastung {{ $base['region_name'] }}', 'Auslastung alle Regionen']
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
valueFormatter: (value) => value.toFixed(2)+' %'
|
||||
},
|
||||
grid: {
|
||||
top: 40,
|
||||
left: 25,
|
||||
right: 10,
|
||||
bottom: 20,
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: {!! json_encode($propertyCapacities['dates']) !!},
|
||||
name: 'Zeitpunkt Scraping',
|
||||
nameLocation: 'center',
|
||||
nameGap: 24,
|
||||
nameTextStyle: {
|
||||
fontWeight: 'bold',
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
min: 0,
|
||||
max: 100,
|
||||
name: 'Auslastung in Prozent',
|
||||
nameLocation: 'center',
|
||||
nameGap: 38,
|
||||
nameTextStyle: {
|
||||
fontWeight: 'bold',
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: 'Auslastung Property',
|
||||
type: 'line',
|
||||
symbolSize: 7,
|
||||
data: {!! json_encode($propertyCapacities['capacities']) !!}
|
||||
},
|
||||
{
|
||||
name: 'Auslastung {{ $base['region_name'] }}',
|
||||
type: 'line',
|
||||
symbolSize: 7,
|
||||
data: {!! json_encode($regionCapacities[0]) !!}
|
||||
},
|
||||
{
|
||||
name: 'Auslastung alle Regionen',
|
||||
type: 'line',
|
||||
symbolSize: 7,
|
||||
data: {!! json_encode($regionCapacities[1]) !!}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
cCapacity.setOption(cCapacityOptions);
|
||||
|
||||
const chartCalendar = document.getElementById('chart-calendar');
|
||||
const cCalendar = echarts.init(chartCalendar);
|
||||
const h2Belegung = document.getElementById('belegung-title');
|
||||
|
||||
const cCalendarOptions = {
|
||||
timeline: {
|
||||
show: false,
|
||||
data: {!! json_encode($propertyCapacities['dates']) !!},
|
||||
axisType: 'time',
|
||||
},
|
||||
visualMap: {
|
||||
categories: [0,1,2],
|
||||
inRange: {
|
||||
color: ['#ca0020', '#92c5de', '#0571b0']
|
||||
},
|
||||
formatter: (cat) => {
|
||||
switch (cat) {
|
||||
case 0:
|
||||
return 'Ausgebucht';
|
||||
case 1:
|
||||
return 'Verfügbar (kein Anreisetag)';
|
||||
case 2:
|
||||
return 'Verfügbar';
|
||||
}
|
||||
},
|
||||
type: 'piecewise',
|
||||
orient: 'horizontal',
|
||||
left: 'center',
|
||||
top: 0
|
||||
},
|
||||
calendar:[
|
||||
{
|
||||
orient: 'horizontal',
|
||||
range: '2024',
|
||||
top: '15%',
|
||||
right: 10,
|
||||
bottom: '65%',
|
||||
left: 50,
|
||||
},
|
||||
{
|
||||
orient: 'horizontal',
|
||||
range: '2025',
|
||||
top: '47%',
|
||||
right: 10,
|
||||
bottom: '33%',
|
||||
left: 50,
|
||||
},
|
||||
{
|
||||
orient: 'horizontal',
|
||||
range: '2026',
|
||||
top: '79%',
|
||||
right: 10,
|
||||
bottom: '1%',
|
||||
left: 50,
|
||||
}
|
||||
],
|
||||
options: [
|
||||
@foreach ($calendar as $c)
|
||||
{
|
||||
series: [{
|
||||
type: 'heatmap',
|
||||
coordinateSystem: 'calendar',
|
||||
calendarIndex: 0,
|
||||
data: {!! json_encode($c) !!}
|
||||
},
|
||||
{
|
||||
type: 'heatmap',
|
||||
coordinateSystem: 'calendar',
|
||||
calendarIndex: 1,
|
||||
data: {!! json_encode($c) !!}
|
||||
},
|
||||
{
|
||||
type: 'heatmap',
|
||||
coordinateSystem: 'calendar',
|
||||
calendarIndex: 2,
|
||||
data: {!! json_encode($c) !!}
|
||||
}]
|
||||
},
|
||||
@endforeach
|
||||
]
|
||||
};
|
||||
|
||||
cCalendar.setOption(cCalendarOptions);
|
||||
|
||||
|
||||
cTimeline.on('timelinechanged', (e) => {
|
||||
|
||||
let dateTitles = document.querySelectorAll('span.date');
|
||||
dateTitles.forEach(el => {
|
||||
el.innerText = cTimelineOptions.timeline.data[e.currentIndex];
|
||||
});
|
||||
|
||||
// Set markpoint on linechart
|
||||
let x = cCapacityOptions.xAxis.data[e.currentIndex];
|
||||
let y = cCapacityOptions.series[0].data[e.currentIndex];
|
||||
|
||||
cCapacityMonthly.dispatchAction({
|
||||
type: 'timelineChange',
|
||||
currentIndex: e.currentIndex
|
||||
});
|
||||
|
||||
cCapacityDaily.dispatchAction({
|
||||
type: 'timelineChange',
|
||||
currentIndex: e.currentIndex
|
||||
});
|
||||
|
||||
cCalendar.dispatchAction({
|
||||
type: 'timelineChange',
|
||||
currentIndex: e.currentIndex
|
||||
});
|
||||
|
||||
cCapacity.setOption({
|
||||
series: {
|
||||
markPoint: {
|
||||
data: [{
|
||||
coord: [x, y]
|
||||
}]
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
})
|
||||
|
||||
/* Map w/ neighbours*/
|
||||
const map = L.map('chart-map');
|
||||
|
||||
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||
maxZoom: 19,
|
||||
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
|
||||
}).addTo(map);
|
||||
|
||||
function icon(id = 0){
|
||||
return L.divIcon({
|
||||
className: "region"+id,
|
||||
html: '<span></span>'
|
||||
})
|
||||
}
|
||||
|
||||
const markers = L.featureGroup([
|
||||
L.marker([{{ $base['check_data'] }}], {icon: icon(1)}),
|
||||
@foreach($neighbours as $n)
|
||||
L.marker([{{ $n['lat'] }}, {{ $n['lon'] }}], {icon: icon()}).bindPopup('<a href="/property/{{ $n['id'] }}">{{ $n['lat'] }}, {{ $n['lon'] }}</a>'),
|
||||
@endforeach
|
||||
]).addTo(map);
|
||||
|
||||
map.fitBounds(markers.getBounds(), {padding: [20,20]})
|
||||
|
||||
cCapacity.on('click', 'series', (e) => {
|
||||
|
||||
// Switch to correct calendar in the timeline
|
||||
cTimeline.dispatchAction({
|
||||
type: 'timelineChange',
|
||||
currentIndex: e.dataIndex
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
@endsection
|
|
@ -1,510 +0,0 @@
|
|||
@extends('base')
|
||||
@section('body-class', 'region')
|
||||
@section('header')
|
||||
<nav>
|
||||
<strong>{{ $region[0]['region_name'] }}</strong>
|
||||
<ul>
|
||||
<li><a href="/">Start</a></li>
|
||||
@foreach($regions as $r)
|
||||
@if($r['region_id'] != $region_id)
|
||||
<li><a href="/region/{{ $r['region_id'] }}">{{ $r['region_name'] }}</a></li>
|
||||
@endif
|
||||
@endforeach
|
||||
</ul>
|
||||
</nav>
|
||||
@endsection
|
||||
@section('main')
|
||||
<article style="grid-area: timeline;">
|
||||
<div id="timeline"></div>
|
||||
</article>
|
||||
<article class="header" style="grid-area: chart6;">
|
||||
<header>
|
||||
<h2 id="prediction-title">Gleitender Mittelwert für die Auslastung der Region</h2>
|
||||
</header>
|
||||
<div id="chart-prediction"></div>
|
||||
</article>
|
||||
<article class="header" style="grid-area: chart1;">
|
||||
<header>
|
||||
<h2 id="belegung-title">Auslastung aller Mietobjekte über Gesamte Zeit der Region</h2>
|
||||
</header>
|
||||
<div id="chart-heatmap"></div>
|
||||
</article>
|
||||
<article class="header" style="grid-area: chart3;">
|
||||
<header>
|
||||
<h2>
|
||||
Auslastung Region nach Monat am <span class="date">{{ $startDate }}</span>
|
||||
</h2>
|
||||
</header>
|
||||
<div id="chart-capacity-monthly">
|
||||
</div>
|
||||
</article>
|
||||
<article class="header" style="grid-area: chart2;">
|
||||
<header>
|
||||
<h2>
|
||||
Entwicklung der Auslastung
|
||||
</h2>
|
||||
<button popovertarget="chart-capacity-popover"></button>
|
||||
<div id="chart-capacity-popover" popover>
|
||||
<h2>Erkläung zum Diagramm «Entwicklung der Auslastung»</h2>
|
||||
<p>Das Liniendiagramm zeigt die Auslastung von Regionen. 100 % = die Region ist kaum ausgelastet; 100 % der Mietobjekte sind verfügbar. 0 % = Die Region ist komplett ausgelastet; Es stehen keine Mietangebote zur Verfügung.</p>
|
||||
</div>
|
||||
</header>
|
||||
<div id="chart-capacity"></div>
|
||||
</article>
|
||||
<article class="header" style="grid-area: chart4;">
|
||||
<header>
|
||||
<h2>
|
||||
Auslastung Wochentage am <span class="date">{{ $startDate }}</span>
|
||||
</h2>
|
||||
</header>
|
||||
<div id="chart-capacity-daily">
|
||||
</article>
|
||||
|
||||
<script type="module">
|
||||
|
||||
const sharedOptions = {
|
||||
basic: {
|
||||
color: {!! $chartOptions['colors'] !!},
|
||||
grid: {
|
||||
top: 20,
|
||||
left: 60,
|
||||
right: 0,
|
||||
bottom: 50
|
||||
},
|
||||
tooltip: {
|
||||
show: true,
|
||||
trigger: 'axis',
|
||||
valueFormatter: (value) => value.toFixed(2)+' %'
|
||||
},
|
||||
name: (opt) => {
|
||||
return {
|
||||
name: opt.name,
|
||||
nameLocation: opt.location,
|
||||
nameGap: 24,
|
||||
nameTextStyle: {
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const chartCapacity = document.getElementById('chart-capacity');
|
||||
const cCapacity = echarts.init(chartCapacity);
|
||||
|
||||
const cCapacityOptions = {
|
||||
legend: {
|
||||
show: true
|
||||
},
|
||||
tooltip: sharedOptions.basic.tooltip,
|
||||
color: sharedOptions.basic.color,
|
||||
grid: {
|
||||
top: 20,
|
||||
left: 25,
|
||||
right: 10,
|
||||
bottom: 20,
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: {!! json_encode($regionCapacities['region']['dates']) !!},
|
||||
name: 'Zeitpunkt Scraping',
|
||||
nameLocation: 'center',
|
||||
nameGap: 24,
|
||||
nameTextStyle: {
|
||||
fontWeight: 'bold',
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
min: 0,
|
||||
max: 100,
|
||||
name: 'Auslastung in %',
|
||||
nameLocation: 'center',
|
||||
nameGap: 38,
|
||||
nameTextStyle: {
|
||||
fontWeight: 'bold',
|
||||
}
|
||||
},
|
||||
series: [{
|
||||
name: 'Auslastung alle Regionen',
|
||||
type: 'line',
|
||||
symbolSize: 7,
|
||||
data: {!! json_encode($regionCapacities['all']['capacities']) !!}
|
||||
},
|
||||
{
|
||||
name: 'Auslastung Region',
|
||||
type: 'line',
|
||||
symbolSize: 7,
|
||||
data: {!! json_encode($regionCapacities['region']['capacities']) !!}
|
||||
}]
|
||||
};
|
||||
|
||||
cCapacity.setOption(cCapacityOptions);
|
||||
|
||||
const chartCapacityMonthly = document.getElementById('chart-capacity-monthly');
|
||||
const cCapacityMonthly = echarts.init(chartCapacityMonthly);
|
||||
|
||||
const cCapacityMonthlyOptions = {
|
||||
timeline: {
|
||||
show: false,
|
||||
data: {!! json_encode($regionCapacities['region']['dates']) !!},
|
||||
axisType: 'time',
|
||||
},
|
||||
grid: {
|
||||
top: 5,
|
||||
bottom: 40,
|
||||
left: 70,
|
||||
right: 10
|
||||
},
|
||||
xAxis: {
|
||||
type: 'value',
|
||||
max: 100,
|
||||
name: 'Auslastung in %',
|
||||
nameLocation: 'center',
|
||||
nameGap: 25,
|
||||
nameTextStyle: {
|
||||
fontWeight: 'bold',
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'category',
|
||||
},
|
||||
tooltip: sharedOptions.basic.tooltip,
|
||||
options: [
|
||||
@foreach ($regionCapacities['region_monthly'] as $m)
|
||||
{
|
||||
yAxis: {
|
||||
data: {!! json_encode($m['months']) !!}
|
||||
},
|
||||
series: [{
|
||||
type: 'bar',
|
||||
itemStyle: {
|
||||
color: sharedOptions.basic.color[3]
|
||||
},
|
||||
data: {!! json_encode($m['capacities']) !!}
|
||||
}]
|
||||
},
|
||||
@endforeach
|
||||
]
|
||||
};
|
||||
|
||||
cCapacityMonthly.setOption(cCapacityMonthlyOptions);
|
||||
|
||||
const chartCapacityDaily = document.getElementById('chart-capacity-daily');
|
||||
const cCapacityDaily = echarts.init(chartCapacityDaily);
|
||||
|
||||
const cCapacityDailyOptions = {
|
||||
timeline: {
|
||||
show: false,
|
||||
data: {!! json_encode($regionCapacities['region']['dates']) !!},
|
||||
axisType: 'time',
|
||||
},
|
||||
tooltip: sharedOptions.basic.tooltip,
|
||||
grid: {
|
||||
top: 5,
|
||||
bottom: 40,
|
||||
left: 70,
|
||||
right: 10
|
||||
},
|
||||
xAxis: {
|
||||
type: 'value',
|
||||
max: 100,
|
||||
name: 'Auslastung in %',
|
||||
nameLocation: 'center',
|
||||
nameGap: 25,
|
||||
nameTextStyle: {
|
||||
fontWeight: 'bold',
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'category',
|
||||
},
|
||||
options: [
|
||||
@foreach ($regionCapacities['region_daily'] as $d)
|
||||
{
|
||||
yAxis: {
|
||||
data: {!! json_encode($d['weekdays']) !!}
|
||||
},
|
||||
series: [{
|
||||
type: 'bar',
|
||||
itemStyle: {
|
||||
color: sharedOptions.basic.color[3]
|
||||
},
|
||||
data: {!! json_encode($d['capacities']) !!}
|
||||
}]
|
||||
},
|
||||
@endforeach
|
||||
]
|
||||
};
|
||||
|
||||
cCapacityDaily.setOption(cCapacityDailyOptions);
|
||||
|
||||
const chartPrediction = document.getElementById('chart-prediction');
|
||||
const cPrediction = echarts.init(chartPrediction);
|
||||
|
||||
const cPredictionOptions = {
|
||||
color: sharedOptions.basic.color,
|
||||
timeline: {
|
||||
show: false,
|
||||
data: {!! json_encode($regionCapacities['region']['dates']) !!},
|
||||
axisType: 'time',
|
||||
replaceMerge: ['graphic', 'series']
|
||||
},
|
||||
legend: {
|
||||
show: true
|
||||
},
|
||||
tooltip: sharedOptions.basic.tooltip,
|
||||
grid: {
|
||||
top: 20,
|
||||
left: 25,
|
||||
right: 10,
|
||||
bottom: 20,
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
name: 'Zeitpunkt Scraping',
|
||||
nameLocation: 'center',
|
||||
nameGap: 24,
|
||||
nameTextStyle: {
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
min: 0,
|
||||
max: 100,
|
||||
name: 'Auslastung in %',
|
||||
nameLocation: 'center',
|
||||
nameGap: 38,
|
||||
nameTextStyle: {
|
||||
fontWeight: 'bold',
|
||||
}
|
||||
},
|
||||
options: [
|
||||
@foreach ($predictions as $p)
|
||||
@if($p === null)
|
||||
{
|
||||
graphic: {
|
||||
elements: [
|
||||
{
|
||||
type: 'text',
|
||||
left: 'center',
|
||||
top: 'center',
|
||||
style: {
|
||||
text: 'Keine Daten für Zeitspanne',
|
||||
fontSize: 44,
|
||||
fontWeight: 'bold',
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
@else
|
||||
{
|
||||
color: sharedOptions.basic.color,
|
||||
graphic: {
|
||||
elements: []
|
||||
},
|
||||
xAxis: {
|
||||
data: {!! json_encode($p['dates']) !!}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: 'Gleitender Mittelwert',
|
||||
type: 'line',
|
||||
symbolSize: 7,
|
||||
data: {!! json_encode($p['movAvg']) !!}
|
||||
},
|
||||
{
|
||||
name: 'Daten vom ...',
|
||||
type: 'line',
|
||||
symbolSize: 7,
|
||||
data: {!! json_encode($p['cap_earlierTimeframe']) !!}
|
||||
},
|
||||
{
|
||||
name: 'Daten vom',
|
||||
type: 'line',
|
||||
symbolSize: 7,
|
||||
data: {!! json_encode($p['cap_laterTimeframe']) !!}
|
||||
}
|
||||
]
|
||||
},
|
||||
@endif
|
||||
@endforeach
|
||||
]
|
||||
};
|
||||
|
||||
cPrediction.setOption(cPredictionOptions);
|
||||
|
||||
const chartHeatmap = document.getElementById('chart-heatmap');
|
||||
const cHeatmap = echarts.init(chartHeatmap);
|
||||
const cHeatmapOptions = {
|
||||
animation: false,
|
||||
tooltip: {
|
||||
position: 'top'
|
||||
},
|
||||
grid: {
|
||||
top: 30,
|
||||
right: 45,
|
||||
bottom: 50,
|
||||
left: 5
|
||||
},
|
||||
dataZoom: [{
|
||||
type: 'slider'
|
||||
},
|
||||
{
|
||||
type: 'slider',
|
||||
show: true,
|
||||
yAxisIndex: 0,
|
||||
}],
|
||||
xAxis: {
|
||||
show: false,
|
||||
name: 'Kurzzeitmietobjekt',
|
||||
type: 'category',
|
||||
data: {!! json_encode($regionPropertiesCapacities['scrapeDates']) !!},
|
||||
splitArea: {
|
||||
show: false
|
||||
},
|
||||
axisLabel: {
|
||||
show: true,
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
show: false,
|
||||
type: 'category',
|
||||
data: {!! json_encode($regionPropertiesCapacities['property_ids']) !!},
|
||||
splitArea: {
|
||||
show: true
|
||||
}
|
||||
},
|
||||
visualMap: {
|
||||
type: 'piecewise',
|
||||
min: 0,
|
||||
max: 100,
|
||||
calculable: true,
|
||||
orient: 'horizontal',
|
||||
left: 'center',
|
||||
top: 0,
|
||||
formatter: (v1, v2) => {
|
||||
return `${v1} – ${v2} %`;
|
||||
},
|
||||
inRange: {
|
||||
color: sharedOptions.basic.color,
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: 'Auslastung',
|
||||
type: 'heatmap',
|
||||
blurSize: 0,
|
||||
data: {!! json_encode($regionPropertiesCapacities['values']) !!},
|
||||
label: {
|
||||
show: false
|
||||
},
|
||||
tooltip: {
|
||||
formatter: (data) => {
|
||||
return `Kurzzeitmietobjekte-ID: ${data.data[1]}<br />Datum Scraping: ${data.data[0]}<br/>Auslastung: ${data.data[2].toFixed(2)} %`
|
||||
},
|
||||
},
|
||||
emphasis: {
|
||||
itemStyle: {
|
||||
borderColor: '#000',
|
||||
borderWidth: 2
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
cHeatmap.setOption(cHeatmapOptions);
|
||||
|
||||
const chartTimeline = document.getElementById('timeline');
|
||||
const cTimeline = echarts.init(chartTimeline);
|
||||
|
||||
const cTimelineOptions = {
|
||||
grid: {
|
||||
show: false,
|
||||
},
|
||||
timeline: {
|
||||
data: {!! json_encode($regionCapacities['region']['dates']) !!},
|
||||
playInterval: 2000,
|
||||
axisType: 'time',
|
||||
left: 8,
|
||||
right: 8,
|
||||
bottom: 0,
|
||||
label: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
cTimeline.setOption(cTimelineOptions);
|
||||
|
||||
cTimeline.on('timelinechanged', (e) => {
|
||||
|
||||
let dateTitles = document.querySelectorAll('span.date');
|
||||
dateTitles.forEach(el => {
|
||||
el.innerText = cTimelineOptions.timeline.data[e.currentIndex];
|
||||
});
|
||||
|
||||
// Set markpoint on linechart
|
||||
let x = cCapacityOptions.xAxis.data[e.currentIndex];
|
||||
let y = cCapacityOptions.series[0].data[e.currentIndex];
|
||||
|
||||
cCapacityMonthly.dispatchAction({
|
||||
type: 'timelineChange',
|
||||
currentIndex: e.currentIndex
|
||||
});
|
||||
|
||||
cCapacityDaily.dispatchAction({
|
||||
type: 'timelineChange',
|
||||
currentIndex: e.currentIndex
|
||||
});
|
||||
|
||||
cPrediction.dispatchAction({
|
||||
type: 'timelineChange',
|
||||
currentIndex: e.currentIndex
|
||||
});
|
||||
|
||||
cCapacity.setOption({
|
||||
series: {
|
||||
markPoint: {
|
||||
data: [{
|
||||
coord: [x, y]
|
||||
}]
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
})
|
||||
|
||||
|
||||
document.querySelector('header').addEventListener('click', () => {
|
||||
console.log('test');
|
||||
cCapacityMonthly.dispatchAction({
|
||||
type: 'timelineChange',
|
||||
currentIndex: 10
|
||||
});
|
||||
})
|
||||
|
||||
|
||||
cCapacity.on('click', 'series', (e) => {
|
||||
|
||||
// Switch to correct calendar in the timeline
|
||||
cTimeline.dispatchAction({
|
||||
type: 'timelineChange',
|
||||
currentIndex: e.dataIndex
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
cHeatmap.on('click', 'series', (e) => {
|
||||
window.open(`/property/${e.value[1]}?date=${e.value[0]}`, '_self');
|
||||
})
|
||||
|
||||
</script>
|
||||
@endsection
|
|
@ -1,153 +0,0 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use App\Api;
|
||||
use App\Chart;
|
||||
|
||||
Route::get('/', function () {
|
||||
|
||||
$regionBase = Api::regionBase(-1);
|
||||
$regionBase[] = ['region_name' => 'Alle Regionen', 'region_id' => -1];
|
||||
$regionPropertyCapacities = Api::regionPropertiesCapacities(-1);
|
||||
$propertiesGrowth = Api::propertiesGrowth();
|
||||
$propsPerRegion = Api::propertiesPerRegion();
|
||||
$propsPerRegionName = [];
|
||||
$propsPerRegionCounts = [];
|
||||
$propsPerRegionId = [];
|
||||
|
||||
foreach ($propsPerRegion as $el) {
|
||||
$propsPerRegionName[] = $el['name'];
|
||||
$propsPerRegionId[] = $el['id'];
|
||||
$propsPerRegionCounts[] = $el['count_properties'];
|
||||
}
|
||||
|
||||
$chartOptions = [
|
||||
'colors' => Chart::colors()
|
||||
];
|
||||
|
||||
$propertiesGeo = Api::propertiesGeo();
|
||||
|
||||
return view('overview', [
|
||||
"regions" => $regionBase,
|
||||
"regionPropertiesCapacities" => $regionPropertyCapacities,
|
||||
"geo" => $propertiesGeo,
|
||||
"growth" => $propertiesGrowth,
|
||||
"chartOptions" => $chartOptions,
|
||||
"propsPerRegion" => [json_encode($propsPerRegionId), json_encode($propsPerRegionName), json_encode($propsPerRegionCounts)]]);
|
||||
});
|
||||
|
||||
Route::get('/region/{id}', function (int $id) {
|
||||
|
||||
$regionBaseAll = Api::regionBase(-1);
|
||||
$regionBaseAll[] = ['region_name' => 'Alle Regionen', 'region_id' => -1];
|
||||
$regionBaseRegion = $id >= 0 ? Api::regionBase($id) : [['region_name' => 'Alle Regionen']];
|
||||
|
||||
$regionPropertiesCapacities = Api::regionPropertiesCapacities($id);
|
||||
$regionCapacitiesRegion = Api::regionCapacities($id);
|
||||
$regionCapacitiesAll = Api::regionCapacities(-1);
|
||||
|
||||
$regionCapacitiesMonthly = [];
|
||||
$regionCapacitiesDaily = [];
|
||||
$regionPredictions = [];
|
||||
|
||||
foreach ($regionCapacitiesRegion['dates'] as $date) {
|
||||
$regionCapacitiesMonthly[] = Api::regionCapacitiesMonthly($id, $date);
|
||||
$regionCapacitiesDaily[] = Api::regionCapacitiesDaily($id, $date);
|
||||
$regionPredictions[] = Api::regionMovingAverage($id, $date);
|
||||
}
|
||||
|
||||
$chartOptions = [
|
||||
'colors' => Chart::colors()
|
||||
];
|
||||
|
||||
$regionCapacities = [
|
||||
'all' => $regionCapacitiesAll,
|
||||
'region' => $regionCapacitiesRegion,
|
||||
'region_monthly' => $regionCapacitiesMonthly,
|
||||
'region_daily' => $regionCapacitiesDaily
|
||||
|
||||
];
|
||||
|
||||
return view('region', [
|
||||
'chartOptions' => $chartOptions,
|
||||
'startDate' => $regionCapacitiesRegion['dates'][0],
|
||||
'regions' => $regionBaseAll,
|
||||
'region' => $regionBaseRegion,
|
||||
'region_id' => $id,
|
||||
'regionCapacities' => $regionCapacities,
|
||||
'regionPropertiesCapacities' => $regionPropertiesCapacities,
|
||||
'predictions' => $regionPredictions]);
|
||||
|
||||
|
||||
});
|
||||
|
||||
Route::get('/property/{id}', function (int $id) {
|
||||
|
||||
$chartOptions = [
|
||||
'colors' => Chart::colors()
|
||||
];
|
||||
$regionBaseAll = Api::regionBase(-1);
|
||||
$regionBaseAll[] = ['region_name' => 'Alle Regionen', 'region_id' => -1];
|
||||
$propertyBase = Api::propertyBase($id);
|
||||
$calendars = Api::propertyExtractions($id);
|
||||
$propertyCapacities = Api::propertyCapacities($id);
|
||||
$propertyNeighbours = Api::propertyNeighbours($id);
|
||||
$regionCapacitiesRegion = Api::regionCapacities($propertyBase[0]['region_id']);
|
||||
$regionCapacitiesAll = Api::regionCapacities(-1);
|
||||
$regionCapacities = [[],[]];
|
||||
|
||||
$propertyCapacitiesMonthly = [];
|
||||
$propertyCapacitiesDaily = [];
|
||||
|
||||
foreach ($propertyCapacities['dates'] as $date) {
|
||||
$propertyCapacitiesMonthly[] = Api::propertyCapacitiesMonthly($id, $date);
|
||||
$propertyCapacitiesDaily[] = Api::propertyCapacitiesDaily($id, $date);
|
||||
}
|
||||
|
||||
// filter out all date, which were not scraped for the property
|
||||
foreach ($regionCapacitiesAll['dates'] as $index => $date) {
|
||||
if(in_array($date, $propertyCapacities['dates'])){
|
||||
$regionCapacities[0][] = $regionCapacitiesAll['capacities'][$index];
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($regionCapacitiesRegion['dates'] as $index => $date) {
|
||||
if(in_array($date, $propertyCapacities['dates'])){
|
||||
$regionCapacities[1][] = $regionCapacitiesRegion['capacities'][$index];
|
||||
}
|
||||
}
|
||||
|
||||
// prepare data for calendar chart
|
||||
$data = [];
|
||||
$dates = [];
|
||||
|
||||
foreach ($calendars as $el) {
|
||||
|
||||
$series = [];
|
||||
$calendar = json_decode($el['calendar'], 1);
|
||||
|
||||
foreach ($calendar as $date => $status) {
|
||||
$series[] = [$date, $status];
|
||||
}
|
||||
|
||||
$data[] = $series;
|
||||
|
||||
}
|
||||
|
||||
return view('property', [
|
||||
'chartOptions' => $chartOptions,
|
||||
'startDate' => $propertyCapacities['dates'][0],
|
||||
'base' => $propertyBase[0],
|
||||
'regions' => $regionBaseAll,
|
||||
'extractiondates' => json_encode($propertyCapacities['dates']),
|
||||
'calendar' => $data,
|
||||
'propertyCapacities' => $propertyCapacities,
|
||||
'capacitiesMonthly' => $propertyCapacitiesMonthly,
|
||||
'capacitiesDaily' => $propertyCapacitiesDaily,
|
||||
'regionCapacities' => $regionCapacities,
|
||||
'neighbours' => $propertyNeighbours
|
||||
]);
|
||||
|
||||
});
|
||||
|
||||
|
|
@ -1,118 +0,0 @@
|
|||
<mxfile host="app.diagrams.net" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36" version="26.0.5">
|
||||
<diagram name="Seite-1" id="WNMV8rePnVf-2Vz_xhjt">
|
||||
<mxGraphModel dx="1688" dy="1050" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<object placeholders="1" c4Name="Datenbank Aggregation" c4Type="Container" c4Technology="MySQL" c4Description="Datenbank welche während Aggregation verwendet wurde." label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%:&nbsp;%c4Technology%]</div><br><div><font style="font-size: 11px"><font color="#E6E6E6">%c4Description%</font></div>" id="0Mexl9jQAquWokRCgHYt-1">
|
||||
<mxCell style="shape=cylinder3;size=15;whiteSpace=wrap;html=1;boundedLbl=1;rounded=0;labelBackgroundColor=none;fillColor=#23A2D9;fontSize=12;fontColor=#ffffff;align=center;strokeColor=#0E7DAD;metaEdit=1;points=[[0.5,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.5,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];resizable=0;" vertex="1" parent="1">
|
||||
<mxGeometry x="40" y="100" width="240" height="120" as="geometry" />
|
||||
</mxCell>
|
||||
</object>
|
||||
<object placeholders="1" c4Name="Datenbank Analyse" c4Type="Container" c4Technology="DuckDB" c4Description="Datenbank, welcher für die Analysen verwendet wurden." label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%:&nbsp;%c4Technology%]</div><br><div><font style="font-size: 11px"><font color="#E6E6E6">%c4Description%</font></div>" id="0Mexl9jQAquWokRCgHYt-2">
|
||||
<mxCell style="shape=cylinder3;size=15;whiteSpace=wrap;html=1;boundedLbl=1;rounded=0;labelBackgroundColor=none;fillColor=#23A2D9;fontSize=12;fontColor=#ffffff;align=center;strokeColor=#0E7DAD;metaEdit=1;points=[[0.5,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.5,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];resizable=0;" vertex="1" parent="1">
|
||||
<mxGeometry x="790" y="100" width="240" height="120" as="geometry" />
|
||||
</mxCell>
|
||||
</object>
|
||||
<mxCell id="0Mexl9jQAquWokRCgHYt-5" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;dashed=1;dashPattern=8 8;" edge="1" parent="1" source="0Mexl9jQAquWokRCgHYt-3" target="0Mexl9jQAquWokRCgHYt-1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="0Mexl9jQAquWokRCgHYt-7" value="liest Datenbank" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="0Mexl9jQAquWokRCgHYt-5">
|
||||
<mxGeometry x="-0.2497" y="-1" relative="1" as="geometry">
|
||||
<mxPoint x="-10" y="1" as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<object placeholders="1" c4Name="Sling" c4Type="sling-cli" c4Description="Kommandozeilenprogramm zur Migration von Datensätzen." label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%]</div><br><div><font style="font-size: 11px"><font color="#cccccc">%c4Description%</font></div>" id="0Mexl9jQAquWokRCgHYt-3">
|
||||
<mxCell style="rounded=1;whiteSpace=wrap;html=1;labelBackgroundColor=none;fillColor=#1061B0;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#0D5091;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
|
||||
<mxGeometry x="400" y="100" width="240" height="120" as="geometry" />
|
||||
</mxCell>
|
||||
</object>
|
||||
<mxCell id="0Mexl9jQAquWokRCgHYt-6" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;dashed=1;dashPattern=8 8;" edge="1" parent="1" source="0Mexl9jQAquWokRCgHYt-3" target="0Mexl9jQAquWokRCgHYt-2">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="0Mexl9jQAquWokRCgHYt-8" value="schreibt in Datenbank" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="0Mexl9jQAquWokRCgHYt-6">
|
||||
<mxGeometry x="-0.1744" relative="1" as="geometry">
|
||||
<mxPoint x="16" y="-1" as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<object placeholders="1" c4Name="Preprocessing" c4Type="ContainerScopeBoundary" c4Application="Component" label="<font style="font-size: 16px"><b><div style="text-align: left">%c4Name%</div></b></font><div style="text-align: left">[%c4Application%]</div>" id="0Mexl9jQAquWokRCgHYt-9">
|
||||
<mxCell style="rounded=1;fontSize=11;whiteSpace=wrap;html=1;dashed=1;arcSize=20;fillColor=none;strokeColor=#666666;fontColor=#333333;labelBackgroundColor=none;align=left;verticalAlign=bottom;labelBorderColor=none;spacingTop=0;spacing=10;dashPattern=8 4;metaEdit=1;rotatable=0;perimeter=rectanglePerimeter;noLabel=0;labelPadding=0;allowArrows=0;connectable=0;expand=0;recursiveResize=0;editable=1;pointerEvents=0;absoluteArcSize=1;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
|
||||
<mxGeometry x="20" y="40" width="1030" height="270" as="geometry" />
|
||||
</mxCell>
|
||||
</object>
|
||||
<object placeholders="1" c4Name="Datenbank Analyse" c4Type="Container" c4Technology="DuckDB" c4Description="Datenbank, welcher für die Analysen verwendet wurden." label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%:&nbsp;%c4Technology%]</div><br><div><font style="font-size: 11px"><font color="#E6E6E6">%c4Description%</font></div>" id="0Mexl9jQAquWokRCgHYt-10">
|
||||
<mxCell style="shape=cylinder3;size=15;whiteSpace=wrap;html=1;boundedLbl=1;rounded=0;labelBackgroundColor=none;fillColor=#23A2D9;fontSize=12;fontColor=#ffffff;align=center;strokeColor=#0E7DAD;metaEdit=1;points=[[0.5,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.5,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];resizable=0;" vertex="1" parent="1">
|
||||
<mxGeometry x="80" y="480" width="240" height="120" as="geometry" />
|
||||
</mxCell>
|
||||
</object>
|
||||
<object placeholders="1" c4Name="Datenaufbereitung" c4Type="ContainerScopeBoundary" c4Application="ETL" label="<font style="font-size: 16px"><b><div style="text-align: left">%c4Name%</div></b></font><div style="text-align: left">[%c4Application%]</div>" id="0Mexl9jQAquWokRCgHYt-11">
|
||||
<mxCell style="rounded=1;fontSize=11;whiteSpace=wrap;html=1;dashed=1;arcSize=20;fillColor=none;strokeColor=#666666;fontColor=#333333;labelBackgroundColor=none;align=left;verticalAlign=bottom;labelBorderColor=none;spacingTop=0;spacing=10;dashPattern=8 4;metaEdit=1;rotatable=0;perimeter=rectanglePerimeter;noLabel=0;labelPadding=0;allowArrows=0;connectable=0;expand=0;recursiveResize=0;editable=1;pointerEvents=0;absoluteArcSize=1;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
|
||||
<mxGeometry x="30" y="440" width="1030" height="490" as="geometry" />
|
||||
</mxCell>
|
||||
</object>
|
||||
<mxCell id="0Mexl9jQAquWokRCgHYt-23" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;dashed=1;dashPattern=8 8;" edge="1" parent="1" source="0Mexl9jQAquWokRCgHYt-12" target="0Mexl9jQAquWokRCgHYt-14">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="0Mexl9jQAquWokRCgHYt-24" value="verwendet" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="0Mexl9jQAquWokRCgHYt-23">
|
||||
<mxGeometry x="-0.0114" y="-2" relative="1" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<object placeholders="1" c4Name="etl_*.py" c4Type="Python (Polars)" c4Description="Diverse Python Skripts zur Aufbereitung / Zusammenstellung der Daten." label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%]</div><br><div><font style="font-size: 11px"><font color="#cccccc">%c4Description%</font></div>" id="0Mexl9jQAquWokRCgHYt-12">
|
||||
<mxCell style="rounded=1;whiteSpace=wrap;html=1;labelBackgroundColor=none;fillColor=#1061B0;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#0D5091;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
|
||||
<mxGeometry x="430" y="710" width="240" height="120" as="geometry" />
|
||||
</mxCell>
|
||||
</object>
|
||||
<mxCell id="0Mexl9jQAquWokRCgHYt-16" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;exitPerimeter=0;dashed=1;dashPattern=8 8;" edge="1" parent="1" source="0Mexl9jQAquWokRCgHYt-13" target="0Mexl9jQAquWokRCgHYt-10">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="0Mexl9jQAquWokRCgHYt-17" value="Liest Datenbank" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="0Mexl9jQAquWokRCgHYt-16">
|
||||
<mxGeometry x="-0.1633" relative="1" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<object placeholders="1" c4Name="database.py" c4Type="Python (DuckDB Interface)" c4Description="Wrapper Skript zum Ausführen von SQL." label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%]</div><br><div><font style="font-size: 11px"><font color="#cccccc">%c4Description%</font></div>" id="0Mexl9jQAquWokRCgHYt-13">
|
||||
<mxCell style="rounded=1;whiteSpace=wrap;html=1;labelBackgroundColor=none;fillColor=#1061B0;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#0D5091;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
|
||||
<mxGeometry x="80" y="710" width="240" height="120" as="geometry" />
|
||||
</mxCell>
|
||||
</object>
|
||||
<mxCell id="0Mexl9jQAquWokRCgHYt-18" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.25;exitY=0;exitDx=0;exitDy=0;exitPerimeter=0;dashed=1;dashPattern=8 8;entryX=0.24;entryY=0.981;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" source="0Mexl9jQAquWokRCgHYt-14" target="0Mexl9jQAquWokRCgHYt-15">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="900" y="600" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="0Mexl9jQAquWokRCgHYt-19" value="schreibt pickle objekt" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="0Mexl9jQAquWokRCgHYt-18">
|
||||
<mxGeometry x="-0.1818" y="2" relative="1" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<object placeholders="1" c4Name="etl_cache.py" c4Type="Python (Pickle)" c4Description="Diverse Python Skripts zur Aufbereitung / Zusammenstellung der Daten." label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%]</div><br><div><font style="font-size: 11px"><font color="#cccccc">%c4Description%</font></div>" id="0Mexl9jQAquWokRCgHYt-14">
|
||||
<mxCell style="rounded=1;whiteSpace=wrap;html=1;labelBackgroundColor=none;fillColor=#1061B0;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#0D5091;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
|
||||
<mxGeometry x="780" y="710" width="240" height="120" as="geometry" />
|
||||
</mxCell>
|
||||
</object>
|
||||
<object placeholders="1" c4Name="Cache" c4Type="Container" c4Technology="Filesystem" c4Description="Das Dateisystem wird als Pufferspeicher verwendet. Die Daten werden als Pickle Objekte gespeichert." label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%:&nbsp;%c4Technology%]</div><br><div><font style="font-size: 11px"><font color="#E6E6E6">%c4Description%</font></div>" id="0Mexl9jQAquWokRCgHYt-15">
|
||||
<mxCell style="shape=cylinder3;size=15;whiteSpace=wrap;html=1;boundedLbl=1;rounded=0;labelBackgroundColor=none;fillColor=#23A2D9;fontSize=12;fontColor=#ffffff;align=center;strokeColor=#0E7DAD;metaEdit=1;points=[[0.5,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.5,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];resizable=0;" vertex="1" parent="1">
|
||||
<mxGeometry x="780" y="480" width="240" height="120" as="geometry" />
|
||||
</mxCell>
|
||||
</object>
|
||||
<mxCell id="0Mexl9jQAquWokRCgHYt-20" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.746;entryY=1.002;entryDx=0;entryDy=0;entryPerimeter=0;dashed=1;dashPattern=8 8;exitX=0.75;exitY=0;exitDx=0;exitDy=0;exitPerimeter=0;" edge="1" parent="1" source="0Mexl9jQAquWokRCgHYt-14" target="0Mexl9jQAquWokRCgHYt-15">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="0Mexl9jQAquWokRCgHYt-21" value="liest pickle objekt" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="0Mexl9jQAquWokRCgHYt-20">
|
||||
<mxGeometry x="-0.1076" y="1" relative="1" as="geometry">
|
||||
<mxPoint x="8" y="-11" as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="0Mexl9jQAquWokRCgHYt-25" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;dashed=1;dashPattern=8 8;" edge="1" parent="1" source="0Mexl9jQAquWokRCgHYt-12" target="0Mexl9jQAquWokRCgHYt-13">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="0Mexl9jQAquWokRCgHYt-26" value="Verwendet" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="0Mexl9jQAquWokRCgHYt-25">
|
||||
<mxGeometry x="0.0473" relative="1" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
|
@ -1,184 +0,0 @@
|
|||
<mxfile host="app.diagrams.net" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36" version="26.0.5" pages="2">
|
||||
<diagram name="Seite-1" id="chpUGVRRn7alPJZ1I-il">
|
||||
<mxGraphModel dx="2761" dy="1531" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<object placeholders="1" c4Name="RDBMS" c4Type="Container" c4Technology="DuckDB" c4Description="Aggregierte Daten." label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%:&nbsp;%c4Technology%]</div><br><div><font style="font-size: 11px"><font color="#E6E6E6">%c4Description%</font></div>" id="_wAeSdXpbb6KPP4DEc36-2">
|
||||
<mxCell style="shape=cylinder3;size=15;whiteSpace=wrap;html=1;boundedLbl=1;rounded=0;labelBackgroundColor=none;fillColor=#23A2D9;fontSize=12;fontColor=#ffffff;align=center;strokeColor=#0E7DAD;metaEdit=1;points=[[0.5,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.5,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];resizable=0;" parent="1" vertex="1">
|
||||
<mxGeometry x="50" y="60" width="240" height="120" as="geometry" />
|
||||
</mxCell>
|
||||
</object>
|
||||
<object placeholders="1" c4Name="ETL" c4Type="SQL, Python (Polars)" c4Description="Bereitet Daten mittels algorithmischer<br> Verfahren auf." label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%]</div><br><div><font style="font-size: 11px"><font color="#cccccc">%c4Description%</font></div>" id="_wAeSdXpbb6KPP4DEc36-3">
|
||||
<mxCell style="rounded=1;whiteSpace=wrap;html=1;labelBackgroundColor=none;fillColor=#1061B0;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#0D5091;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" parent="1" vertex="1">
|
||||
<mxGeometry x="480" y="60" width="240" height="120" as="geometry" />
|
||||
</mxCell>
|
||||
</object>
|
||||
<mxCell id="_wAeSdXpbb6KPP4DEc36-4" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;dashed=1;dashPattern=8 8;" parent="1" source="_wAeSdXpbb6KPP4DEc36-3" target="_wAeSdXpbb6KPP4DEc36-2" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_wAeSdXpbb6KPP4DEc36-5" value="Liest Datenbank" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="_wAeSdXpbb6KPP4DEc36-4" vertex="1" connectable="0">
|
||||
<mxGeometry x="0.0412" y="1" relative="1" as="geometry">
|
||||
<mxPoint x="-1" y="-1" as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_wAeSdXpbb6KPP4DEc36-15" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;dashed=1;dashPattern=8 8;entryX=0;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" source="_wAeSdXpbb6KPP4DEc36-6" target="_wAeSdXpbb6KPP4DEc36-13" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_wAeSdXpbb6KPP4DEc36-21" value="<div>Führt Abfragen aus</div><div>[JSON/HTTPS]<br></div>" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="_wAeSdXpbb6KPP4DEc36-15" vertex="1" connectable="0">
|
||||
<mxGeometry x="-0.0541" y="-1" relative="1" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<object placeholders="1" c4Name="Webapplikation" c4Type="PHP (Laravel)" c4Description="Verarbeitet Anfragen von Benutzer:innen" label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%]</div><br><div><font style="font-size: 11px"><font color="#cccccc">%c4Description%</font></div>" id="_wAeSdXpbb6KPP4DEc36-6">
|
||||
<mxCell style="rounded=1;whiteSpace=wrap;html=1;labelBackgroundColor=none;fillColor=#1061B0;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#0D5091;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" parent="1" vertex="1">
|
||||
<mxGeometry x="50" y="230" width="240" height="120" as="geometry" />
|
||||
</mxCell>
|
||||
</object>
|
||||
<object placeholders="1" c4Name="Dashboard" c4Type="Container" c4Technology="Apache Echarts" c4Description="Stellt Benutzer:innen Auswertungs-<br>möglichkeiten zur Verfügbarkeit von Kurzzeitmietobjekten." label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%:&nbsp;%c4Technology%]</div><br><div><font style="font-size: 11px"><font color="#E6E6E6">%c4Description%</font></div>" id="_wAeSdXpbb6KPP4DEc36-8">
|
||||
<mxCell style="shape=mxgraph.c4.webBrowserContainer2;whiteSpace=wrap;html=1;boundedLbl=1;rounded=0;labelBackgroundColor=none;strokeColor=#118ACD;fillColor=#23A2D9;strokeColor=#118ACD;strokeColor2=#0E7DAD;fontSize=12;fontColor=#ffffff;align=center;metaEdit=1;points=[[0.5,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.5,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];resizable=0;" parent="1" vertex="1">
|
||||
<mxGeometry x="480" y="370" width="240" height="160" as="geometry" />
|
||||
</mxCell>
|
||||
</object>
|
||||
<mxCell id="_wAeSdXpbb6KPP4DEc36-10" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;exitPerimeter=0;dashed=1;dashPattern=8 8;" parent="1" source="_wAeSdXpbb6KPP4DEc36-9" target="_wAeSdXpbb6KPP4DEc36-6" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_wAeSdXpbb6KPP4DEc36-16" value="<div>Besucht Webapplikation</div><div>[HTTPS]<br></div>" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="_wAeSdXpbb6KPP4DEc36-10" vertex="1" connectable="0">
|
||||
<mxGeometry x="0.1247" y="-2" relative="1" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_wAeSdXpbb6KPP4DEc36-11" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;exitPerimeter=0;dashed=1;dashPattern=8 8;" parent="1" source="_wAeSdXpbb6KPP4DEc36-9" target="_wAeSdXpbb6KPP4DEc36-8" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_wAeSdXpbb6KPP4DEc36-17" value="Betrachtet Auswertungen" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="_wAeSdXpbb6KPP4DEc36-11" vertex="1" connectable="0">
|
||||
<mxGeometry x="0.2151" y="-1" relative="1" as="geometry">
|
||||
<mxPoint x="2" as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<object placeholders="1" c4Name="Benutzer:in" c4Type="Person" c4Description="Person welche Auswertungen zur Verfügbarkeit von Kurzzeitmietobjekten in Ferienregionen durchführt." label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%]</div><br><div><font style="font-size: 11px"><font color="#cccccc">%c4Description%</font></div>" id="_wAeSdXpbb6KPP4DEc36-9">
|
||||
<mxCell style="html=1;fontSize=11;dashed=0;whiteSpace=wrap;fillColor=#083F75;strokeColor=#06315C;fontColor=#ffffff;shape=mxgraph.c4.person2;align=center;metaEdit=1;points=[[0.5,0,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0]];resizable=0;" parent="1" vertex="1">
|
||||
<mxGeometry x="314" y="600" width="200" height="180" as="geometry" />
|
||||
</mxCell>
|
||||
</object>
|
||||
<mxCell id="_wAeSdXpbb6KPP4DEc36-14" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;entryPerimeter=0;dashed=1;dashPattern=8 8;" parent="1" source="_wAeSdXpbb6KPP4DEc36-13" target="_wAeSdXpbb6KPP4DEc36-3" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_wAeSdXpbb6KPP4DEc36-20" value="Ruft ETL Verfahren auf" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="_wAeSdXpbb6KPP4DEc36-14" vertex="1" connectable="0">
|
||||
<mxGeometry x="-0.0667" y="-1" relative="1" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<object placeholders="1" c4Name="FastAPI" c4Type="Python (FastAPI)" c4Description="Stellt aufbereitete Daten via <br>JSON/HTTPS API zur Verfügung." label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%]</div><br><div><font style="font-size: 11px"><font color="#cccccc">%c4Description%</font></div>" id="_wAeSdXpbb6KPP4DEc36-13">
|
||||
<mxCell style="rounded=1;whiteSpace=wrap;html=1;labelBackgroundColor=none;fillColor=#1061B0;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#0D5091;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" parent="1" vertex="1">
|
||||
<mxGeometry x="480" y="230" width="240" height="120" as="geometry" />
|
||||
</mxCell>
|
||||
</object>
|
||||
<mxCell id="_wAeSdXpbb6KPP4DEc36-18" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;dashed=1;dashPattern=8 8;" parent="1" source="_wAeSdXpbb6KPP4DEc36-6" target="_wAeSdXpbb6KPP4DEc36-8" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_wAeSdXpbb6KPP4DEc36-19" value="<div>Liefert Inhalte zum Webbrowser&nbsp;</div><div>von Benutzer:innen</div>" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="_wAeSdXpbb6KPP4DEc36-18" vertex="1" connectable="0">
|
||||
<mxGeometry x="-0.0888" y="-2" relative="1" as="geometry">
|
||||
<mxPoint x="5" y="7" as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<object placeholders="1" c4Name="Visual Analytics Tool" c4Type="SystemScopeBoundary" c4Application="Software System" label="<font style="font-size: 16px"><b><div style="text-align: left">%c4Name%</div></b></font><div style="text-align: left">[%c4Application%]</div>" id="_wAeSdXpbb6KPP4DEc36-23">
|
||||
<mxCell style="rounded=1;fontSize=11;whiteSpace=wrap;html=1;dashed=1;arcSize=20;fillColor=none;strokeColor=#666666;fontColor=#333333;labelBackgroundColor=none;align=left;verticalAlign=bottom;labelBorderColor=none;spacingTop=0;spacing=10;dashPattern=8 4;metaEdit=1;rotatable=0;perimeter=rectanglePerimeter;noLabel=0;labelPadding=0;allowArrows=0;connectable=0;expand=0;recursiveResize=0;editable=1;pointerEvents=0;absoluteArcSize=1;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" parent="1" vertex="1">
|
||||
<mxGeometry x="30" y="40" width="710" height="540" as="geometry" />
|
||||
</mxCell>
|
||||
</object>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
<diagram id="2goo0GJ--Dnj9rEJibSb" name="Seite-2">
|
||||
<mxGraphModel dx="2285" dy="1267" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<object placeholders="1" c4Name="RDBMS" c4Type="Container" c4Technology="DuckDB" c4Description="Aggregierte Daten." label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%:&nbsp;%c4Technology%]</div><br><div><font style="font-size: 11px"><font color="#E6E6E6">%c4Description%</font></div>" id="Xmw1x83A06H2_JC6hK8s-1">
|
||||
<mxCell style="shape=cylinder3;size=15;whiteSpace=wrap;html=1;boundedLbl=1;rounded=0;labelBackgroundColor=none;fillColor=#23A2D9;fontSize=12;fontColor=#ffffff;align=center;strokeColor=#0E7DAD;metaEdit=1;points=[[0.5,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.5,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];resizable=0;" vertex="1" parent="1">
|
||||
<mxGeometry x="40" y="230" width="240" height="120" as="geometry" />
|
||||
</mxCell>
|
||||
</object>
|
||||
<object placeholders="1" c4Name="ETL" c4Type="SQL, Python (Polars)" c4Description="Bereitet Daten mittels algorithmischer<br> Verfahren auf." label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%]</div><br><div><font style="font-size: 11px"><font color="#cccccc">%c4Description%</font></div>" id="Xmw1x83A06H2_JC6hK8s-2">
|
||||
<mxCell style="rounded=1;whiteSpace=wrap;html=1;labelBackgroundColor=none;fillColor=#1061B0;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#0D5091;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
|
||||
<mxGeometry x="40" y="464" width="240" height="120" as="geometry" />
|
||||
</mxCell>
|
||||
</object>
|
||||
<mxCell id="Xmw1x83A06H2_JC6hK8s-3" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;entryPerimeter=0;dashed=1;dashPattern=8 8;" edge="1" parent="1" source="Xmw1x83A06H2_JC6hK8s-2" target="Xmw1x83A06H2_JC6hK8s-1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Xmw1x83A06H2_JC6hK8s-4" value="Liest Datenbank" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="Xmw1x83A06H2_JC6hK8s-3">
|
||||
<mxGeometry x="0.0412" y="1" relative="1" as="geometry">
|
||||
<mxPoint x="-1" y="-1" as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="Xmw1x83A06H2_JC6hK8s-5" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;dashed=1;dashPattern=8 8;entryX=1;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" source="Xmw1x83A06H2_JC6hK8s-7" target="Xmw1x83A06H2_JC6hK8s-16">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Xmw1x83A06H2_JC6hK8s-6" value="<div>Führt Abfragen aus</div><div>[JSON/HTTPS]<br></div>" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="Xmw1x83A06H2_JC6hK8s-5">
|
||||
<mxGeometry x="-0.0541" y="-1" relative="1" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<object placeholders="1" c4Name="Webapplikation" c4Type="PHP (Laravel)" c4Description="Verarbeitet Anfragen von Benutzer:innen" label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%]</div><br><div><font style="font-size: 11px"><font color="#cccccc">%c4Description%</font></div>" id="Xmw1x83A06H2_JC6hK8s-7">
|
||||
<mxCell style="rounded=1;whiteSpace=wrap;html=1;labelBackgroundColor=none;fillColor=#1061B0;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#0D5091;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
|
||||
<mxGeometry x="710" y="240" width="240" height="120" as="geometry" />
|
||||
</mxCell>
|
||||
</object>
|
||||
<object placeholders="1" c4Name="Dashboard" c4Type="Container" c4Technology="Apache Echarts" c4Description="Stellt Benutzer:innen Auswertungs-<br>möglichkeiten zur Verfügbarkeit von Kurzzeitmietobjekten." label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%:&nbsp;%c4Technology%]</div><br><div><font style="font-size: 11px"><font color="#E6E6E6">%c4Description%</font></div>" id="Xmw1x83A06H2_JC6hK8s-8">
|
||||
<mxCell style="shape=mxgraph.c4.webBrowserContainer2;whiteSpace=wrap;html=1;boundedLbl=1;rounded=0;labelBackgroundColor=none;strokeColor=#118ACD;fillColor=#23A2D9;strokeColor=#118ACD;strokeColor2=#0E7DAD;fontSize=12;fontColor=#ffffff;align=center;metaEdit=1;points=[[0.5,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.5,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];resizable=0;" vertex="1" parent="1">
|
||||
<mxGeometry x="710" y="470" width="240" height="160" as="geometry" />
|
||||
</mxCell>
|
||||
</object>
|
||||
<mxCell id="Xmw1x83A06H2_JC6hK8s-9" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;dashed=1;dashPattern=8 8;entryX=1;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" source="Xmw1x83A06H2_JC6hK8s-13" target="Xmw1x83A06H2_JC6hK8s-7">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Xmw1x83A06H2_JC6hK8s-10" value="<div>Besucht Webapplikation</div><div>[HTTPS]<br></div>" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="Xmw1x83A06H2_JC6hK8s-9">
|
||||
<mxGeometry x="0.1247" y="-2" relative="1" as="geometry">
|
||||
<mxPoint x="4" y="4" as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="Xmw1x83A06H2_JC6hK8s-11" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;dashed=1;dashPattern=8 8;entryX=1;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" source="Xmw1x83A06H2_JC6hK8s-13" target="Xmw1x83A06H2_JC6hK8s-8">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Xmw1x83A06H2_JC6hK8s-12" value="Betrachtet Auswertungen" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="Xmw1x83A06H2_JC6hK8s-11">
|
||||
<mxGeometry x="0.2151" y="-1" relative="1" as="geometry">
|
||||
<mxPoint x="13" as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<object placeholders="1" c4Name="Benutzer:in" c4Type="Person" c4Description="Person welche Auswertungen zur Verfügbarkeit von Kurzzeitmietobjekten in Ferienregionen durchführt." label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%]</div><br><div><font style="font-size: 11px"><font color="#cccccc">%c4Description%</font></div>" id="Xmw1x83A06H2_JC6hK8s-13">
|
||||
<mxCell style="html=1;fontSize=11;dashed=0;whiteSpace=wrap;fillColor=#083F75;strokeColor=#06315C;fontColor=#ffffff;shape=mxgraph.c4.person2;align=center;metaEdit=1;points=[[0.5,0,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0]];resizable=0;" vertex="1" parent="1">
|
||||
<mxGeometry x="1120" y="320" width="200" height="180" as="geometry" />
|
||||
</mxCell>
|
||||
</object>
|
||||
<mxCell id="Xmw1x83A06H2_JC6hK8s-14" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;dashed=1;dashPattern=8 8;" edge="1" parent="1" source="Xmw1x83A06H2_JC6hK8s-16" target="Xmw1x83A06H2_JC6hK8s-2">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Xmw1x83A06H2_JC6hK8s-15" value="Ruft ETL Verfahren auf" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="Xmw1x83A06H2_JC6hK8s-14">
|
||||
<mxGeometry x="-0.0667" y="-1" relative="1" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<object placeholders="1" c4Name="FastAPI" c4Type="Python (FastAPI)" c4Description="Stellt aufbereitete Daten via <br>JSON/HTTPS API zur Verfügung." label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%]</div><br><div><font style="font-size: 11px"><font color="#cccccc">%c4Description%</font></div>" id="Xmw1x83A06H2_JC6hK8s-16">
|
||||
<mxCell style="rounded=1;whiteSpace=wrap;html=1;labelBackgroundColor=none;fillColor=#1061B0;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#0D5091;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
|
||||
<mxGeometry x="330" y="240" width="240" height="120" as="geometry" />
|
||||
</mxCell>
|
||||
</object>
|
||||
<mxCell id="Xmw1x83A06H2_JC6hK8s-17" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;entryPerimeter=0;dashed=1;dashPattern=8 8;" edge="1" parent="1" source="Xmw1x83A06H2_JC6hK8s-7" target="Xmw1x83A06H2_JC6hK8s-8">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Xmw1x83A06H2_JC6hK8s-18" value="<div>Liefert Inhalte zum Webbrowser&nbsp;</div><div>von Benutzer:innen</div>" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="Xmw1x83A06H2_JC6hK8s-17">
|
||||
<mxGeometry x="-0.0888" y="-2" relative="1" as="geometry">
|
||||
<mxPoint x="5" as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<object placeholders="1" c4Name="Visual Analytics Tool" c4Type="SystemScopeBoundary" c4Application="Software System" label="<font style="font-size: 16px"><b><div style="text-align: left">%c4Name%</div></b></font><div style="text-align: left">[%c4Application%]</div>" id="Xmw1x83A06H2_JC6hK8s-19">
|
||||
<mxCell style="rounded=1;fontSize=11;whiteSpace=wrap;html=1;dashed=1;arcSize=20;fillColor=none;strokeColor=#666666;fontColor=#333333;labelBackgroundColor=none;align=left;verticalAlign=bottom;labelBorderColor=none;spacingTop=0;spacing=10;dashPattern=8 4;metaEdit=1;rotatable=0;perimeter=rectanglePerimeter;noLabel=0;labelPadding=0;allowArrows=0;connectable=0;expand=0;recursiveResize=0;editable=1;pointerEvents=0;absoluteArcSize=1;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
|
||||
<mxGeometry x="20" y="210" width="1080" height="460" as="geometry" />
|
||||
</mxCell>
|
||||
</object>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
|
@ -1,4 +0,0 @@
|
|||
# How to run
|
||||
```bash
|
||||
fastapi dev api/main.py --port 8080
|
||||
```
|
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,7 @@
|
|||
[project]
|
||||
authors = [{name = "Giò Diani", email = "mail@gionathandiani.name"}, {name = "Mauro Stoffel", email = "mauro.stoffel@stud.fhgr.ch"}, {name = "Colin Bolli", email = "colin.bolli@stud.fhgr.ch"}, {name = "Charles Winkler", email = "charles.winkler@stud.fhgr.ch"}]
|
||||
description = "Datenauferbeitung"
|
||||
authors = [{name = "Giò Diani", email = "mail@gionathandiani.name"}]
|
||||
dependencies = []
|
||||
description = "Add a short description here"
|
||||
name = "consultancy_2"
|
||||
requires-python = ">= 3.11"
|
||||
version = "0.1.0"
|
||||
|
@ -24,6 +25,5 @@ pandas = ">=2.2.3,<3"
|
|||
plotly = ">=5.24.1,<6"
|
||||
duckdb = ">=1.1.2,<2"
|
||||
python-dotenv = ">=1.0.1,<2"
|
||||
fastapi = ">=0.115.4,<0.116"
|
||||
polars = ">=0.20.26,<2"
|
||||
pyarrow = ">=18.0.0,<19"
|
||||
|
|
|
@ -1,104 +0,0 @@
|
|||
import data
|
||||
import polars as pl
|
||||
from data import etl_property_capacities as etl_pc
|
||||
from data import etl_property_capacities_monthly as etl_pcm
|
||||
from data import etl_property_capacities_weekdays as etl_pcw
|
||||
from data import etl_property_neighbours as etl_pn
|
||||
from data import etl_region_capacities as etl_rc
|
||||
from data import etl_region_capacities_comparison as etl_rcc
|
||||
from data import etl_region_capacities_monthly as etl_rcm
|
||||
from data import etl_region_capacities_weekdays as etl_rcw
|
||||
from data import etl_region_movAverage as etl_rmA
|
||||
from data import etl_region_properties_capacities as etl_rpc
|
||||
from fastapi import FastAPI, Response
|
||||
|
||||
d = data.load()
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
@app.get("/")
|
||||
def read_root():
|
||||
return {"Hi there!"}
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int):
|
||||
ext = d.extractions_for(item_id).pl()
|
||||
out = ext.with_columns(pl.col("calendar").str.extract_all(r"([0-9]{4}-[0-9]{2}-[0-9]{2})|[0-2]").alias("calendar_data"))
|
||||
out = out.drop(['calendar', 'property_id'])
|
||||
return Response(content=out.write_json(), media_type="application/json")
|
||||
|
||||
@app.get("/region/properties")
|
||||
def properties_region():
|
||||
return d.properties_per_region().pl().to_dicts()
|
||||
|
||||
@app.get("/properties/growth")
|
||||
def properties_growth():
|
||||
options = {"dates" : d.properties_growth().pl()['date'].to_list(), "total_all" : d.properties_growth().pl()['total_all'].to_list(), "total_heidiland" : d.properties_growth().pl()['total_heidiland'].to_list(), "total_engadin" : d.properties_growth().pl()['total_engadin'].to_list(), "total_davos" : d.properties_growth().pl()['total_davos'].to_list(), "total_stmoritz" : d.properties_growth().pl()['total_stmoritz'].to_list()}
|
||||
return options
|
||||
|
||||
@app.get("/properties/geo")
|
||||
def properties_geo():
|
||||
return d.properties_geo().pl().to_dicts()
|
||||
|
||||
@app.get("/property/{id}/neighbours")
|
||||
def property_neighbours(id: int):
|
||||
capacities = etl_pn.property_neighbours(id)
|
||||
return capacities
|
||||
|
||||
@app.get("/property/{id}/extractions")
|
||||
def property_extractions(id: int):
|
||||
return d.extractions_for(property_id = id).pl().to_dicts()
|
||||
|
||||
@app.get("/property/{id}/capacities")
|
||||
def property_capacities_data(id: int):
|
||||
capacities = etl_pc.property_capacities(id)
|
||||
return capacities
|
||||
|
||||
@app.get("/property/{id}/capacities/monthly/{scrapeDate}")
|
||||
def property_capacities_data(id: int, scrapeDate: str):
|
||||
capacities = etl_pcm.property_capacities_monthly(id, scrapeDate)
|
||||
return capacities
|
||||
|
||||
@app.get("/property/{id}/capacities/weekdays/{scrapeDate}")
|
||||
def property_capacities_data(id: int, scrapeDate: str):
|
||||
capacities = etl_pcw.property_capacities_weekdays(id, scrapeDate)
|
||||
return capacities
|
||||
|
||||
@app.get("/property/{id}/base")
|
||||
def property_base_data(id: int):
|
||||
return d.property_base_data(id).pl().to_dicts()
|
||||
|
||||
@app.get("/region/{id}/properties/capacities")
|
||||
def region_property_capacities_data(id: int):
|
||||
capacities = etl_rpc.region_properties_capacities(id)
|
||||
return capacities
|
||||
|
||||
@app.get("/region/{id}/capacities")
|
||||
def region_capacities_data(id: int):
|
||||
capacities = etl_rc.region_capacities(id)
|
||||
return capacities
|
||||
|
||||
@app.get("/region/{id}/capacities/monthly/{scrapeDate}")
|
||||
def region_capacities_data(id: int, scrapeDate: str):
|
||||
capacities = etl_rcm.region_capacities_monthly(id, scrapeDate)
|
||||
return capacities
|
||||
|
||||
@app.get("/region/{id}/capacities/weekdays/{scrapeDate}")
|
||||
def region_capacities_data(id: int, scrapeDate: str):
|
||||
capacities = etl_rcw.region_capacities_weekdays(id, scrapeDate)
|
||||
return capacities
|
||||
|
||||
@app.get("/region/capacities/comparison/{id_1}/{id_2}")
|
||||
def region_capacities_data(id_1: int, id_2: int):
|
||||
capacities = etl_rcc.region_capacities_comparison(id_1, id_2)
|
||||
return capacities
|
||||
|
||||
@app.get("/region/{id}/movingAverage/{startDate}")
|
||||
def region_capacities_data(id: int, startDate: str):
|
||||
result = etl_rmA.region_movingAverage(id, startDate)
|
||||
return result
|
||||
|
||||
@app.get("/region/{id}/base")
|
||||
def region_base_data(id: int):
|
||||
return d.region_base_data(id).pl().to_dicts()
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
from typing import Union
|
||||
|
||||
import polars as pl
|
||||
from fastapi import FastAPI, Response
|
||||
|
||||
import data
|
||||
|
||||
d = data.load()
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/")
|
||||
def read_root():
|
||||
return {"Hello": "World"}
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int):
|
||||
ext = d.extractions_for(item_id).pl()
|
||||
out = ext.with_columns(pl.col("calendar").str.extract_all(r"([0-9]{4}-[0-9]{2}-[0-9]{2})|[0-2]").alias("calendar_data"))
|
||||
out = out.drop(['calendar', 'property_id'])
|
||||
return Response(content=out.write_json(), media_type="application/json")
|
|
@ -28,6 +28,8 @@ class Database:
|
|||
if(spatial_installed and not spatial_installed[0]):
|
||||
self.connection.sql("INSTALL spatial")
|
||||
|
||||
|
||||
|
||||
def db_overview(self):
|
||||
return self.connection.sql("DESCRIBE;").show()
|
||||
|
||||
|
@ -44,100 +46,19 @@ class Database:
|
|||
|
||||
def properties_growth(self):
|
||||
return self.connection.sql("""
|
||||
WITH PropertiesALL AS (
|
||||
SELECT
|
||||
strftime(created_at, '%Y-%m-%d') AS date,
|
||||
COUNT(*) as properties_count,
|
||||
SUM(properties_count) OVER (ORDER BY date) AS total
|
||||
FROM
|
||||
consultancy_d.properties p
|
||||
GROUP BY
|
||||
date
|
||||
ORDER BY
|
||||
date
|
||||
),
|
||||
PropertiesR1 AS (
|
||||
SELECT
|
||||
strftime(created_at, '%Y-%m-%d') AS date,
|
||||
COUNT(*) as properties_count,
|
||||
SUM(properties_count) OVER (ORDER BY date) AS total
|
||||
FROM
|
||||
consultancy_d.properties p
|
||||
WHERE
|
||||
p.seed_id = 1
|
||||
GROUP BY
|
||||
date
|
||||
ORDER BY
|
||||
date
|
||||
),
|
||||
PropertiesR2 AS (
|
||||
SELECT
|
||||
strftime(created_at, '%Y-%m-%d') AS date,
|
||||
COUNT(*) as properties_count,
|
||||
SUM(properties_count) OVER (ORDER BY date) AS total
|
||||
FROM
|
||||
consultancy_d.properties p
|
||||
WHERE
|
||||
p.seed_id = 2
|
||||
GROUP BY
|
||||
date
|
||||
ORDER BY
|
||||
date
|
||||
),
|
||||
PropertiesR3 AS (
|
||||
SELECT
|
||||
strftime(created_at, '%Y-%m-%d') AS date,
|
||||
COUNT(*) as properties_count,
|
||||
SUM(properties_count) OVER (ORDER BY date) AS total
|
||||
FROM
|
||||
consultancy_d.properties p
|
||||
WHERE
|
||||
p.seed_id = 3
|
||||
GROUP BY
|
||||
date
|
||||
ORDER BY
|
||||
date
|
||||
),
|
||||
PropertiesR4 AS (
|
||||
SELECT
|
||||
strftime(created_at, '%Y-%m-%d') AS date,
|
||||
COUNT(*) as properties_count,
|
||||
SUM(properties_count) OVER (ORDER BY date) AS total
|
||||
FROM
|
||||
consultancy_d.properties p
|
||||
WHERE
|
||||
p.seed_id = 4
|
||||
GROUP BY
|
||||
date
|
||||
ORDER BY
|
||||
date
|
||||
)
|
||||
SELECT
|
||||
p.date,
|
||||
p.total AS total_all,
|
||||
pR1.total as total_heidiland,
|
||||
pR2.total AS total_davos,
|
||||
pR3.total AS total_engadin,
|
||||
pR4.total AS total_stmoritz
|
||||
strftime(created_at, '%Y-%m-%d') AS date,
|
||||
COUNT(*) as properties_count
|
||||
FROM
|
||||
PropertiesAll p
|
||||
LEFT JOIN
|
||||
PropertiesR1 pR1 ON p.date = pR1.date
|
||||
LEFT JOIN
|
||||
PropertiesR2 pR2 ON p.date = pR2.date
|
||||
LEFT JOIN
|
||||
PropertiesR3 pR3 ON p.date = pR3.date
|
||||
LEFT JOIN
|
||||
PropertiesR4 pR4 ON p.date = pR4.date
|
||||
ORDER BY
|
||||
p.date
|
||||
consultancy_d.properties
|
||||
GROUP BY
|
||||
date;
|
||||
""")
|
||||
|
||||
def properties_per_region(self):
|
||||
return self.connection.sql("""
|
||||
SELECT
|
||||
regions.name,
|
||||
regions.id,
|
||||
COUNT(*) AS count_properties
|
||||
FROM
|
||||
consultancy_d.properties
|
||||
|
@ -147,22 +68,7 @@ class Database:
|
|||
consultancy_d.regions ON regions.id = seeds.region_id
|
||||
GROUP BY
|
||||
properties.seed_id,
|
||||
regions.name,
|
||||
regions.id
|
||||
ORDER BY
|
||||
count_properties ASC
|
||||
""")
|
||||
|
||||
def propIds_with_region(self):
|
||||
return self.connection.sql("""
|
||||
SELECT
|
||||
properties.id, seed_id, regions.name
|
||||
FROM
|
||||
consultancy_d.properties
|
||||
LEFT JOIN
|
||||
consultancy_d.seeds ON seeds.id = properties.seed_id
|
||||
LEFT JOIN
|
||||
consultancy_d.regions ON regions.id = seeds.region_id
|
||||
regions.name
|
||||
""")
|
||||
|
||||
def properties_unreachable(self):
|
||||
|
@ -290,7 +196,7 @@ class Database:
|
|||
""")
|
||||
|
||||
def extractions(self):
|
||||
return self.connection.sql("""
|
||||
return self.connection.sql(f"""
|
||||
SELECT
|
||||
JSON_EXTRACT(body, '$.content.days') as calendar,
|
||||
property_id,
|
||||
|
@ -303,54 +209,19 @@ class Database:
|
|||
property_id
|
||||
""")
|
||||
|
||||
def extractions_with_region(self):
|
||||
return self.connection.sql("""
|
||||
SELECT
|
||||
JSON_EXTRACT(body, '$.content.days') as calendar,
|
||||
extractions.property_id,
|
||||
extractions.created_at,
|
||||
properties.seed_id,
|
||||
regions.name
|
||||
FROM
|
||||
consultancy_d.extractions
|
||||
LEFT JOIN
|
||||
consultancy_d.properties ON properties.id = extractions.property_id
|
||||
LEFT JOIN
|
||||
consultancy_d.seeds ON seeds.id = properties.seed_id
|
||||
LEFT JOIN
|
||||
consultancy_d.regions ON regions.id = seeds.region_id
|
||||
""")
|
||||
|
||||
def extractions_for(self, property_id):
|
||||
return self.connection.sql(f"""
|
||||
SELECT
|
||||
JSON_EXTRACT(body, '$.content.days') as calendar,
|
||||
property_id,
|
||||
created_at
|
||||
FROM
|
||||
consultancy_d.extractions
|
||||
WHERE
|
||||
type == 'calendar' AND
|
||||
property_id = {property_id} AND
|
||||
calendar NOT NULL
|
||||
property_id = {property_id}
|
||||
ORDER BY
|
||||
created_at
|
||||
""")
|
||||
|
||||
def extractions_propId_scrapeDate(self, property_id: int, scrape_date: str):
|
||||
return self.connection.sql(f"""
|
||||
SELECT
|
||||
JSON_EXTRACT(body, '$.content.days') as calendar,
|
||||
created_at
|
||||
FROM
|
||||
consultancy_d.extractions
|
||||
WHERE
|
||||
type == 'calendar' AND
|
||||
property_id = {property_id} AND
|
||||
calendar NOT NULL AND
|
||||
created_at >= '{scrape_date}'
|
||||
ORDER BY
|
||||
created_at
|
||||
LIMIT 1
|
||||
property_id
|
||||
""")
|
||||
|
||||
# Anzahl der extrahierten properties pro Exktraktionsvorgang
|
||||
|
@ -396,172 +267,3 @@ class Database:
|
|||
ORDER BY property_id
|
||||
""")
|
||||
|
||||
def property_base_data(self, id):
|
||||
return self.connection.sql(f"""
|
||||
SELECT
|
||||
p.property_platform_id,
|
||||
p.created_at as first_found,
|
||||
p.last_found,
|
||||
p.check_data,
|
||||
r.id as region_id,
|
||||
r.name as region_name
|
||||
FROM
|
||||
consultancy_d.properties p
|
||||
INNER JOIN consultancy_d.seeds s ON s.id = p.seed_id
|
||||
INNER JOIN consultancy_d.regions r ON s.region_id = r.id
|
||||
WHERE
|
||||
p.id = {id}
|
||||
""")
|
||||
|
||||
def region_base_data(self, id):
|
||||
if id == -1:
|
||||
where = ''
|
||||
else:
|
||||
where = f"WHERE r.id = {id}"
|
||||
return self.connection.sql(f"""
|
||||
SELECT
|
||||
r.id as region_id,
|
||||
r.name as region_name
|
||||
FROM
|
||||
consultancy_d.regions r
|
||||
{where}
|
||||
""")
|
||||
|
||||
def properties_geo(self):
|
||||
return self.connection.sql("""
|
||||
SELECT
|
||||
p.id as property_id,
|
||||
p.check_data as latlng,
|
||||
r.id as region_id
|
||||
FROM
|
||||
consultancy_d.properties p
|
||||
LEFT JOIN
|
||||
consultancy_d.seeds s ON s.id = p.seed_id
|
||||
LEFT JOIN
|
||||
consultancy_d.regions r ON r.id = s.region_id
|
||||
""")
|
||||
|
||||
def properties_geo_seeds(self):
|
||||
return self.connection.sql("""
|
||||
SELECT
|
||||
p.id,
|
||||
p.seed_id,
|
||||
p.check_data as coordinates
|
||||
FROM
|
||||
consultancy_d.properties p
|
||||
""")
|
||||
|
||||
def capacity_of_region(self, region_id):
|
||||
return self.connection.sql(f"""
|
||||
SELECT
|
||||
JSON_EXTRACT(body, '$.content.days') as calendarBody,
|
||||
strftime(extractions.created_at, '%Y-%m-%d') AS ScrapeDate,
|
||||
extractions.property_id,
|
||||
FROM
|
||||
consultancy_d.extractions
|
||||
LEFT JOIN
|
||||
consultancy_d.properties ON properties.id = extractions.property_id
|
||||
WHERE
|
||||
type == 'calendar' AND
|
||||
properties.seed_id = {region_id}
|
||||
""")
|
||||
|
||||
def singleScrape_of_region(self, region_id: int, scrape_date_min: str, scrape_date_max: str):
|
||||
return self.connection.sql(f"""
|
||||
SELECT
|
||||
JSON_EXTRACT(body, '$.content.days') as calendarBody,
|
||||
FROM
|
||||
consultancy_d.extractions
|
||||
LEFT JOIN
|
||||
consultancy_d.properties ON properties.id = extractions.property_id
|
||||
WHERE
|
||||
type == 'calendar' AND
|
||||
properties.seed_id = {region_id} AND
|
||||
extractions.created_at >= '{scrape_date_min}' AND
|
||||
extractions.created_at < '{scrape_date_max}'
|
||||
""")
|
||||
|
||||
def singleScrape_of_global(self, scrape_date_min: str, scrape_date_max: str):
|
||||
return self.connection.sql(f"""
|
||||
SELECT
|
||||
JSON_EXTRACT(body, '$.content.days') as calendarBody,
|
||||
FROM
|
||||
consultancy_d.extractions
|
||||
LEFT JOIN
|
||||
consultancy_d.properties ON properties.id = extractions.property_id
|
||||
WHERE
|
||||
type == 'calendar' AND
|
||||
extractions.created_at >= '{scrape_date_min}' AND
|
||||
extractions.created_at < '{scrape_date_max}'
|
||||
""")
|
||||
|
||||
def singleScrape_of_region_scrapDate(self, region_id: int, scrape_date_min: str, scrape_date_max: str):
|
||||
return self.connection.sql(f"""
|
||||
SELECT
|
||||
JSON_EXTRACT(body, '$.content.days') as calendarBody,
|
||||
extractions.created_at
|
||||
FROM
|
||||
consultancy_d.extractions
|
||||
LEFT JOIN
|
||||
consultancy_d.properties ON properties.id = extractions.property_id
|
||||
WHERE
|
||||
type == 'calendar' AND
|
||||
properties.seed_id = {region_id} AND
|
||||
extractions.created_at >= '{scrape_date_min}' AND
|
||||
extractions.created_at < '{scrape_date_max}'
|
||||
""")
|
||||
|
||||
def singleScrape_of_global_scrapDate(self, scrape_date_min: str, scrape_date_max: str):
|
||||
return self.connection.sql(f"""
|
||||
SELECT
|
||||
JSON_EXTRACT(body, '$.content.days') as calendarBody,
|
||||
extractions.created_at
|
||||
FROM
|
||||
consultancy_d.extractions
|
||||
LEFT JOIN
|
||||
consultancy_d.properties ON properties.id = extractions.property_id
|
||||
WHERE
|
||||
type == 'calendar' AND
|
||||
extractions.created_at >= '{scrape_date_min}' AND
|
||||
extractions.created_at < '{scrape_date_max}'
|
||||
""")
|
||||
|
||||
def capacity_global(self):
|
||||
return self.connection.sql(f"""
|
||||
SELECT
|
||||
JSON_EXTRACT(body, '$.content.days') as calendarBody,
|
||||
strftime(extractions.created_at, '%Y-%m-%d') AS ScrapeDate,
|
||||
extractions.property_id,
|
||||
FROM
|
||||
consultancy_d.extractions
|
||||
LEFT JOIN
|
||||
consultancy_d.properties ON properties.id = extractions.property_id
|
||||
WHERE
|
||||
type == 'calendar'
|
||||
""")
|
||||
|
||||
def capacity_comparison_of_region(self, region_id_1, region_id_2):
|
||||
return self.connection.sql(f"""
|
||||
SELECT
|
||||
JSON_EXTRACT(body, '$.content.days') as calendarBody,
|
||||
strftime(extractions.created_at, '%Y-%m-%d') AS ScrapeDate,
|
||||
extractions.property_id,
|
||||
properties.seed_id
|
||||
FROM
|
||||
consultancy_d.extractions
|
||||
LEFT JOIN
|
||||
consultancy_d.properties ON properties.id = extractions.property_id
|
||||
WHERE
|
||||
type == 'calendar' AND
|
||||
(properties.seed_id = {region_id_1} OR
|
||||
properties.seed_id = {region_id_2})
|
||||
""")
|
||||
|
||||
def unique_scrapeDates(self):
|
||||
return self.connection.sql(f"""
|
||||
SELECT DISTINCT
|
||||
strftime(extractions.created_at, '%Y-%m-%d') AS ScrapeDate,
|
||||
FROM
|
||||
consultancy_d.extractions
|
||||
""")
|
||||
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
from pathlib import Path
|
||||
from pickle import dump, load
|
||||
|
||||
Path('cache').mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# load pickle obj
|
||||
def openObj(file):
|
||||
filepath = Path(f"cache/{file}")
|
||||
if filepath.is_file():
|
||||
with open(filepath, 'rb') as f:
|
||||
return load(f)
|
||||
return False
|
||||
|
||||
# save pickle obj
|
||||
def saveObj(file, result):
|
||||
filepath = Path(f"cache/{file}")
|
||||
with open(filepath, 'wb') as f:
|
||||
dump(result, f)
|
|
@ -23,6 +23,7 @@ def expansion_Pipeline(df):
|
|||
df = pl.DataFrame(data, schema=["property_id", "created_at", "calendar_date", "calendar_value"])
|
||||
return df
|
||||
|
||||
|
||||
def liveDates_Pipeline(df):
|
||||
'''
|
||||
Returns the expanded Dataframe with only the live data and no future data
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
from io import StringIO
|
||||
|
||||
import polars as pl
|
||||
|
||||
import data
|
||||
from data import etl_cache
|
||||
|
||||
d = data.load()
|
||||
|
||||
def property_capacities(id: int):
|
||||
|
||||
file = f"etl_property_capacities_{id}.obj"
|
||||
obj = etl_cache.openObj(file)
|
||||
if obj:
|
||||
return obj
|
||||
|
||||
extractions = d.extractions_for(id).pl()
|
||||
df_dates = pl.DataFrame()
|
||||
|
||||
for row in extractions.rows(named=True):
|
||||
df_calendar = pl.read_json(StringIO(row['calendar']))
|
||||
#df_calendar.insert_column(0, pl.Series("created_at", [row['created_at']]))
|
||||
df_dates = pl.concat([df_calendar, df_dates], how="diagonal")
|
||||
|
||||
# order = sorted(df_dates.columns)
|
||||
# df_dates = df_dates.select(order)
|
||||
sum_hor = df_dates.sum_horizontal()
|
||||
#print(sum_hor)
|
||||
# Get the available dates per extraction
|
||||
count_days = []
|
||||
for dates in df_dates.rows():
|
||||
# Remove all None values
|
||||
liste = [x for x in dates if x is not None]
|
||||
count_days.append(len(liste))
|
||||
|
||||
counts = pl.DataFrame({"count_days" : count_days, "sum" : sum_hor})
|
||||
result = {"capacities": [], "dates": extractions['created_at'].cast(pl.Date).to_list() }
|
||||
|
||||
for row in counts.rows(named=True):
|
||||
max_capacity = row['count_days'] * 2
|
||||
max_capacity_perc = 100 / max_capacity
|
||||
result['capacities'].append(round(max_capacity_perc * row['sum'], 2))
|
||||
result['capacities'].reverse()
|
||||
|
||||
etl_cache.saveObj(file, result)
|
||||
return result
|
|
@ -1,35 +0,0 @@
|
|||
from io import StringIO
|
||||
|
||||
import polars as pl
|
||||
|
||||
import data
|
||||
from data import etl_cache
|
||||
|
||||
d = data.load()
|
||||
|
||||
def property_capacities_monthly(id: int, scrapeDate: str):
|
||||
|
||||
file = f"etl_property_capacities_monthly_{id}_{scrapeDate}.obj"
|
||||
obj = etl_cache.openObj(file)
|
||||
if obj:
|
||||
return obj
|
||||
|
||||
extractions = d.extractions_propId_scrapeDate(id, scrapeDate).pl()
|
||||
df_calendar = pl.DataFrame()
|
||||
|
||||
for row in extractions.rows(named=True):
|
||||
scrapeDate = row['created_at']
|
||||
df_calendar = pl.read_json(StringIO(row['calendar']))
|
||||
columnTitles = df_calendar.columns
|
||||
df_calendar = df_calendar.transpose()
|
||||
df_calendar = df_calendar.with_columns(pl.Series(name="dates", values=columnTitles))
|
||||
df_calendar = df_calendar.with_columns((pl.col("dates").str.to_date()))
|
||||
df_calendar = df_calendar.with_columns((pl.col("dates").dt.strftime("%b") + " " + (pl.col("dates").dt.strftime("%Y"))).alias('date_short'))
|
||||
df_calendar = df_calendar.with_columns((pl.col("dates").dt.strftime("%Y") + " " + (pl.col("dates").dt.strftime("%m"))).alias('dates'))
|
||||
|
||||
df_calendar = df_calendar.group_by(['dates', 'date_short']).agg(pl.col("column_0").sum())
|
||||
df_calendar = df_calendar.sort('dates')
|
||||
df_calendar = df_calendar.drop('dates')
|
||||
result = {"scraping-date": scrapeDate, "months": df_calendar['date_short'].to_list(), 'capacities': df_calendar['column_0'].to_list()}
|
||||
etl_cache.saveObj(file, result)
|
||||
return result
|
|
@ -1,41 +0,0 @@
|
|||
from io import StringIO
|
||||
|
||||
import polars as pl
|
||||
|
||||
import data
|
||||
from data import etl_cache
|
||||
|
||||
d = data.load()
|
||||
|
||||
def property_capacities_weekdays(id: int, scrapeDate: str):
|
||||
|
||||
file = f"etl_property_capacities_weekdays_{id}_{scrapeDate}.obj"
|
||||
obj = etl_cache.openObj(file)
|
||||
if obj:
|
||||
return obj
|
||||
|
||||
extractions = d.extractions_propId_scrapeDate(id, scrapeDate).pl()
|
||||
weekdays = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
|
||||
df_calendar = pl.DataFrame()
|
||||
numWeeks = 0
|
||||
|
||||
for row in extractions.rows(named=True):
|
||||
scrapeDate = row['created_at']
|
||||
df_calendar = pl.read_json(StringIO(row['calendar']))
|
||||
columnTitles = df_calendar.columns
|
||||
df_calendar = df_calendar.transpose()
|
||||
df_calendar = df_calendar.with_columns(pl.Series(name="dates", values=columnTitles))
|
||||
df_calendar = df_calendar.with_columns((pl.col("dates").str.to_date()))
|
||||
numWeeks = round((df_calendar.get_column("dates").max() - df_calendar.get_column("dates").min()).days / 7, 0)
|
||||
df_calendar = df_calendar.with_columns(pl.col("dates").dt.weekday().alias("weekday_num"))
|
||||
df_calendar = df_calendar.with_columns(pl.col("dates").dt.strftime("%A").alias("weekday"))
|
||||
df_calendar = df_calendar.drop("dates")
|
||||
|
||||
df_calendar = df_calendar.group_by(["weekday", "weekday_num"]).agg(pl.col("column_0").sum())
|
||||
df_calendar = df_calendar.with_columns((pl.col("column_0") / numWeeks / 2 * 100).alias("column_0"))
|
||||
df_calendar = df_calendar.sort('weekday_num')
|
||||
df_calendar = df_calendar.drop('weekday_num')
|
||||
|
||||
result = {"scraping-date": scrapeDate, "weekdays": df_calendar['weekday'].to_list(), 'capacities': df_calendar['column_0'].to_list()}
|
||||
etl_cache.saveObj(file, result)
|
||||
return result
|
|
@ -1,74 +0,0 @@
|
|||
from math import asin, atan2, cos, degrees, radians, sin, sqrt
|
||||
|
||||
import polars as pl
|
||||
|
||||
import data
|
||||
from data import etl_cache
|
||||
|
||||
d = data.load()
|
||||
|
||||
|
||||
def calcHaversinDistance(latMain, lonMain, lat, lon):
|
||||
R = 6371
|
||||
|
||||
# convert decimal degrees to radians
|
||||
latMain, lonMain, lat, lon = map(radians, [latMain, lonMain, lat, lon])
|
||||
|
||||
# haversine formula
|
||||
dlon = lonMain - lon
|
||||
dlat = latMain - lat
|
||||
|
||||
a = sin(dlat / 2) ** 2 + cos(lat) * cos(latMain) * sin(dlon / 2) ** 2
|
||||
c = 2 * asin(sqrt(a)) # 2 * atan2(sqrt(a), sqrt(1-a))
|
||||
d = R * c
|
||||
|
||||
return d
|
||||
|
||||
def property_neighbours(id: int):
|
||||
|
||||
file = f"etl_property_neighbours_{id}.obj"
|
||||
obj = etl_cache.openObj(file)
|
||||
if obj:
|
||||
return obj
|
||||
|
||||
extractions = d.properties_geo_seeds().pl()
|
||||
|
||||
# Get lat, long and region from main property
|
||||
latMain, lonMain = extractions.filter(pl.col('id') == str(id))['coordinates'][0].split(',')
|
||||
latMain, lonMain = map(float, [latMain, lonMain])
|
||||
region = extractions.filter(pl.col('id') == str(id))['seed_id'][0]
|
||||
|
||||
# Prefilter the dataframe to only the correct region
|
||||
extractions = extractions.filter(pl.col('seed_id') == str(region))
|
||||
extractions = extractions.drop('seed_id')
|
||||
|
||||
# Remove main property from DF
|
||||
extractions = extractions.filter(pl.col('id') != str(id))
|
||||
|
||||
# Split coordinate into lat and lon
|
||||
#extractions = extractions.with_columns((pl.col('coordinates').str.split(','))[0].alias("coordinates")).unnest("fields")
|
||||
extractions = extractions.with_columns(pl.col("coordinates").str.split_exact(",", 1).struct.rename_fields(["lat", "lon"]).alias("lat/lon")).unnest("lat/lon")
|
||||
extractions = extractions.drop('coordinates')
|
||||
extractions = extractions.with_columns(pl.col("lat").cast(pl.Float32))
|
||||
extractions = extractions.with_columns(pl.col("lon").cast(pl.Float32))
|
||||
|
||||
# Calculate distances
|
||||
distances = []
|
||||
for row in extractions.rows(named=True):
|
||||
lat = row['lat']
|
||||
lon = row['lon']
|
||||
dist = calcHaversinDistance(latMain, lonMain, lat, lon)
|
||||
distances.append(dist)
|
||||
|
||||
# Add distance to DF
|
||||
extractions = extractions.with_columns(pl.Series(name="distances", values=distances))
|
||||
|
||||
# Sort for distance and give only first 10
|
||||
extractions = extractions.sort("distances").head(10)
|
||||
extractions = extractions.drop('distances')
|
||||
|
||||
#result = {"ids": extractions['id'].to_list(), "lat": extractions['lat'].to_list(), "lon": extractions['lon'].to_list()}
|
||||
result = extractions.to_dicts()
|
||||
etl_cache.saveObj(file, result)
|
||||
|
||||
return result
|
|
@ -1,58 +0,0 @@
|
|||
from datetime import date
|
||||
from io import StringIO
|
||||
|
||||
import polars as pl
|
||||
|
||||
import data
|
||||
from data import etl_cache
|
||||
|
||||
d = data.load()
|
||||
|
||||
def region_capacities(id: int):
|
||||
|
||||
file = f"etl_region_capacities_{id}.obj"
|
||||
obj = etl_cache.openObj(file)
|
||||
if obj:
|
||||
return obj
|
||||
|
||||
# Get Data
|
||||
if id == -1:
|
||||
extractions = d.capacity_global().pl()
|
||||
else:
|
||||
extractions = d.capacity_of_region(id).pl()
|
||||
# turn PropertyIDs to ints for sorting
|
||||
extractions = extractions.cast({"property_id": int})
|
||||
|
||||
extractions.drop('property_id')
|
||||
df_dates = pl.DataFrame()
|
||||
|
||||
# Get Data from JSON
|
||||
gridData = pl.DataFrame(schema=[("scrape_date", pl.String), ("sum_hor", pl.Int64), ("calendar_width", pl.Int64)])
|
||||
dayCounts = []
|
||||
for row in extractions.rows(named=True):
|
||||
# Return 0 for sum if calendar is null
|
||||
if row['calendarBody']:
|
||||
calDF = pl.read_json(StringIO(row['calendarBody']))
|
||||
sum_hor = calDF.sum_horizontal()[0]
|
||||
else:
|
||||
sum_hor = 0
|
||||
gridData = gridData.vstack(pl.DataFrame({"scrape_date" : row['ScrapeDate'], "sum_hor": sum_hor, "calendar_width": calDF.width}))
|
||||
|
||||
# Create Aggregates of values
|
||||
df_count = gridData.group_by("scrape_date").agg(pl.col("sum_hor").count())
|
||||
df_sum = gridData.group_by("scrape_date").agg(pl.col("sum_hor").sum())
|
||||
df_numDays = gridData.group_by("scrape_date").agg(pl.col("calendar_width").max())
|
||||
|
||||
# Join and rename DF's
|
||||
df = df_sum.join(df_count, on= 'scrape_date').join(df_numDays, on= 'scrape_date')
|
||||
|
||||
# Calculate normed capacities for each scrapeDate
|
||||
df = df.with_columns((pl.col("sum_hor") / pl.col("sum_hor_right") / (pl.col("calendar_width")*2) * 100).alias("capacity"))
|
||||
|
||||
# Sort the date column
|
||||
df = df.cast({"scrape_date": date}).sort('scrape_date')
|
||||
|
||||
result = {"capacities": df['capacity'].to_list(), "dates": df['scrape_date'].to_list()}
|
||||
|
||||
etl_cache.saveObj(file, result)
|
||||
return result
|
|
@ -1,65 +0,0 @@
|
|||
import data
|
||||
import polars as pl
|
||||
from io import StringIO
|
||||
import numpy as np
|
||||
|
||||
|
||||
d = data.load()
|
||||
|
||||
def region_capacities_comparison(id_1: int, id_2: int):
|
||||
fulldf = d.capacity_comparison_of_region(id_1, id_2).pl()
|
||||
# turn PropertyIDs and seedIDs to ints for sorting and filtering
|
||||
fulldf = fulldf.cast({"property_id": int})
|
||||
fulldf = fulldf.cast({"seed_id": int})
|
||||
df_region1 = fulldf.filter(pl.col("seed_id") == id_1)
|
||||
df_region2 = fulldf.filter(pl.col("seed_id") == id_2)
|
||||
df_list = [df_region1, df_region2]
|
||||
outDictList = []
|
||||
|
||||
for df in df_list:
|
||||
# Get uniques for dates and propIDs and sort them
|
||||
listOfDates = df.get_column("ScrapeDate").unique().sort()
|
||||
listOfPropertyIDs = df.get_column("property_id").unique().sort()
|
||||
|
||||
# Create DFs from lists to merge later
|
||||
datesDF = pl.DataFrame(listOfDates).with_row_index("date_index")
|
||||
propIdDF = pl.DataFrame(listOfPropertyIDs).with_row_index("prop_index")
|
||||
|
||||
# Merge Dataframe to generate indices
|
||||
df = df.join(datesDF, on='ScrapeDate')
|
||||
df = df.join(propIdDF, on='property_id')
|
||||
# Drop now useless columns ScrapeDate and property_id
|
||||
df = df[['ScrapeDate', 'calendarBody', 'date_index', 'prop_index']]
|
||||
# Calculate grid values
|
||||
gridData = []
|
||||
for row in df.rows(named=True):
|
||||
# Return 0 for sum if calendar is null
|
||||
if row['calendarBody']:
|
||||
calDF = pl.read_json(StringIO(row['calendarBody']))
|
||||
sum_hor = calDF.sum_horizontal()[0]
|
||||
else:
|
||||
sum_hor = 0
|
||||
# With Index
|
||||
# gridData.append([row['prop_index'], row['date_index'], sum_hor])
|
||||
# With ScrapeDate
|
||||
gridData.append([row['ScrapeDate'], row['date_index'], sum_hor])
|
||||
|
||||
gridData = np.array(gridData)
|
||||
# get all values to calculate Max
|
||||
allValues = gridData[:, 2].astype(int)
|
||||
maxValue = np.max(allValues)
|
||||
gridData[:, 2] = (allValues*100)/maxValue
|
||||
|
||||
# Return back to list
|
||||
gridData = gridData.tolist()
|
||||
|
||||
# Cast listOfDates to datetime
|
||||
listOfDates = listOfDates.cast(pl.Date).to_list()
|
||||
listOfPropertyIDs = listOfPropertyIDs.to_list()
|
||||
|
||||
# Create JSON
|
||||
tempDict = {'scrapeDates': listOfDates, 'property_ids': listOfPropertyIDs, 'values': gridData}
|
||||
outDictList.append(tempDict)
|
||||
|
||||
outDict = {'region1': outDictList[0], 'region2': outDictList[1],}
|
||||
return outDict
|
|
@ -1,65 +0,0 @@
|
|||
from datetime import datetime, timedelta
|
||||
from io import StringIO
|
||||
|
||||
import polars as pl
|
||||
|
||||
import data
|
||||
from data import etl_cache
|
||||
|
||||
d = data.load()
|
||||
|
||||
|
||||
def region_capacities_monthly(id: int, scrapeDate_start: str):
|
||||
|
||||
file = f"etl_region_capacities_monthly_{id}_{scrapeDate_start}.obj"
|
||||
obj = etl_cache.openObj(file)
|
||||
if obj:
|
||||
return obj
|
||||
|
||||
# String to Date
|
||||
scrapeDate_start = datetime.strptime(scrapeDate_start, '%Y-%m-%d')
|
||||
|
||||
# Get end date of start search-window
|
||||
scrapeDate_end = scrapeDate_start + timedelta(days=1)
|
||||
|
||||
# Get Data
|
||||
if id == -1:
|
||||
extractions = d.singleScrape_of_global_scrapDate(scrapeDate_start, scrapeDate_end).pl()
|
||||
else:
|
||||
extractions = d.singleScrape_of_region_scrapDate(id, scrapeDate_start, scrapeDate_end).pl()
|
||||
|
||||
df_calendar = pl.DataFrame()
|
||||
numWeeks = 0
|
||||
firstExe = True
|
||||
counter = 0
|
||||
for row in extractions.rows(named=True):
|
||||
scrapeDate = row['created_at']
|
||||
if row['calendarBody']:
|
||||
counter += 1
|
||||
df_calendar = pl.read_json(StringIO(row['calendarBody']))
|
||||
columnTitles = df_calendar.columns
|
||||
df_calendar = df_calendar.transpose()
|
||||
df_calendar = df_calendar.with_columns(pl.Series(name="dates", values=columnTitles))
|
||||
df_calendar = df_calendar.with_columns((pl.col("dates").str.to_date()))
|
||||
df_calendar = df_calendar.with_columns((pl.col("dates").dt.strftime("%b") + " " + (pl.col("dates").dt.strftime("%Y"))).alias('date_short'))
|
||||
df_calendar = df_calendar.with_columns((pl.col("dates").dt.strftime("%Y") + " " + (pl.col("dates").dt.strftime("%m"))).alias('dates'))
|
||||
df_calendar = df_calendar.group_by(['dates', 'date_short']).agg(pl.col("column_0").sum())
|
||||
df_calendar = df_calendar.sort('dates')
|
||||
df_calendar = df_calendar.drop('dates')
|
||||
|
||||
df_calendar = df_calendar.rename({'column_0': str(counter)})
|
||||
|
||||
if firstExe:
|
||||
outDf = df_calendar
|
||||
firstExe = False
|
||||
else:
|
||||
outDf = outDf.join(df_calendar, on='date_short')
|
||||
|
||||
# Calculate horizontal Mean
|
||||
means = outDf.mean_horizontal()
|
||||
outDf = outDf.insert_column(1, means)
|
||||
outDf = outDf[['date_short', 'mean']]
|
||||
|
||||
result = {"scraping-date": scrapeDate, "months": outDf['date_short'].to_list(),'capacities': outDf['mean'].to_list()}
|
||||
etl_cache.saveObj(file, result)
|
||||
return result
|
|
@ -1,67 +0,0 @@
|
|||
from datetime import datetime, timedelta
|
||||
from io import StringIO
|
||||
|
||||
import polars as pl
|
||||
|
||||
import data
|
||||
from data import etl_cache
|
||||
|
||||
d = data.load()
|
||||
|
||||
def region_capacities_weekdays(id: int, scrapeDate_start: str):
|
||||
|
||||
file = f"etl_region_capacities_weekdays_{id}_{scrapeDate_start}.obj"
|
||||
obj = etl_cache.openObj(file)
|
||||
if obj:
|
||||
return obj
|
||||
|
||||
# String to Date
|
||||
scrapeDate_start = datetime.strptime(scrapeDate_start, '%Y-%m-%d')
|
||||
|
||||
# Get end date of start search-window
|
||||
scrapeDate_end = scrapeDate_start + timedelta(days=1)
|
||||
|
||||
# Get Data
|
||||
if id == -1:
|
||||
extractions = d.singleScrape_of_global_scrapDate(scrapeDate_start, scrapeDate_end).pl()
|
||||
else:
|
||||
extractions = d.singleScrape_of_region_scrapDate(id, scrapeDate_start, scrapeDate_end).pl()
|
||||
|
||||
df_calendar = pl.DataFrame()
|
||||
numWeeks = 0
|
||||
firstExe = True
|
||||
counter = 0
|
||||
for row in extractions.rows(named=True):
|
||||
scrapeDate = row['created_at']
|
||||
if row['calendarBody']:
|
||||
counter += 1
|
||||
df_calendar = pl.read_json(StringIO(row['calendarBody']))
|
||||
columnTitles = df_calendar.columns
|
||||
df_calendar = df_calendar.transpose()
|
||||
df_calendar = df_calendar.with_columns(pl.Series(name="dates", values=columnTitles))
|
||||
df_calendar = df_calendar.with_columns((pl.col("dates").str.to_date()))
|
||||
numWeeks = round((df_calendar.get_column("dates").max() - df_calendar.get_column("dates").min()).days / 7, 0)
|
||||
df_calendar = df_calendar.with_columns(pl.col("dates").dt.weekday().alias("weekday_num"))
|
||||
df_calendar = df_calendar.with_columns(pl.col("dates").dt.strftime("%A").alias("weekday"))
|
||||
df_calendar = df_calendar.drop("dates")
|
||||
|
||||
df_calendar = df_calendar.group_by(["weekday", "weekday_num"]).agg(pl.col("column_0").sum())
|
||||
df_calendar = df_calendar.with_columns((pl.col("column_0") / numWeeks / 2 * 100).alias("column_0"))
|
||||
df_calendar = df_calendar.sort('weekday_num')
|
||||
df_calendar = df_calendar.drop('weekday_num')
|
||||
df_calendar = df_calendar.rename({'column_0': str(counter)})
|
||||
|
||||
if firstExe:
|
||||
outDf = df_calendar
|
||||
firstExe = False
|
||||
else:
|
||||
outDf = outDf.join(df_calendar, on='weekday')
|
||||
|
||||
# Calculate horizontal Mean
|
||||
means = outDf.mean_horizontal()
|
||||
outDf = outDf.insert_column(1, means)
|
||||
outDf = outDf[['weekday', 'mean']]
|
||||
|
||||
result = {"scraping-date": scrapeDate, "weekdays": outDf['weekday'].to_list(),'capacities': outDf['mean'].to_list()}
|
||||
etl_cache.saveObj(file, result)
|
||||
return result
|
|
@ -1,138 +0,0 @@
|
|||
from datetime import date, datetime, timedelta
|
||||
from io import StringIO
|
||||
|
||||
import polars as pl
|
||||
|
||||
import data
|
||||
from data import etl_cache
|
||||
|
||||
d = data.load()
|
||||
|
||||
def region_movingAverage(id: int, scrape_date_start_min: str):
|
||||
|
||||
file = f"etl_region_movingAverage_{id}_{scrape_date_start_min}.obj"
|
||||
obj = etl_cache.openObj(file)
|
||||
if obj:
|
||||
return obj
|
||||
|
||||
# Settings
|
||||
# Offset between actual and predict ScrapeDate
|
||||
timeOffset = 30
|
||||
|
||||
# Calculation Frame
|
||||
calcFrame = 180
|
||||
|
||||
# Filter Setting
|
||||
windowSize = 7
|
||||
|
||||
|
||||
# Get unique ScrapeDates
|
||||
uniqueScrapeDates = d.unique_scrapeDates().pl()
|
||||
uniqueScrapeDates = uniqueScrapeDates.get_column('ScrapeDate').str.to_date()
|
||||
uniqueScrapeDates = uniqueScrapeDates.sort().to_list()
|
||||
|
||||
# String to Date
|
||||
scrape_date_start_min = datetime.strptime(scrape_date_start_min, '%Y-%m-%d')
|
||||
|
||||
# Get end date of start search-window
|
||||
scrape_date_start_max = scrape_date_start_min + timedelta(days=1)
|
||||
|
||||
# Get start and end date of End search-window
|
||||
scrape_date_end_min = scrape_date_start_min + timedelta(days=timeOffset)
|
||||
|
||||
# Get closest ScrapeDate
|
||||
scrape_date_end_min = min(uniqueScrapeDates, key=lambda x: abs(x - scrape_date_end_min.date()))
|
||||
scrape_date_end_max = scrape_date_end_min + timedelta(days=1)
|
||||
|
||||
final_end_date = scrape_date_end_min + timedelta(days=calcFrame)
|
||||
|
||||
# Get Data
|
||||
if id == -1:
|
||||
ex_start = d.singleScrape_of_global(scrape_date_start_min, scrape_date_start_max)
|
||||
ex_start_count = ex_start.shape[0]
|
||||
|
||||
ex_end = d.singleScrape_of_global(scrape_date_end_min, scrape_date_end_max)
|
||||
ex_end_count = ex_end.shape[0]
|
||||
else:
|
||||
ex_start = d.singleScrape_of_region(id, scrape_date_start_min, scrape_date_start_max)
|
||||
ex_start_count = ex_start.shape[0]
|
||||
|
||||
ex_end = d.singleScrape_of_region(id, scrape_date_end_min, scrape_date_end_max)
|
||||
ex_end_count = ex_end.shape[0]
|
||||
|
||||
num_properties = [ex_start_count, ex_end_count]
|
||||
start_end = [ex_start, ex_end]
|
||||
outDFList = []
|
||||
|
||||
for df in start_end:
|
||||
df = df.pl()
|
||||
firstExe = True
|
||||
counter = 1
|
||||
outDF = pl.DataFrame(schema={"0": int, "dates": date})
|
||||
for row in df.rows(named=True):
|
||||
if row['calendarBody']:
|
||||
calDF = pl.read_json(StringIO(row['calendarBody']))
|
||||
columnTitles = calDF.columns
|
||||
calDF = calDF.transpose()
|
||||
calDF = calDF.with_columns(pl.Series(name="dates", values=columnTitles))
|
||||
calDF = calDF.with_columns((pl.col("dates").str.to_date()))
|
||||
|
||||
# Filter out all Data that's in the calculation frame
|
||||
calDF = calDF.filter((pl.col("dates") >= scrape_date_end_min))
|
||||
calDF = calDF.filter((pl.col("dates") < final_end_date))
|
||||
|
||||
# Join all information into one Dataframe
|
||||
if firstExe:
|
||||
outDF = calDF
|
||||
firstExe = False
|
||||
else:
|
||||
outDF = outDF.join(calDF, on='dates')
|
||||
outDF = outDF.rename({'column_0': str(counter)})
|
||||
counter += 1
|
||||
|
||||
outDF = outDF.sort('dates')
|
||||
outDFList.append(outDF)
|
||||
|
||||
# Calculate the horizontal Sum for all Dates
|
||||
arrayCunter = 0
|
||||
tempDFList = []
|
||||
for df in outDFList:
|
||||
dates = df.select(pl.col("dates"))
|
||||
values = df.select(pl.exclude("dates"))
|
||||
sum_hor = values.sum_horizontal()
|
||||
|
||||
sum_hor = sum_hor / num_properties[arrayCunter] / 2 * 100
|
||||
arrayCunter += 1
|
||||
|
||||
newDF = dates.with_columns(sum_hor=pl.Series(sum_hor))
|
||||
tempDFList.append(newDF)
|
||||
|
||||
# Join actual and predict Values
|
||||
outDF = tempDFList[1].join(tempDFList[0], on='dates', how='outer')
|
||||
|
||||
# Rename Columns for clarity
|
||||
outDF = outDF.drop_nulls()
|
||||
outDF = outDF.drop('dates_right')
|
||||
|
||||
# sum_hor_predict is the data from the earlier ScrapeDate
|
||||
outDF = outDF.rename({'sum_hor': 'sum_hor_actual', 'sum_hor_right': 'sum_hor_predict'})
|
||||
|
||||
# Calculate Moving average from Start
|
||||
baseValues = outDF.get_column('sum_hor_predict').to_list()
|
||||
i = 0
|
||||
moving_averages = []
|
||||
while i < len(baseValues) - windowSize + 1:
|
||||
window = baseValues[i: i + windowSize]
|
||||
window_average = sum(window) / windowSize
|
||||
moving_averages.append(window_average)
|
||||
i += 1
|
||||
|
||||
# Add empty values back to the front and end of moving_averages
|
||||
num_empty = int(windowSize / 2)
|
||||
moving_averages = [None] *num_empty + moving_averages + [None] * num_empty
|
||||
|
||||
# Add moving_averages to df
|
||||
outDF = outDF.with_columns(moving_averages=pl.Series(moving_averages))
|
||||
result = {'dates':outDF.get_column('dates').to_list(), 'cap_earlierTimeframe':outDF.get_column('sum_hor_predict').to_list(), 'cap_laterTimeframe':outDF.get_column('sum_hor_actual').to_list(), 'movAvg':outDF.get_column('moving_averages').to_list(),}
|
||||
etl_cache.saveObj(file, result)
|
||||
return result
|
|
@ -1,64 +0,0 @@
|
|||
from io import StringIO
|
||||
|
||||
import polars as pl
|
||||
|
||||
import data
|
||||
from data import etl_cache
|
||||
|
||||
d = data.load()
|
||||
|
||||
def region_properties_capacities(id: int):
|
||||
|
||||
file = f"etl_region_properties_capacities_{id}.obj"
|
||||
obj = etl_cache.openObj(file)
|
||||
if obj:
|
||||
return obj
|
||||
|
||||
# Get Data
|
||||
if id == -1:
|
||||
df = d.capacity_global().pl()
|
||||
else:
|
||||
df = d.capacity_of_region(id).pl()
|
||||
# turn PropertyIDs to ints for sorting
|
||||
df = df.cast({"property_id": int})
|
||||
|
||||
# Get uniques for dates and propIDs and sort them
|
||||
listOfDates = df.get_column("ScrapeDate").unique().sort()
|
||||
listOfPropertyIDs = df.get_column("property_id").unique().sort()
|
||||
|
||||
# Create DFs from lists to merge later
|
||||
datesDF = pl.DataFrame(listOfDates).with_row_index("date_index")
|
||||
propIdDF = pl.DataFrame(listOfPropertyIDs).with_row_index("prop_index")
|
||||
|
||||
# Merge Dataframe to generate indices
|
||||
df = df.join(datesDF, on='ScrapeDate')
|
||||
df = df.join(propIdDF, on='property_id')
|
||||
|
||||
# Calculate grid values
|
||||
gridData = pl.DataFrame(schema=[("scrape_date", pl.String), ("property_id", pl.String), ("sum_hor", pl.Int64)])
|
||||
for row in df.rows(named=True):
|
||||
# Return 0 for sum if calendar is null
|
||||
if row['calendarBody']:
|
||||
calDF = pl.read_json(StringIO(row['calendarBody']))
|
||||
sum_hor = calDF.sum_horizontal()[0]
|
||||
else:
|
||||
sum_hor = 0
|
||||
|
||||
gridData = gridData.vstack(pl.DataFrame({"scrape_date" : row['ScrapeDate'], "property_id": str(row['property_id']), "sum_hor": sum_hor}))
|
||||
|
||||
# get the overall maximum sum
|
||||
maxValue = gridData['sum_hor'].max()
|
||||
values = []
|
||||
|
||||
for row in gridData.rows(named=True):
|
||||
capacity = (row['sum_hor']*100)/maxValue
|
||||
values.append((row['scrape_date'], row['property_id'], capacity))
|
||||
|
||||
# Cast listOfDates to datetime
|
||||
listOfDates = listOfDates.cast(pl.Date).to_list()
|
||||
listOfPropertyIDs = listOfPropertyIDs.cast(pl.String).to_list()
|
||||
|
||||
# Create JSON
|
||||
outDict = {'scrapeDates': listOfDates, 'property_ids': listOfPropertyIDs, 'values': values}
|
||||
etl_cache.saveObj(file, outDict)
|
||||
return outDict
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,22 @@
|
|||
import polars as pl
|
||||
|
||||
import data
|
||||
|
||||
inst = data.load()
|
||||
test = inst.extractions_for(1).pl()
|
||||
|
||||
out = test.with_columns(
|
||||
pl.col("calendar").str.extract_all(r"([0-9]{4}-[0-9]{2}-[0-9]{2})|[0-2]").alias("extracted_nrs"),
|
||||
)
|
||||
out.drop(['calendar', 'property_id'])
|
||||
ll = out.get_column("extracted_nrs").explode().gather_every(2)
|
||||
llo = out.get_column("extracted_nrs").explode().gather_every(2, offset=1)
|
||||
lli = ll.list.concat(llo)
|
||||
|
||||
|
||||
print(ll)
|
||||
print(lli)
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,121 +0,0 @@
|
|||
from etl.src import data
|
||||
import json
|
||||
import polars as pl
|
||||
from datetime import datetime
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
|
||||
'''
|
||||
# Get Data from DB
|
||||
inst = data.load()
|
||||
|
||||
df = inst.extractions_with_region().pl()
|
||||
print(df)
|
||||
|
||||
counter = 0
|
||||
data = []
|
||||
for row in df.iter_rows():
|
||||
property_id = row[1]
|
||||
created_at = row[2].date()
|
||||
dict = {'property_id': property_id, 'created_at': created_at, 'name': row[3]}
|
||||
|
||||
jsonStr = row[0]
|
||||
if jsonStr:
|
||||
calendarDict = json.loads(jsonStr)
|
||||
for key in calendarDict:
|
||||
dict[key] = calendarDict[key]
|
||||
|
||||
data.append(dict)
|
||||
|
||||
dfNew = pl.from_dicts(data)
|
||||
dfNew.write_csv('results/data_quality.csv')
|
||||
print(dfNew)
|
||||
|
||||
'''
|
||||
dfNew = pl.read_csv('results/data_quality.csv')
|
||||
dfNew = dfNew.with_columns(pl.col("created_at").map_elements(lambda x: datetime.strptime(x, "%Y-%m-%d").date()))
|
||||
|
||||
# Create Row Means
|
||||
dfTemp = dfNew
|
||||
# Temporary Remove leading columns but save for later
|
||||
prop = dfTemp.get_column('property_id')
|
||||
dfTemp = dfTemp.drop('property_id')
|
||||
crea = dfTemp.get_column('created_at')
|
||||
dfTemp = dfTemp.drop('created_at')
|
||||
name = dfTemp.get_column('name')
|
||||
dfTemp = dfTemp.drop('name')
|
||||
dfTemp = dfTemp.with_columns(sum=pl.sum_horizontal(dfTemp.columns))
|
||||
sumCol = dfTemp.get_column('sum')
|
||||
|
||||
# Create new DF with only property_id, created_at ,Location name and sum
|
||||
df = pl.DataFrame([prop, crea, name, sumCol])
|
||||
df = df.sort('created_at')
|
||||
|
||||
# Create Full Copy
|
||||
# 0 = Alles
|
||||
# 1 = Heidiland
|
||||
# 2 = Davos
|
||||
# 3 = Engadin
|
||||
# 4 = St. Moritz
|
||||
filterList = ['Alle Regionen', 'Heidiland', 'Davos', 'Engadin', 'St. Moritz']
|
||||
|
||||
filter = 4
|
||||
if filter != 0:
|
||||
df = df.filter(pl.col("name") == filter)
|
||||
|
||||
# Remove Location name
|
||||
df = df.drop('name')
|
||||
|
||||
|
||||
# Get unique property_ids
|
||||
propsIDs = df.unique(subset=["property_id"])
|
||||
propsIDs = propsIDs.get_column("property_id").to_list()
|
||||
propsIDs.sort()
|
||||
|
||||
# create Matrix
|
||||
matrix = []
|
||||
for id in propsIDs:
|
||||
dict = {}
|
||||
temp = df.filter(pl.col("property_id") == id)
|
||||
for row in temp.iter_rows():
|
||||
dict[row[1].strftime('%Y-%m-%d')] = row[2]
|
||||
matrix.append(dict)
|
||||
|
||||
matrix = pl.DataFrame(matrix)
|
||||
dates = matrix.columns
|
||||
matrix = matrix.to_numpy()
|
||||
# normalized
|
||||
matrix = matrix/1111
|
||||
|
||||
|
||||
yRange = range(len(dates))
|
||||
xRange = range(len(propsIDs))
|
||||
matrix = matrix.T
|
||||
plt.imshow(matrix)
|
||||
plt.yticks(yRange[::5], dates[::5])
|
||||
plt.xticks(xRange[::10], propsIDs[::10])
|
||||
plt.title(filterList[filter])
|
||||
plt.xlabel("Property ID")
|
||||
plt.ylabel("Scrape Date")
|
||||
plt.colorbar()
|
||||
plt.tight_layout()
|
||||
|
||||
# Create DiffMatrix
|
||||
diffMatrix = np.zeros((len(matrix)-1, len(matrix[0])))
|
||||
for y in range(len(matrix[0])):
|
||||
for x in range(len(matrix)-1):
|
||||
diffMatrix[x][y] = abs(matrix[x][y] - matrix[x+1][y])
|
||||
|
||||
plt.figure()
|
||||
plt.imshow(diffMatrix, cmap="Reds")
|
||||
plt.yticks(yRange[::5], dates[::5])
|
||||
plt.xticks(xRange[::10], propsIDs[::10])
|
||||
plt.title(filterList[filter])
|
||||
plt.xlabel("Property ID")
|
||||
plt.ylabel("Scrape Date")
|
||||
plt.colorbar()
|
||||
plt.tight_layout()
|
||||
|
||||
plt.show()
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
|
@ -1,115 +1,34 @@
|
|||
from etl.src import data
|
||||
from etl.src.data import etl_pipelines as ep
|
||||
import data
|
||||
from data import etl_pipelines as ep
|
||||
import polars as pl
|
||||
from datetime import datetime, timedelta
|
||||
import pandas as pd
|
||||
|
||||
|
||||
'''
|
||||
# Get Data from DB
|
||||
#Create Data
|
||||
inst = data.load()
|
||||
|
||||
df = inst.extractions().pl()
|
||||
df = ep.expansion_Pipeline(df)
|
||||
df = ep.liveDates_Pipeline(df)
|
||||
|
||||
df.write_csv('dok/flatDates.csv')
|
||||
df.write_csv('dok/liveDates.csv')
|
||||
print(df)
|
||||
'''
|
||||
'''
|
||||
#Load Data from DF
|
||||
dfLive = pl.read_csv('dok/liveDates.csv')
|
||||
dfFlat = pl.read_csv('dok/flatDates.csv')
|
||||
|
||||
#Load Data
|
||||
df = pl.read_csv('dok/liveDates.csv')
|
||||
|
||||
# Step 1 Get all occupied dates in live data
|
||||
dfLive = dfLive.filter(pl.col("calendar_value") == 0)
|
||||
dfLive = dfLive.with_columns(pl.col("created_at").str.to_date("%Y-%m-%d"))
|
||||
dfLive = dfLive.with_columns(pl.col("calendar_date").str.to_date("%Y-%m-%d"))
|
||||
#print(dfLive)
|
||||
propIds = df.get_column('property_id').unique()
|
||||
|
||||
dfFlat = dfFlat.with_columns(pl.col("created_at").str.to_date("%Y-%m-%d"))
|
||||
dfFlat = dfFlat.with_columns(pl.col("calendar_date").str.to_date("%Y-%m-%d"))
|
||||
|
||||
propIds = dfLive.get_column('property_id').unique()
|
||||
createdAt = dfLive.get_column('created_at').unique()
|
||||
#print(createdAt)
|
||||
|
||||
fullPreorderMatrix = []
|
||||
createdAt = df.get_column('created_at').unique()
|
||||
|
||||
for propId in propIds:
|
||||
curPreorderList = []
|
||||
print("Property ID = " + str(propId))
|
||||
tempPropFlatDf = dfFlat.filter(pl.col("property_id") == propId)
|
||||
tempPropLiveDf = dfLive.filter(pl.col("property_id") == propId)
|
||||
allLiveOccupiedDates = tempPropLiveDf.filter(pl.col("calendar_value") == 0).get_column('created_at')
|
||||
#print("allLiveOccupiedDates = ",allLiveOccupiedDates)
|
||||
for date in allLiveOccupiedDates:
|
||||
calLiveDate = tempPropLiveDf.filter(pl.col("created_at") == date).get_column('calendar_date')[0]
|
||||
#print("Occupied Date = " + str(date), "with Calendar Date =", str(calLiveDate))
|
||||
numOfScrapedPreordered = 0
|
||||
foundLastDate = False
|
||||
for createDate in createdAt:
|
||||
if date > createDate:
|
||||
#print("Finding Flat Date with CreateDate =",createDate, "and Calendar Date =", calLiveDate)
|
||||
tempFlatDf = tempPropFlatDf.filter(pl.col("created_at") == createDate)
|
||||
tempFlatDf = tempFlatDf.filter(pl.col("calendar_date") == calLiveDate)
|
||||
#print("tempLiveDf = ", tempFlatDf)
|
||||
|
||||
calVal = tempFlatDf.get_column('calendar_value')
|
||||
if len(calVal) > 0:
|
||||
if calVal[0] == 0:
|
||||
# Still Occupied
|
||||
if not foundLastDate:
|
||||
numOfScrapedPreordered += 1
|
||||
else:
|
||||
# Found last Date where not occupied
|
||||
foundLastDate = True
|
||||
#print("number of Scrapes already occupied =", numOfScrapedPreordered)
|
||||
#break
|
||||
#else:
|
||||
#print("Skipped: Live Date = ",date, "Flat Date =",createDate)
|
||||
#print(propId, date, numOfScrapedPreordered)
|
||||
curPreorderList.append(numOfScrapedPreordered)
|
||||
if len(curPreorderList) > 0:
|
||||
mean = sum(curPreorderList) / len(curPreorderList)
|
||||
else: mean = 0
|
||||
#fullPreorderMatrix.append([propId, mean, curPreorderList])
|
||||
fullPreorderMatrix.append([propId, mean])
|
||||
|
||||
print(fullPreorderMatrix)
|
||||
fullPreoDF = pl.DataFrame(fullPreorderMatrix,orient="row")
|
||||
fullPreoDF.write_csv('dok/fullPreoDF.csv')
|
||||
print(fullPreoDF)
|
||||
'''
|
||||
|
||||
# Filter Props to locations and calculate Means per location
|
||||
inst = data.load()
|
||||
|
||||
propDf = inst.propIds_with_region().pl()
|
||||
print(propDf)
|
||||
propDf = propDf.select(
|
||||
pl.col("id").cast(pl.Int64),
|
||||
pl.col("seed_id").cast(pl.Int64),
|
||||
)
|
||||
|
||||
preoDF = pl.read_csv('dok/fullPreoDF.csv')
|
||||
preoDF = preoDF.rename({"column_0": "id", "column_1": "meanPreorderScrapeNum"})
|
||||
for createdAt in createdAt:
|
||||
temp = df.filter(pl.col("created_at") == createdAt)
|
||||
temp = temp.filter(pl.col("property_id") == propId)
|
||||
if temp.shape[0] > 0:
|
||||
print(temp.get_column('calendar_value')[0])
|
||||
else:
|
||||
print(0)
|
||||
|
||||
|
||||
merge = preoDF.join(propDf, how='inner', on='id')
|
||||
print(merge)
|
||||
|
||||
print("Global meanPreorderTime = ",round(merge.get_column("meanPreorderScrapeNum").mean()*3,2))
|
||||
|
||||
# 1 = Heidiland
|
||||
heidi = merge.filter(pl.col("seed_id") == 1)
|
||||
print("Heidiland meanPreorderTime = ", round(heidi.get_column("meanPreorderScrapeNum").mean()*3,2))
|
||||
# 2 = Davos
|
||||
Davos = merge.filter(pl.col("seed_id") == 2)
|
||||
print("Davos meanPreorderTime = ", (Davos.get_column("meanPreorderScrapeNum").mean()*3,2))
|
||||
# 3 = Engadin
|
||||
Engadin = merge.filter(pl.col("seed_id") == 3)
|
||||
print("Engadin meanPreorderTime = ", round(Engadin.get_column("meanPreorderScrapeNum").mean()*3,2))
|
||||
# 4 = St. Moritz
|
||||
Moritz = merge.filter(pl.col("seed_id") == 4)
|
||||
print("St. Moritz meanPreorderTime = ", round(Moritz.get_column("meanPreorderScrapeNum").mean()*3,2))
|
||||
#Hier weiter
|
|
@ -21,14 +21,14 @@ LOG_STACK=single
|
|||
LOG_DEPRECATIONS_CHANNEL=null
|
||||
LOG_LEVEL=debug
|
||||
|
||||
# DB_CONNECTION=sqlite
|
||||
DB_CONNECTION=sqlite
|
||||
# DB_HOST=127.0.0.1
|
||||
# DB_PORT=3306
|
||||
# DB_DATABASE=laravel
|
||||
# DB_USERNAME=root
|
||||
# DB_PASSWORD=
|
||||
|
||||
SESSION_DRIVER=file
|
||||
SESSION_DRIVER=database
|
||||
SESSION_LIFETIME=120
|
||||
SESSION_ENCRYPT=false
|
||||
SESSION_PATH=/
|
||||
|
@ -38,7 +38,7 @@ BROADCAST_CONNECTION=log
|
|||
FILESYSTEM_DISK=local
|
||||
QUEUE_CONNECTION=database
|
||||
|
||||
CACHE_STORE=file
|
||||
CACHE_STORE=database
|
||||
CACHE_PREFIX=
|
||||
|
||||
MEMCACHED_HOST=127.0.0.1
|
||||
|
@ -49,11 +49,11 @@ REDIS_PASSWORD=null
|
|||
REDIS_PORT=6379
|
||||
|
||||
MAIL_MAILER=log
|
||||
MAIL_SCHEME=null
|
||||
MAIL_HOST=127.0.0.1
|
||||
MAIL_PORT=2525
|
||||
MAIL_USERNAME=null
|
||||
MAIL_PASSWORD=null
|
||||
MAIL_ENCRYPTION=null
|
||||
MAIL_FROM_ADDRESS="hello@example.com"
|
||||
MAIL_FROM_NAME="${APP_NAME}"
|
||||
|
||||
|
@ -64,5 +64,3 @@ AWS_BUCKET=
|
|||
AWS_USE_PATH_STYLE_ENDPOINT=false
|
||||
|
||||
VITE_APP_NAME="${APP_NAME}"
|
||||
|
||||
FASTAPI_URI=http://localhost:8080
|
|
@ -0,0 +1,66 @@
|
|||
<p align="center"><a href="https://laravel.com" target="_blank"><img src="https://raw.githubusercontent.com/laravel/art/master/logo-lockup/5%20SVG/2%20CMYK/1%20Full%20Color/laravel-logolockup-cmyk-red.svg" width="400" alt="Laravel Logo"></a></p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/laravel/framework/actions"><img src="https://github.com/laravel/framework/workflows/tests/badge.svg" alt="Build Status"></a>
|
||||
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/dt/laravel/framework" alt="Total Downloads"></a>
|
||||
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/v/laravel/framework" alt="Latest Stable Version"></a>
|
||||
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/l/laravel/framework" alt="License"></a>
|
||||
</p>
|
||||
|
||||
## About Laravel
|
||||
|
||||
Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as:
|
||||
|
||||
- [Simple, fast routing engine](https://laravel.com/docs/routing).
|
||||
- [Powerful dependency injection container](https://laravel.com/docs/container).
|
||||
- Multiple back-ends for [session](https://laravel.com/docs/session) and [cache](https://laravel.com/docs/cache) storage.
|
||||
- Expressive, intuitive [database ORM](https://laravel.com/docs/eloquent).
|
||||
- Database agnostic [schema migrations](https://laravel.com/docs/migrations).
|
||||
- [Robust background job processing](https://laravel.com/docs/queues).
|
||||
- [Real-time event broadcasting](https://laravel.com/docs/broadcasting).
|
||||
|
||||
Laravel is accessible, powerful, and provides tools required for large, robust applications.
|
||||
|
||||
## Learning Laravel
|
||||
|
||||
Laravel has the most extensive and thorough [documentation](https://laravel.com/docs) and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework.
|
||||
|
||||
You may also try the [Laravel Bootcamp](https://bootcamp.laravel.com), where you will be guided through building a modern Laravel application from scratch.
|
||||
|
||||
If you don't feel like reading, [Laracasts](https://laracasts.com) can help. Laracasts contains thousands of video tutorials on a range of topics including Laravel, modern PHP, unit testing, and JavaScript. Boost your skills by digging into our comprehensive video library.
|
||||
|
||||
## Laravel Sponsors
|
||||
|
||||
We would like to extend our thanks to the following sponsors for funding Laravel development. If you are interested in becoming a sponsor, please visit the [Laravel Partners program](https://partners.laravel.com).
|
||||
|
||||
### Premium Partners
|
||||
|
||||
- **[Vehikl](https://vehikl.com/)**
|
||||
- **[Tighten Co.](https://tighten.co)**
|
||||
- **[WebReinvent](https://webreinvent.com/)**
|
||||
- **[Kirschbaum Development Group](https://kirschbaumdevelopment.com)**
|
||||
- **[64 Robots](https://64robots.com)**
|
||||
- **[Curotec](https://www.curotec.com/services/technologies/laravel/)**
|
||||
- **[Cyber-Duck](https://cyber-duck.co.uk)**
|
||||
- **[DevSquad](https://devsquad.com/hire-laravel-developers)**
|
||||
- **[Jump24](https://jump24.co.uk)**
|
||||
- **[Redberry](https://redberry.international/laravel/)**
|
||||
- **[Active Logic](https://activelogic.com)**
|
||||
- **[byte5](https://byte5.de)**
|
||||
- **[OP.GG](https://op.gg)**
|
||||
|
||||
## Contributing
|
||||
|
||||
Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions).
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct).
|
||||
|
||||
## Security Vulnerabilities
|
||||
|
||||
If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [taylor@laravel.com](mailto:taylor@laravel.com). All security vulnerabilities will be promptly addressed.
|
||||
|
||||
## License
|
||||
|
||||
The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).
|
|
@ -15,7 +15,7 @@ class User extends Authenticatable
|
|||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var list<string>
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
|
@ -26,7 +26,7 @@ class User extends Authenticatable
|
|||
/**
|
||||
* The attributes that should be hidden for serialization.
|
||||
*
|
||||
* @var list<string>
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $hidden = [
|
||||
'password',
|
|
@ -3,10 +3,7 @@
|
|||
"name": "laravel/laravel",
|
||||
"type": "project",
|
||||
"description": "The skeleton application for the Laravel framework.",
|
||||
"keywords": [
|
||||
"laravel",
|
||||
"framework"
|
||||
],
|
||||
"keywords": ["laravel", "framework"],
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": "^8.2",
|
||||
|
@ -71,4 +68,4 @@
|
|||
},
|
||||
"minimum-stability": "stable",
|
||||
"prefer-stable": true
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -39,10 +39,10 @@ return [
|
|||
|
||||
'smtp' => [
|
||||
'transport' => 'smtp',
|
||||
'scheme' => env('MAIL_SCHEME'),
|
||||
'url' => env('MAIL_URL'),
|
||||
'host' => env('MAIL_HOST', '127.0.0.1'),
|
||||
'port' => env('MAIL_PORT', 2525),
|
||||
'encryption' => env('MAIL_ENCRYPTION', 'tls'),
|
||||
'username' => env('MAIL_USERNAME'),
|
||||
'password' => env('MAIL_PASSWORD'),
|
||||
'timeout' => null,
|
|
@ -1,11 +1,10 @@
|
|||
{
|
||||
"name": "dashboard",
|
||||
"name": "frontend",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"@patternfly/patternfly": "^6.0.0",
|
||||
"@picocss/pico": "^2.0.6",
|
||||
"echarts": "^5.5.1",
|
||||
"leaflet": "^1.9.4"
|
||||
|
@ -443,9 +442,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@jridgewell/gen-mapping": {
|
||||
"version": "0.3.8",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz",
|
||||
"integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==",
|
||||
"version": "0.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
|
||||
"integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
@ -533,12 +532,6 @@
|
|||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/@patternfly/patternfly": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@patternfly/patternfly/-/patternfly-6.1.0.tgz",
|
||||
"integrity": "sha512-w+QazL8NHKkg5j01eotblsswKxQQSYB0CN3yBXQL9ScpHdp/fK8M6TqWbKZNRpf+NqhMxcH/om8eR0N/fDCJqw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@picocss/pico": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@picocss/pico/-/pico-2.0.6.tgz",
|
||||
|
@ -560,9 +553,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||
"version": "4.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.28.1.tgz",
|
||||
"integrity": "sha512-2aZp8AES04KI2dy3Ss6/MDjXbwBzj+i0GqKtWXgw2/Ma6E4jJvujryO6gJAghIRVz7Vwr9Gtl/8na3nDUKpraQ==",
|
||||
"version": "4.27.4",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.27.4.tgz",
|
||||
"integrity": "sha512-2Y3JT6f5MrQkICUyRVCw4oa0sutfAsgaSsb0Lmmy1Wi2y7X5vT9Euqw4gOsCyy0YfKURBg35nhUKZS4mDcfULw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
|
@ -574,9 +567,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm64": {
|
||||
"version": "4.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.28.1.tgz",
|
||||
"integrity": "sha512-EbkK285O+1YMrg57xVA+Dp0tDBRB93/BZKph9XhMjezf6F4TpYjaUSuPt5J0fZXlSag0LmZAsTmdGGqPp4pQFA==",
|
||||
"version": "4.27.4",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.27.4.tgz",
|
||||
"integrity": "sha512-wzKRQXISyi9UdCVRqEd0H4cMpzvHYt1f/C3CoIjES6cG++RHKhrBj2+29nPF0IB5kpy9MS71vs07fvrNGAl/iA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
@ -588,9 +581,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-arm64": {
|
||||
"version": "4.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.28.1.tgz",
|
||||
"integrity": "sha512-prduvrMKU6NzMq6nxzQw445zXgaDBbMQvmKSJaxpaZ5R1QDM8w+eGxo6Y/jhT/cLoCvnZI42oEqf9KQNYz1fqQ==",
|
||||
"version": "4.27.4",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.27.4.tgz",
|
||||
"integrity": "sha512-PlNiRQapift4LNS8DPUHuDX/IdXiLjf8mc5vdEmUR0fF/pyy2qWwzdLjB+iZquGr8LuN4LnUoSEvKRwjSVYz3Q==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
@ -602,9 +595,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-x64": {
|
||||
"version": "4.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.28.1.tgz",
|
||||
"integrity": "sha512-WsvbOunsUk0wccO/TV4o7IKgloJ942hVFK1CLatwv6TJspcCZb9umQkPdvB7FihmdxgaKR5JyxDjWpCOp4uZlQ==",
|
||||
"version": "4.27.4",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.27.4.tgz",
|
||||
"integrity": "sha512-o9bH2dbdgBDJaXWJCDTNDYa171ACUdzpxSZt+u/AAeQ20Nk5x+IhA+zsGmrQtpkLiumRJEYef68gcpn2ooXhSQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
@ -616,9 +609,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-arm64": {
|
||||
"version": "4.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.28.1.tgz",
|
||||
"integrity": "sha512-HTDPdY1caUcU4qK23FeeGxCdJF64cKkqajU0iBnTVxS8F7H/7BewvYoG+va1KPSL63kQ1PGNyiwKOfReavzvNA==",
|
||||
"version": "4.27.4",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.27.4.tgz",
|
||||
"integrity": "sha512-NBI2/i2hT9Q+HySSHTBh52da7isru4aAAo6qC3I7QFVsuhxi2gM8t/EI9EVcILiHLj1vfi+VGGPaLOUENn7pmw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
@ -630,9 +623,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-x64": {
|
||||
"version": "4.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.28.1.tgz",
|
||||
"integrity": "sha512-m/uYasxkUevcFTeRSM9TeLyPe2QDuqtjkeoTpP9SW0XxUWfcYrGDMkO/m2tTw+4NMAF9P2fU3Mw4ahNvo7QmsQ==",
|
||||
"version": "4.27.4",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.27.4.tgz",
|
||||
"integrity": "sha512-wYcC5ycW2zvqtDYrE7deary2P2UFmSh85PUpAx+dwTCO9uw3sgzD6Gv9n5X4vLaQKsrfTSZZ7Z7uynQozPVvWA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
@ -644,9 +637,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
||||
"version": "4.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.28.1.tgz",
|
||||
"integrity": "sha512-QAg11ZIt6mcmzpNE6JZBpKfJaKkqTm1A9+y9O+frdZJEuhQxiugM05gnCWiANHj4RmbgeVJpTdmKRmH/a+0QbA==",
|
||||
"version": "4.27.4",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.27.4.tgz",
|
||||
"integrity": "sha512-9OwUnK/xKw6DyRlgx8UizeqRFOfi9mf5TYCw1uolDaJSbUmBxP85DE6T4ouCMoN6pXw8ZoTeZCSEfSaYo+/s1w==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
|
@ -658,9 +651,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
||||
"version": "4.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.28.1.tgz",
|
||||
"integrity": "sha512-dRP9PEBfolq1dmMcFqbEPSd9VlRuVWEGSmbxVEfiq2cs2jlZAl0YNxFzAQS2OrQmsLBLAATDMb3Z6MFv5vOcXg==",
|
||||
"version": "4.27.4",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.27.4.tgz",
|
||||
"integrity": "sha512-Vgdo4fpuphS9V24WOV+KwkCVJ72u7idTgQaBoLRD0UxBAWTF9GWurJO9YD9yh00BzbkhpeXtm6na+MvJU7Z73A==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
|
@ -672,9 +665,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
||||
"version": "4.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.28.1.tgz",
|
||||
"integrity": "sha512-uGr8khxO+CKT4XU8ZUH1TTEUtlktK6Kgtv0+6bIFSeiSlnGJHG1tSFSjm41uQ9sAO/5ULx9mWOz70jYLyv1QkA==",
|
||||
"version": "4.27.4",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.27.4.tgz",
|
||||
"integrity": "sha512-pleyNgyd1kkBkw2kOqlBx+0atfIIkkExOTiifoODo6qKDSpnc6WzUY5RhHdmTdIJXBdSnh6JknnYTtmQyobrVg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
@ -686,9 +679,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
||||
"version": "4.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.28.1.tgz",
|
||||
"integrity": "sha512-QF54q8MYGAqMLrX2t7tNpi01nvq5RI59UBNx+3+37zoKX5KViPo/gk2QLhsuqok05sSCRluj0D00LzCwBikb0A==",
|
||||
"version": "4.27.4",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.27.4.tgz",
|
||||
"integrity": "sha512-caluiUXvUuVyCHr5DxL8ohaaFFzPGmgmMvwmqAITMpV/Q+tPoaHZ/PWa3t8B2WyoRcIIuu1hkaW5KkeTDNSnMA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
@ -699,24 +692,10 @@
|
|||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
|
||||
"version": "4.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.28.1.tgz",
|
||||
"integrity": "sha512-vPul4uodvWvLhRco2w0GcyZcdyBfpfDRgNKU+p35AWEbJ/HPs1tOUrkSueVbBS0RQHAf/A+nNtDpvw95PeVKOA==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
|
||||
"version": "4.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.28.1.tgz",
|
||||
"integrity": "sha512-pTnTdBuC2+pt1Rmm2SV7JWRqzhYpEILML4PKODqLz+C7Ou2apEV52h19CR7es+u04KlqplggmN9sqZlekg3R1A==",
|
||||
"version": "4.27.4",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.27.4.tgz",
|
||||
"integrity": "sha512-FScrpHrO60hARyHh7s1zHE97u0KlT/RECzCKAdmI+LEoC1eDh/RDji9JgFqyO+wPDb86Oa/sXkily1+oi4FzJQ==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
|
@ -728,9 +707,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
||||
"version": "4.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.28.1.tgz",
|
||||
"integrity": "sha512-vWXy1Nfg7TPBSuAncfInmAI/WZDd5vOklyLJDdIRKABcZWojNDY0NJwruY2AcnCLnRJKSaBgf/GiJfauu8cQZA==",
|
||||
"version": "4.27.4",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.27.4.tgz",
|
||||
"integrity": "sha512-qyyprhyGb7+RBfMPeww9FlHwKkCXdKHeGgSqmIXw9VSUtvyFZ6WZRtnxgbuz76FK7LyoN8t/eINRbPUcvXB5fw==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
|
@ -742,9 +721,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
||||
"version": "4.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.28.1.tgz",
|
||||
"integrity": "sha512-/yqC2Y53oZjb0yz8PVuGOQQNOTwxcizudunl/tFs1aLvObTclTwZ0JhXF2XcPT/zuaymemCDSuuUPXJJyqeDOg==",
|
||||
"version": "4.27.4",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.27.4.tgz",
|
||||
"integrity": "sha512-PFz+y2kb6tbh7m3A7nA9++eInGcDVZUACulf/KzDtovvdTizHpZaJty7Gp0lFwSQcrnebHOqxF1MaKZd7psVRg==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
|
@ -756,9 +735,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
||||
"version": "4.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.28.1.tgz",
|
||||
"integrity": "sha512-fzgeABz7rrAlKYB0y2kSEiURrI0691CSL0+KXwKwhxvj92VULEDQLpBYLHpF49MSiPG4sq5CK3qHMnb9tlCjBw==",
|
||||
"version": "4.27.4",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.27.4.tgz",
|
||||
"integrity": "sha512-Ni8mMtfo+o/G7DVtweXXV/Ol2TFf63KYjTtoZ5f078AUgJTmaIJnj4JFU7TK/9SVWTaSJGxPi5zMDgK4w+Ez7Q==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
@ -770,9 +749,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-musl": {
|
||||
"version": "4.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.28.1.tgz",
|
||||
"integrity": "sha512-xQTDVzSGiMlSshpJCtudbWyRfLaNiVPXt1WgdWTwWz9n0U12cI2ZVtWe/Jgwyv/6wjL7b66uu61Vg0POWVfz4g==",
|
||||
"version": "4.27.4",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.27.4.tgz",
|
||||
"integrity": "sha512-5AeeAF1PB9TUzD+3cROzFTnAJAcVUGLuR8ng0E0WXGkYhp6RD6L+6szYVX+64Rs0r72019KHZS1ka1q+zU/wUw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
@ -784,9 +763,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
||||
"version": "4.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.28.1.tgz",
|
||||
"integrity": "sha512-wSXmDRVupJstFP7elGMgv+2HqXelQhuNf+IS4V+nUpNVi/GUiBgDmfwD0UGN3pcAnWsgKG3I52wMOBnk1VHr/A==",
|
||||
"version": "4.27.4",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.27.4.tgz",
|
||||
"integrity": "sha512-yOpVsA4K5qVwu2CaS3hHxluWIK5HQTjNV4tWjQXluMiiiu4pJj4BN98CvxohNCpcjMeTXk/ZMJBRbgRg8HBB6A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
@ -798,9 +777,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
||||
"version": "4.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.28.1.tgz",
|
||||
"integrity": "sha512-ZkyTJ/9vkgrE/Rk9vhMXhf8l9D+eAhbAVbsGsXKy2ohmJaWg0LPQLnIxRdRp/bKyr8tXuPlXhIoGlEB5XpJnGA==",
|
||||
"version": "4.27.4",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.27.4.tgz",
|
||||
"integrity": "sha512-KtwEJOaHAVJlxV92rNYiG9JQwQAdhBlrjNRp7P9L8Cb4Rer3in+0A+IPhJC9y68WAi9H0sX4AiG2NTsVlmqJeQ==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
|
@ -812,9 +791,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
||||
"version": "4.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.28.1.tgz",
|
||||
"integrity": "sha512-ZvK2jBafvttJjoIdKm/Q/Bh7IJ1Ose9IBOwpOXcOvW3ikGTQGmKDgxTC6oCAzW6PynbkKP8+um1du81XJHZ0JA==",
|
||||
"version": "4.27.4",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.27.4.tgz",
|
||||
"integrity": "sha512-3j4jx1TppORdTAoBJRd+/wJRGCPC0ETWkXOecJ6PPZLj6SptXkrXcNqdj0oclbKML6FkQltdz7bBA3rUSirZug==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
@ -935,9 +914,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.7.9",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz",
|
||||
"integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==",
|
||||
"version": "1.7.8",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.8.tgz",
|
||||
"integrity": "sha512-Uu0wb7KNqK2t5K+YQyVCLM76prD5sRFjKHbJYCP1J7JFGEQ6nN7HWn9+04LAeiJ3ji54lgS/gZCH1oxyrf1SPw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
@ -990,9 +969,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/browserslist": {
|
||||
"version": "4.24.3",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.3.tgz",
|
||||
"integrity": "sha512-1CPmv8iobE2fyRMV97dAcMVegvvWKxmq94hkLiAkUGwKVTyDLw33K+ZxiFrREKmmps4rIw6grcCFCnTMSZ/YiA==",
|
||||
"version": "4.24.2",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz",
|
||||
"integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1010,9 +989,9 @@
|
|||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"caniuse-lite": "^1.0.30001688",
|
||||
"electron-to-chromium": "^1.5.73",
|
||||
"node-releases": "^2.0.19",
|
||||
"caniuse-lite": "^1.0.30001669",
|
||||
"electron-to-chromium": "^1.5.41",
|
||||
"node-releases": "^2.0.18",
|
||||
"update-browserslist-db": "^1.1.1"
|
||||
},
|
||||
"bin": {
|
||||
|
@ -1033,9 +1012,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001689",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001689.tgz",
|
||||
"integrity": "sha512-CmeR2VBycfa+5/jOfnp/NpWPGd06nf1XYiefUvhXFfZE4GkRc9jv+eGPS4nT558WS/8lYCzV8SlANCIPvbWP1g==",
|
||||
"version": "1.0.30001684",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001684.tgz",
|
||||
"integrity": "sha512-G1LRwLIQjBQoyq0ZJGqGIJUXzJ8irpbjHLpVRXDvBEScFJ9b17sgK6vlx0GAJFE21okD7zXl08rRRUfq6HdoEQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1344,9 +1323,9 @@
|
|||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.5.74",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.74.tgz",
|
||||
"integrity": "sha512-ck3//9RC+6oss/1Bh9tiAVFy5vfSKbRHAFh7Z3/eTRkEqJeWgymloShB17Vg3Z4nmDNp35vAd1BZ6CMW4Wt6Iw==",
|
||||
"version": "1.5.66",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.66.tgz",
|
||||
"integrity": "sha512-pI2QF6+i+zjPbqRzJwkMvtvkdI7MjVbSh2g8dlMguDJIXEPw+kwasS1Jl+YGPEBfGVxsVgGUratAKymPdPo2vQ==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
|
@ -1632,9 +1611,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/is-core-module": {
|
||||
"version": "2.16.0",
|
||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.0.tgz",
|
||||
"integrity": "sha512-urTSINYfAYgcbLb0yDQ6egFm6h3Mo1DcF9EkyXSRjjzdHbsulg01qhwWuXdOoUBuTkbQ80KDboXa0vFJ+BDH+g==",
|
||||
"version": "2.15.1",
|
||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz",
|
||||
"integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
@ -1714,9 +1693,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/jiti": {
|
||||
"version": "1.21.7",
|
||||
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz",
|
||||
"integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==",
|
||||
"version": "1.21.6",
|
||||
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz",
|
||||
"integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
|
@ -1724,9 +1703,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/laravel-vite-plugin": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-1.1.1.tgz",
|
||||
"integrity": "sha512-HMZXpoSs1OR+7Lw1+g4Iy/s3HF3Ldl8KxxYT2Ot8pEB4XB/QRuZeWgDYJdu552UN03YRSRNK84CLC9NzYRtncA==",
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-1.0.6.tgz",
|
||||
"integrity": "sha512-B34OqmZc/rV1KvSjst8SsUm/LKHsuDusw8jiZCIhlnTHXbXnK89JUM9pTJuk6E/Vc/1DT2gX7qNfhipak1WS8w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
@ -1737,10 +1716,10 @@
|
|||
"clean-orphaned-assets": "bin/clean.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.0.0 || ^20.0.0 || >=22.0.0"
|
||||
"node": "^18.0.0 || >=20.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vite": "^5.0.0 || ^6.0.0"
|
||||
"vite": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/leaflet": {
|
||||
|
@ -1750,16 +1729,13 @@
|
|||
"license": "BSD-2-Clause"
|
||||
},
|
||||
"node_modules/lilconfig": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",
|
||||
"integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==",
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
|
||||
"integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/antonk52"
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/lines-and-columns": {
|
||||
|
@ -1888,9 +1864,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/node-releases": {
|
||||
"version": "2.0.19",
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
|
||||
"integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==",
|
||||
"version": "2.0.18",
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz",
|
||||
"integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
|
@ -2118,6 +2094,19 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-load-config/node_modules/lilconfig": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz",
|
||||
"integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/antonk52"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-nested": {
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz",
|
||||
|
@ -2227,13 +2216,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/resolve": {
|
||||
"version": "1.22.9",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.9.tgz",
|
||||
"integrity": "sha512-QxrmX1DzraFIi9PxdG5VkRfRwIgjwyud+z/iBwfRRrVmHc+P9Q7u2lSSpQ6bjr2gy5lrqIiU9vb6iAeGf2400A==",
|
||||
"version": "1.22.8",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
|
||||
"integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-core-module": "^2.16.0",
|
||||
"is-core-module": "^2.13.0",
|
||||
"path-parse": "^1.0.7",
|
||||
"supports-preserve-symlinks-flag": "^1.0.0"
|
||||
},
|
||||
|
@ -2256,9 +2245,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
"version": "4.28.1",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.28.1.tgz",
|
||||
"integrity": "sha512-61fXYl/qNVinKmGSTHAZ6Yy8I3YIJC/r2m9feHo6SwVAVcLT5MPwOUFe7EuURA/4m0NR8lXG4BBXuo/IZEsjMg==",
|
||||
"version": "4.27.4",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.27.4.tgz",
|
||||
"integrity": "sha512-RLKxqHEMjh/RGLsDxAEsaLO3mWgyoU6x9w6n1ikAzet4B3gI2/3yP6PWY2p9QzRTh6MfEIXB3MwsOY0Iv3vNrw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
@ -2272,25 +2261,24 @@
|
|||
"npm": ">=8.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rollup/rollup-android-arm-eabi": "4.28.1",
|
||||
"@rollup/rollup-android-arm64": "4.28.1",
|
||||
"@rollup/rollup-darwin-arm64": "4.28.1",
|
||||
"@rollup/rollup-darwin-x64": "4.28.1",
|
||||
"@rollup/rollup-freebsd-arm64": "4.28.1",
|
||||
"@rollup/rollup-freebsd-x64": "4.28.1",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.28.1",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.28.1",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.28.1",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.28.1",
|
||||
"@rollup/rollup-linux-loongarch64-gnu": "4.28.1",
|
||||
"@rollup/rollup-linux-powerpc64le-gnu": "4.28.1",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.28.1",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.28.1",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.28.1",
|
||||
"@rollup/rollup-linux-x64-musl": "4.28.1",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.28.1",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.28.1",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.28.1",
|
||||
"@rollup/rollup-android-arm-eabi": "4.27.4",
|
||||
"@rollup/rollup-android-arm64": "4.27.4",
|
||||
"@rollup/rollup-darwin-arm64": "4.27.4",
|
||||
"@rollup/rollup-darwin-x64": "4.27.4",
|
||||
"@rollup/rollup-freebsd-arm64": "4.27.4",
|
||||
"@rollup/rollup-freebsd-x64": "4.27.4",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.27.4",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.27.4",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.27.4",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.27.4",
|
||||
"@rollup/rollup-linux-powerpc64le-gnu": "4.27.4",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.27.4",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.27.4",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.27.4",
|
||||
"@rollup/rollup-linux-x64-musl": "4.27.4",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.27.4",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.27.4",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.27.4",
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
|
@ -2544,9 +2532,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/tailwindcss": {
|
||||
"version": "3.4.17",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz",
|
||||
"integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==",
|
||||
"version": "3.4.15",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.15.tgz",
|
||||
"integrity": "sha512-r4MeXnfBmSOuKUWmXe6h2CcyfzJCEk4F0pptO5jlnYSIViUkVmsawj80N5h2lO3gwcmSb4n3PuN+e+GC1Guylw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
@ -2559,7 +2547,7 @@
|
|||
"glob-parent": "^6.0.2",
|
||||
"is-glob": "^4.0.3",
|
||||
"jiti": "^1.21.6",
|
||||
"lilconfig": "^3.1.3",
|
||||
"lilconfig": "^2.1.0",
|
||||
"micromatch": "^4.0.8",
|
||||
"normalize-path": "^3.0.0",
|
||||
"object-hash": "^3.0.0",
|
|
@ -15,7 +15,6 @@
|
|||
"vite": "^5.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@patternfly/patternfly": "^6.0.0",
|
||||
"@picocss/pico": "^2.0.6",
|
||||
"echarts": "^5.5.1",
|
||||
"leaflet": "^1.9.4"
|
|
@ -0,0 +1,17 @@
|
|||
article{
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
#extractions{
|
||||
height: 500px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
#test{
|
||||
height: 500px;
|
||||
}
|
||||
|
||||
#capacity,
|
||||
#leaflet{
|
||||
height: 600px;
|
||||
}
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,37 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Document</title>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css">
|
||||
@vite(['resources/css/app.css', 'resources/js/app.js', '/home/gio/Code/ConsultancyProject_2_ETL/frontend/node_modules/leaflet/dist/leaflet.css'])
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<header>Dashboard</header>
|
||||
<main class="container-fluid">
|
||||
<div class="grid">
|
||||
<div class="grid">
|
||||
<article id="leaflet"></article>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid">
|
||||
<div>
|
||||
<article id="capacity"></article>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid">
|
||||
<div>
|
||||
<article id="extractions"></article>
|
||||
</div>
|
||||
<div>
|
||||
<article id="test"></article>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
</body>
|
||||
|
||||
</html>
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::get('/', function () {
|
||||
return view('main');
|
||||
});
|
Loading…
Reference in New Issue