Add chart line to display stock as well as price.

This commit is contained in:
Krzysztof Płaczek
2025-01-26 11:41:42 +01:00
parent 44254ed12a
commit 3705990be1
2 changed files with 69 additions and 19 deletions

View File

@@ -26,9 +26,26 @@ final class ProductController extends BaseController
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);
} }
} }

View File

@@ -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)', label: 'Price (PLN)',
data: [{{ price_list }}], data: {{ price_list|raw }},
yAxisID: 'yPrice',
tension: 0.1,
borderWidth: 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'
},
} }
} }
}); });