|
|
| Riga 1: |
Riga 1: |
| <includeonly> | | <includeonly> |
| <div id="chartwrap_<!--{$id|escape:'html'}-->" | | <div id="wrap_<!--{$id|escape:'html'}-->" style="padding:8px;border:1px solid #ccc;width:620px;"> |
| style="width:<!--{$width|default:600|escape:'html'}-->px;height:<!--{$height|default:380|escape:'html'}-->px;">
| | <div style="font-size:12px;color:#555;margin-bottom:6px;"> |
| <canvas id="canvas_<!--{$id|escape:'html'}-->" | | Widget Grafico — test base (id: <!--{$id|escape:'html'}-->) |
| width="<!--{$width|default:600|escape:'html'}-->"
| | </div> |
| height="<!--{$height|default:380|escape:'html'}-->"
| | <canvas id="canvas_<!--{$id|escape:'html'}-->" width="600" height="240" style="border:1px solid #ddd;"></canvas> |
| data-id="<!--{$id|escape:'html'}-->"
| | <div id="msg_<!--{$id|escape:'html'}-->" style="font-size:12px;color:#a00;margin-top:6px;"></div> |
| data-title="<!--{$title|escape:'html'}-->"
| |
| data-x-title="<!--{$xTitle|default:'Quantità di appartamenti'|escape:'html'}-->"
| |
| data-y-title="<!--{$yTitle|default:'Prezzo dell\'affitto'|escape:'html'}-->"
| |
| data-labels="<!--{$labels|default:'0,2,4,6,8,10'|escape:'html'}-->"
| |
| data-series1-title="<!--{$series1title|escape:'html'}-->"
| |
| data-series1-data="<!--{$series1data|escape:'html'}-->"
| |
| data-series1-type="<!--{$series1type|default:'line'|escape:'html'}-->"
| |
| data-series1-color="<!--{$series1color|escape:'html'}-->"
| |
| data-series2-title="<!--{$series2title|escape:'html'}-->"
| |
| data-series2-data="<!--{$series2data|escape:'html'}-->"
| |
| data-series2-type="<!--{$series2type|default:'line'|escape:'html'}-->"
| |
| data-series2-color="<!--{$series2color|escape:'html'}-->"
| |
| data-series3-title="<!--{$series3title|escape:'html'}-->"
| |
| data-series3-data="<!--{$series3data|escape:'html'}-->"
| |
| data-series3-type="<!--{$series3type|default:'line'|escape:'html'}-->"
| |
| data-series3-color="<!--{$series3color|escape:'html'}-->"
| |
| data-series4-title="<!--{$series4title|escape:'html'}-->"
| |
| data-series4-data="<!--{$series4data|escape:'html'}-->"
| |
| data-series4-type="<!--{$series4type|default:'line'|escape:'html'}-->"
| |
| data-series4-color="<!--{$series4color|escape:'html'}-->"
| |
| data-eqx="<!--{$eqX|escape:'html'}-->"
| |
| data-eqy="<!--{$eqY|escape:'html'}-->"
| |
| data-show-legend="<!--{$showLegend|default:'true'|escape:'html'}-->"
| |
| data-responsive="<!--{$responsive|default:'true'|escape:'html'}-->"
| |
| data-xmin="<!--{$xMin|escape:'html'}-->"
| |
| data-xmax="<!--{$xMax|escape:'html'}-->"
| |
| data-ymin="<!--{$yMin|escape:'html'}-->"
| |
| data-ymax="<!--{$yMax|escape:'html'}-->"
| |
| ></canvas>
| |
| <div id="chartmsg_<!--{$id|escape:'html'}-->" style="font-size:12px;color:#a00;margin-top:4px;"></div> | |
| </div> | | </div> |
|
| |
|
| Riga 43: |
Riga 13: |
| <script> | | <script> |
| (function(){ | | (function(){ |
| function csvToArray(str){ if(!str) return []; return str.split(',').map(s=>s.trim()); }
| |
| function csvToNum(str){ return csvToArray(str).map(v=>{const n=Number(v); return isNaN(n)?null:n;}); }
| |
| function truthy(s){ return String(s||'').toLowerCase() !== 'false'; }
| |
| function numOrUndef(s){ const n = Number(s); return isNaN(n) ? undefined : n; }
| |
|
| |
| var id = "<!--{$id|escape:'html'}-->"; | | var id = "<!--{$id|escape:'html'}-->"; |
| var c = document.getElementById("canvas_" + id); | | var c = document.getElementById("canvas_" + id); |
| var msg = document.getElementById("chartmsg_" + id); | | var msg = document.getElementById("msg_" + id); |
|
| |
|
| if(!c){ if(msg) msg.textContent = "Canvas non trovato (id="+id+")"; return; } | | if (!c) { if (msg) msg.textContent = "Canvas non trovato (id="+id+")"; return; } |
| if(typeof Chart === "undefined"){ if(msg) msg.textContent = "Chart.js (locale) non caricato: controlla /resources/chart.umd.js"; return; } | | if (typeof Chart === "undefined") { if (msg) msg.textContent = "Chart.js locale non caricato: controlla /resources/chart.umd.js"; return; } |
|
| |
|
| try { | | try { |
| var ds = c.dataset;
| | // Dati DEMO fissi (niente Smarty qui) |
| var labels = csvToArray(ds.labels);
| | var labels = [0, 2, 4, 6, 8, 10]; |
| | | var data1 = [10, 8, 6, 4, 2, 0]; // Domanda |
| // Leggi i data-attributes (camelCase) | | var data2 = [0, 2, 4, 6, 8, 10]; // Offerta |
| var seriesDefs = [ | |
| { t: ds.series1Title, d: ds.series1Data, ty: ds.series1Type, c: ds.series1Color },
| |
| { t: ds.series2Title, d: ds.series2Data, ty: ds.series2Type, c: ds.series2Color },
| |
| { t: ds.series3Title, d: ds.series3Data, ty: ds.series3Type, c: ds.series3Color },
| |
| { t: ds.series4Title, d: ds.series4Data, ty: ds.series4Type, c: ds.series4Color }
| |
| ];
| |
| | |
| var datasets = []; | |
| seriesDefs.forEach(function(s){
| |
| if(s.t && s.d){
| |
| datasets.push({
| |
| label: s.t,
| |
| data: csvToNum(s.d),
| |
| type: (s.ty || 'line'),
| |
| fill: false,
| |
| borderColor: s.c || undefined,
| |
| backgroundColor: s.c || undefined,
| |
| tension: 0,
| |
| pointRadius: 2
| |
| });
| |
| }
| |
| });
| |
| | |
| // Punto di equilibrio opzionale
| |
| var eqx = Number(ds.eqx), eqy = Number(ds.eqy); | |
| if(!isNaN(eqx) && !isNaN(eqy)){
| |
| datasets.push({
| |
| label: 'Equilibrio',
| |
| type: 'scatter',
| |
| data: [{x:eqx, y:eqy}],
| |
| showLine: false,
| |
| pointRadius: 5,
| |
| pointHoverRadius: 6,
| |
| borderColor: '#000', backgroundColor: '#000'
| |
| });
| |
| }
| |
| | |
| var numericLabels = labels.every(function(l){ return !isNaN(Number(l)); });
| |
|
| |
|
| new Chart(c.getContext('2d'), { | | new Chart(c.getContext('2d'), { |
| type: 'line', | | type: 'line', |
| data: { labels: labels, datasets: datasets }, | | data: { |
| | labels: labels, |
| | datasets: [ |
| | { label: 'Domanda', data: data1, fill: false }, |
| | { label: 'Offerta', data: data2, fill: false } |
| | ] |
| | }, |
| options: { | | options: { |
| responsive: truthy(ds.responsive), | | responsive: false, |
| maintainAspectRatio: false,
| |
| plugins: { | | plugins: { |
| title: { display: !!ds.title, text: ds.title }, | | title: { display: true, text: 'Mercato affitti (demo)' }, |
| legend: { display: truthy(ds.showLegend) },
| | legend: { display: true } |
| tooltip: { enabled: true }
| |
| },
| |
| elements: { line: { borderWidth: 2 } },
| |
| scales: {
| |
| x: numericLabels ? {
| |
| type: 'linear',
| |
| title: { display: true, text: ds.xTitle || 'Quantità di appartamenti' },
| |
| min: numOrUndef(ds.xmin), max: numOrUndef(ds.xmax)
| |
| } : {
| |
| type: 'category',
| |
| title: { display: true, text: ds.xTitle || 'Quantità di appartamenti' }
| |
| },
| |
| y: { | |
| title: { display: true, text: ds.yTitle || "Prezzo dell'affitto" },
| |
| min: numOrUndef(ds.ymin), max: numOrUndef(ds.ymax),
| |
| beginAtZero: false
| |
| }
| |
| } | | } |
| } | | } |
| }); | | }); |
|
| |
| if (msg) msg.textContent = ""; | | if (msg) msg.textContent = ""; |
| } catch(e){ | | } catch (e) { |
| if (msg) msg.textContent = "Errore rendering: " + (e && e.message ? e.message : e); | | if (msg) msg.textContent = "Errore rendering: " + (e && e.message ? e.message : e); |
| console.error("[Widget:Grafico] errore:", e); | | console.error("[Widget:Grafico] errore:", e); |