Prediction Charts

main
Giò Diani 2025-01-13 22:50:03 +01:00
parent 18a672a5de
commit cd66207bc7
5 changed files with 272 additions and 34 deletions

View File

@ -74,11 +74,21 @@ class Api
return self::get("/region/{$id}/properties/capacities"); 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 public static function propertyCapacitiesMonthly(int $id, string $date): mixed
{ {
return self::get("/property/{$id}/capacities/monthly/{$date}"); 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 public static function propertyCapacitiesDaily(int $id, string $date): mixed
{ {
return self::get("/property/{$id}/capacities/weekdays/{$date}"); return self::get("/property/{$id}/capacities/weekdays/{$date}");

12
dashboard/app/Chart.php Normal file
View File

@ -0,0 +1,12 @@
<?php
namespace App;
class Chart
{
public static function colors(int $count = 5){
$colors = ['#fff7fb','#ece7f2','#d0d1e6','#a6bddb','#74a9cf','#3690c0','#0570b0','#045a8d','#023858'];
return json_encode($colors);
}
}

View File

@ -186,12 +186,13 @@ body.property main{
body.region main{ body.region main{
grid-template-columns: repeat(4, minmax(10%, 50%)); grid-template-columns: repeat(4, minmax(10%, 50%));
grid-template-rows: repeat(3, 1fr) 4em; grid-template-rows: repeat(4, 1fr) 4em;
grid-template-areas: grid-template-areas:
"chart1 chart1 chart2 chart2" "chart1 chart1 chart2 chart2"
"chart1 chart1 chart6 chart6"
"chart1 chart1 chart3 chart4" "chart1 chart1 chart3 chart4"
"chart6 chart6 chart3 chart4" "chart1 chart1 chart3 chart4"
"chart6 chart6 timeline timeline"; "chart1 chart1 timeline timeline";
} }
article{ article{

View File

@ -19,7 +19,7 @@
</article> </article>
<article class="header" style="grid-area: chart6;"> <article class="header" style="grid-area: chart6;">
<header> <header>
<h2 id="prediction-title">Auslastung Vorhersage</h2> <h2 id="prediction-title">Gleitender Mittelwert für die Auslastung von {{ $region[0]['region_name'] }}</h2>
</header> </header>
<div id="chart-prediction"></div> <div id="chart-prediction"></div>
</article> </article>
@ -105,7 +105,7 @@ const cCapacityOptions = {
xAxis: { xAxis: {
type: 'category', type: 'category',
boundaryGap: false, boundaryGap: false,
data: {!! json_encode($regionCapacities[1]['dates']) !!}, data: {!! json_encode($regionCapacities['region']['dates']) !!},
name: 'Zeitpunkt Scraping', name: 'Zeitpunkt Scraping',
nameLocation: 'center', nameLocation: 'center',
nameGap: 24, nameGap: 24,
@ -117,7 +117,7 @@ const cCapacityOptions = {
type: 'value', type: 'value',
min: 0, min: 0,
max: 100, max: 100,
name: 'Auslastung in Prozent', name: 'Auslastung in %',
nameLocation: 'center', nameLocation: 'center',
nameGap: 38, nameGap: 38,
nameTextStyle: { nameTextStyle: {
@ -128,24 +128,108 @@ const cCapacityOptions = {
name: 'Auslastung alle Regionen', name: 'Auslastung alle Regionen',
type: 'line', type: 'line',
symbolSize: 7, symbolSize: 7,
data: {!! json_encode($regionCapacities[0]['capacities']) !!} data: {!! json_encode($regionCapacities['all']['capacities']) !!}
}, },
{ {
name: 'Auslastung Region', name: 'Auslastung Region',
type: 'line', type: 'line',
symbolSize: 7, symbolSize: 7,
data: {!! json_encode($regionCapacities[1]['capacities']) !!} data: {!! json_encode($regionCapacities['all']['capacities']) !!}
}] }]
}; };
cCapacity.setOption(cCapacityOptions); 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: 0,
bottom: 25,
left: 70,
right: 10
},
xAxis: {
type: 'value',
max: 100
},
yAxis: {
type: 'category',
},
options: [
@foreach ($regionCapacities['region_monthly'] as $m)
{
yAxis: {
data: {!! json_encode($m['months']) !!}
},
series: [{
type: 'bar',
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',
},
grid: {
top: 0,
bottom: 25,
left: 70,
right: 10
},
xAxis: {
type: 'value',
max: 100
},
yAxis: {
type: 'category',
},
options: [
@foreach ($regionCapacities['region_daily'] as $d)
{
yAxis: {
data: {!! json_encode($d['weekdays']) !!}
},
series: [{
type: 'bar',
data: {!! json_encode($d['capacities']) !!}
}]
},
@endforeach
]
};
cCapacityDaily.setOption(cCapacityDailyOptions);
const chartPrediction = document.getElementById('chart-prediction'); const chartPrediction = document.getElementById('chart-prediction');
const cPrediction = echarts.init(chartPrediction); const cPrediction = echarts.init(chartPrediction);
const cPredictionOptions = { const cPredictionOptions = {
timeline: {
show: false,
data: {!! json_encode($regionCapacities['region']['dates']) !!},
axisType: 'time',
replaceMerge: ['graphic', 'series']
},
legend: { legend: {
data: ['Moving Average', 'Earlier', 'Later'] show: true
}, },
tooltip: { tooltip: {
trigger: 'axis', trigger: 'axis',
@ -161,48 +245,79 @@ const cPredictionOptions = {
xAxis: { xAxis: {
type: 'category', type: 'category',
boundaryGap: false, boundaryGap: false,
data: {!! json_encode($prediction['dates']) !!},
name: 'Zeitpunkt Scraping', name: 'Zeitpunkt Scraping',
nameLocation: 'center', nameLocation: 'center',
nameGap: 24, nameGap: 24,
nameTextStyle: { nameTextStyle: {
fontWeight: 'bold', fontWeight: 'bold',
} },
}, },
yAxis: { yAxis: {
type: 'value', type: 'value',
min: 0, min: 0,
max: 1, max: 100,
name: 'Auslastung in Prozent', name: 'Auslastung in %',
nameLocation: 'center', nameLocation: 'center',
nameGap: 38, nameGap: 38,
nameTextStyle: { nameTextStyle: {
fontWeight: 'bold', fontWeight: 'bold',
} }
}, },
series: [{ options: [
name: 'Moving Average', @foreach ($predictions as $p)
type: 'line', @if($p === null)
symbolSize: 7,
data: {!! json_encode($prediction['movAvg']) !!}
},
{ {
name: 'Earlier', graphic: {
type: 'line', elements: [
symbolSize: 7, {
data: {!! json_encode($prediction['cap_earlierTimeframe']) !!} type: 'text',
left: 'center',
top: 'center',
style: {
text: 'Keine Daten für Zeitspanne',
fontSize: 44,
fontWeight: 'bold',
}
}
]
}
}, },
{ @else
name: 'Later', {
type: 'line', graphic: {
symbolSize: 7, elements: []
data: {!! json_encode($prediction['cap_laterTimeframe']) !!} },
}] 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); cPrediction.setOption(cPredictionOptions);
const chartHeatmap = document.getElementById('chart-heatmap'); const chartHeatmap = document.getElementById('chart-heatmap');
const cHeatmap = echarts.init(chartHeatmap); const cHeatmap = echarts.init(chartHeatmap);
const cHeatmapOptions = { const cHeatmapOptions = {
@ -284,5 +399,70 @@ const cHeatmapOptions = {
} }
cHeatmap.setOption(cHeatmapOptions); 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) => {
// 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]
}]
}
}
});
})
cCapacity.on('click', 'series', (e) => {
// Switch to correct calendar in the timeline
cTimeline.dispatchAction({
type: 'timelineChange',
currentIndex: e.dataIndex
});
});
</script> </script>
@endsection @endsection

View File

@ -2,6 +2,7 @@
use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Route;
use App\Api; use App\Api;
use App\Chart;
Route::get('/', function () { Route::get('/', function () {
@ -20,9 +21,19 @@ Route::get('/', function () {
$propsPerRegionCounts[] = $el['count_properties']; $propsPerRegionCounts[] = $el['count_properties'];
} }
$chartOptions = [
'colors' => Chart::colors()
];
$propertiesGeo = Api::propertiesGeo(); $propertiesGeo = Api::propertiesGeo();
return view('overview', ["regions" => $regionBase, "regionPropertiesCapacities" => $regionPropertyCapacities, "geo" => $propertiesGeo, "growth" => $propertiesGrowth, "propsPerRegion" => [json_encode($propsPerRegionId), json_encode($propsPerRegionName), json_encode($propsPerRegionCounts)]]); 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('/property/{id}', function (int $id) { Route::get('/property/{id}', function (int $id) {
@ -92,14 +103,38 @@ Route::get('/region/{id}', function (int $id) {
$regionBaseAll = Api::regionBase(-1); $regionBaseAll = Api::regionBase(-1);
$regionBaseAll[] = ['region_name' => 'Alle Regionen', 'region_id' => -1]; $regionBaseAll[] = ['region_name' => 'Alle Regionen', 'region_id' => -1];
$regionBaseRegion = $id >= 0 ? Api::regionBase($id) : [['region_name' => 'Alle Regionen']]; $regionBaseRegion = $id >= 0 ? Api::regionBase($id) : [['region_name' => 'Alle Regionen']];
$regionMovingAverage = Api::regionMovingAverage($id, '2024-04-25');
$regionPropertiesCapacities = Api::regionPropertiesCapacities($id); $regionPropertiesCapacities = Api::regionPropertiesCapacities($id);
$regionCapacitiesRegion = Api::regionCapacities($id); $regionCapacitiesRegion = Api::regionCapacities($id);
$regionCapacitiesAll = Api::regionCapacities(-1); $regionCapacitiesAll = Api::regionCapacities(-1);
$regionCapacities = [$regionCapacitiesAll, $regionCapacitiesRegion];
return view('region', ['regions' => $regionBaseAll, 'region' => $regionBaseRegion, 'region_id' => $id, 'regionCapacities' => $regionCapacities, 'regionPropertiesCapacities' => $regionPropertiesCapacities, 'prediction' => $regionMovingAverage]); $regionCapacitiesMonthly = [];
$regionCapacitiesDaily = [];
$regionPredictions = [];
foreach ($regionCapacitiesRegion['dates'] as $date) {
$regionCapacitiesMonthly[] = Api::regionCapacitiesMonthly($id, $date);
$regionCapacitiesDaily[] = Api::regionCapacitiesDaily($id, $date);
$regionPredictions[] = Api::regionMovingAverage($id, $date);
}
$regionCapacities = [
'all' => $regionCapacitiesAll,
'region' => $regionCapacitiesRegion,
'region_monthly' => $regionCapacitiesMonthly,
'region_daily' => $regionCapacitiesDaily
];
dump($regionPredictions);
return view('region', [
'regions' => $regionBaseAll,
'region' => $regionBaseRegion,
'region_id' => $id,
'regionCapacities' => $regionCapacities,
'regionPropertiesCapacities' => $regionPropertiesCapacities,
'predictions' => $regionPredictions]);
}); });