366 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			366 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| @extends('base')
 | ||
| @section('body-class', 'overview')
 | ||
| @section('header')
 | ||
| <nav>
 | ||
|   <strong>Start</strong>
 | ||
|   <ul>
 | ||
|     @foreach($regions as $r)
 | ||
|     <li><a href="/region/{{ $r['id'] }}">{{ $r['name'] }}</a></li>
 | ||
|     @endforeach
 | ||
|   </ul>
 | ||
| </nav>
 | ||
| @endsection
 | ||
| @section('main')
 | ||
| <article class="header" style="grid-area: chart1;">
 | ||
|   <header>
 | ||
|     <h2>Verfügbarkeit aller Mietobjekte über gesamten beobachteten Zeitraum</h2>
 | ||
|     <button popovertarget="pop1">
 | ||
|       <span>Erklärungen zum Diagramm</span>
 | ||
|     </button>
 | ||
|     <div popover id="pop1">
 | ||
|       <h2>Verfügbarkeit aller Mietobjekte über gesamten beobachteten Zeitraum</h2>
 | ||
|       <p>
 | ||
|         Das Diagramm zeigt die Verfügbarkeit aller Mietobjekte zu allen beobachteten Zeitpunkten.
 | ||
|       </p>
 | ||
|       <ul>
 | ||
|         <li>X-Achse: Zeitpunkt Beobachtung.</li>
 | ||
|         <li>Y-Achse: Mietobjekte.</li>
 | ||
|         <li>Kategorien: 0% = Das Mietobjekt ist komplett Ausgebucht; 100% = Das Mietobjekt kann zu allen Verfügbaren Daten gebucht werden.</li>
 | ||
|       </ul>
 | ||
| 
 | ||
|       <h3>Berrechnung Verfügbarkeit</h3>
 | ||
|       <p>Die Verfügbarkeit eines Mietobjekt errechnet sich folgendermassen:</p>
 | ||
|       <p class="formula">
 | ||
|         Verfügbarkeit = (100 / (Anzahl Buchungsdaten * 2)) * Summe Status
 | ||
|       </p>
 | ||
|       <ul>
 | ||
|         <li>Status: Jeder verfügbare Kalendertag kann den Status «Nicht Verfügbar» (0), «Verfügbar (kein Anreisetag)» (1) oder «Verfügbar» (2) aufweisen.</li>
 | ||
|         <li>Anzahl Buchungsdaten: Die Summe aller angebotenen Buchungsdaten mit zwei multipliziert (= Alle Buchungdaten haben den Status «Verfügbar»)</li>
 | ||
|       </ul>
 | ||
|     </div>
 | ||
|     <div>
 | ||
|   </header>
 | ||
|   <div id="chart-heatmap"></div>
 | ||
| </article>
 | ||
| <article class="header" style="grid-area: chart2;">
 | ||
|   <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 gefundener Mietobjekte pro Region</h2>
 | ||
|       <p>
 | ||
|         Das Balkendiagramm zeigt die Anzahl jemals gefundener Mietobjekte pro Region.
 | ||
|       </p>
 | ||
|       <ul>
 | ||
|         <li>X-Achse: 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: chart3;">
 | ||
|   <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 Mietobjekte pro Region</h2>
 | ||
|       <p>
 | ||
|         Das Liniendiagramm zeigt die Entwicklung aller jemals gefundener Mietobjekte pro Region.
 | ||
|       </p>
 | ||
|       <ul>
 | ||
|         <li>X-Achse: Zeitpunkt Beobachtung</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: {!! $diagramsOptions['shared']['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 = {!! $diagramsOptions['shared']['extractionDates'] !!};
 | ||
| 
 | ||
| const chartHeatmap = document.getElementById('chart-heatmap');
 | ||
| const cHeatmap = echarts.init(chartHeatmap);
 | ||
| const cHeatmapOptions = {
 | ||
|   animation: false,
 | ||
|   tooltip: {
 | ||
|     position: 'top'
 | ||
|   },
 | ||
|   grid: {
 | ||
|     show: true,
 | ||
|     borderWidth: 1,
 | ||
|     borderColor: '#aaa',
 | ||
|     top: 30,
 | ||
|     right: 45,
 | ||
|     bottom: 70,
 | ||
|     left: 30
 | ||
|   },
 | ||
|   dataZoom: [{
 | ||
|       type: 'slider'
 | ||
|     },
 | ||
|     {
 | ||
|       type: 'slider',
 | ||
|       show: true,
 | ||
|       yAxisIndex: 0,
 | ||
|   }],
 | ||
|   xAxis: {
 | ||
|     show: true,
 | ||
|     name: 'Zeitpunkt Beobachtung',
 | ||
|     type: 'category',
 | ||
|     data: extractionDates,
 | ||
|     splitArea: {
 | ||
|       show: false
 | ||
|     },
 | ||
|     splitArea: {
 | ||
|       show: false
 | ||
|     },
 | ||
|     axisLabel: {
 | ||
|       show: false,
 | ||
|     },
 | ||
|     axisTick: {
 | ||
|         show: false,
 | ||
|     },
 | ||
|     axisLine: {
 | ||
|         show: false,
 | ||
|     },
 | ||
|     nameLocation: 'center',
 | ||
|     nameGap: 10,
 | ||
|     nameTextStyle: {
 | ||
|       fontWeight: 'bold',
 | ||
|     }
 | ||
|   },
 | ||
|   yAxis: {
 | ||
|     show: true,
 | ||
|     type: 'category',
 | ||
|     data: {!! $diagramsOptions['heatmap']['yAxis']['data'] !!},
 | ||
|     splitArea: {
 | ||
|       show: false
 | ||
|     },
 | ||
|     axisTick: {
 | ||
|         show: false,
 | ||
|     },
 | ||
|     axisLine: {
 | ||
|         show: false,
 | ||
|     },
 | ||
|     axisLabel: {
 | ||
|       show: false,
 | ||
|     },
 | ||
|     name: 'Mietobjekte',
 | ||
|     nameLocation: 'center',
 | ||
|     nameGap: 10,
 | ||
|     nameTextStyle: {
 | ||
|       fontWeight: 'bold',
 | ||
|     }
 | ||
|   },
 | ||
|   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: 'Verfügbarkeit',
 | ||
|       type: 'heatmap',
 | ||
|       blurSize: 0,
 | ||
|       data: {!! $diagramsOptions['heatmap']['series']['data'] !!},
 | ||
|       label: {
 | ||
|         show: false
 | ||
|       },
 | ||
|       tooltip: {
 | ||
|         formatter: (data) => {
 | ||
|           return `Kurzzeitmietobjekte-ID: ${data.data[1]}<br />Beobachtungszeitpunkt: ${data.data[0]}<br/>Verfügbarkeit: ${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: {!! $diagramsOptions['propertiesPerRegion']['xAxis']['data'] !!}
 | ||
|   },
 | ||
|   yAxis: {
 | ||
|     type: 'value',
 | ||
|     name: 'Anzahl Mietobjekte',
 | ||
|     nameLocation: 'middle',
 | ||
|     nameGap: 50,
 | ||
|     nameTextStyle: {
 | ||
|       fontWeight: 'bold',
 | ||
|     },
 | ||
|   },
 | ||
|   series: [
 | ||
|     {
 | ||
|       data: {!! $diagramsOptions['propertiesPerRegion']['yAxis']['data'] !!},
 | ||
|       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 cExtractionsOptions = {
 | ||
|   color: sharedOptions.basic.color,
 | ||
|   tooltip: {
 | ||
|     trigger: 'axis'
 | ||
|   },
 | ||
|   legend: {
 | ||
|     show: true
 | ||
|   },
 | ||
|   grid: sharedOptions.basic.grid,
 | ||
|   xAxis: {
 | ||
|     name: 'Zeitpunkt Beobachtung',
 | ||
|     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($diagramsOptions['extractions']['series']['total_all']) !!},
 | ||
|     },
 | ||
|     {
 | ||
|       connectNulls: true,
 | ||
|       name: 'Davos',
 | ||
|       type: 'line',
 | ||
|       data: {!! json_encode($diagramsOptions['extractions']['series']['total_davos']) !!}
 | ||
|     },
 | ||
|     {
 | ||
|       connectNulls: true,
 | ||
|       name: 'Engadin',
 | ||
|       type: 'line',
 | ||
|       data: {!! json_encode($diagramsOptions['extractions']['series']['total_engadin']) !!}
 | ||
|     },
 | ||
|     {
 | ||
|       connectNulls: true,
 | ||
|       name: 'Heidiland',
 | ||
|       type: 'line',
 | ||
|       data: {!! json_encode($diagramsOptions['extractions']['series']['total_heidiland']) !!}
 | ||
|     },
 | ||
|     {
 | ||
|       connectNulls: true,
 | ||
|       name: 'St. Moritz',
 | ||
|       type: 'line',
 | ||
|       data: {!! json_encode($diagramsOptions['extractions']['series']['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');
 | ||
| })
 | ||
| 
 | ||
| 
 | ||
| </script>
 | ||
| @endsection
 | 
