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");
}
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}");

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{
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:
"chart1 chart1 chart2 chart2"
"chart1 chart1 chart6 chart6"
"chart1 chart1 chart3 chart4"
"chart6 chart6 chart3 chart4"
"chart6 chart6 timeline timeline";
"chart1 chart1 chart3 chart4"
"chart1 chart1 timeline timeline";
}
article{

View File

@ -19,7 +19,7 @@
</article>
<article class="header" style="grid-area: chart6;">
<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>
<div id="chart-prediction"></div>
</article>
@ -105,7 +105,7 @@ const cCapacityOptions = {
xAxis: {
type: 'category',
boundaryGap: false,
data: {!! json_encode($regionCapacities[1]['dates']) !!},
data: {!! json_encode($regionCapacities['region']['dates']) !!},
name: 'Zeitpunkt Scraping',
nameLocation: 'center',
nameGap: 24,
@ -117,7 +117,7 @@ const cCapacityOptions = {
type: 'value',
min: 0,
max: 100,
name: 'Auslastung in Prozent',
name: 'Auslastung in %',
nameLocation: 'center',
nameGap: 38,
nameTextStyle: {
@ -128,24 +128,108 @@ const cCapacityOptions = {
name: 'Auslastung alle Regionen',
type: 'line',
symbolSize: 7,
data: {!! json_encode($regionCapacities[0]['capacities']) !!}
data: {!! json_encode($regionCapacities['all']['capacities']) !!}
},
{
name: 'Auslastung Region',
type: 'line',
symbolSize: 7,
data: {!! json_encode($regionCapacities[1]['capacities']) !!}
data: {!! json_encode($regionCapacities['all']['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: 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 cPrediction = echarts.init(chartPrediction);
const cPredictionOptions = {
timeline: {
show: false,
data: {!! json_encode($regionCapacities['region']['dates']) !!},
axisType: 'time',
replaceMerge: ['graphic', 'series']
},
legend: {
data: ['Moving Average', 'Earlier', 'Later']
show: true
},
tooltip: {
trigger: 'axis',
@ -161,48 +245,79 @@ const cPredictionOptions = {
xAxis: {
type: 'category',
boundaryGap: false,
data: {!! json_encode($prediction['dates']) !!},
name: 'Zeitpunkt Scraping',
nameLocation: 'center',
nameGap: 24,
nameTextStyle: {
fontWeight: 'bold',
}
},
},
yAxis: {
type: 'value',
min: 0,
max: 1,
name: 'Auslastung in Prozent',
max: 100,
name: 'Auslastung in %',
nameLocation: 'center',
nameGap: 38,
nameTextStyle: {
fontWeight: 'bold',
}
},
series: [{
name: 'Moving Average',
type: 'line',
symbolSize: 7,
data: {!! json_encode($prediction['movAvg']) !!}
},
options: [
@foreach ($predictions as $p)
@if($p === null)
{
name: 'Earlier',
type: 'line',
symbolSize: 7,
data: {!! json_encode($prediction['cap_earlierTimeframe']) !!}
graphic: {
elements: [
{
type: 'text',
left: 'center',
top: 'center',
style: {
text: 'Keine Daten für Zeitspanne',
fontSize: 44,
fontWeight: 'bold',
}
}
]
}
},
{
name: 'Later',
type: 'line',
symbolSize: 7,
data: {!! json_encode($prediction['cap_laterTimeframe']) !!}
}]
@else
{
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 = {
@ -284,5 +399,70 @@ const 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>
@endsection

View File

@ -2,6 +2,7 @@
use Illuminate\Support\Facades\Route;
use App\Api;
use App\Chart;
Route::get('/', function () {
@ -20,9 +21,19 @@ Route::get('/', function () {
$propsPerRegionCounts[] = $el['count_properties'];
}
$chartOptions = [
'colors' => Chart::colors()
];
$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) {
@ -92,14 +103,38 @@ 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']];
$regionMovingAverage = Api::regionMovingAverage($id, '2024-04-25');
$regionPropertiesCapacities = Api::regionPropertiesCapacities($id);
$regionCapacitiesRegion = Api::regionCapacities($id);
$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]);
});