|
|
| Riga 1: |
Riga 1: |
| <!-- Widget:Grafico — Grafici domanda/offerta con Chart.js, fino a 4 serie + punto equilibrio opzionale -->
| | <div style="padding:8px;border:1px solid #ccc;"> |
| <div id="chart_{{{id}}}" style="width:{{{width|600}}}px;height:{{{height|380}}}px;"> | | Widget attivo: {{{id}}} |
| <canvas id="canvas_{{{id}}}" width="{{{width|600}}}" height="{{{height|380}}}"></canvas> | |
| </div> | | </div> |
|
| |
| <!-- Chart.js (CDN) -->
| |
| <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
| |
|
| |
| <script>
| |
| /* ===== Helpers ===== */
| |
| function parseCSVNumbers(str){
| |
| if(!str) return [];
| |
| return str.split(',').map(s=>{
| |
| const n = Number(s.trim());
| |
| return isNaN(n) ? null : n;
| |
| });
| |
| }
| |
| function parseCSVStrings(str){
| |
| if(!str) return [];
| |
| return str.split(',').map(s=>s.trim());
| |
| }
| |
| function colorOrNull(s){ return (s && s.trim()) ? s.trim() : null; }
| |
| function numOrUndef(x){ var n = Number(x); return isNaN(n) ? undefined : n; }
| |
|
| |
| /* ===== Costruzione grafico ===== */
| |
| (function(){
| |
| var id = "{{{id}}}";
| |
| var canvas = document.getElementById("canvas_{{{id}}}");
| |
| if(!canvas){ return; }
| |
| var ctx = canvas.getContext("2d");
| |
|
| |
| // Parametri base
| |
| var labels = parseCSVStrings("{{{labels|0,2,4,6,8,10}}}");
| |
| var chartTitle = "{{{title|}}}";
| |
| var xTitle = "{{{xTitle|Quantità di appartamenti}}}";
| |
| var yTitle = "{{{yTitle|Prezzo dell'affitto}}}";
| |
| var showLegend = "{{{showLegend|true}}}".toLowerCase() !== "false";
| |
| var responsive = "{{{responsive|true}}}".toLowerCase() !== "false";
| |
|
| |
| // Limiti assi opzionali
| |
| var yMin = numOrUndef("{{{yMin|}}}");
| |
| var yMax = numOrUndef("{{{yMax|}}}");
| |
| var xMin = numOrUndef("{{{xMin|}}}");
| |
| var xMax = numOrUndef("{{{xMax|}}}");
| |
|
| |
| // Serie 1..4
| |
| var series = [
| |
| {t:"{{{series1title|}}}", d:"{{{series1data|}}}", ty:"{{{series1type|line}}}", c:"{{{series1color|}}}"},
| |
| {t:"{{{series2title|}}}", d:"{{{series2data|}}}", ty:"{{{series2type|line}}}", c:"{{{series2color|}}}"},
| |
| {t:"{{{series3title|}}}", d:"{{{series3data|}}}", ty:"{{{series3type|line}}}", c:"{{{series3color|}}}"},
| |
| {t:"{{{series4title|}}}", d:"{{{series4data|}}}", ty:"{{{series4type|line}}}", c:"{{{series4color|}}}"}
| |
| ];
| |
|
| |
| var datasets = [];
| |
| series.forEach(function(s){
| |
| if(!s.t || !s.d) return;
| |
| var dataArr = parseCSVNumbers(s.d);
| |
| datasets.push({
| |
| label: s.t,
| |
| data: dataArr,
| |
| type: (s.ty && s.ty.trim()) || 'line',
| |
| fill: false,
| |
| borderColor: colorOrNull(s.c),
| |
| backgroundColor: colorOrNull(s.c),
| |
| tension: 0,
| |
| pointRadius: 2
| |
| });
| |
| });
| |
|
| |
| // Punto di equilibrio opzionale (eqX, eqY)
| |
| var eqX = numOrUndef("{{{eqX|}}}");
| |
| var eqY = numOrUndef("{{{eqY|}}}");
| |
| if(eqX !== undefined && eqY !== undefined){
| |
| datasets.push({
| |
| label: "Equilibrio",
| |
| type: "scatter",
| |
| data: [{x:eqX, y:eqY}],
| |
| showLine: false,
| |
| pointRadius: 5,
| |
| pointHoverRadius: 6,
| |
| borderColor: "#000000",
| |
| backgroundColor: "#000000"
| |
| });
| |
| }
| |
|
| |
| // Se le labels sono numeriche, usa asse X lineare
| |
| var numericLabels = labels.every(function(l){ return !isNaN(Number(l)); });
| |
| var dataConfig = { labels: labels, datasets: datasets };
| |
|
| |
| new Chart(ctx, {
| |
| type: 'line',
| |
| data: dataConfig,
| |
| options: {
| |
| responsive: responsive,
| |
| maintainAspectRatio: false,
| |
| plugins: {
| |
| title: { display: !!chartTitle, text: chartTitle },
| |
| legend: { display: showLegend },
| |
| tooltip: { enabled: true }
| |
| },
| |
| elements: { line: { borderWidth: 2 } },
| |
| scales: {
| |
| x: numericLabels ? {
| |
| type: 'linear',
| |
| title: { display: true, text: xTitle },
| |
| min: xMin, max: xMax
| |
| } : {
| |
| type: 'category',
| |
| title: { display: true, text: xTitle }
| |
| },
| |
| y: {
| |
| title: { display: true, text: yTitle },
| |
| min: yMin, max: yMax,
| |
| beginAtZero: false
| |
| }
| |
| }
| |
| }
| |
| });
| |
| })();
| |
| </script>
| |
|
| |
| <!--
| |
| Documentazione rapida parametri:
| |
|
| |
| Obbligatorio: id
| |
| Opzionali: width, height, title, xTitle, yTitle, showLegend, responsive, xMin, xMax, yMin, yMax
| |
| labels = CSV (es. 0,2,4,6,8,10)
| |
|
| |
| Fino a 4 serie:
| |
| seriesNtitle, seriesNdata (CSV), seriesNtype (line|bar), seriesNcolor (es. #d62728)
| |
|
| |
| Punto equilibrio opzionale:
| |
| eqX=numero, eqY=numero
| |
|
| |
| Esempio minimo:
| |
| {{#widget:Grafico
| |
| | id=test
| |
| | labels=0,2,4,6
| |
| | series1title=Domanda
| |
| | series1data=10,7,4,1
| |
| | series2title=Offerta
| |
| | series2data=0,3,6,9
| |
| }}
| |
| -->
| |