Create graphs for hours during the weekday and dates for the year #409

This commit is contained in:
Kendrick Chan 2020-05-21 00:33:32 +08:00
parent 616537d055
commit d63dfcabbd
2 changed files with 184 additions and 68 deletions

View file

@ -5,6 +5,7 @@ namespace App\Controller;
use Doctrine\ORM\Query;
use Doctrine\ORM\QueryBuilder;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
@ -14,6 +15,7 @@ use Catalyst\MenuBundle\Annotation\Menu;
use CrEOF\Spatial\PHP\Types\Geometry\Point;
use DateTime;
use DateInterval;
use App\Entity\JobOrder;
use App\Entity\Hub;
@ -26,6 +28,10 @@ class AnalyticsController extends Controller
*/
public function forecast(EntityManagerInterface $em)
{
$date_start = DateTime::createFromFormat('Y-m-d H:i:s', '2018-01-01 00:00:00');
$date_end = DateTime::createFromFormat('Y-m-d H:i:s', '2020-04-31 23:59:59');
// get hub to analyze
$hub = $em->getRepository(Hub::class)->find(86);
$hub_coord = $hub->getCoordinates();
@ -33,20 +39,130 @@ class AnalyticsController extends Controller
// distance limit in meters
$distance = 5000;
$conn = $em->getConnection();
// create query
// formula to convert to km is 111195 * st_distance
$query = $em->createQuery('select jo from App\\Entity\\JobOrder jo where st_distance(jo.coordinates, point(:lng, :lat)) * 111195 <= :distance_limit and jo.date_schedule >= :date_start and jo.date_schedule <= :date_end');
$query->setParameter('lng', $hub_coord->getLongitude())
->setParameter('lat', $hub_coord->getLatitude())
->setParameter('distance_limit', $distance)
->setParameter('date_start', DateTime::createFromFormat('YmdHis', '20180501000000'))
->setParameter('date_end', DateTime::createFromFormat('YmdHis', '20180531235959'));
$jos = $query->getResult();
$sql = "select id, round(st_distance(coordinates, Point(:lng, :lat)) * 111195) as dist, date_schedule from job_order where st_distance(coordinates, Point(:lng, :lat)) * 111195 <= :distance_limit and date_schedule >= :date_start and date_schedule <= :date_end and status <> 'cancelled' order by date_schedule asc";
// $query = $em->createQuery('select jo from App\\Entity\\JobOrder jo where st_distance(jo.coordinates, point(:lng, :lat)) * 111195 <= :distance_limit and jo.date_schedule >= :date_start and jo.date_schedule <= :date_end');
$stmt = $conn->prepare($sql);
$stmt->bindValue('lng', $hub_coord->getLongitude());
$stmt->bindValue('lat', $hub_coord->getLatitude());
$stmt->bindValue('distance_limit', $distance);
$stmt->bindValue('date_start', $date_start->format('Y-m-d H:i:s'));
$stmt->bindValue('date_end', $date_end->format('Y-m-d H:i:s'));
$stmt->execute();
$jos = $stmt->fetchAll();
error_log(count($jos));
// get 'today'
$today = new DateTime();
$today = DateTime::createFromFormat('Ymd', '20201101');
// initialize counters
$c_weekday = [];
$c_day = [];
// loop through job orders
foreach ($jos as $jo)
{
$date = DateTime::createFromFormat('Y-m-d H:i:s', $jo['date_schedule']);
$year = $date->format('Y');
$month = $date->format('m');
$day = $date->format('d');
$weekday = $date->format('l');
$hour = $date->format('H');
// year day
if (!isset($c_day[$year][$month][$day]))
$c_day[$year][$month][$day] = 0;
$c_day[$year][$month][$day]++;
// weekday
if (!isset($c_weekday[$year][$month][$weekday][$hour]))
$c_weekday[$year][$month][$weekday][$hour] = 0;
$c_weekday[$year][$month][$weekday][$hour]++;
}
error_log(print_r($c_weekday, true));
$res_year = [];
$date_loop = clone $date_start;
for (; $date_loop <= $date_end; $date_loop->add(new DateInterval('P1D')))
{
$year = $date_loop->format('Y');
$month = $date_loop->format('m');
$day = $date_loop->format('d');
$year_field = 'y' . $date_loop->format('Y');
$id = $date_loop->format('m-d');
// NOTE: toss aside feb 29
if ($id == '02-29')
continue;
if (!isset($res_year[$id][$year_field]))
{
$res_year[$id]['date'] = $date_loop->format('M j');
$res_year[$id][$year_field] = 0;
}
if (isset($c_day[$year][$month][$day]))
$res_year[$id][$year_field] = $c_day[$year][$month][$day];
}
// error_log(print_r($res_year, true));
$chart_year = [];
foreach ($res_year as $day => $day_data)
$chart_year[] = $day_data;
// error_log(print_r($chart_year, true));
// error_log(print_r($c_day, true));
$chart_weekday = $this->generateWeekdayData($c_weekday, $today);
error_log(print_r($chart_weekday, true));
$params = [];
$params = [
'data_year' => $chart_year,
'data_weekday' => $chart_weekday,
];
return $this->render('analytics/forecast.html.twig', $params);
}
protected function generateWeekdayData($all_weekday_data, $today)
{
$data = [];
// build hours
$hours = [];
for ($i = 0; $i < 24; $i++)
$hours[] = sprintf('%02d', $i);
$month = $today->format('m');
$weekday = $today->format('l');
$year_data = [];
foreach ($all_weekday_data as $year => $year_data)
{
// go through the hours
foreach ($hours as $hour)
{
$id = $hour + 0;
if (!isset($data[$id]))
$data[$id] = [
'hour' => $hour,
];
// get hour data
if (isset($year_data[$month][$weekday][$hour]))
$data[$id]['y' . $year] = $year_data[$month][$weekday][$hour];
}
}
return $data;
}
}

View file

@ -25,7 +25,10 @@
</div>
</div>
<div id="year-month-chart" style="height: 400px;">
<div id="year-day-chart" style="height: 400px;">
</div>
<div id="month-weekday-chart" style="height: 400px;">
</div>
</div>
</div>
@ -39,70 +42,67 @@
<script src="//www.amcharts.com/lib/4/maps.js"></script>
<script>
// Create chart instance
var chart = am4core.create("year-month-chart", am4charts.XYChart);
// create chart instance
var chart = am4core.create("year-day-chart", am4charts.XYChart);
// Add data
chart.data = [{
"country": "Lithuania",
"litres": 501.9,
"units": 250
}, {
"country": "Czech Republic",
"litres": 301.9,
"units": 222
}, {
"country": "Ireland",
"litres": 201.1,
"units": 170
}, {
"country": "Germany",
"litres": 165.8,
"units": 122
}, {
"country": "Australia",
"litres": 139.9,
"units": 99
}, {
"country": "Austria",
"litres": 128.3,
"units": 85
}, {
"country": "UK",
"litres": 99,
"units": 93
}, {
"country": "Belgium",
"litres": 60,
"units": 50
}, {
"country": "The Netherlands",
"litres": 50,
"units": 42
}];
// add data
chart.data = {{ data_year|json_encode|raw }};
// Create axes
let categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
categoryAxis.dataFields.category = "country";
categoryAxis.title.text = "Countries";
// create axes
var categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
categoryAxis.dataFields.category = "date";
categoryAxis.title.text = "Date";
let valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
valueAxis.title.text = "Litres sold (M)";
var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
valueAxis.title.text = "Orders";
// Create series
var series = chart.series.push(new am4charts.ColumnSeries());
series.dataFields.valueY = "litres";
series.dataFields.categoryX = "country";
series.name = "Sales";
series.columns.template.tooltipText = "Series: {name}\nCategory: {categoryX}\nValue: {valueY}";
series.columns.template.fill = am4core.color("#00ff00"); // fill
// year day
var s2018 = chart.series.push(new am4charts.LineSeries());
s2018.name = "2018";
s2018.stroke = am4core.color("#0000FF");
s2018.strokeWidth = 2;
s2018.dataFields.valueY = "y2018";
s2018.dataFields.categoryX = "date";
var series2 = chart.series.push(new am4charts.LineSeries());
series2.name = "Units";
series2.stroke = am4core.color("#CDA2AB");
series2.strokeWidth = 3;
series2.dataFields.valueY = "units";
series2.dataFields.categoryX = "country";
var s2019 = chart.series.push(new am4charts.LineSeries());
s2019.name = "2019";
s2019.stroke = am4core.color("#FF0000");
s2019.strokeWidth = 2;
s2019.dataFields.valueY = "y2019";
s2019.dataFields.categoryX = "date";
var s2020 = chart.series.push(new am4charts.LineSeries());
s2020.name = "2020";
s2020.stroke = am4core.color("#00FF00");
s2020.strokeWidth = 2;
s2020.dataFields.valueY = "y2020";
s2020.dataFields.categoryX = "date";
//------------------------------------------------------------------------
var chart2 = am4core.create("month-weekday-chart", am4charts.XYChart);
chart2.data = {{ data_weekday|json_encode|raw }};
var xAxis = chart2.xAxes.push(new am4charts.CategoryAxis());
xAxis.dataFields.category = "hour";
xAxis.title.text = "Hour";
var yAxis = chart2.yAxes.push(new am4charts.ValueAxis());
yAxis.title.text = "Orders";
var l2018 = chart2.series.push(new am4charts.LineSeries());
l2018.name = "2018";
l2018.stroke = am4core.color("#0000FF");
l2018.strokeWidth = 2;
l2018.dataFields.valueY = "y2018";
l2018.dataFields.categoryX = "hour";
var l2019 = chart2.series.push(new am4charts.LineSeries());
l2019.name = "2019";
l2019.stroke = am4core.color("#FF0000");
l2019.strokeWidth = 3;
l2019.dataFields.valueY = "y2019";
l2019.dataFields.categoryX = "hour";
</script>
{% endblock %}