Add chart line to display stock as well as price.
This commit is contained in:
@@ -23,12 +23,29 @@ final class ProductController extends BaseController
|
|||||||
'price' => fn($query) => $query->orderBy('created_at', 'desc'),
|
'price' => fn($query) => $query->orderBy('created_at', 'desc'),
|
||||||
'stock' => fn($query) => $query->orderBy('created_at', 'desc'),
|
'stock' => fn($query) => $query->orderBy('created_at', 'desc'),
|
||||||
])->find($productId);
|
])->find($productId);
|
||||||
if(null === $product) {
|
if (null === $product) {
|
||||||
throw $this->createNotFoundException('Product not found');
|
throw $this->createNotFoundException('Product not found');
|
||||||
}
|
}
|
||||||
|
$priceList = $product->price()->pluck('price');
|
||||||
|
$stockList = $product->stock()->pluck('stock');
|
||||||
|
$priceDates = $product->price()->pluck('created_at')->map(fn($date) => $date->format('Y-m-d'))->toArray();
|
||||||
|
$stockDates = $product->stock()->pluck('created_at')->map(fn($date) => $date->format('Y-m-d'))->toArray();
|
||||||
|
|
||||||
$priceList = $product->price()->pluck('price')->implode(',');
|
return $this->render('product.html.twig', [
|
||||||
$priceDates = $product->price()->pluck('created_at')->map(fn($date) => $date->format('Y-m-d'))->implode("','");
|
'product' => $product,
|
||||||
return $this->render('product.html.twig', ['product' => $product, 'price_list' => $priceList, 'price_dates' => $priceDates]);
|
'price_list' => $this->prepareChartData($priceDates, $priceList),
|
||||||
|
'stock_list' => $this->prepareChartData($stockDates, $stockList),
|
||||||
|
'price_dates' => implode("','", $priceDates),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function prepareChartData($set1, $set2): string
|
||||||
|
{
|
||||||
|
$data = [];
|
||||||
|
foreach ($set1 as $key => $value) {
|
||||||
|
$data[] = ['x' => $value, 'y' => $set2[$key]];
|
||||||
|
}
|
||||||
|
$stringData = json_encode($data);
|
||||||
|
return str_replace(['"x"', '"y"'], ['x', 'y'], $stringData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
<nav aria-label="breadcrumb" style="--bs-breadcrumb-divider: '>';" >
|
<nav aria-label="breadcrumb" style="--bs-breadcrumb-divider: '>';" >
|
||||||
<ol class="breadcrumb">
|
<ol class="breadcrumb">
|
||||||
{% for category in product.categories %}
|
{% for category in product.categories %}
|
||||||
<li class="breadcrumb-item" aria-current="page"><a class="breadcrumb-item text-decoration-none" href="{{ path('app_category', {'category': category}) }}">{{ category }}</a></li></li>
|
<li class="breadcrumb-item" aria-current="page"><a class="breadcrumb-item text-decoration-none" href="{{ path('app_category', {'category': category}) }}">{{ category }}</a></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ol>
|
</ol>
|
||||||
</nav>
|
</nav>
|
||||||
@@ -55,26 +55,32 @@
|
|||||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const ctx = document.getElementById('price');
|
const ctx = document.getElementById('price').getContext('2d');
|
||||||
|
|
||||||
new Chart(ctx, {
|
new Chart(ctx, {
|
||||||
type: 'line',
|
type: 'line',
|
||||||
data: {
|
data: {
|
||||||
labels: ['{{ price_dates|raw }}'],
|
labels: ['{{ price_dates|raw }}'],
|
||||||
datasets: [{
|
datasets: [
|
||||||
label: 'Price (PLN)',
|
{
|
||||||
data: [{{ price_list }}],
|
label: 'Price (PLN)',
|
||||||
borderWidth: 1
|
data: {{ price_list|raw }},
|
||||||
}]
|
yAxisID: 'yPrice',
|
||||||
|
tension: 0.1,
|
||||||
|
borderWidth: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Stock (units)',
|
||||||
|
data: {{ stock_list|raw }},
|
||||||
|
yAxisID: 'yStock',
|
||||||
|
tension: 0.1,
|
||||||
|
borderWidth: 1
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
options: {
|
options: {
|
||||||
|
responsive: true,
|
||||||
animation: false,
|
animation: false,
|
||||||
plugins: {
|
|
||||||
title: {
|
|
||||||
display: true,
|
|
||||||
text: 'Price in time'
|
|
||||||
},
|
|
||||||
},
|
|
||||||
scales: {
|
scales: {
|
||||||
x: {
|
x: {
|
||||||
title: {
|
title: {
|
||||||
@@ -82,13 +88,40 @@
|
|||||||
text: 'Date'
|
text: 'Date'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
y: {
|
yPrice: {
|
||||||
|
type: 'linear',
|
||||||
|
position: 'left',
|
||||||
beginAtZero: true,
|
beginAtZero: true,
|
||||||
title: {
|
title: {
|
||||||
display: true,
|
display: true,
|
||||||
text: 'Price'
|
text: 'Price (PLN)'
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
drawOnChartArea: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
yStock: {
|
||||||
|
type: 'linear',
|
||||||
|
position: 'right',
|
||||||
|
beginAtZero: true,
|
||||||
|
title: {
|
||||||
|
display: true,
|
||||||
|
text: 'Stock (units)'
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
drawOnChartArea: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
plugins: {
|
||||||
|
legend: {
|
||||||
|
display: true,
|
||||||
|
position: 'top'
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
display: true,
|
||||||
|
text: 'Price and Stock in time'
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user