Widget:Grafico: differenze tra le versioni
Da WikiLectio.
m test Etichette: Sostituito Annullato |
m test Etichette: Ripristino manuale Annullato |
||
| Riga 1: | Riga 1: | ||
<div style=" | <!-- Widget:Grafico — Grafici domanda/offerta con Chart.js, fino a 4 serie + punto equilibrio opzionale --> | ||
<div id="chart_{{{id}}}" style="width:{{{width|600}}}px;height:{{{height|380}}}px;"> | |||
<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 | |||
}} | |||
--> | |||
Versione delle 15:06, 19 set 2025
<canvas id="canvas_{{{id}}}" width="600" height="380"></canvas>
<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("0,2,4,6,8,10");
var chartTitle = "";
var xTitle = "Quantità di appartamenti";
var yTitle = "Prezzo dell'affitto";
var showLegend = "true".toLowerCase() !== "false";
var responsive = "true".toLowerCase() !== "false";
// Limiti assi opzionali
var yMin = numOrUndef("");
var yMax = numOrUndef("");
var xMin = numOrUndef("");
var xMax = numOrUndef("");
// Serie 1..4
var series = [
{t:"", d:"", ty:"line", c:""},
{t:"", d:"", ty:"line", c:""},
{t:"", d:"", ty:"line", c:""},
{t:"", d:"", ty:"line", c:""}
];
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("");
var eqY = numOrUndef("");
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>